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, jsonSchema } from "ai"; /** * 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: jsonSchema(toolSchema as any), // @ts-expect-error - 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 }; }