fix(mcp): surface scope-gated tools in exec search#60676
Conversation
|
Size Change: 0 B Total Size: 81 MB ℹ️ View Unchanged
|
|
PR overviewAll previously flagged issues have been addressed. No open security concerns remain on this pull request. Security reviewNo open security issues remain on this pull request. Fixed/addressed: 1 · PR risk: 0/10 |
There was a problem hiding this comment.
Pull request overview
This PR improves MCP tool discoverability in single-exec mode by making the exec search command scope-aware, so tools that exist but are hidden due to missing API key scopes are surfaced with an actionable scope hint instead of being silently omitted.
Changes:
- Add a
getScopeGatedTools()helper to compute “feature-enabled but scope-filtered” tools and thread this through both MCP wiring paths. - Update
exec searchto returnscope_gated_matchesplus ahintlisting missing scope(s) when relevant. - Update tool-search guidance and extend unit/hono tests + snapshots to cover the new behavior.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| services/mcp/src/tools/toolDefinitions.ts | Adds ScopeGatedTool + getScopeGatedTools() to compute tools filtered only by missing scopes. |
| services/mcp/src/tools/exec.ts | Extends search output to include scope-gated matches and a missing-scope hint. |
| services/mcp/src/mcp.ts | Computes and passes scopeGatedTools into createExecTool for the DO (mcp.ts) execution path. |
| services/mcp/src/hono/request-state-resolver.ts | Adds scopeGatedTools to resolved request state and computes it alongside allTools. |
| services/mcp/src/hono/tool-executor.ts | Passes state.scopeGatedTools into createExecTool for the Hono execution path. |
| services/mcp/src/templates/sections/tool-search.md | Updates agent instructions to interpret scope_gated_matches as missing scopes (not missing tools). |
| services/mcp/tests/unit/exec.test.ts | Adds unit coverage for search returning plain arrays vs scope-gated hint payloads. |
| services/mcp/tests/unit/snapshots/instructions/tools-instructions.txt | Snapshot update reflecting the new scope_gated_matches guidance. |
| services/mcp/tests/unit/snapshots/instructions/exec-command-reference-full.txt | Snapshot update reflecting the new scope_gated_matches guidance. |
| services/mcp/tests/unit/snapshots/exec-tool.json | Snapshot update to exec tool command-reference text including the new guidance. |
| services/mcp/tests/hono/tool-executor.test.ts | Updates test helper state to include scopeGatedTools. |
| services/mcp/tests/hono/tool-executor-metrics.test.ts | Updates test helper state to include scopeGatedTools. |
| services/mcp/tests/hono/analytics.test.ts | Updates test helper state to include scopeGatedTools. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Rebased onto master. Surfaces scope-gated tools in the exec `search` command so an agent gets an actionable "add this scope" hint instead of concluding a tool is missing. Includes the review-feedback fixes: forward `scoped_teams` in the DO path, cap the search pattern length, and only compute scope-gated tools in single-exec mode. Generated-By: PostHog Code Task-Id: e8456582-7050-4ffb-9bae-d42084574eea
f7c9565 to
f651279
Compare
skoob13
left a comment
There was a problem hiding this comment.
Looks good. This addresses the CLI mode (exec), but there is also the tools mode. I'm wondering if we should remove the scope filter and add a gate in the tool executor checking the scopes before calling an endpoint, so we can return a matching explanation prompt to agents.
Address review feedback: add OAuth re-authentication guidance to the scope-gated search hint, and drop the redundant scope_gated_matches line from the tool-search instructions (agents infer it from the hint). Update affected instruction snapshots. Generated-By: PostHog Code Task-Id: f3013a13-4b55-479d-850c-e6cceda5314d
Problem
This came out of MCP agent feedback that the data-warehouse source/schema management tools were "missing" — an agent doing a source-sync follow-up could find
external-data-sync-logsbut notexternal-data-sources-refresh-schemas,external-data-schemas-list,external-data-schemas-partial-update, or thereloadtools.Those tools are not missing — they have been defined and enabled since March 2026. The real issue is in the discovery layer: the exec
searchcommand only matches over the session's already-loaded tool set, which is silently filtered by the API key's scopes (getToolsFromContext→hasScopes). A key withquery:readbut notexternal_data_sourceseesexecute-sqlandexternal-data-sync-logs(bothquery:read) but every source/schema management tool (external_data_source:read/:write) is dropped with no signal. The agent then reasonably concludes the tools don't exist.Changes
Made the exec
searchcommand scope-aware. When a query matches tools that exist and are enabled for the session's features but were hidden by scope filtering,searchnow returns them under ascope_gated_matchesfield alongside ahintnaming the missing scope(s) — turning a silent omission into an actionable "add this scope to your personal API key" message.tools/toolDefinitions.ts— newgetScopeGatedTools()helper +ScopeGatedTooltype (tools that pass every filter except scopes).tools/exec.ts—searchsurfaces scope-gated matches; new optionalscopeGatedToolsparam oncreateExecTool.mcp.ts,hono/request-state-resolver.ts,hono/tool-executor.ts— compute and thread the scope-gated set through both exec wiring paths.templates/sections/tool-search.md— instruct agents to surface the scope hint to the user rather than declaring the tool unavailable.No tool definitions or scopes changed — this is purely a discoverability improvement.
How did you test this code?
I'm an agent (Claude Code); I did not perform manual MCP-client testing. Automated tests I actually ran:
tests/unit/exec.test.tscovering: plain-array search results (unchanged), scope-gated matches producing the hint +scope_gated_matches, and scope-gated tools that don't match the query being ignored.tool-executor,tool-executor-metrics,analytics): 19 pass.tsc --noEmitclean for all touched files.tool-search.mdline.🤖 Agent context
Authored by Claude Code (Opus) at Tom's direction, in response to a piece of MCP agent feedback categorized as "missing_tool".
Investigation path: first verified the supposedly-missing tools were in fact present and
enabled: trueinproducts/data_warehouse/mcp/tools.yaml(since PR #50859, March 2026), ruling out the "missing tool" premise. Then traced the discovery path —tool-search.md→ execsearch(exec.ts) →allTools, which is built post-scope-filter in both the DO path (mcp.tsviagetToolsFromContext) and the hono path (request-state-resolver.tsviaToolCatalog.getFilteredTools). Confirmed the differentiator was scopes:external-data-sync-logsrequiresquery:readwhile every source/schema tool requiresexternal_data_source:*, which matches exactly the tool set the reporter could vs. couldn't use.Considered but rejected: (1) editing tool descriptions/keywords — descriptions were already good, this wasn't a keyword-match problem; (2) changing the domain-collapsing logic in
instructions.ts— orthogonal to the scope issue; (3) loosening scope filtering — wrong, the filter is correct, the problem was the silent failure. Chose to make the failure visible instead.