Skip to content

Commit 63bf9f4

Browse files
committed
docs(mcp): the switch-off 404 and the no-service 501 are what a caller with a key or token sees; an anonymous caller gets 401 first
handleMcpRequest now takes its anonymous decision first (ADR-0138 D2), so three published sentences that said the endpoint answers 404 (switch off) or 501 (no service) were false for an anonymous caller, an OAuth-track client before it signs in included. Each now says what both callers see. Claude-Session: https://claude.ai/code/session_01SYEJqDL3NXxrJRBVqaMu9T Co-authored-by: Claude <noreply@anthropic.com>
1 parent a3fba9c commit 63bf9f4

2 files changed

Lines changed: 6 additions & 5 deletions

File tree

‎content/docs/ai/connect-mcp.mdx‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ about the only thing left to do: **connecting a client and proving it works**.
1212

1313
<Callout type="info">
1414
To turn the surface off, set `OS_MCP_SERVER_ENABLED=false` — the endpoint then
15-
returns 404 and the **Connect an Agent** page disappears with it, along with
16-
both its Setup and Account navigation entries. See
15+
returns 404 to a caller with an API key or token (an anonymous caller still gets
16+
401 first, with no OAuth metadata advertised), and the **Connect an Agent** page
17+
disappears with it, along with both its Setup and Account navigation entries. See
1718
[environment variables](/docs/deployment/environment-variables#mcp-server).
1819
</Callout>
1920

@@ -380,8 +381,8 @@ skill and a guided `/objectstack:connect` command.
380381
| **✘ Failed to connect** / `ConnectionRefused` on a server that used to work | The app is not running. Start it — the client reconnects on its own, no need to re-register |
381382
| The server is missing from `/mcp` in a running session | Sessions read MCP config at start — open a new one. If it is still missing, you registered at **local** scope from another directory; re-add with `-s user` |
382383
| `Object 'x' not found` on `query_records` / `get_record` | Wrong object name — pass the API name from `list_objects` in **`objectName`** (`crm_opportunity`, not `opportunity`) |
383-
| `404` on `/api/v1/mcp` | The HTTP surface is disabled — unset `OS_MCP_SERVER_ENABLED` (default is on) |
384-
| `501 Not Implemented` | The MCP plugin isn't part of this build — check your stack's plugins |
384+
| `404` on `/api/v1/mcp` | The HTTP surface is disabled — unset `OS_MCP_SERVER_ENABLED` (default is on). A client with an API key or token sees the `404`; an anonymous client, including an OAuth client before it signs in, sees a plain `401` with no `resource_metadata` in `WWW-Authenticate` |
385+
| `501 Not Implemented` | The MCP plugin isn't part of this build — check your stack's plugins. A client with an API key or token sees the `501`; an anonymous client sees a plain `401` with no `resource_metadata` |
385386
| `mcp` missing from `GET /api/v1/discovery` and no Connect-an-Agent card, but `OS_MCP_SERVER_ENABLED` is on | The same cause as the `501` above, seen from the other side: the surface is *enabled* but not *serveable*, so discovery declines to advertise a route that would 501 rather than over-promising it (`declared === enforced`). Load the MCP plugin — `os serve` / `os dev` do it for you; a host that embeds `@objectstack/rest` directly must add `@objectstack/mcp` itself |
386387
| stdio won't start / boot fails closed | `OS_MCP_STDIO_ENABLED=true` but `OS_MCP_STDIO_API_KEY` is missing, unknown, revoked, or expired — fail-closed by design (ADR-0101). Set a valid `osk_` key; there is no unscoped or `system` fallback |
387388
| `401` on every call | Anonymous or invalid credentials. Interactive clients: complete the browser login (the `WWW-Authenticate` header advertises the OAuth metadata). Headless: check the `osk_` key and header spelling |

‎content/docs/deployment/environment-variables.mdx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ OS_MCP_STDIO_ENABLED=true OS_MCP_STDIO_API_KEY=osk_... os start # start the lo
268268

269269
| Variable | Type | Default | Description |
270270
|:---|:---|:---|:---|
271-
| `OS_MCP_SERVER_ENABLED` | boolean | `true` | The MCP **HTTP** surface (`/api/v1/mcp`) is a core capability and defaults **on**. Set `false` to disable it (endpoint 404s, the Connect-an-Agent page disappears). |
271+
| `OS_MCP_SERVER_ENABLED` | boolean | `true` | The MCP **HTTP** surface (`/api/v1/mcp`) is a core capability and defaults **on**. Set `false` to disable it (the endpoint answers 404 to a caller with an API key or token and 401 to an anonymous one, and the Connect-an-Agent page disappears). |
272272
| `OS_MCP_STDIO_ENABLED` | boolean | `false` | Auto-start the long-lived **stdio** transport at boot. Opt-in and **stricter** than the HTTP surface. **Requires `OS_MCP_STDIO_API_KEY`** — stdio runs as that key's identity with RLS/FLS/tenant applied; if the key is missing or invalid, boot **fails closed** (stdio refuses to start). See ADR-0101. |
273273
| `OS_MCP_STDIO_API_KEY` | string | — | The `osk_...` API key the **stdio** transport runs as. Resolved through the same verify chain as the HTTP/REST surfaces, so reads are scoped to that identity's permissions. Mint one from the **Connect an Agent** page — **Account → Developer** for any signed-in user, **Setup → Connect an Agent** for platform admins — or `POST /api/v1/keys`. For full authority, mint a key on a platform-admin or dedicated **service** identity — there is deliberately no `system`/unscoped bypass. |
274274
| `OS_MCP_SERVER_NAME` | string | `objectstack` | Server name advertised to MCP clients. |

0 commit comments

Comments
 (0)