Skip to content

tool_search can miss exactly named deferred MCP tools, causing false unavailable conclusions #21503

Description

@dergachoff

tool_search can omit a deferred MCP tool even when the user/model query names that tool exactly.

In a real Codex session with codebase-memory-mcp configured and working, a broad discovery query like:

search_graph trace_path get_code_snippet query_graph search_code index_repository codebase-memory-mcp

did not surface search_graph in the first tool_search result set. A second exact-name query for:

search_graph

did surface the tool.

That creates a false negative: the agent may conclude an MCP tool is unavailable when it is actually installed, callable, and discoverable through a more specific query.

This matters because deferred tool discovery is now a core path for MCP-heavy workflows. Agents are commonly instructed to search for a family of tools first, then fall back only if expected tools are unavailable. A top-N ranking miss makes that workflow unreliable and pushes agents toward worse fallbacks like shell search.

Likely root cause from main: codex-rs/core/src/tools/handlers/tool_search.rs ranks deferred tools through BM25 over ToolSearchEntry.search_text. ToolSearchEntry includes canonical/callable/raw names in the search text, but the handler does not guarantee that exact tool-name matches survive the requested/default result limit.

What steps can reproduce the bug?

  1. Configure an MCP server whose tools are deferred behind tool_search.
  2. Include a tool with a specific callable name, for example search_graph.
  3. Have enough deferred tools with overlapping descriptions/server vocabulary that top-N BM25 ranking is competitive.
  4. Run tool_search with a broad discovery query that includes the exact tool name plus related tool names/server names, for example:
search_graph trace_path get_code_snippet query_graph search_code index_repository codebase-memory-mcp
  1. Observe that the exact named tool can be omitted from the first result set.
  2. Run tool_search again with only the exact name:
search_graph
  1. Observe that the tool is returned.

What is the expected behavior?

If a tool_search query contains an exact deferred tool name, callable name, or canonical MCP name, matching tools should be included ahead of lower-confidence BM25-only matches, while still respecting the requested/default result limit.

Exact-name matches should not require a second retry query to prove the tool exists.

Additional information

I investigated the current implementation and prototyped a small fix locally.

Prototype shape:

  • Add normalized exact-match terms to ToolSearchEntry.
  • For MCP tools, exact terms include canonical MCP name, callable name, and raw tool name.
  • For dynamic tools, exact terms include tool name and namespaced tool name.
  • In ToolSearchHandler, prepend exact-name matches before BM25 results, dedupe by entry id, then truncate to the requested/default limit.
  • Preserve the existing computer-use expanded default cap behavior.

Local validation:

cargo test -p codex-core tools::handlers::tool_search::tests
cargo clippy -p codex-core --lib

Results:

  • tool_search handler tests: 6 passed.
  • clippy: no issues found.

I noticed open PR #19881 overlaps the deferred MCP / tool_search area. If maintainers prefer, this could be handled as a follow-up to that direction rather than as a standalone change.

I am happy to share the patch or open a PR if invited.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingmcpIssues related to the use of model context protocol (MCP) serverstool-callsIssues related to tool calling

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions