CedarCopilot wants to merge 1 commit into staging from fix/mcp-acting-session-scope-by-connection
Live on prod, no production signal yet
Strict CloudWatch fallback found 6 prod failure log lines for [processBufferedSlackWebhookEvents] Parked non-recoverable row (No valid connection tokens found for user <id>) in the last 24h while checking mcp-schema, mcp_acting_session_scope_by_connection, acting-session.test.
Since the deploy, 9,208 prod OTEL spans matching POST /mcp JSON-RPC tools/call cedar-staff-debug and subsequent MCP tool calls ran with 63 error spans. In the 40h before the deploy the same surface ran 4,920 OTEL spans with 46 error spans. Confidence is medium because 63 error.
Since the deploy, 9,317 prod OTEL spans matching POST /mcp JSON-RPC tools/call cedar-staff-debug({clear:true}) ran with 63 error spans. In the 41h before the deploy the same surface ran 4,970 OTEL spans with 46 error spans. Confidence is medium because 63 error spans remain at.
Since the deploy, 9,359 prod OTEL spans matching POST /mcp (initialize) ran with 63 error spans. In the 42h before the deploy the same surface ran 5,003 OTEL spans with 46 error spans. Confidence is medium because 63 error spans remain at 0.7% of traffic, under the 1% noise.
Libra has verdicts on 3 of 4 tracked behaviors on prod; 1 is still being checked. Libra has 1 low-confidence degraded verdict it is still confirming. Libra checks hourly for 3 days after each deploy.
mcp_acting_session was keyed by caller_user_id alone, so two Claude Code windows on the same staff account calling cedar-staff-debug against two different users silently overwrote one row with the other , no error, and a guarded-SQL analysis in one window could run against the wrong tenant.external-mcp.ts now mints a Streamable HTTP Mcp-Session-Id for every Cedar-staff caller regardless of the Armature-analytics flag, and acting-session.ts keys every read/write/clear on (caller_user_id, mcp_session_id) instead.cedar-staff-debug's own banner text (it used to claim "only one debug session per staff account can be active" , no longer true) and docs/design/mcp-impersonation.md.DB migration status: apps/server/src/db/migrations/mcp_acting_session_scope_by_connection.sql has already been applied to the shared DB (additive: new mcp_session_id column defaulting to '', PK swapped to the composite). This PR is the matching code , until it deploys, the currently-live server's ON CONFLICT ("caller_user_id") won't match the new composite constraint, so cedar-staff-debug will fail on every call. Please merge/deploy this promptly to close that gap.
pnpm --filter @zero/server exec vitest run src/mastra/mcp/external/__tests__/acting-session.test.ts src/mastra/mcp/external/__tests__/resolve-session.test.ts src/mastra/mcp/external/__tests__/server.test.ts src/mastra/mcp/external/__tests__/tool-call-observability.test.ts src/routes/__tests__/external-mcp.e2e.test.ts , 78 passedpnpm --filter @zero/server run types , clean\d mcp_acting_session): composite PK in place, FKs intact, 0 rows🤖 Generated with Claude Code
https://claude.ai/code/session_016hB3VjDQvdLHTDdQW76z23
This PR scopes Cedar-staff impersonation state by both the authenticated caller and the Streamable HTTP connection ID, updates the database key and tool messaging, and adds focused coverage for the new behavior.
Mcp-Session-Id for Cedar-staff initialization requests.The PR is not yet safe to merge because headerless staff requests can still share an impersonation row and reproduce the wrong-tenant behavior being fixed.
The composite key works when clients consistently echo the issued connection ID, but the server accepts missing IDs and deliberately collapses those requests into a shared caller-wide key; connection-scoped rows also have no eventual cleanup after clients disconnect.
Files Needing Attention: apps/server/src/routes/external-mcp.ts, apps/server/src/mastra/mcp/external/cedar-staff-debug-tool.ts, apps/server/src/mastra/mcp/external/acting-session.ts
A Cedar-staff request without an echoed Mcp-Session-Id is accepted and mapped to the shared empty-string key. Multiple headerless connections on the same staff account can consequently overwrite one another’s impersonation targets and execute tools against an unintended tenant.
| Filename | Overview |
|---|---|
| apps/server/src/routes/external-mcp.ts | Resolves the staff connection ID before server construction, but does not reject later staff requests when that ID is absent. |
| apps/server/src/mastra/mcp/external/acting-session.ts | Correctly applies the composite key throughout, while retaining an unsafe shared fallback and request-driven-only expiry cleanup. |
| apps/server/src/mastra/mcp |
Libra has not measured any production surfaces for this change yet.