import { Client } from '@modelcontextprotocol/sdk/client/index.js' import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js' import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js' import { tool } from 'ai' import { z } from 'zod' /** * Connects to an external MCP Server and maps its tools to Vercel AI SDK Tools. */ export async function createMcpTools(mcpConfig: { name: string, url?: string, command?: string, args?: string[] }) { let transport // Support both HTTP/SSE and STDIO transports if (mcpConfig.url) { transport = new SSEClientTransport(new URL(mcpConfig.url)) } else if (mcpConfig.command) { transport = new StdioClientTransport({ command: mcpConfig.command, args: mcpConfig.args || [], }) } else { throw new Error('Invalid MCP config: Must provide either URL or Command.') } const client = new Client( { name: `payload-ai-client-${mcpConfig.name}`, version: '1.0.0' }, { capabilities: {} } ) await client.connect(transport) // Fetch available tools from the external MCP server const toolListResult = await client.listTools() const externalTools = toolListResult.tools || [] const aiSdkTools: Record = {} // Map each external tool to a Vercel AI SDK Tool for (const extTool of externalTools) { // Basic conversion of JSON Schema to Zod for the AI SDK // Note: For a production ready adapter, you might need a more robust jsonSchemaToZod converter // or use AI SDK's new experimental generateSchema feature if available. // Here we use a generic `z.any()` as a fallback since AI SDK requires a Zod schema. const toolSchema = extTool.inputSchema as Record // We create a simplified parameter parser. // An ideal approach uses `jsonSchemaToZod` library or native AI SDK JSON schema support // (introduced recently in `ai` package). aiSdkTools[`${mcpConfig.name}_${extTool.name}`] = tool({ description: `[From ${mcpConfig.name}] ${extTool.description || extTool.name}`, parameters: z.any().describe('JSON matching the original MCP input_schema'), // Simplify for prototype // @ts-ignore - AI strict mode overload bug with implicit zod inferences execute: async (args: any) => { const result = await client.callTool({ name: extTool.name, arguments: args }) return result } }) } return { tools: aiSdkTools, client } }