[{"data":1,"prerenderedAt":186},["ShallowReactive",2],{"guide-mcp":3},{"slug":4,"module":5,"group":6,"title":7,"updatedOn":8,"description":9,"intro":10,"sections":13},"mcp","getting-started","Introduction","Connect an agent with MCP","2026-10-19","Create a scoped API key, connect Codex or an SDK client, verify access and troubleshoot the connection.",[11,12],"A finance lead wants Codex to help review the Main Campus ledger without giving it a browser login or access to another organization. She creates an expiring integration key with only the required reads, connects the MCP endpoint and checks the returned workspace identity before requesting any accounting data.","MCP (Model Context Protocol) lets a compatible agent discover tools, read resources and use prompts. Schoolbooks serves stateless Streamable HTTP at \u002Fapi\u002Fv1\u002Fmcp. Every request rechecks the key and live access; the agent cannot choose its own tenant or organization.",[14,35,44,77,85,94,102,113,121,128,161,169],{"id":15,"title":16,"table":17},"choose-connection","Choose Spark or an external agent",{"headings":18,"rows":22},[19,20,21],"Use","Authentication","Start here",[23,27,31],[24,25,26],"Spark inside Schoolbooks","Your signed-in account and current workspace","Open the Spark chat control in the top bar.",[28,29,30],"Codex or another custom-header MCP client","An expiring X-API-Key integration credential","Follow this guide and verify the context resource.",[32,33,34],"An OAuth-only MCP host","Not supported by the current custom-key transport","Use a client that can send custom HTTP headers.",{"id":36,"title":37,"bullets":38,"note":43},"prerequisites","Before you begin",[39,40,41,42],"An active Schoolbooks user, account membership and workspace membership, with permission to manage integration keys.","The intended modules enabled and available under the account subscription.","A compatible Codex installation or MCP SDK client that can send the X-API-Key header.","A deployment containing the MCP endpoint and platform migrations. For local development, run the API at http:\u002F\u002Flocalhost:3001.","Production endpoint: https:\u002F\u002Fapi.schoolbooks.ke\u002Fapi\u002Fv1\u002Fmcp. A published guide or pushed commit does not prove that release is deployed. A 404 means the server or proxy does not expose that path; ask the operator to verify the release and migrations.",{"id":45,"title":46,"steps":47,"figure":54,"paragraphs":75},"create-key","Create a key for the intended workspace",[48,49,50,51,52,53],"Sign in to Schoolbooks with your own account and select the intended organization and workspace.","Open Settings → Security and find API keys. Choose Create API key.","Give it a purpose-specific name, such as Main Campus Codex ledger review, and choose an expiry.","Select only needed permissions. accounts.read and workspaces.read support orientation; add organizations.read or accounting.read when those reads are needed.","For an integration that needs your full available API access, choose Select all. It includes permissions hidden by search; Clear removes the selection. The server still checks every grant against your current workspace access.","Create the key and store the one-time secret in your secret manager. Do not put it in a chat, screenshot, repository, URL or shared document.",{"src":55,"caption":56,"highlights":57},"\u002Fdocs\u002Fmcp-key-permissions.jpg","Select all chose 138 currently available permissions in the local demo form. Clear was then used and the dialog cancelled; no key was issued.",[58,64,69],{"label":59,"x":60,"y":61,"width":62,"height":63},"Select all available user-scoped permissions",62.611,41.501,4.073,3.101,{"label":65,"x":66,"y":67,"width":68,"height":63},"Clear the draft selection",63.371,47.148,2.831,{"label":70,"x":71,"y":72,"width":73,"height":74},"Set an integration purpose before creating a key",33.315,21.096,33.369,3.544,[76],"The key is pinned to its owning user, account, workspace and organization. Its grants do not bypass the owner’s live access. If membership is suspended, access is removed, or the workspace’s organization binding changes, authentication or the requested action fails rather than moving the key into another scope.",{"id":78,"title":79,"paragraphs":80,"code":82},"register-codex","Register the server in Codex",[81],"Run this command to add the hosted endpoint. It registers the URL; it does not configure our required custom authentication header. For local development replace the URL with http:\u002F\u002Flocalhost:3001\u002Fapi\u002Fv1\u002Fmcp.",{"language":83,"text":84},"bash","codex mcp add schoolbooks --url https:\u002F\u002Fapi.schoolbooks.ke\u002Fapi\u002Fv1\u002Fmcp",{"id":86,"title":87,"paragraphs":88,"code":90,"note":93},"configure-header","Configure the API-key header",[89],"Open ~\u002F.codex\u002Fconfig.toml and merge the following into the existing schoolbooks entry. Do not create a second table with the same name. Only the environment variable name belongs in this file; keep the secret itself outside source control.",{"language":91,"text":92},"toml","[mcp_servers.schoolbooks]\nurl = \"https:\u002F\u002Fapi.schoolbooks.ke\u002Fapi\u002Fv1\u002Fmcp\"\nenv_http_headers = { \"X-API-Key\" = \"SCHOOLBOOKS_API_KEY\" }","Do not use --bearer-token-env-var or codex mcp login for this endpoint. Those configure bearer or OAuth authentication; Schoolbooks MCP requires X-API-Key and rejects mixed Authorization credentials.",{"id":95,"title":96,"paragraphs":97,"code":99,"note":101},"supply-secret","Supply the secret and start Codex",[98],"Provide SCHOOLBOOKS_API_KEY through your secret manager or the environment inherited by the Codex process. In a temporary Bash terminal, the following prompts without putting the typed secret into shell history. Start Codex from that same terminal. A desktop application launched elsewhere will not automatically inherit that terminal’s environment.",{"language":83,"text":100},"read -rsp 'Schoolbooks API key: ' SCHOOLBOOKS_API_KEY\nexport SCHOOLBOOKS_API_KEY\ncodex","Do not paste a real key into a command example or a committed configuration. Close the terminal or unset SCHOOLBOOKS_API_KEY when the temporary session is finished.",{"id":103,"title":104,"steps":105,"paragraphs":111},"verify-scope","Verify the connection before reading records",[106,107,108,109,110],"Open \u002Fmcp in Codex and confirm that schoolbooks connected and its tools were discovered.","Ask: “Read schoolbooks:\u002F\u002Fcontext\u002Fcurrent. Show the authorized user, account, workspace, organization and effective permissions. Do not change anything.”","Compare the returned identifiers to the workspace you selected when creating the key. Stop if they are not the intended scope.","Ask the agent to list its available Schoolbooks tools, then use a discovered accounting read to retrieve a small ledger-account or journal-register page.","For a real review, give the reporting period and record reference. Open the source record in Schoolbooks to verify the result.",[112],"A key with accounting.read still needs an enabled Accounting module and the owner’s current permission. An empty tool list can reflect access or entitlement restrictions rather than a broken transport. The orientation prompt explains the connection but cannot grant authority.",{"id":114,"title":115,"paragraphs":116,"code":118},"sdk-client","Connect from a TypeScript SDK client",[117],"Install the official @modelcontextprotocol\u002Fsdk package in your integration project. Set SCHOOLBOOKS_MCP_URL to the complete endpoint URL and SCHOOLBOOKS_API_KEY to the scoped secret. This client initializes the protocol and reads identity before any domain operation.",{"language":119,"text":120},"typescript","import { Client } from '@modelcontextprotocol\u002Fsdk\u002Fclient\u002Findex.js'\nimport { StreamableHTTPClientTransport } from '@modelcontextprotocol\u002Fsdk\u002Fclient\u002FstreamableHttp.js'\n\nconst endpoint = process.env.SCHOOLBOOKS_MCP_URL\nconst apiKey = process.env.SCHOOLBOOKS_API_KEY\nif (!endpoint || !apiKey) throw new Error('Configure MCP URL and API key')\n\nconst client = new Client({ name: 'school-review', version: '1.0.0' })\ntry {\n  await client.connect(new StreamableHTTPClientTransport(new URL(endpoint), {\n    requestInit: { headers: { 'X-API-Key': apiKey } },\n  }))\n  const context = await client.readResource({ uri: 'schoolbooks:\u002F\u002Fcontext\u002Fcurrent' })\n  const discovered = await client.listTools()\n  \u002F\u002F Verify context and use only a discovered tool with its declared schema.\n  \u002F\u002F Treat identity and domain results as private; do not send them to logs.\n} finally {\n  await client.close()\n}",{"id":122,"title":123,"paragraphs":124},"capabilities","What tools can do",[125,126,127],"Tool discovery is filtered by permissions, credential policy, installed modules and subscription. Execution checks the same authoritative policy again. A REST operation is not automatically an MCP tool, and interactive-user access does not imply that an API key may perform the same write.","Remote key management and session-only actions are unavailable. An operation requiring a server-approved human approval cannot be enabled by a prompt, an approved=true argument or an agent approving its own request. Financial posting restrictions remain enforced.","Tools return declared input\u002Foutput schemas. Object outputs remain objects, lists use a records wrapper, and nullable or scalar results use a result wrapper. A tool can report isError even when HTTP returns 200; inspect the tool result before treating an action as complete.",{"id":129,"title":130,"table":131,"note":160},"troubleshooting","Troubleshoot connection and access errors",{"headings":132,"rows":135},[133,134],"Symptom","Check",[136,139,142,145,148,151,154,157],[137,138],"404 at the endpoint","Confirm the complete \u002Fapi\u002Fv1\u002Fmcp path, intended host, deployed release and proxy routing.",[140,141],"401 \u002F MCP_API_KEY_REQUIRED","Set the secret in the environment used to launch the client. Send X-API-Key only; remove Authorization. Check expiry, rotation and revocation.",[143,144],"403 or scope mismatch","Check live membership, permissions, subscription and the pinned organization. Do not add tenant or organization overrides.",[146,147],"Browser Origin rejected","Use a trusted integration or ask the operator to allow the exact required browser origin. Do not disable origin checks.",[149,150],"No domain tool appears","Check the owner’s permissions, key grants, enabled modules and whether that capability supports API keys and MCP.",[152,153],"400 \u002F 406 \u002F 415 with raw HTTP","Use a compatible SDK. Streamable HTTP requires JSON and Accept negotiation for application\u002Fjson and text\u002Fevent-stream.",[155,156],"GET or DELETE returns 405","This stateless endpoint handles MCP through POST. It does not offer a persistent session or standalone GET event stream.",[158,159],"HTTP 200 but a tool failed","Inspect isError and the tool message. Check the source record before retrying a possible mutation.","Credentials and scope selectors are rejected in query strings. Do not add a project_ref, organization ID or API key to the endpoint URL.",{"id":162,"title":163,"steps":164},"rotate-revoke","Rotate, revoke or change scope",[165,166,167,168],"Open Settings → Security → API keys using your signed-in browser session.","To replace a key in the current UI, create another key with the intended scope and permissions. Store its one-time secret, update the integration and verify the connection.","Revoke the old key to end its access after replacing it. For a suspected compromise, revoke it immediately before replacement. Removing a local Codex configuration does not revoke the server-side credential.","For a different workspace or organization, create a separately scoped key in that workspace rather than changing selectors in the client.",{"id":170,"title":171,"references":172,"links":179},"references","References and next steps",[173,176],{"title":174,"href":175},"Official Codex MCP configuration","https:\u002F\u002Fdevelopers.openai.com\u002Fcodex\u002Fmcp",{"title":177,"href":178},"Official MCP TypeScript SDK","https:\u002F\u002Fgithub.com\u002Fmodelcontextprotocol\u002Ftypescript-sdk",[180,183],{"title":181,"slug":182},"Use Spark inside Schoolbooks","spark",{"title":184,"slug":185},"Review accounting setup","accounting-setup",1792394828510]