Use MCP server instructions in deferred namespace descriptions (#21053)

## Why

MCP servers can provide `instructions` that explain what their tools are
for. Directly exposed MCP namespaces already use those instructions when
a connector description is not available, but deferred `tool_search`
results did not preserve that fallback. The direct path falls back from
connector metadata to server instructions, while the deferred path only
carried `connector_description` and otherwise fell back to generic
namespace text.

That meant a plain MCP server could provide useful model-facing guidance
and still appear as `Tools in the X namespace.` whenever it was
discovered lazily through `tool_search`.

## What changed

- Store one model-facing `namespace_description` on `ToolInfo`, using
connector descriptions for connector-backed tools and server
instructions for plain MCP servers.
- Thread that namespace description through the `tool_search` source
list, search indexing, and returned namespace metadata.
- Add an end-to-end regression test for deferred non-app MCP search
results exposing server instructions as the namespace description.

## Verification

- `cargo test -p codex-tools
search_tool_description_lists_each_mcp_source_once --lib`
- `cargo test -p codex-core --test all
tool_search_uses_non_app_mcp_server_instructions_as_namespace_description`
This commit is contained in:
sayan-oai authored and GitHub committed 2026-05-04 19:36:07 +00:00
1 parent 48402be6fa
commit b9e8df47da
16 files changed
+138 -52

No files matched your search

+9 -5
View File
@@ -27,7 +27,7 @@ pub struct ToolSearchSourceInfo {
pub struct ToolSearchSource<'a> {
pub server_name: &'a str,
pub connector_name: Option<&'a str>,
pub connector_description: Option<&'a str>,
pub description: Option<&'a str>,
}
#[derive(Clone, Copy, Debug, PartialEq)]
@@ -37,7 +37,7 @@ pub struct ToolSearchResultSource<'a> {
pub tool_name: &'a str,
pub tool: &'a rmcp::model::Tool,
pub connector_name: Option<&'a str>,
pub connector_description: Option<&'a str>,
pub description: Option<&'a str>,
}
#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
@@ -215,7 +215,7 @@ pub fn tool_search_result_source_to_loadable_tool_spec(
fn tool_search_result_source_namespace_description(source: ToolSearchResultSource<'_>) -> String {
source
.connector_description
.description
.map(str::trim)
.filter(|description| !description.is_empty())
.map(str::to_string)
@@ -251,7 +251,7 @@ pub fn collect_tool_search_source_infos<'a>(
return Some(ToolSearchSourceInfo {
name: name.to_string(),
description: tool
.connector_description
.description
.map(str::trim)
.filter(|description| !description.is_empty())
.map(str::to_string),
@@ -265,7 +265,11 @@ pub fn collect_tool_search_source_infos<'a>(
Some(ToolSearchSourceInfo {
name: name.to_string(),
description: None,
description: tool
.description
.map(str::trim)
.filter(|description| !description.is_empty())
.map(str::to_string),
})
})
.collect()