diff --git a/src/utils/__tests__/mcp-name.spec.ts b/src/utils/__tests__/mcp-name.spec.ts index 9b6eac6d0c..cb25e33e34 100644 --- a/src/utils/__tests__/mcp-name.spec.ts +++ b/src/utils/__tests__/mcp-name.spec.ts @@ -33,7 +33,7 @@ describe("mcp-name utilities", () => { }) it("should have correct max tool name length", () => { - expect(MAX_TOOL_NAME_LENGTH).toBe(128) + expect(MAX_TOOL_NAME_LENGTH).toBe(64) }) it("should have correct hash suffix length", () => { @@ -165,24 +165,24 @@ describe("mcp-name utilities", () => { expect(buildMcpToolName("server@name", "tool!name")).toBe("mcp--servername--toolname") }) - it("should truncate long names to 128 characters with hash suffix", () => { - const longServer = "a".repeat(80) - const longTool = "b".repeat(80) + it("should truncate long names to 64 characters with hash suffix", () => { + const longServer = "a".repeat(50) + const longTool = "b".repeat(50) const result = buildMcpToolName(longServer, longTool) - expect(result.length).toBeLessThanOrEqual(128) - expect(result.length).toBe(128) + expect(result.length).toBeLessThanOrEqual(64) + expect(result.length).toBe(64) expect(result.startsWith("mcp--")).toBe(true) // Should end with underscore + 8 char hash suffix expect(result).toMatch(/_[a-f0-9]{8}$/) }) it("should use hash suffix for long names and cache them", () => { - const longServer = "a".repeat(80) - const longTool = "b".repeat(80) + const longServer = "a".repeat(50) + const longTool = "b".repeat(50) const result = buildMcpToolName(longServer, longTool) // The shortened name should be deterministic - expect(result.length).toBe(128) + expect(result.length).toBe(64) expect(result).toMatch(/_[a-f0-9]{8}$/) // Building again should return the same result (from cache) @@ -191,8 +191,8 @@ describe("mcp-name utilities", () => { }) it("should produce deterministic hash suffixes", () => { - const longServer = "a".repeat(80) - const longTool = "b".repeat(80) + const longServer = "a".repeat(50) + const longTool = "b".repeat(50) // Build the same name twice with cache cleared between clearEncodedNameCache() const result1 = buildMcpToolName(longServer, longTool) @@ -203,12 +203,12 @@ describe("mcp-name utilities", () => { }) it("should produce unique hash suffixes for different tools", () => { - const longServer = "a".repeat(80) - const result1 = buildMcpToolName(longServer, "tool1_" + "x".repeat(70)) - const result2 = buildMcpToolName(longServer, "tool2_" + "y".repeat(70)) + const longServer = "a".repeat(50) + const result1 = buildMcpToolName(longServer, "tool1_" + "x".repeat(40)) + const result2 = buildMcpToolName(longServer, "tool2_" + "y".repeat(40)) // Both should be truncated - expect(result1.length).toBe(128) - expect(result2.length).toBe(128) + expect(result1.length).toBe(64) + expect(result2.length).toBe(64) // Should have different hash suffixes expect(result1).not.toBe(result2) }) @@ -437,7 +437,7 @@ describe("mcp-name utilities", () => { // Should NOT have hash suffix expect(builtName).toBe("mcp--server--get___data") - expect(builtName.length).toBeLessThan(128) + expect(builtName.length).toBeLessThan(64) // Normal decode path should work const parsed = parseMcpToolName(builtName) @@ -456,7 +456,7 @@ describe("mcp-name utilities", () => { const encodedName = buildMcpToolName(serverName, toolName) // Should be truncated to 128 chars with hash suffix - expect(encodedName.length).toBe(128) + expect(encodedName.length).toBe(64) expect(encodedName).toMatch(/_[a-f0-9]{8}$/) // The new approach: use findToolByEncodedMcpName to find the matching tool @@ -487,8 +487,8 @@ describe("mcp-name utilities", () => { }) it("should find tool for shortened names with hash suffix", () => { - const serverName = "a".repeat(80) - const toolName = "b".repeat(80) + "-hyphen" + const serverName = "a".repeat(50) + const toolName = "b".repeat(50) + "-hyphen" const encodedName = buildMcpToolName(serverName, toolName) // The encoded name should have a hash suffix @@ -541,8 +541,8 @@ describe("mcp-name utilities", () => { describe("clearEncodedNameCache", () => { it("should clear the encoded name cache", () => { // Build some names to populate cache - const longServer = "a".repeat(80) - const longTool = "b".repeat(80) + const longServer = "a".repeat(50) + const longTool = "b".repeat(50) buildMcpToolName(longServer, longTool) buildMcpToolName("server", "tool") @@ -552,7 +552,7 @@ describe("mcp-name utilities", () => { // Verify cache is cleared by checking that rebuilding takes the same path // (we can't directly access the cache, but the function should work) const result = buildMcpToolName(longServer, longTool) - expect(result.length).toBe(128) + expect(result.length).toBe(64) expect(result).toMatch(/_[a-f0-9]{8}$/) }) }) diff --git a/src/utils/mcp-name.ts b/src/utils/mcp-name.ts index 57ff975677..cd1d782313 100644 --- a/src/utils/mcp-name.ts +++ b/src/utils/mcp-name.ts @@ -33,10 +33,10 @@ export const MCP_TOOL_PREFIX = "mcp" export const HYPHEN_ENCODING = "___" /** - * Maximum length for tool names (MCP spec limit). - * See: https://modelcontextprotocol.io/specification/2025-11-25/server/tools#tool-names + * Maximum length for tool names (Gemini's function name limit). + * * The MCP spec recommends 128, but Gemini enforces 64 characters. */ -export const MAX_TOOL_NAME_LENGTH = 128 +export const MAX_TOOL_NAME_LENGTH = 64 /** * Length of hash suffix used when truncation is needed. @@ -192,7 +192,7 @@ export function sanitizeMcpName(name: string): string { * Build a full MCP tool function name from server and tool names. * The format is: mcp--{sanitized_server_name}--{sanitized_tool_name} * - * The total length is capped at 128 characters per MCP spec. + * The total length is capped at 64 characters for Gemini compatibility. * When truncation is needed, a hash suffix is appended to preserve uniqueness. * The result is cached for efficient repeated lookups. * @@ -224,7 +224,7 @@ export function buildMcpToolName(serverName: string, toolName: string): string { // Format: truncated_name_HASHSUFFIX (underscore + 8 hex chars = 9 chars for suffix) const hashSuffix = computeHashSuffix(serverName, toolName) const suffixWithSeparator = `_${hashSuffix}` // "_" + 8 chars = 9 chars - const maxTruncatedLength = MAX_TOOL_NAME_LENGTH - suffixWithSeparator.length // 128 - 9 = 119 + const maxTruncatedLength = MAX_TOOL_NAME_LENGTH - suffixWithSeparator.length // 64 - 9 = 55 // Truncate the full name and append hash suffix const truncatedBase = fullName.slice(0, maxTruncatedLength)