Skip to content

feat(mcp): load the structural tools upfront and say what the graph answers - #2698

Merged
DeusData merged 1 commit into
mainfrom
feat/mcp-tool-search-discovery
Oct 19, 2026
Merged

DeusData merged 1 commit into
mainfrom
feat/mcp-tool-search-discovery

Conversation

@DeusData

Copy link
Copy Markdown
Owner

Why

Agents with codebase-memory-mcp installed often answer structural questions with grep and never call the graph (#509, discussion #2025). One documented cause is tool deferral. Claude Code defers every MCP tool by default: at session start the model sees only tool names and server instructions, while Grep, Read and Bash are always loaded. Codex does the same; its tool_search lists each server under its instructions text (codex-rs/codex-mcp/src/rmcp_client.rs).

What changes

  1. The structural path loads upfront. In tools/list, search_graph, trace_path and get_code_snippet carry _meta["anthropic/alwaysLoad"]: true. This is the documented per-tool hint, and it follows Anthropic's guidance to keep the most-used tools loaded and defer the rest. The other 14 tools stay deferred. Clients that don't know the key ignore it, since MCP reserves _meta. No user configuration is written.
  2. The server instructions state what the graph answers. The default-profile instructions now say, keywords first and as facts, which structural questions the graph answers (where a symbol is defined, who calls a function, call chains, which code a change affects, …) and where grep and file reads fit better. That is what the MCP docs ask server authors to put there.
  3. The SessionStart label covers only the project name. The untrusted-metadata label now applies to the graph-derived project name alone. Before, it also wrapped cbm's own routing sentences, which told the model to treat that guidance as data; the hooks docs ask for hook context written as plain facts. All other sentences are unchanged, and so is sanitization.

Proof on real output

Main 354ccec against this branch, over MCP stdio and hook-augment, using an isolated cache:

before after
tools with _meta.anthropic/alwaysLoad none search_graph, trace_path, get_code_snippet
server instructions 309 chars 999 chars (Claude Code cuts at 4,096)
initialize response 498 B 1,188 B
tools/list 20,824 B 20,938 B (budget 21,504 B)
SessionStart on a django index label wraps the whole guidance label wraps the project name only; other sentences byte-identical

The mcp_metadata_byte_budget test raises the initialize budget deliberately, from 512 B to 1.5 KiB, and its comment says why. mcp_initialize_response now checks for the new freshness wording ("refreshes automatically").

Tests

  • New: mcp_tools_list_loads_structural_path_upfront (all three tool profiles), mcp_server_instructions_name_structural_questions, cli_hook_session_untrusted_label_covers_project_name_only.
  • Revert check: with main's src/mcp/mcp.c and src/cli/hook_augment.c, exactly the four tests that encode this change fail; with the change, all pass.
  • Local (macOS arm64, ASan/UBSan test runner): mcp 379 / 0 / 4 (the 4 skips are Windows-only), cli 362 / 0, daemon_application 74 / 0, agent_clients 38 / 0.
  • Lint: clang-format (Homebrew LLVM 22) clean; cppcheck 2.20 (the CI lint image) clean on both production files.
  • Legs skipped locally: Linux and Windows. The change is platform-neutral (string literals plus one bool field in the tool annotation table, with no new buffers, paths or threads), so PR CI is the gate.

Not in this PR

  • The scout and analysis profile instructions follow in a separate change.
  • The effect on how often agents choose the graph is not measured here.

Refs #509

…nswers

Claude Code defers every MCP tool behind ToolSearch by default: at session
start the model sees only tool names and server instructions, while Grep and
Read are always loaded. Codex does the same and shows the server instructions
as the namespace description of the deferred tools. Agents therefore reached
for grep before the graph tools were even loaded (#509, discussion #2025).

- tools/list: search_graph, trace_path and get_code_snippet carry
  _meta["anthropic/alwaysLoad"] = true (a documented per-tool hint), so the
  structural discovery path loads upfront while the other 14 tools stay
  deferred. About 4.6K characters of schema; clients that do not know the key
  ignore it, as MCP reserves _meta.
- Server instructions (default profile) now state, keywords first and as
  facts, which structural questions the graph answers and where grep fits
  better: 309 -> 999 characters, within Claude Code's 4,096-character cut.
- SessionStart/SubagentStart: the untrusted-metadata label now covers the
  graph-derived project name only. Wrapping the routing sentences too told the
  model to treat cbm's own guidance as data. The other sentences are unchanged;
  sanitization is unchanged.

The initialize byte budget is raised deliberately from 512 B to 1.5 KiB (1,188
bytes now); tools/list stays within its 21 KiB budget (20,938 bytes).

Refs #509

Signed-off-by: Martin Vogel <[email protected]>
@DeusData
DeusData merged commit 2248ae1 into main Oct 19, 2026
37 checks passed
timothybrush pushed a commit to timothybrush/codebase-memory-mcp that referenced this pull request Oct 19, 2026
…rofiles

The read-only analysis profile and the fast scout profile serve the graph
subagents (codebase-memory-auditor, codebase-memory-scout). Their server
instructions listed tools only. Like the default profile, they now state as
facts which structural questions the graph answers (where a symbol is defined,
who calls a function, what it calls, and for analysis also call chains, data
flow and change impact), keywords first: analysis 190 -> 648 characters, scout
199 -> 427, well within Claude Code's 4,096-character cut. The profile names,
check_index_coverage and the absence of index_repository are unchanged.

Stacked on DeusData#2698.

Refs DeusData#509

Signed-off-by: Martin Vogel <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant