Libra CodeHub

CedarCopilot/cedar-mail

Branch: staging

fix(mcp): pass Manufact app-directory readiness checks

merged#2831CedarCopilot

CedarCopilot wants to merge 0 commits into staging from fix/mcp-manufact-readiness

Live on prod, watching, 1 day leftTimeline and evidence
  1. Opened
    Sep 19, 2026, 6:40 PM
  2. Merged
    Sep 19, 2026, 7:15 PM
  3. Live on staging
    Sep 19, 2026, 7:15 PM
  4. Live on prod
    Sep 19, 2026, 7:15 PM
  5. Observed 0 hours
    Sep 19, 2026, 7:15 PM
  6. Watching

    Live on prod, watching, 1 day left

    Sep 19, 2026, 7:15 PM
  7. Pipelines steady after this deploy
    Sep 19, 2026, 7:15 PM
  8. Pipelines steady after this deploy
    Sep 19, 2026, 7:15 PM

Behaviors Libra is checking

MCP sessions instruct the agent to load the cedar-configuration skill before Cedar tasks involving configuration, integrations, playbooks, sync behavior, or the data model, or whenever applicability is uncertain, without coercing it on every task.Inconclusivemedium confidence

No matching POST /mcp or MCP-labeled OTEL spans were found in staging for the post-deploy window beginning 2026-09-20T02:15:30Z. Source confirms the changed external MCP server is the stateless handler behind POST /mcp, but the exact runtime instrumentation identifiers could.

staging, checked Sep 21, 2026, 1:07 AM
The deprecated record-message and record-tool-call MCP shims continue accepting arbitrary legacy arguments while opting out of automatic telemetry.agent_thinking and telemetry.user_intent injection.Inconclusivehigh confidence

Since 2026-09-20T02:15:30Z, staging telemetry contains 0 OTEL spans matching /mcp, MCP, record-message, or record-tool-call across both repository-scoped and broader environment queries, and 0 matching CloudWatch API log records in /aws/ecs/aws-staging-api/api-service.

staging, checked Sep 20, 2026, 11:21 AM
MCP sessions instruct agents to call load-skill('cedar-configuration') for tasks involving configuration, integrations, playbooks, sync behavior, or Cedar's data model, or whenever applicability is uncertain, while allowing unrelated tasks to proceed without a forced call.Not checked
prod
The deprecated record-message and record-tool-call MCP shims remain callable with arbitrary legacy payloads without Armature automatically soliciting agent_thinking or user_intent telemetry fields.Not checked
prod

Failures attributed to this change

No prod customers are affected while this is only in staging. If promoted, prod impact is unknown because Libra still needs a concrete exception, route, and failed user action before assigning severity. 0 hits · no retained affected-user count · no retained trace sample.Introducedmedium confidence

internal_only

staging, first seen Sep 19, 2026, 8:22 PM
No prod customers are affected while this is only in staging. If promoted, customer impact is not proven from the retained evidence. 0 hits · no retained affected-user count · no retained trace sample.Introducedmedium confidence

single_user

staging, first seen Sep 20, 2026, 1:15 PM
No prod customers are affected while this is only in staging. If promoted, this likely touches a customer-facing path; Libra should verify the failed user action before escalating. 0 hits · no retained affected-user count · no retained trace sample.Introducedmedium confidence

single_user

staging, first seen Sep 20, 2026, 1:15 PM

Libra has verdicts on 0 of 2 tracked behaviors on prod; 2 are still being checked. Libra checks hourly for 3 days after each deploy.

Summary

Reopens the work from #2828 (closed) on the same branch , all 10 commits carry forward unchanged, plus this description reflects the final state after Greptile's review passes.

Fixes all 7 issues from Manufact's automated app-directory readiness check against Cedar's public MCP server (https://api.mail.cedarcopilot.com/mcp), ahead of submission to the Claude and OpenAI (Codex) app directories, then addresses everything Greptile's review turned up across two rounds.

The 7 original issues:

  • tool-hints-present / tool-title-present / claude-tool-hints-present , every externally-registered MCP tool now declares a title and real-behavior-matched annotations.{readOnlyHint,destructiveHint,openWorldHint} via EXTERNAL_TOOL_METADATA in server.ts.
  • claude-code-metadata-length , the 7 flagged tools trimmed under Claude Code's 2KB byte budget.
  • policy-review (telemetry over-collection) , patched @armature-tech/mcp-analytics@0.6.36 so telemetry.agent_thinking reads as genuinely optional instead of coercive.
  • policy-review (document tool scope) , the single document tool (one generic action selector spanning read alongside delete/share) is now document-read/document-write, the minimum split Manufact's finding asked for ("at minimum separating read/list/search from create/update, delete/restore, move, and share/revoke"), used identically by every internal and external consumer with zero special-casing , mirroring conversationTool.ts's existing conversation-read/conversation-write pattern. documentTool.ts's old single-tool id is fully retired.
  • policy-review (exposed identifiers) , session instructions no longer echo the caller's literal userId/orgId.

What Greptile's review caught, verified and fixed (not just patched cosmetically):

  • 4 mis-set tool annotations (document-write, ui-config, task under-claimed destructiveness; conversation-read under-claimed reaching an external CRM).
  • Two truncation edge cases in buildSessionInstructions: an unbounded impersonated-user header that could exceed the 2KB budget with nothing to trim, and a UTF-16 surrogate-pair-splitting bug in the byte-truncation helper , both fixed with new regression tests that fail against the pre-fix logic.
  • A real security-relevant approval-gate key that would have silently stopped working: document.sharedocument-write.share in HUMAN_ONLY_ACTIONS (matched via a literal ${toolId}.${action} string) , without the rename, autonomous callers could mint/revoke public document share links with zero human-in-the-loop gate.
  • Several live model-facing prompts still calling the deleted document tool by name after the split , most seriously, workflows/chat/harness/subagents.ts's buildSubagentDefinitions() constructs the literal prompt handed to every configured chat subagent, telling it to load its own instructions via the now-nonexistent tool; every subagent delegation would have hit a tool-not-found error. Also fixed in draftCommsTool.ts and two skill markdown files.
  • documentTool.schemas.ts added to the targetUserId-reaches-the-authority allowlist (a pure-schema file with no logic, split out of documentTool.ts purely for the 1,000-line budget , the real gating call is unchanged) , this was a CI failure, not a Greptile finding.
  • A jose peer-dependency regression: apps/server pinned jose@6.0.11, one minor below @better-auth/core@1.6.33's ^6.1.0 peer requirement. Diffed against staging's lockfile and confirmed this exact resolution slot correctly resolved jose@6.2.12 there and regressed to 6.0.11 on this branch (a side effect of the earlier pnpm patch triggering re-resolution). Bumped to 6.1.3 (already used elsewhere in this lockfile) and regenerated , jose@6.0.11 no longer appears anywhere in pnpm-lock.yaml.

Test plan

  • pnpm --filter @zero/server run types , clean
  • pnpm deps:check , no dependency-direction violations
  • Sco
Show production surfaces and changed-file mapping

Production surfaces

Libra has not measured any production surfaces for this change yet.

Changed files → surfaces

  • apps/server/package.jsonno production surface mapped
  • apps/server/src/mastra/mcp/external/__tests__/server.test.tsno production surface mapped
  • apps/server/src/mastra/mcp/external/deprecated-record-shims.tsno production surface mapped
  • apps/server/src/mastra/mcp/external/server.tsno production surface mapped
  • pnpm-lock.yamlno production surface mapped