CedarCopilot wants to merge 1 commit into staging from fix/mcp-directory-round3
Live on prod, 0 of 8 surfaces working, 1 day left
Libra found 8 production surfaces on prod but could not judge any of them yet. 8 surfaces had no requests at all. Libra checks hourly for 3 days after each deploy.
Fourth round of fixes against Manufact's Claude/OpenAI app-directory readiness checklist for the public MCP server (apps/server/src/mastra/mcp/external/server.ts), following PR #2831's earlier round.
buildSessionInstructions's purposeSentence told the model to "use these tools whenever a request touches" a long list of subjects , flagged under "descriptions must not recommend overly broad triggering beyond the explicit user intent." Reworded to state what Cedar is and gate on the user's own request actually needing a tool, with an explicit disclaimer against reaching for Cedar merely because a request is adjacent or another tool could help. server.test.ts updated to assert the old phrasing is gone and the new scoped wording is present (mirrors the existing configLoadNote test in the same file). Verified the assembled instructions stay well under the 2KB Claude Code truncation budget (1429 of 2048 bytes for the four fixed notes).
config-read.get-credentials and systems-write's manage_credential_entry/authorizationHeader were already scope-gated to in-app (never reachable at runtime over external MCP), but the schema and description advertised to a client at tools/list time still solicited them , the actual evidence Manufact's review cited.
Built a new, generic, throw-on-mismatch redaction helper , apps/server/src/mastra/mcp/external/external-capability-redaction.ts , the subtractive counterpart to the (now-removed, see Fix #3) injectIntentFields. It can drop enum values, whole param objects, or specific fields/variants out of a nested discriminated union, plus trim matching prose from the description, and it throws if a removal target no longer exists (so a redaction can't silently rot into a no-op).
Applied it to:
config-read: drops get-credentials from the action enum and the whole getCredentials params object.systems-write: drops the entire manage_credential_entry change type (storing a named credential is the secret bag , no non-secret sub-path exists) and trims authorizationHeader off manage_mcp_connection (which does have a legitimate non-secret sub-path: adding a server by URL alone , the "headless account setup over external MCP" case scope-map.ts's own history calls out). update_mcp_connection_settings is untouched (never carried a secret).Important structural finding caught during self-review: the redaction must NOT be applied to the shared FAMILY_TOOLS array in server.ts, because that array is also iterated directly by two genuinely-internal call sites , workflows/chat/harness/mcp-server.ts (the in-app Chat Agent SDK harness) and tools/master-surface.ts (the Master agent family surface) , where get-credentials/manage_credential_entry are legitimate, needed capabilities. The fix is a new pure function, externalFamilyTools(), that applies the redaction only for the external registration path; FAMILY_TOOLS itself is untouched. A regression test locks this in (external-capability-redaction.test.ts's "FAMILY_TOOLS itself... stays un-redacted" suite).
As defense-in-depth, scope-map.ts's systems-write entry moved from a fixed playbook:write scope to an action/type-override family (mirroring config-read): both secret-bearing change.type variants now also require the never-externally-grantable in-app scope, so a stale/cached client that never re-reads the trimmed schema still can't get the call through.
EXTERNAL_TOOL_METADATA titles/comments updated (systems-write's title is now "Manage MCP server connections", reflecting that credential management is gone from this surface).
user_request_summary/is_new_request were injected as REQUIRED fields into every external-MCP tool's schema, and their own `.describe()
| Surface | Requests | Errors | p95 | Users | Verdict |
|---|---|---|---|---|---|
| /api/trpc/admin.documents.writeGuarded | 0 → 0 | 0 → 0 (0%) | not measured | 0 | No traffic No requests recorded since this deploy. |
| execute_tool write-document | 0 → 0 | 0 → 0 (0%) | not measured | 0 | No traffic No requests recorded since this deploy. |
| execute_tool read-document | 0 → 0 | 0 → 0 (0%) | not measured | 0 | No traffic No requests recorded since this deploy. |
| execute_tool list-documents | 0 → 0 | 0 → 0 (0%) | not measured | 0 | No traffic No requests recorded since this deploy. |
| /api/trpc/documents.lastEditors | 0 → 0 | 0 → 0 (0%) | not measured | 0 | No traffic No requests recorded since this deploy. |
| POST /api/trpc/documents.lastEditors | 0 → 0 | 0 → 0 (0%) | not measured | 0 | No traffic No requests recorded since this deploy. |
| /api/trpc/documents.getDoc | 0 → 0 | 0 → 0 (0%) | not measured | 0 | No traffic No requests recorded since this deploy. |
| POST /api/trpc/documents.getDoc | 0 → 0 | 0 → 0 (0%) | not measured | 0 | No traffic No requests recorded since this deploy. |