-
Notifications
You must be signed in to change notification settings - Fork 2.8k
fix: use hash suffix instead of truncation for long MCP tool names #10770
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Addresses Issue #10766 where MCP tool names with hyphens fail when using native tool calling due to truncation cutting in the middle of hyphen encodings (___). Changes: - Add hash suffix (8 hex chars) when tool names exceed 64 characters instead of simple truncation - Register shortened names in a registry to allow lookup of original server/tool names - Parse function now checks registry first for shortened names - Add comprehensive tests for hash suffix behavior and roundtrip This ensures that long tool names with hyphens can be correctly resolved even after shortening, preserving the original tool identity.
All issues resolved. The latest commit correctly reverts MAX_TOOL_NAME_LENGTH to 64 for Gemini compatibility (which enforces a stricter limit than the MCP spec's 128).
Mention @roomote in a comment to request specific changes to this pull request or fix all unresolved issues. |
| /** | ||
| * Maximum length for tool names (Gemini's limit). | ||
| */ | ||
| export const MAX_TOOL_NAME_LENGTH = 64 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@roomote Why are we truncating to 64?
MCP spec states:
Tool names SHOULD be between 1 and 128 characters in length (inclusive).
See https://modelcontextprotocol.io/specification/2025-11-25/server/tools#tool-names
| */ | ||
| export function clearMcpToolNameRegistry(): void { | ||
| mcpToolNameRegistry.clear() | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The registry is never cleared in production code. Looking at McpHub.ts, none of the lifecycle methods (refreshAllConnections(), handleMcpEnabledChange(), dispose(), deleteConnection()) call clearMcpToolNameRegistry(). This leads to a memory leak as the registry grows unbounded, and stale mappings remain when servers are disconnected or refreshed. The JSDoc here says this "should be called when MCP servers are refreshed or disconnected" but this is not implemented.
Fix it with Roo Code or mention @roomote and request a fix.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@roomote Why do we need a registry? Couldn't we just compare encoded tool names on both sides when looking up tools? And maybe only LRU cache that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixaroo
See task on Roo Cloud
Implemented the suggested approach: replaced the unbounded registry with an LRU cache and encoded name comparison at lookup time. All local checks passed.
Updated MAX_TOOL_NAME_LENGTH from 64 to 128 per MCP spec. All tests (61) pass. |
- Remove mcpToolNameRegistry (unbounded Map) and clearMcpToolNameRegistry - Add LRU cache with size limit of 100 entries for encoded name computation - Add findToolByEncodedMcpName() to compare encoded names at lookup time - Add hasHashSuffix() helper for checking if a name needs lookup - Pass original encoded MCP name through the tool call stack - Update UseMcpToolTool.validateToolExists() to use encoded comparison - Update tests to cover new functions and LRU cache behavior This addresses the reviewer feedback to avoid memory leaks from the unbounded registry by comparing encoded tool names on both sides and using an LRU cache for performance.
src/utils/mcp-name.ts
Outdated
| * Maximum length for tool names (MCP spec limit). | ||
| * See: https://modelcontextprotocol.io/specification/2025-11-25/server/tools#tool-names | ||
| */ | ||
| export const MAX_TOOL_NAME_LENGTH = 128 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe there was a reason for using 64 before...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@roomote check if it is safe to use 128 with all current models
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixaroo
See task on Roo Cloud
Investigated whether 128-char limit is safe for all models. Finding: No, Gemini enforces a 64-character limit for function names. The original 64-char limit was correct. Reverted MAX_TOOL_NAME_LENGTH to 64 for Gemini compatibility. All 67 tests pass.
The MCP spec recommends 128 characters, but Gemini enforces a 64-character limit for function names. Since buildMcpToolName() is provider-agnostic (called without provider context), we must use the lowest common denominator. This ensures compatibility with all supported API providers.
|
@roomote Two tests are failing: https://github.com/RooCodeInc/Roo-Code/actions/runs/21069991548/job/60596816909?pr=10770 |
Working on the following issues:
|
I investigated the E2E test failures and found that they appear unrelated to this PR's code changes: Verification performed:
Analysis: The test failure "The use_mcp_tool should have been requested" indicates the Gemini model completed the task without calling the MCP tool. This is consistent with LLM-based E2E test non-determinism rather than a code bug, especially since:
Recommendation: Re-run the CI workflow to check if the failures are flaky. If they persist, the issue is likely in the E2E test infrastructure or MCP time server setup, not the hash suffix implementation. |
Related GitHub Issue
Closes: #10766
Description
This PR addresses the suggestion from @pdecat in Issue #10766 to use a hash suffix instead of simple truncation when MCP tool names exceed the 64-character limit.
Problem:
When MCP tool names with hyphens exceed 64 characters, the previous simple truncation (
slice(0, 64)) could cut in the middle of the___encoding sequence used to preserve hyphens through the model's tool calling process. This resulted in corrupted tool names that couldn't be resolved back to the original tool.Solution:
Instead of simple truncation, we now:
_+ 8-char hash suffix)This ensures that even very long tool names with hyphens can be correctly resolved back to their original server and tool names.
Test Procedure
src/utils/__tests__/mcp-name.spec.ts:Run the tests with:
All 61 tests pass.
Pre-Submission Checklist
Documentation Updates
Additional Notes
This PR implements the suggestion from @pdecat to hash the end of tool names instead of truncating them, which prevents information loss. The hash suffix approach:
Feedback and guidance are welcome!
Important
This PR introduces a hash suffix for long MCP tool names to ensure uniqueness and correct resolution, replacing simple truncation.
mcp-name.ts.UseMcpToolTool.tsto handle encoded names with hash suffixes.computeHashSuffix(),findToolByEncodedMcpName(), andhasHashSuffix()inmcp-name.ts.buildMcpToolName()to append hash suffix when needed.mcp-name.spec.tsfor hash suffix behavior, deterministic hash generation, and registry lookup.This description was created by
for ef21f94. You can customize this summary. It will automatically update as commits are pushed.