Skip to content

Fix workspace-scoped MCP resources/list and resources/read (#6770) - #6773

Merged
AmyShang-alt merged 2 commits into
nexu-io:mainfrom
xxiaoxiong:fix/mcp-resources-workspace-headers-6770
Aug 12, 2026
Merged

Fix workspace-scoped MCP resources/list and resources/read (#6770)#6773
AmyShang-alt merged 2 commits into
nexu-io:mainfrom
xxiaoxiong:fix/mcp-resources-workspace-headers-6770

Conversation

@xxiaoxiong

Copy link
Copy Markdown
Contributor

Problem

MCP resources/list and resources/read call the daemon's /api/skills and /api/design-systems without forwarding the workspace headers (x-od-workspace-id, x-od-workspace-member-id). This means:

  • An MCP client's resource catalog is filtered to the NO-SCOPE view — any Personal design system that the workspace actually owns is hidden.
  • Reading od://design-systems/<personal-id>/DESIGN.md returns 404 design system not found, even though the binding exists under the workspace.

This differs from the project/run tools (introduced in #6569) which already resolve the signed-in workspace and forward headers on every daemon call.

Fix

  1. _listMcpResources — extract the ListResourcesRequestSchema handler body into an exported helper. Inside the daemonTarget.call callback, resolve the workspace context once and pass the headers to both getJson calls for /api/skills and /api/design-systems.
  2. _readMcpResource — same pattern for ReadResourceRequestSchema. The skill/design-systems branch now resolves the workspace and forwards headers so reads of Personal design systems land on the binding instead of returning 404.
  3. The original stdio server.setRequestHandler bodies now delegate to the helpers (no behavioral change to the stdio path).

Tests

Added apps/daemon/tests/mcp-resources-workspace-scope.test.ts covering:

  • Header forwarding on resources/list calls
  • Header forwarding on resources/read for design-system URIs
  • NO-SCOPE fallback when no workspace context resolves
  • Brief-app resource fast-path (bypasses daemon)
  • Unsupported URI rejection

Related

Closes #6770

)

The MCP `resources/list` and `resources/read` handlers were calling
`/api/skills` and `/api/design-systems` without workspace headers, while
the project/run tools (after nexu-io#6569) all resolve the signed-in workspace
and forward `x-od-workspace-id` / `x-od-workspace-member-id`.

This meant an MCP client listing resources only saw the NO-SCOPE catalog:
any Personal design system that the workspace actually owned was filtered
out, and reading `od://design-systems/<personal-id>/DESIGN.md` returned
`404 design system not found` from the daemon even though the binding
exists. The same blind spot affected `/api/skills` listing.

Fix: route both handlers through the same `resolveMcpWorkspaceContext`
that the project/run tools use, and forward the headers on the listing
and read calls. The two handlers are extracted to exported
`_listMcpResources` / `_readMcpResource` helpers so the logic is
reachable from a vitest harness without spinning up a real stdio MCP
server; the original `server.setRequestHandler` bodies now delegate to
those helpers (no behavioral change to the stdio path).

Tests: `apps/daemon/tests/mcp-resources-workspace-scope.test.ts` covers
the header forwarding on both `resources/list` and `resources/read`, the
NO-SCOPE fallback when no workspace resolves, the brief-app resource
fast path that bypasses the daemon, and the unsupported-URI rejection.
@lefarcen
lefarcen requested a review from PerishCode August 12, 2026 00:50
@lefarcen lefarcen added size/L PR changes 300-700 lines risk/high High risk: apps/desktop, daemon, auth, migration, workflows, package deps type/bugfix Bug fix labels Aug 12, 2026
@lefarcen lefarcen added the needs-validation Runtime change detected; needs human or /explore agent validation. label Aug 12, 2026
@lefarcen

Copy link
Copy Markdown
Contributor

🧪 Queued for QA validation — this PR changes live MCP resource behavior, so we'll want a manual QA pass before merge. Nothing needed from you right now; we'll pick that up once the review/CI gates are clear. Thanks for the contribution! 🙏

@lefarcen

Copy link
Copy Markdown
Contributor

Hey @xxiaoxiong — the workspace-header gap and the regression coverage are both clear from the current write-up. Before pool review picks this up, could you add the user-facing outcome (What users will see), tick the relevant Surface area, and note what you actually ran under Validation? Problem already covers the why, so there's no need to rename headings.

Related: #6770 (linked bug report with the end-user repro).

The new mcp-resources-workspace-scope test imports this constant to
assert the brief-app resource fast path bypasses the daemon. It is
referenced inside mcp.ts but never exported — typecheck broke with
TS2459.
@lefarcen

Copy link
Copy Markdown
Contributor

One more PR-body item after this push: because this is labeled type/bugfix, could you add a short Bug fix verification note describing the failing repro seam and what confirms it now passes? The earlier asks for What users will see, Surface area, and Validation still apply.

@PerishCode PerishCode left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@xxiaoxiong I reviewed the workspace-scoped MCP resource changes across both modified files. The list and read handlers now consistently reuse the existing workspace resolver, preserve the headerless fallback and brief-app fast path, and retain the stdio handler behavior through the extracted helpers. I also verified the focused regression suite (5 tests), daemon source/test typecheck, and repository guard all pass. Nice work closing this resource-catalog gap with focused coverage.

🔁 Powered by Looper · runner=reviewer · agent=codex · An autonomous AI dev team for your GitHub repos.

@lefarcen
lefarcen requested a review from AmyShang-alt August 12, 2026 01:13
@AmyShang-alt AmyShang-alt added validated Runtime change validated (via /explore Pass or manual QA). and removed needs-validation Runtime change detected; needs human or /explore agent validation. labels Aug 12, 2026
@AmyShang-alt

Copy link
Copy Markdown
Contributor

@xxiaoxiong

Thanks for the contribution. I completed QA validation for this PR.

QA Acceptance Record

Scope:

  • Workspace-scoped MCP resources/list and resources/read
  • Personal design-system visibility, reads, and cross-member isolation

Verified:

  • Reproduced the bug on base eefe79677: the Personal design system was absent from resources/list, and resources/read failed with WORKSPACE_CONTEXT_REQUIRED
  • Verified head dc7d51f84: the resource is listed and its complete DESIGN.md is readable through a real MCP stdio client
  • Verified another workspace member cannot list or read the Personal design system; a forced read is rejected with 403
  • Verified the signed-out path remains fail-closed
  • Focused MCP tests passed (5/5), design-system workspace isolation tests passed (12/12), daemon typecheck passed, and CI is green

Not verified:

  • None blocking

Risks / notes:

  • The fully signed-out read returns an explicit permission-denied error rather than WORKSPACE_CONTEXT_REQUIRED, but remains fail-closed and does not expose resource content.

Conclusion:

  • Accepted

@AmyShang-alt
AmyShang-alt added this pull request to the merge queue Aug 12, 2026
Merged via the queue into nexu-io:main with commit 27d2f07 Aug 12, 2026
27 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk/high High risk: apps/desktop, daemon, auth, migration, workflows, package deps size/L PR changes 300-700 lines type/bugfix Bug fix validated Runtime change validated (via /explore Pass or manual QA).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: MCP resources do not forward workspace scope for personal design systems

4 participants