Skip to content

Add lazy schema loading for MCP tools to reduce token usage#19

Merged
chinmaymk merged 7 commits intomainfrom
claude/mcp-token-optimization-1OYpx
Mar 11, 2026
Merged

Add lazy schema loading for MCP tools to reduce token usage#19
chinmaymk merged 7 commits intomainfrom
claude/mcp-token-optimization-1OYpx

Conversation

@chinmaymk
Copy link
Copy Markdown
Owner

Summary

Implements lazy schema loading for MCP tools to reduce token consumption when working with many tools. Instead of sending full tool schemas to the model upfront, tools are registered with truncated descriptions and minimal schemas. The model can request full schemas on-demand via a new get_mcp_tool_schema meta-tool before calling a tool.

Key Changes

  • New wrapMcpToolsLazy function (src/mcp/lazy-tools.ts): Wraps MCP tools with lightweight stubs containing only name and truncated description. Full schemas are stored internally and retrieved via the meta-tool.
  • Meta-tool get_mcp_tool_schema: Allows the model to fetch the complete description and parameter schema for any MCP tool by name. Returns helpful error messages listing available tools if an unknown tool is requested.
  • Updated McpClient.connect(): Added McpConnectOptions parameter to support lazy schema loading. Tools are either wrapped lazily or registered directly based on the lazySchemas option.
  • Configuration support: Added lazySchemas (boolean, default: true) and maxDescriptionLength (number, default: 100) to MCP config. These can be set via environment variables (RA_MCP_LAZY_SCHEMAS, RA_MCP_MAX_DESCRIPTION_LENGTH).
  • Comprehensive test suite: 12 tests covering description truncation, schema minimization, meta-tool functionality, error handling, and edge cases.

Implementation Details

  • Description truncation preserves the original text up to the limit and appends ... if truncated
  • Input schemas for wrapped tools include a helpful hint directing the model to use get_mcp_tool_schema
  • The original tool execute functions are preserved, so wrapped tools remain fully functional
  • The meta-tool is always registered, even with an empty tool list (harmless and consistent)
  • Full schemas are stored in a closure within the meta-tool, avoiding registry pollution

https://claude.ai/code/session_01FnU9oVREyZ2kf1npbnHStq

claude added 7 commits March 10, 2026 19:55
Instead of dumping full schemas for all MCP tools into every model call,
tools are registered with truncated descriptions and minimal schemas.
A `get_mcp_tool_schema` meta-tool lets the model fetch full schemas on
demand before calling a tool. Enabled by default, configurable via
`mcp.lazySchemas` and `mcp.maxDescriptionLength` in config or
`RA_MCP_LAZY_SCHEMAS` / `RA_MCP_MAX_DESCRIPTION_LENGTH` env vars.

https://claude.ai/code/session_01FnU9oVREyZ2kf1npbnHStq
Each MCP tool stub now includes a [serverName] prefix in its description
so the model can identify which server provides which tool. The
get_mcp_tool_schema meta-tool lists tools grouped by server and returns
the server name in its response. Error messages include server attribution.

Also adds documentation to README, docs/site (MCP, configuration, tools),
and src/mcp/CLAUDE.md.

https://claude.ai/code/session_01FnU9oVREyZ2kf1npbnHStq
Instead of a separate get_mcp_tool_schema meta-tool, the first call to
each MCP tool now returns the full schema as an error. The model retries
with correct parameters on the next call. This eliminates the extra
meta-tool and simplifies the two-level tool calling to normal error
handling that LLMs already understand.

https://claude.ai/code/session_01FnU9oVREyZ2kf1npbnHStq
Each tool closure only tracks its own state, so a boolean is sufficient.

https://claude.ai/code/session_01FnU9oVREyZ2kf1npbnHStq
Tool names become `serverName__toolName` to avoid conflicts across servers.
Descriptions are passed through unchanged from the MCP server. Removed
maxDescriptionLength config option and truncation logic — only inputSchema
is stripped for lazy loading.

https://claude.ai/code/session_01FnU9oVREyZ2kf1npbnHStq
…compat

- prefixToolName() applies to both lazy and non-lazy paths in client.ts
- Server names sanitized to [a-zA-Z0-9_] (e.g. my-server → my_server)
- Inlined formatSchemaHint for conciseness
- Added prefixToolName and sanitization tests

https://claude.ai/code/session_01FnU9oVREyZ2kf1npbnHStq
The test looked up tools by bare name 'greet' but tools are now
registered as 'test_stdio_server__greet'.

https://claude.ai/code/session_01FnU9oVREyZ2kf1npbnHStq
@chinmaymk chinmaymk merged commit 24f4657 into main Mar 11, 2026
1 check passed
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