docs(adr): ADR-0100 — serve-side MCP default wiring; register the MCP tool-execution surface in the authz matrix (#3167) - #3182
Closed
os-zhuang wants to merge 2 commits into
Closed
Conversation
… tool-execution surface in the authz matrix (#3167) #3167 is a decision issue whose #1 (identity admission) is the hard gate: "nothing else proceeds before it." Two findings shaped the response: 1. The issue's premise — "MCPServerPlugin is wired nowhere by default" — is stale against main. MCP is already a default-on core capability (isMcpServerEnabled() default true + serve.ts capability push + the matching route gate), and the HTTP tool surface is already fail-closed on identity (handleMcp 401 for a principal-less caller; buildMcpBridge threads the caller ExecutionContext into callData on every verb; OAuth callers run at the ADR-0090 D10 ceiling∩user intersection). 2. What was genuinely missing is exactly the gate: the MCP tool-execution surface had NO row in the ADR-0096 D4 authz conformance matrix, so "whose ExecutionContext runs a tools/call" lived only in ADR-0096 prose, not as a checked, red-CI-on-regression property. This lands: - ADR-0100 recording the four decisions grounded in the verified state: D1 identity admission (caller-principal posture, registered as the gate), D2 dev/prod boundary is identity + off-switch not a default flip, D3 HTTP-only default with stdio kept explicit-opt-in, D4 bounded default exposure (apiEnabled + ai.exposed). - Two authz-conformance rows: an enforced `mcp-tool-exec-identity` (fail-closed gate + bridge threading) and an experimental `mcp-stdio-resource-read` classifying the ADR-0096 E1 context-less stdio resource read (opt-in, never networked) with its admission requirement — registered honestly, not patched with a discouraged { isSystem: true } literal. - Three source probes pinning both halves of the HTTP admission and the stdio fall-open, so dropping the gate/threading or networking the stdio read trips CI (STALE/UNCLASSIFIED) instead of being an adversarial-review finding. Test-only + docs (packages/qa/dogfood is private) — no runtime behavior change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0155A3k1CMJQb44V4iwTLUcH
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
📓 Docs Drift CheckThis PR changes 1 package(s): 2 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
…3167) Upgrades the `mcp-tool-exec-identity` conformance row from cited-tests-only to a real end-to-end boundary proof (ADR-0096 D4 requires one for an agent/ external-reachable surface). `showcase-mcp-identity.dogfood.test.ts` boots the showcase with MCPServerPlugin registered (via the harness `extraPlugins` — the verify harness boots the plugin set directly, not through the CLI capability push) and asserts on the real in-process HTTP stack: - anonymous POST /mcp (tools/list) → 401 (fail-closed: not 404/501, so the surface IS served and the service IS registered — the denial is identity); - an authenticated member clears the gate (not 401); - GET /mcp/skill → 200 (surface served default-on while tool-exec is gated). Wires it in as the row's `proof:` and adds the row to the test's HIGH_RISK set (so the surface must carry a proof). Adds @objectstack/mcp to the private @objectstack/dogfood dev deps (lockfile updated). Validated locally: `pnpm --filter @objectstack/dogfood test` authz-conformance + showcase-mcp-identity → 10/10 pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0155A3k1CMJQb44V4iwTLUcH
Contributor
Author
|
Superseded by #3202, which already registered the MCP execution-surface identity admission in the ADR-0096 matrix ( Generated by Claude Code |
This was referenced Aug 2, 2026
akarma-synetal
pushed a commit
to akarma-synetal/framework
that referenced
this pull request
Aug 3, 2026
…-ai#4576) * feat(agents): pm-dispatch escalation bar — obvious fixes ship, the maintainer gets a veto window, not a permission gate Maintainer feedback after objectstack-ai#3182 sat waiting for confirmation: obvious problems should just be fixed. Escalation now requires genuine product/ contract divergence with no repo-norm answer, or destructive/irreversible action. Named non-escalation classes act immediately: restore-invariant fixes (dual-version dependency graphs, inert tripwires, unwired gates), sequencing, verification strategy, and dev needs_decision reports that fall into those classes (the PM answers the dev directly). Also records the GitHub body-sanitizer generics trap in the os-dev definition. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012C2cd7tL8QDoZ2QKN3djJ5 * feat(agents): resource discipline for parallel dev agents in one container Maintainer-reported OOM under parallel dispatch. Memory peaks are the build/test phases, so heavy phases serialize on a container-wide flock (/tmp/os-heavy-verify.lock) while editing stays parallel; plus heap caps (NODE_OPTIONS max-old-space-size), scoped --filter builds/tests, capped vitest/turbo workers, and worktree cleanup after the PR is up. PM-side: batch:2 or mode:cloud for build-heavy tasks; OOM-killed agents redispatch alone. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012C2cd7tL8QDoZ2QKN3djJ5 * feat(agents): pm-dispatch scaling — repo sharding for multi-PM, multi-account claims, batch:5 operating point - Multiple PM sessions shard by whole repo, never share one queue (batch independence is only checked within one PM's view; the merge queue is one lane regardless). Scaling order: bigger batch + mode:cloud first, repo shard second, same-queue multi-PM prohibited. - Multiple GitHub accounts (colleagues' Claude Code) simplify claiming: assignee alone disambiguates across accounts; the claim-comment ritual is for sessions within one account. Partition by repo/label with a recorded assignment table. - batch:5 recorded as the maintainer's operating point, riding on the container resource discipline. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012C2cd7tL8QDoZ2QKN3djJ5 --------- Co-authored-by: Claude <noreply@anthropic.com>
akarma-synetal
pushed a commit
to akarma-synetal/framework
that referenced
this pull request
Aug 3, 2026
* feat(agents): pm-dispatch backlog sweep duty + stale-premise triage checks + PID-only process discipline - Step 0: classifying the unlabeled backlog is a standing PM duty — auto-queue concrete/no-risk work, flag design cards and programs for the maintainer, request repair for sanitizer-truncated bodies. - Fetch step now requires reading issue comments and running a stale-premise check against recent main history before dispatch (three same-day cases: objectstack-ai#4525, objectstack-ai#4379, objectstack-ai#4075 step 1). - os-dev resource discipline: never kill by process name; PID-scoped operations only (from the objectstack-ai#3182 agent's pkill disclosure). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012C2cd7tL8QDoZ2QKN3djJ5 * feat(agents): pm-dispatch cross-shard transfer protocol — work crosses shards via the target queue, PMs never do A sharded PM whose task needs a change in another shard's repo files it into the target repo's queue (pm:queue + source line) instead of dispatching across the line; dependencies via Blocked-by, follow-up chores belong to the consuming shard, and anything touching packages/spec transfers to the main-backlog PM. The queue label is the inter-PM channel — no direct PM-to-PM coordination needed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012C2cd7tL8QDoZ2QKN3djJ5 * feat(agents): pm-dispatch shard ownership registry — caretaker mode is explicit, never assumed A registry issue in the main backlog records which session owns which shard; taking over or handing off a shard is a comment there. Unowned shards may be caretaken by the main-backlog PM, but a registered shard ends caretaking immediately — in-flight claimed tasks finish under their claimant, everything else belongs to the new owner. Claim comments state the mode so registry and claims never disagree silently. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012C2cd7tL8QDoZ2QKN3djJ5 --------- Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Decision-issue response to #3167 (default wiring for the serve-side MCP server — identity admission first). #3167 makes decision #1 (identity admission) a hard gate: "nothing else in this issue proceeds before it." This PR lands the decision record and that gate, with an end-to-end proof.
Two findings that shaped the response
The issue's premise is stale against
main. decision: default wiring for the serve-side MCP server (@objectstack/mcp) in dev — identity admission first #3167 saysMCPServerPluginis "wired nowhere by default." Verified againstmain, MCP is already a default-on core capability:isMcpServerEnabled()defaults ON (packages/types/src/env.ts),packages/cli/src/commands/serve.tspushes themcpcapability intoos serve/os devunless opted out, and the dispatcher route gate reads the same helper. The HTTP tool surface is also already fail-closed on identity —handleMcpreturns 401 for a principal-less caller (no dev-admin fallback, no fall-open), andbuildMcpBridgethreads the callerExecutionContextintocallData(..., ec)on every verb (OAuth callers run at the ADR-0090 D10 ceiling∩user intersection).What was genuinely missing is exactly the gate. The MCP tool-execution surface had no row in the ADR-0096 D4 authz conformance matrix — so "whose
ExecutionContextruns atools/call" lived only in ADR-0096 prose, not as a checked, red-CI-on-regression property.What this lands
docs/adr/0100-serve-side-mcp-default-wiring-identity-admission.md— the four decisions grounded in the verified state:user) posture, fail-closed, registered as the gate.OS_MCP_SERVER_ENABLED=falsegates registration and route), not a code-level default flip (an opt-in-for-prod amendment is documented for ratification).os devowns the process; the stdio resource path carries the ADR-0096 E1 context-less read).apiEnabledobjects,sys_*fail-closed, actions only whenai.exposed; metadata-declared exposure is the future story.authz-conformance.matrix.ts— two rows: enforcedmcp-tool-exec-identity(fail-closed 401 gate +buildMcpBridgethreading + OAuth scope gate; now carrying a real dogfoodproofand marked high-risk) and experimentalmcp-stdio-resource-readclassifying the ADR-0096 E1 context-less stdio resource read (opt-in, never networked) with its admission requirement — registered honestly, not patched with a discouraged{ isSystem: true }literal (ADR-0096 D2 retires those; thesystemContext(reason)constructor doesn't exist yet).authz-conformance.test.ts— three source probes pinning both halves of the HTTP admission and the stdio fall-open, so dropping the gate/threading or networking the stdio read trips CI (STALE / UNCLASSIFIED) instead of surfacing in an adversarial review later.showcase-mcp-identity.dogfood.test.ts— the end-to-end proof: boots the showcase withMCPServerPluginregistered and asserts on the real HTTP stack that anonymousPOST /mcp→401 (not 404/501 — the surface is served and the service is registered; the denial is identity), an authenticated member clears the gate, andGET /mcp/skill→200 (served default-on while tool-exec is gated).Scope / safety
Docs + a private test package (
@objectstack/dogfood) only — no runtime behavior change, no changeset. The identity path, OAuth admission (#2698), andai.exposed+ capability action gate are pre-existing and unchanged; this PR registers and proves them. (@objectstack/mcpadded to the dogfood dev deps; lockfile updated.)Validation
Validated locally:
pnpm --filter @objectstack/dogfood testforauthz-conformance+showcase-mcp-identity→ 10/10 pass (7 conformance ratchet + 3 dogfood-boot). The three new probes each match their source anchor exactly once and are a clean bijection with the two rows'covers; theproof:-exists and high-risk assertions pass.Open for ratification
NODE_ENV-aware opt-in-for-prod amendment.Closes #3167 pending ratification of D2.
🤖 Generated with Claude Code