Libra CodeHub

CedarCopilot/cedar-mail

Branch: staging

fix(mcp): accept Krisp's origin-scoped OAuth resource identifier

merged#2754CedarCopilot

CedarCopilot wants to merge 1 commit into staging from fix/krisp-mcp-oauth-resource-origin-scope

Live on prod, no production signal yetTimeline and evidence
  1. Opened
    Sep 10, 2026, 12:29 PM
  2. Sep 10, 2026, 3:59 PM
  3. Merged
    Sep 10, 2026, 6:35 PM
  4. Live on prod
    Sep 10, 2026, 6:35 PM
  5. Observed 47 hours
    Sep 10, 2026, 6:35 PM
  6. Pipelines steady after this deploy
    Sep 10, 2026, 6:35 PM
  7. Unobserved

    Live on prod, no production signal yet

    Sep 12, 2026, 5:17 PM

Behaviors Libra is checking

MCP OAuth discovery accepts protected-resource metadata whose resource identifier is the same origin or an ancestor path of the requested MCP endpoint, including Krisp's bare-origin identifier.Inconclusivelow confidence

Verification reached its 130s outer budget before the verifier returned. Libra is keeping this intent verifying until the next check.

prod, checked Sep 12, 2026, 5:16 PM
MCP OAuth discovery continues to reject protected-resource metadata that names a same-origin sibling or otherwise unrelated endpoint path.Inconclusivehigh confidence

Since 2026-09-11T01:35:52Z in production, OTEL returned 0 rows for span names matching discoverMcpOAuth/MCP OAuth discovery, and CloudWatch returned 0 rows for discoverMcpOAuth, probeMcpServer, McpDiscoveryError, protected-resource metadata, or OAuth discovery. No positive.

prod, checked Sep 12, 2026, 5:17 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

  • Krisp's live protected-resource metadata now declares resource: "https://mcp.krisp.ai" (the bare origin) for the MCP endpoint https://mcp.krisp.ai/mcp, rather than the exact endpoint URL Cedar's RFC 9728 anti-spoofing check requires an exact match against. Every Krisp OAuth connect attempt was failing with Refusing to authorize against a resource identifier the server does not own.
  • Added resourceIdentifierCovers() in server-url.ts: still hard-requires the same origin (the actual anti-spoofing property the check exists for), but accepts a resource claim scoped to the whole origin or an ancestor path of the requested URL.
  • Swapped it in for the exact-match sameResourceIdentifier() inside resolveResourceIdentifier() in oauth-discovery.ts. sameResourceIdentifier() itself is untouched , it's still used elsewhere for exact driver-identity matching.
  • Verified against Krisp's live endpoints (curl) that this was the only blocker: protected-resource metadata, authorization-server metadata, PKCE S256, and the registration endpoint all resolve fine once the resource check is relaxed.

Test plan

  • pnpm --filter @zero/server exec vitest run src/services/integrations/mcp/__tests__/oauth-discovery.test.ts , 34/34 pass, including two new cases: accepting Krisp's origin-scoped resource, and still rejecting a same-origin-but-unrelated-path claim.
  • pnpm --filter @zero/server run types , clean on touched files.
  • Manually reconnect Krisp in the app to confirm the OAuth flow completes end-to-end.

🤖 Generated with Claude Code

https://claude.ai/code/session_01Andk1EE6XLSG94yLKPrxLu

Greptile Summary

This PR allows MCP protected-resource metadata to identify the requested endpoint using the same origin or an ancestor path, enabling Krisp’s origin-scoped OAuth resource identifier while preserving cross-origin and sibling-path rejection.

  • Adds resourceIdentifierCovers for same-origin, path-segment-aware coverage.
  • Uses the new comparison during protected-resource metadata validation.
  • Adds discovery tests for Krisp’s bare-origin claim and an unrelated same-origin path.

Confidence Score: 4/5

The PR appears safe to merge, with a non-blocking test-coverage gap around the newly supported non-root ancestor-path behavior.

The implemented comparison retains strict origin equality and path-segment boundaries, and no behavioral failure was established; focused coverage should be added for the untested ancestor-prefix branch.

Files Needing Attention: apps/server/src/services/integrations/mcp/server-url.ts, apps/server/src/services/integrations/mcp/tests/oauth-discovery.test.ts

Important Files Changed

FilenameOverview
apps/server/src/services/integrations/mcp/server-url.tsAdds same-origin ancestor-path resource matching; the non-root ancestor branch lacks focused regression coverage.
apps/server/src/services/integrations/mcp/oauth-discovery.tsReplaces exact resource equality with the new coverage predicate while retaining rejection of mismatched origins and paths.
apps/server/src/services/integrations/mcp/tests/oauth-discovery.test.tsCovers Krisp’s origin-scoped resource and unrelated sibling rejection, but omits the helper’s non-root ancestor branch.
Prompt To Fix All With AI
### Issue 1
apps/server/src/services/integrations/mcp/server-url.ts:115
**Ancestor branch lacks coverage**

The new non-root ancestor branch is not exercised by the added tests. They cover an empty-path origin claim and an unrelated sibling, but never a claim such as `/api` covering `/api/mcp`. Add focused coverage for this branch and a segment-prefix lookalike such as `/api-v2` so future changes cannot silently widen or break this security-sensitive resource comparison.

---

For each issue above, determine whether it is 
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/src/services/integrations/mcp/__tests__/oauth-discovery.test.tsno production surface mapped
  • apps/server/src/services/integrations/mcp/oauth-discovery.tsno production surface mapped
  • apps/server/src/services/integrations/mcp/server-url.tsno production surface mapped