You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit da22e1d
Browse filesBrowse the repository at this point in the historyBrowse files
fix(runtime): an anonymous caller of `/api/v1/mcp` is answered `401 UNAUTHENTICATED` whatever `OS_MCP_SERVER_ENABLED` or the `mcp` service says
6
+
7
+
Clause-②: no
8
+
9
+
ADR-0138 D2 takes the anonymous decision once per domain, as the domain's first statement. The `/mcp` domain checked the `OS_MCP_SERVER_ENABLED` switch and the `mcp` service before it, so an anonymous caller was answered `404 RESOURCE_NOT_FOUND` with the switch off and `501 NOT_IMPLEMENTED` with no MCP service installed, and learned whether the deployment runs MCP before it was refused. Measured on both hosts, the standalone server (`HonoServerPlugin` with the dispatcher plugin) and a `createHonoApp` host.
10
+
11
+
- An anonymous request on `/api/v1/mcp` (any verb) is now refused `401 UNAUTHENTICATED` first, in every composition. Only the order of the refusals moves: no request that was refused before is accepted.
12
+
- A signed-in caller, or a system principal, keeps the switch's `404` and the service's `501`, in that order.
13
+
- The `401` advertises RFC 9728 resource metadata (`WWW-Authenticate: Bearer … resource_metadata="…"`) only where the resource is served: the switch on, an `mcp` service that can take the request, and an auth service that answers a metadata URL. With the switch off or no service the `401` is the plain API-key one, so it never points a client at a protected resource the deployment does not serve.
fix(lint): `filter-token-unknown` states what the runtime does with an unresolvable filter placeholder: the data engine refuses the query with `FILTER_TOKEN_UNKNOWN` / 400
6
+
7
+
Clause-②: no
8
+
9
+
The finding's message said the value "is sent to the data engine as a literal string, matches no record, and the surface renders empty". The runtime does not do that. The data engine refuses a query that carries an unresolvable placeholder, `FILTER_TOKEN_UNKNOWN` with HTTP 400, rather than compare it as a literal string. The message now reads:
10
+
11
+
```text
12
+
Filter value "{current_user}" is not a resolvable placeholder. The data engine refuses a query that carries it (`FILTER_TOKEN_UNKNOWN`, 400), so the surface never shows the data the filter meant.
13
+
```
14
+
15
+
Unchanged: the rule id, its severity (`error`), the finding's `path`, its `hint` (the `fix:` line), and which values the rule reports. The message's first sentence is unchanged as well. `os explain filter-token-unknown` already stated the refusal and is unchanged.
@@ -380,8 +381,8 @@ skill and a guided `/objectstack:connect` command.
380
381
|**✘ 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 |
381
382
| 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`|
382
383
|`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`|
385
386
|`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 |
386
387
| 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 |
387
388
|`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 |
Copy file name to clipboardExpand all lines: content/docs/deployment/environment-variables.mdx
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -268,7 +268,7 @@ OS_MCP_STDIO_ENABLED=true OS_MCP_STDIO_API_KEY=osk_... os start # start the lo
268
268
269
269
| Variable | Type | Default | Description |
270
270
|:---|:---|:---|:---|
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). |
272
272
|`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. |
273
273
|`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. |
274
274
|`OS_MCP_SERVER_NAME`| string |`objectstack`| Server name advertised to MCP clients. |
0 commit comments