Skip to content

Conversation

@roomote
Copy link
Contributor

@roomote roomote bot commented Jan 16, 2026

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:

  1. Compute a deterministic SHA-256 hash of the original server and tool names
  2. Truncate to 55 characters (leaving room for _ + 8-char hash suffix)
  3. Append the hash suffix to create a unique, consistent shortened name
  4. Register the mapping from shortened name to original names in a registry
  5. When parsing, check the registry first before attempting normal parsing

This ensures that even very long tool names with hyphens can be correctly resolved back to their original server and tool names.

Test Procedure

Run the tests with:

cd src && pnpm exec vitest run utils/__tests__/mcp-name.spec.ts

All 61 tests pass.

Pre-Submission Checklist

  • Issue Linked: This PR is linked to an approved GitHub Issue (see "Related GitHub Issue" above).
  • Scope: My changes are focused on the linked issue (one major feature/fix per PR).
  • Self-Review: I have performed a thorough self-review of my code.
  • Testing: New and/or updated tests have been added to cover my changes (if applicable).
  • Documentation Impact: I have considered if my changes require documentation updates (see "Documentation Updates" section below).
  • Contribution Guidelines: I have read and agree to the Contributor Guidelines.

Documentation Updates

  • No documentation updates are required.

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:

  • Preserves uniqueness across different long tool names
  • Is deterministic (same input always produces same output)
  • Allows correct resolution back to original names via the registry

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.

  • Behavior:
    • Replaces truncation with hash suffix for MCP tool names exceeding 64 characters in mcp-name.ts.
    • Uses SHA-256 hash to generate an 8-character suffix, ensuring uniqueness.
    • Updates UseMcpToolTool.ts to handle encoded names with hash suffixes.
  • Functions:
    • Adds computeHashSuffix(), findToolByEncodedMcpName(), and hasHashSuffix() in mcp-name.ts.
    • Modifies buildMcpToolName() to append hash suffix when needed.
  • Tests:
    • Adds tests in mcp-name.spec.ts for hash suffix behavior, deterministic hash generation, and registry lookup.
    • Tests for long hyphenated tool names and roundtrip behavior with shortened names.

This description was created by Ellipsis for ef21f94. You can customize this summary. It will automatically update as commits are pushed.

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.
@roomote
Copy link
Contributor Author

roomote bot commented Jan 16, 2026

Rooviewer Clock   See task on Roo Cloud

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).

  • Registry is never cleared in production - Fixed by replacing with bounded LRU cache that self-evicts old entries
Previous reviews

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
Copy link
Contributor

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()
}
Copy link
Contributor Author

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.

Copy link
Contributor

@pdecat pdecat Jan 16, 2026

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.

Copy link
Contributor Author

@roomote roomote bot Jan 16, 2026

Choose a reason for hiding this comment

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

Fixaroo Clock   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.

View commit | Revert commit

@roomote
Copy link
Contributor Author

roomote bot commented Jan 16, 2026

Fixaroo Clock   See task on Roo Cloud

Updated MAX_TOOL_NAME_LENGTH from 64 to 128 per MCP spec. All tests (61) pass.

View commit | Revert commit

- 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.
* 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
Copy link
Contributor

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...

Copy link
Contributor

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

Copy link
Contributor Author

@roomote roomote bot Jan 16, 2026

Choose a reason for hiding this comment

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

Fixaroo Clock   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.

View commit | Revert commit

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.
@pdecat
Copy link
Contributor

pdecat commented Jan 16, 2026

@roomote Two tests are failing:

  38 passing (13m)
  2 failing
  1) Roo Code use_mcp_tool Tool
       Should request MCP time get_current_time tool and complete successfully:

      AssertionError [ERR_ASSERTION]: The use_mcp_tool should have been requested
      + expected - actual

      -false
      +true
      
  	at Context.<anonymous> (out/suite/tools/use-mcp-tool.test.js:239:20)

  2) Roo Code use_mcp_tool Tool
       Should request MCP time convert_time tool and complete successfully:
     Error: Timeout after 60s
  	at Timeout._onTimeout (out/suite/utils.js:27:24)
  	at listOnTimeout (node:internal/timers:588:17)
  	at process.processTimers (node:internal/timers:523:7)


[google/gemini-3-pro-preview] Completed: 38 passed, 2 failed (790.3s)

https://github.com/RooCodeInc/Roo-Code/actions/runs/21069991548/job/60596816909?pr=10770

@roomote
Copy link
Contributor Author

roomote bot commented Jan 16, 2026

Fixaroo Clock   Follow along on Roo Cloud

Working on the following issues:

  • Fix failing integration test: Should request MCP time get_current_time tool and complete successfully
  • Fix failing integration test: Should request MCP time convert_time tool and complete successfully

@roomote
Copy link
Contributor Author

roomote bot commented Jan 16, 2026

Fixaroo Clock   See task on Roo Cloud

I investigated the E2E test failures and found that they appear unrelated to this PR's code changes:

Verification performed:

  • All 67 unit tests pass (cd src && npx vitest run utils/__tests__/mcp-name.spec.ts)
  • TypeScript type checking passes (cd src && npx tsc --noEmit)

Analysis:
The failing tests use MCP time server tools (get_current_time, convert_time) which result in encoded names of ~23-28 characters, well under the 64-character limit where the new hash suffix logic activates. The code path for these short names is unchanged from main.

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:

  • 38 tests pass while only 2 specific MCP time server tests fail
  • The hash suffix logic only activates for names > 64 chars
  • Unit tests comprehensively verify the hash suffix roundtrip behavior

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Triage

Development

Successfully merging this pull request may close these issues.

[BUG] MCP tool names with hyphens fail when using native tool calling

3 participants