diff --git a/src/hooks/useAgentLoop.ts b/src/hooks/useAgentLoop.ts index 63e9e38..61b4ef6 100644 --- a/src/hooks/useAgentLoop.ts +++ b/src/hooks/useAgentLoop.ts @@ -15,6 +15,7 @@ import type { import type { ChatMessage, Tool, ToolCall, InferenceRequest } from '@/types/inference'; import { useInference } from '@/contexts/InferenceContext'; import { useMCP } from '@/contexts/MCPContext'; +import { normalizeServerName } from '@/utils/mcpUtils'; // Test tools that work alongside MCP tools const testTools: TestTool[] = [ @@ -226,17 +227,19 @@ export function useAgentLoop(config: Partial = {}): UseAgentLoo // Check if it's an MCP tool (prefixed with server name using double underscore) if (toolCall.function.name.includes('__')) { - // Extract server name from tool name (format: "server__tool_name") - const [serverName] = toolCall.function.name.split('__'); + // Extract normalized server name from tool name (format: "normalized_server__tool_name") + const [normalizedServerName] = toolCall.function.name.split('__'); - // Find the connection ID for this server name - const connection = connections.find(conn => conn.name === serverName); + // Find the connection ID by comparing normalized server names + const connection = connections.find(conn => { + return normalizeServerName(conn.name) === normalizedServerName; + }); if (connection) { const result = await callMCPTool(connection.id, toolCall.function.name, toolCall.function.arguments); return { result }; } else { - throw new Error(`MCP server "${serverName}" not found or not connected`); + throw new Error(`MCP server with normalized name "${normalizedServerName}" not found or not connected`); } } diff --git a/src/mcp/connection.ts b/src/mcp/connection.ts index 92ca4a9..1b13ad0 100644 --- a/src/mcp/connection.ts +++ b/src/mcp/connection.ts @@ -17,6 +17,7 @@ import type { MCPError, } from '@/types/mcp'; import type { Tool } from '@/types/inference'; +import { normalizeServerName } from '@/utils/mcpUtils'; interface MCPOAuthState { codeVerifier: string; @@ -587,10 +588,11 @@ export class MCPConnectionManager { // Transform MCP tools to our Tool interface with name prefixing // Use double underscore instead of dot to comply with OpenRouter API requirements + const normalizedServerName = normalizeServerName(this.connection.name); return result.tools.map(tool => ({ type: 'function' as const, function: { - name: `${this.connection.name}__${tool.name}`, + name: `${normalizedServerName}__${tool.name}`, description: `[${this.connection.name}] ${tool.description || ''}`, parameters: tool.inputSchema || {}, }, @@ -643,8 +645,9 @@ export class MCPConnectionManager { } // Remove the server prefix from the tool name (using double underscore separator) - const unprefixedName = toolName.startsWith(`${this.connection.name}__`) - ? toolName.slice(this.connection.name.length + 2) + const normalizedServerName = normalizeServerName(this.connection.name); + const unprefixedName = toolName.startsWith(`${normalizedServerName}__`) + ? toolName.slice(normalizedServerName.length + 2) : toolName; try { diff --git a/src/providers/openrouter/client.ts b/src/providers/openrouter/client.ts index f26fc0f..2243cbd 100644 --- a/src/providers/openrouter/client.ts +++ b/src/providers/openrouter/client.ts @@ -126,10 +126,6 @@ export class OpenRouterClient { const inputCost = parseFloat(openRouterModel.pricing.prompt); const outputCost = parseFloat(openRouterModel.pricing.completion); - // Check if model supports tools by looking at supported_parameters - const supportsTools = openRouterModel.supported_parameters?.includes('tools') || false; - console.log(`Model ${openRouterModel.id} supports tools: ${supportsTools}`); - return { id: openRouterModel.id, name: openRouterModel.name, diff --git a/src/utils/mcpUtils.ts b/src/utils/mcpUtils.ts new file mode 100644 index 0000000..eebc103 --- /dev/null +++ b/src/utils/mcpUtils.ts @@ -0,0 +1,14 @@ +// Utility functions for MCP server name normalization + +/** + * Normalize server name to comply with OpenRouter API tool naming requirements + * Pattern: ^[a-zA-Z0-9_-]{1,64}$ + */ +export function normalizeServerName(name: string): string { + return name + .replace(/[^a-zA-Z0-9_-]/g, '_') // Replace invalid characters with underscore + .replace(/_{2,}/g, '_') // Replace multiple underscores with single + .replace(/^_+|_+$/g, '') // Remove leading/trailing underscores + .substring(0, 32) // Limit length to leave room for tool name + || 'server'; // Fallback if name becomes empty +} \ No newline at end of file