Raise the MCP tool name limit to 128 bytes (#39594)

## Why

The Responses API accepts tool names up to 128 bytes, but MCP tool name
normalization limited model-visible names to 64 bytes.

## What changed

- Preserve MCP tool names up to the 128-byte Responses API limit.
- Continue shortening and hashing names that exceed the limit so generated
  names remain bounded and unique.

## Testing

- Cover names at the 128-byte boundary and immediately above it.
- Verify distinct long names remain 128 bytes and code-mode compatible.

GitOrigin-RevId: 75544d00e75dd0e9328b3e2ac763d26f9cc99a48
This commit is contained in:
Angad Singh
2026-08-19 18:29:59 +00:00
committed by copyberry
parent 493e0efb7b
commit 1bfabb21fe
2 changed files with 30 additions and 11 deletions

View File

@@ -1440,19 +1440,38 @@ fn test_normalize_tools_duplicated_names_skipped() {
);
}
#[test]
fn test_normalize_tools_respects_responses_api_name_length_boundaries() {
let namespace = "mcp__codex_apps";
let namespace_len = namespace.len() + "__".len();
for total_len in [128, 129] {
let tool_name = "a".repeat(total_len - namespace_len);
let model_tools = normalize_tools_for_model_with_prefix(
vec![create_test_tool("codex_apps", &tool_name)],
/*prefix_mcp_tool_names*/ true,
&[],
);
let model_name = model_tools[0].canonical_tool_name();
assert_eq!(model_tool_name_len(&model_name), 128);
if total_len == 128 {
assert_eq!(model_name, ToolName::namespaced(namespace, tool_name));
} else {
assert_ne!(model_name.name, tool_name);
}
}
}
#[test]
fn test_normalize_tools_long_names_same_server() {
let server_name = "my_server";
let first_name = "a".repeat(128);
let second_name = "b".repeat(128);
let tools = vec![
create_test_tool(
server_name,
"extremely_lengthy_function_name_that_absolutely_surpasses_all_reasonable_limits",
),
create_test_tool(
server_name,
"yet_another_extremely_lengthy_function_name_that_absolutely_surpasses_all_reasonable_limits",
),
create_test_tool(server_name, &first_name),
create_test_tool(server_name, &second_name),
];
let model_tools =
@@ -1462,7 +1481,7 @@ fn test_normalize_tools_long_names_same_server() {
let names = model_tool_names(&model_tools);
assert!(names.iter().all(|name| model_tool_name_len(name) == 64));
assert!(names.iter().all(|name| model_tool_name_len(name) == 128));
assert!(
names
.iter()

View File

@@ -106,7 +106,7 @@ pub(crate) fn filter_tools(tools: Vec<ToolInfo>, filter: &ToolFilter) -> Vec<Too
///
/// Raw MCP server/tool names are kept on each [`ToolInfo`] for protocol calls, while
/// `callable_namespace` / `callable_name` are sanitized and, when necessary, hashed so
/// every model-visible name is unique and <= 64 bytes.
/// every model-visible name is unique and <= 128 bytes.
///
/// When `prefix_mcp_tool_names` is true, the historical `mcp__` namespace
/// prefix is added except for tools from `non_prefixed_mcp_tool_servers`.
@@ -223,7 +223,7 @@ struct CallableToolCandidate {
}
const MCP_TOOL_NAME_DELIMITER: &str = "__";
const MAX_TOOL_NAME_LENGTH: usize = 64;
const MAX_TOOL_NAME_LENGTH: usize = 128;
const CALLABLE_NAME_HASH_LEN: usize = 12;
fn callable_namespace_with_prefix(namespace: &str, prefix_mcp_tool_names: bool) -> String {
if !prefix_mcp_tool_names || namespace.starts_with(LEGACY_MCP_TOOL_NAME_PREFIX) {