fix(agent): repair MCP tool names with dropped mcp__server__ prefix - #61336
fix(agent): repair MCP tool names with dropped mcp__server__ prefix#61336yingliang-zhang wants to merge 1 commit into
Conversation
Models (notably GLM) sometimes emit MCP tool names without the full mcp__<server>__ prefix — e.g. list_memory_projects instead of mcp__basic_memory__list_memory_projects. The existing repair pipeline (case-folding, CamelCase, suffix stripping, fuzzy match at 0.7 cutoff) cannot map the bare suffix back to the full prefixed name, so the call fails with "Unknown tool" and the agent burns 3 retries before aborting with "Model generated invalid tool call". Add two repair paths in repair_tool_call() before the fuzzy-match fallback: 1. Bare suffix (no __ in emitted name): scan registered mcp__ tools and match on the tool-suffix portion. Skip when ambiguous (multiple servers expose the same suffix) to avoid non-deterministic routing. 2. Partial prefix (__ in emitted name but missing mcp__): prepend mcp__ and check for an exact match. The mcp__server__tool naming convention was introduced in NousResearch#52750 (merged 2026-07-05). Prior PRs NousResearch#21696, NousResearch#37100, NousResearch#33359 target the old single-underscore mcp_ format and do not apply to the new convention. 9 new tests in TestMcpPrefixRepair covering both cases, ambiguity guard, and non-MCP tool passthrough. All 38 tests in test_repair_tool_call_name.py pass.
9849848 to
c464de1
Compare
|
Thanks for the focused investigation and for covering the ambiguity case. This automated hermes-sweeper review is closing this under the standing
Please re-scope any follow-up to the model/provider or MCP schema/prompt source that emits the incorrect name rather than adding another core output-repair path. Closed as not-planned per standing maintainer policy ( |
|
Hi @teknium1, I'd like to request a second look on this. I believe the The existing
All of these are model-output-repair by the same definition. They all normalize/reconstruct incorrect model emissions before the error-retry path in This PR adds two patterns to the same function, same mechanism:
These are structurally identical to steps 3-4 (CamelCase conversion, suffix stripping) — they normalize a known model emission pattern back to the registered name. No new function, no new code path, no new architectural surface. Just two additional Why the model/provider-level fix is insufficient here: The root cause is that models like GLM-5.2 sometimes drop the Summary: This PR is a natural extension of the existing Happy to re-scope or adjust if there are concerns I'm missing. |
What
Models (notably GLM) sometimes emit MCP tool names without the full
mcp__<server>__prefix — e.g.list_memory_projectsinstead ofmcp__basic_memory__list_memory_projects. The existing_repair_tool_callpipeline (case-folding, CamelCase, suffix stripping, fuzzy match at 0.7 cutoff) cannot map the bare suffix back to the full prefixed name. The call fails with "Unknown tool", the agent burns 3 retries, then aborts withModel generated invalid tool call: list_memory_projects.Root cause
After #52750 (merged 2026-07-05) adopted the
mcp__server__tooldouble-underscore naming convention, the repair pipeline has no strategy to bridge a bare tool suffix to its fullmcp__server__toolregistered name. The fuzzy matcher scoreslist_memory_projectsvsmcp__basic_memory__list_memory_projectswell below the 0.7 cutoff.Prior PRs #21696, #37100, #33359 all target the old single-underscore
mcp_format and do not apply to the new convention. #21696 also modifiesrun_agent.py(the pre-refactor location of_repair_tool_call), which would conflict with the currentagent/agent_runtime_helpers.pylocation.Fix
Add two repair paths in
repair_tool_call()before the fuzzy-match fallback:Case 1 — bare suffix (no
__in emitted name): scan registeredmcp__tools and match on the tool-suffix portion (parts[2]after splitting on__). Skip when ambiguous (multiple servers expose the same suffix) to avoid non-deterministic routing.Case 2 — partial prefix (
__in emitted name but missingmcp__): prependmcp__and check for an exact match. Handlesbasic_memory__list_memory_projects→mcp__basic_memory__list_memory_projects.Both paths only resolve on exact matches — they cannot mis-route non-MCP tools.
How to reproduce
basic_memory) with tools registered asmcp__basic_memory__list_memory_projectslist_memory_projects→Tool 'list_memory_projects' does not exist→ 3 retries → session abortsTests
9 new tests in
TestMcpPrefixRepair:test_bare_suffix_matches_mcp_toollist_memory_projects→ full nametest_bare_suffix_different_servertest_bare_suffix_with_underscores_in_nametest_non_mcp_tool_unaffectedtest_unknown_bare_name_returns_nonetest_partial_prefix_prepends_mcpserver__tool→mcp__server__tooltest_partial_prefix_different_servertest_partial_prefix_unknown_returns_nonetest_ambiguous_bare_suffix_skips_repairAll 38 tests in
test_repair_tool_call_name.pypass.Related
mcp__server__toolnaming conventionmcp_prefix (old single-underscore format, pre-feat(mcp): adopt mcp__server__tool naming convention (port from opencode#33533) #52750)mcp_<server>_prefix before fuzzy match (old format)mcp_prefixes (old format)mcp_prefix fuzzy match failuresPlatform
Tested on macOS 26.5 / Python 3.11.