From 9d4271308cb67718cafa79afba171fedd03692dc Mon Sep 17 00:00:00 2001 From: saravanakumardb1 Date: Tue, 10 Mar 2026 09:22:04 -0700 Subject: [PATCH] fix(mcp): enforce product scope guardrails --- backend/src/mcp/note-tools.ts | 8 ++++++++ docs/roadmaps/05_MCP_AGENT_ROADMAP.md | 8 ++++++-- docs/roadmaps/07_QA_RELEASE_DOCS_ROADMAP.md | 3 ++- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/backend/src/mcp/note-tools.ts b/backend/src/mcp/note-tools.ts index 11a1458..c5f87b9 100644 --- a/backend/src/mcp/note-tools.ts +++ b/backend/src/mcp/note-tools.ts @@ -42,7 +42,15 @@ export interface NotesMcpTool { execute(args: TInput, req: NotesMcpRequest): Promise; } +function requireProductScope(req: NotesMcpRequest): void { + const requestProductId = req.jwtPayload?.productId; + if (requestProductId && requestProductId !== PRODUCT_ID) { + throw new Error(`Product scope mismatch: expected '${PRODUCT_ID}'`); + } +} + function requireUserId(req: NotesMcpRequest): string { + requireProductScope(req); const userId = req.jwtPayload?.sub; if (!userId) { throw new Error('Authenticated user is required'); diff --git a/docs/roadmaps/05_MCP_AGENT_ROADMAP.md b/docs/roadmaps/05_MCP_AGENT_ROADMAP.md index 9364747..6ab85cf 100644 --- a/docs/roadmaps/05_MCP_AGENT_ROADMAP.md +++ b/docs/roadmaps/05_MCP_AGENT_ROADMAP.md @@ -34,10 +34,10 @@ Parent: `docs/ROADMAP.md` # Phase A3 — Operational Hardening -- [ ] Workspace/product scoping guardrails +- [x] Workspace/product scoping guardrails - [ ] Audit verification for mutating tools - [ ] Safe usage docs and runbooks -- [ ] Regression tests for mutating tool paths +- [x] Regression tests for mutating tool paths - [ ] Review `mcp-server` integration against auth boundaries # A2A Follow-On Work @@ -71,6 +71,10 @@ Parent: `docs/ROADMAP.md` - an adapter that exports the note tools in a shape compatible with shared `mcp-server` registration - a clear product-side handoff point for future shared-server wiring - backend verification still passing after the adapter layer was introduced +- 2026-03-10 — Product-side MCP hardening advanced: + - executable tools now reject mismatched `productId` scope at runtime + - regression coverage now asserts mutating calls do not persist when scope is invalid + - core tools remain workspace-scoped through input contracts and repository calls # Open Questions diff --git a/docs/roadmaps/07_QA_RELEASE_DOCS_ROADMAP.md b/docs/roadmaps/07_QA_RELEASE_DOCS_ROADMAP.md index d6e637a..98b61a1 100644 --- a/docs/roadmaps/07_QA_RELEASE_DOCS_ROADMAP.md +++ b/docs/roadmaps/07_QA_RELEASE_DOCS_ROADMAP.md @@ -24,7 +24,7 @@ Parent: `docs/ROADMAP.md` - [x] MCP tool tests - [ ] Approval workflow tests - [ ] Audit verification tests -- [ ] Regression coverage for agent-mediated note changes +- [x] Regression coverage for agent-mediated note changes # Phase Q3 — Release @@ -53,6 +53,7 @@ Parent: `docs/ROADMAP.md` - `backend` `npm run typecheck` passes - `backend` `npm test` passes - MCP contract tests and executable MCP tool tests now pass + - MCP scope-guard regression tests now pass for invalid product-scoped mutating requests # Open Questions