Skip to content

feat(mcp)!: stdio transport requires an API-key principal — fail-closed, no unscoped bridge (ADR-0101, #3246)#3253

Merged
os-zhuang merged 2 commits into
mainfrom
claude/mcp-server-default-wiring-ydcj2n
Jul 19, 2026
Merged

feat(mcp)!: stdio transport requires an API-key principal — fail-closed, no unscoped bridge (ADR-0101, #3246)#3253
os-zhuang merged 2 commits into
mainfrom
claude/mcp-server-default-wiring-ydcj2n

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

What & why

实现 ADR-0101 / #3246 v1:关闭平台最后一个无身份执行面——长驻 MCP stdio 传输。此前 record_by_id resource 走裸 dataEngine.findOne(...),无 ExecutionContext → 绕过 RLS/FLS/租户。

改动

  • plugin.ts start():stdio auto-start 时,从 OS_MCP_STDIO_API_KEY与 HTTP/REST 同一条 @objectstack/core 链(resolveStdioExecutionContextresolveAuthzContextresolveApiKeyPrincipal)解析出 caller EC,逐调用重解析后线进 principal-bound 的 record reader。FAIL-CLOSED:无 key / 无 objectql / key 无法解析(unknown|revoked|expired|owner-less)→ 抛错拒启 stdio。system 旁路——满权=mint 一个 admin/service key。
  • mcp-server-runtime.ts bridgeResources:record_by_id 改用 principal-bound getRecord(ql.find(obj,{where:{id},context})),仅在提供 reader 时注册——无裸 fallback。移除裸 IDataEngine 桥。
  • authz 矩阵:mcp-stdio-authority experimentalenforced;探针/bite 从 bridgeResources(unscoped-stdio) 改为 stdio-principal-bound
  • ADR-0101 Proposed → Accepted;env-var 文档新增 OS_MCP_STDIO_API_KEY

身份模型(三方对齐)

stdio 现在与 HTTP 共用同一条 key→EC 链,scope 由该身份权限决定——对齐 MCP 规范(stdio 后端凭据从 env 供给)、Postgres/GitHub MCP server(按凭据 scope)、Anthropic agent-identity(admin 预置 scoped service 身份)。详见 ADR-0101。

验证(本地)

  • @objectstack/mcp 83/83(含 4 个新 fail-closed 用例:无 key / 无 objectql / 无法解析 key 各自拒启;未启用 stdio 则不需 key);
  • dogfood authz-conformance 9/9(矩阵升 enforced + 新探针/bite (g) + baseline sound + proof-file-exists);
  • eslint 干净;turbo build(mcp/verify 闭包,含 tsc)绿。

正向 scope 覆盖说明:驱动真实 stdio 传输进程做进程内 e2e 不现实(会占 stdin/stdout)。scoped 读走的是与 mcp-http-identity(showcase e2e)+ RLS fixtures 完全相同ql.find({context}) 施加路径;key→EC 解析由 core 既有 api-key/authz 测试覆盖;本 PR 新增的是 fail-closed 门的单测。full stdio-transport e2e 列为 v2(spawn-based)。

⚠️ BREAKING(仅 stdio auto-start)

OS_MCP_STDIO_ENABLED=true / autoStart 现在要求 OS_MCP_STDIO_API_KEY;无 key 不再启动(fail-closed)。默认开的 HTTP 面、以及任何不启用 stdio auto-start 的部署,不受影响。changeset 标 @objectstack/mcp minor + body 内注明 breaking——评审时如需 major 可调。

后续(v2,#3246 未阻塞项)

os dev 用 dev-admin 自动 mint 本地 scoped dev key 并打印;命名 service 身份 / 权限集 + key 轮换。

Refs #3246、ADR-0101、#3167、ADR-0096。

🤖 Generated with Claude Code

https://claude.ai/code/session_0115eg8dAaCfWaDYYAm3ma36


Generated by Claude Code

…ed, no unscoped bridge (ADR-0101, #3246)

Closes the platform's last identity-less execution surface: the long-lived MCP
stdio transport, which previously bridged the raw metadata service + data engine
with no ExecutionContext (record_by_id read via dataEngine.findOne, bypassing
RLS/FLS/tenant).

- plugin.ts start(): when stdio auto-start is requested, resolve
  OS_MCP_STDIO_API_KEY through the SAME @objectstack/core chain as HTTP/REST
  (resolveStdioExecutionContext → resolveAuthzContext → resolveApiKeyPrincipal),
  build the caller ExecutionContext, and thread it (re-resolved per call) into a
  principal-bound record reader. FAIL-CLOSED: no key / no objectql / an
  unknown|revoked|expired key throws and refuses to start stdio. No `system`
  bypass — full authority is a minted admin/service key.
- mcp-server-runtime.ts bridgeResources: record_by_id now takes a principal-bound
  getRecord reader (ql.find(obj,{where:{id},context})); registered only when a
  reader is supplied — no unscoped fallback. Dropped the raw IDataEngine bridge.
- authz matrix: mcp-stdio-authority experimental → enforced; probe/bite retargeted
  from bridgeResources(unscoped-stdio) → stdio-principal-bound.
- ADR-0101 Proposed → Accepted; env-var docs add OS_MCP_STDIO_API_KEY.

Tests: mcp 83/83 (4 new fail-closed cases: no key / no objectql / unresolvable
key refuse to start; disabled stdio needs no key); dogfood authz-conformance 9/9.

BREAKING (stdio auto-start only): OS_MCP_STDIO_ENABLED/autoStart now requires
OS_MCP_STDIO_API_KEY; keyless stdio no longer starts. HTTP surface unaffected.

Refs #3246, #3167, ADR-0101, ADR-0096.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0115eg8dAaCfWaDYYAm3ma36
@vercel

vercel Bot commented Jul 19, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
spec Canceled Canceled Jul 19, 2026 6:26am

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling size/m labels Jul 19, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/mcp, packages/qa.

11 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/actions-as-tools.mdx (via @objectstack/mcp)
  • content/docs/ai/agents.mdx (via @objectstack/mcp)
  • content/docs/ai/index.mdx (via @objectstack/mcp)
  • content/docs/ai/natural-language-queries.mdx (via @objectstack/mcp)
  • content/docs/api/index.mdx (via @objectstack/mcp)
  • content/docs/deployment/environment-variables.mdx (via @objectstack/mcp)
  • content/docs/permissions/authorization.mdx (via packages/qa)
  • content/docs/permissions/delegated-administration.mdx (via packages/qa)
  • content/docs/plugins/packages.mdx (via @objectstack/mcp)
  • content/docs/protocol/knowledge.mdx (via @objectstack/mcp)
  • content/docs/releases/implementation-status.mdx (via @objectstack/mcp)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0115eg8dAaCfWaDYYAm3ma36
@os-zhuang
os-zhuang marked this pull request as ready for review July 19, 2026 10:37
@os-zhuang
os-zhuang merged commit 15dbe18 into main Jul 19, 2026
17 checks passed
@os-zhuang
os-zhuang deleted the claude/mcp-server-default-wiring-ydcj2n branch July 19, 2026 10:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants