diff --git a/core/tools/mcpToolName.ts b/core/tools/mcpToolName.ts index 6440ef5e7..30ed18cec 100644 --- a/core/tools/mcpToolName.ts +++ b/core/tools/mcpToolName.ts @@ -1,7 +1,12 @@ import { MCPServerStatus, MCPTool } from ".."; - export function getMCPToolName(server: MCPServerStatus, tool: MCPTool) { - const serverPrefix = server.name.split(" ").join("_").toLowerCase(); + // Replace any sequence of non-alphanumeric characters with a single underscore + const serverPrefix = server.name + .toLowerCase() + .replace(/[^a-z0-9]+/g, "_") + .replace(/^_+|_+$/g, "") // Remove leading/trailing underscores + .replace(/_+/g, "_"); // Replace multiple sequential underscores with single underscore + if (tool.name.startsWith(serverPrefix)) { return tool.name; } diff --git a/core/tools/mcpToolName.vitest.ts b/core/tools/mcpToolName.vitest.ts index ff60d5200..ad3815a9a 100644 --- a/core/tools/mcpToolName.vitest.ts +++ b/core/tools/mcpToolName.vitest.ts @@ -56,3 +56,54 @@ test("getMCPToolName - handles mixed case in server names", () => { const result = getMCPToolName(server, tool); expect(result).toBe("gitlab_create_merge_request"); }); + +test("getMCPToolName - handles server names with special characters (parentheses)", () => { + const server = createMcpServer("Linear MCP (SSE)"); + const tool = createMCPTool("create_issue"); + + const result = getMCPToolName(server, tool); + // Should only contain alphanumeric characters and underscores + expect(result).toMatch(/^[a-zA-Z0-9_]+$/); + expect(result).toBe("linear_mcp_sse_create_issue"); +}); + +test("getMCPToolName - handles server names with dots and other special characters", () => { + const server = createMcpServer("My.Server@Test!"); + const tool = createMCPTool("test_action"); + + const result = getMCPToolName(server, tool); + // Should only contain alphanumeric characters and underscores + expect(result).toMatch(/^[a-zA-Z0-9_]+$/); + expect(result).toBe("my_server_test_test_action"); +}); + +test("getMCPToolName - handles server names with multiple consecutive special characters", () => { + const server = createMcpServer("Server@@##Name"); + const tool = createMCPTool("action"); + + const result = getMCPToolName(server, tool); + // Should only contain alphanumeric characters and underscores (no hyphens or multiple underscores) + expect(result).toMatch(/^[a-zA-Z0-9_]+$/); + expect(result).toBe("server_name_action"); +}); + +test("getMCPToolName - handles server names with hyphens", () => { + const server = createMcpServer("My-Server-Name"); + const tool = createMCPTool("test_action"); + + const result = getMCPToolName(server, tool); + // Should only contain alphanumeric characters and underscores + expect(result).toMatch(/^[a-zA-Z0-9_]+$/); + expect(result).toBe("my_server_name_test_action"); +}); + +test("getMCPToolName - handles multiple consecutive underscores in server name", () => { + const server = createMcpServer("Linear__MCP"); + const tool = createMCPTool("create_issue"); + + const result = getMCPToolName(server, tool); + // Should only contain alphanumeric characters and single underscores + expect(result).toMatch(/^[a-zA-Z0-9_]+$/); + expect(result).not.toMatch(/__/); + expect(result).toBe("linear_mcp_create_issue"); +});