Skip to content

feat(mcp): support progressive tool loading via _meta hints#120

Draft
latekvo wants to merge 2 commits intomainfrom
feat/mcp-progressive-tool-loading
Draft

feat(mcp): support progressive tool loading via _meta hints#120
latekvo wants to merge 2 commits intomainfrom
feat/mcp-progressive-tool-loading

Conversation

@latekvo
Copy link
Copy Markdown
Member

@latekvo latekvo commented Apr 14, 2026

Summary

The Model Context Protocol spec lets a server attach optional _meta hints to each entry in tools/list. Anthropic clients look for two keys that let a server express an opinion about how its tools should be presented:

  • _meta["anthropic/alwaysLoad"] — a request to keep this tool's full schema visible on every turn rather than load it on demand.
  • _meta["anthropic/searchHint"] — a short phrase that helps the client surface the tool when a user request matches it, without needing the full description loaded into context.

This PR threads both hints end-to-end through the Argent stack and sets them conservatively on a small core of tools. Clients that don't consume these keys simply ignore them per the MCP spec, so nothing changes for them.

What changed

Plumbing (3 packages)

  • @argent/registryToolDefinition gains optional alwaysLoad?: boolean and searchHint?: string.
  • @argent/tool-serverGET /tools forwards both fields when set.
  • @swmansion/argent (mcp) — new src/tool-mapping.ts module maps a ToolMeta entry into the MCP tools/list shape, emitting _meta only when at least one hint is present so clients that don't use it see byte-identical responses.

Curation — only the eight tools the model reaches for on practically every turn opt in:

  • describe
  • debugger-component-tree
  • screenshot
  • gesture-tap
  • gesture-swipe
  • launch-app
  • restart-app
  • run-sequence

Everything else — profiler, flows, native-devtools, metro-debugger, and the rest of the long tail — is left untouched. Argent exposes around 125 tools today; keeping the always-on set small is deliberate, so the hints stay a light nudge rather than a blanket override.

Tests

  • packages/tool-server/test/http-tools-meta.test.ts — verifies GET /tools passes both hints through (and omits them for plain tools).
  • packages/mcp/test/tool-mapping.test.ts — 7 cases covering alwaysLoad true / false / missing, searchHint set / empty-string / missing, and that _meta is omitted entirely when neither hint applies.

Test plan

  • npm run build at workspace root — clean tsc build.
  • npm test -w @argent/registry -w @argent/tool-server -w @swmansion/argent — 634 passing (includes the 8 new cases).
  • prettier --check on all touched files — clean.
  • Smoke-test in a live Claude Code session against a React Native project.

Notes

  • alwaysLoad: false behaves identically to undefined (the hint is only forwarded when truthy). Empty-string searchHint is silently dropped.
  • Future work: add searchHint values on the long-tail tools (profiler, flows) so search ranking improves even without expanding the always-on set. Left out here to keep scope tight.

Add optional alwaysLoad and searchHint fields to ToolDefinition,
forward them through GET /tools, and emit them as
_meta["anthropic/alwaysLoad"] / _meta["anthropic/searchHint"] in the
MCP ListTools response. Claude Code's ToolSearch defers MCP tools by
default; tools marked alwaysLoad stay in context on every turn, and
searchHint feeds the BM25 ranker so deferred tools surface for
relevant queries.

Mark the core discovery + interaction tools as alwaysLoad so Claude
never has to round-trip through ToolSearch to tap the screen:
describe, debugger-component-tree, screenshot, gesture-tap,
gesture-swipe, launch-app, run-sequence. Everything else defers.
Copy link
Copy Markdown
Collaborator

@filip131311 filip131311 left a comment

Choose a reason for hiding this comment

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

we have a tool for restarting the app we shoud add it to the curated list:
describe
debugger-component-tree
screenshot
gesture-tap
gesture-swipe
launch-app
run-sequence

as it is vital for othere tools that depend on controling app start to work

@filip131311
Copy link
Copy Markdown
Collaborator

BTW: nice find

Tools that depend on controlling app startup (relaunch for clean
state, refreshing native-devtools injection) need restart-app to be
immediately callable rather than routed through a search round-trip.
@latekvo
Copy link
Copy Markdown
Member Author

latekvo commented Apr 15, 2026

Deferring till 1.0.0 release

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.

2 participants