UNPKG

mcp-use

Version:

A utility library for integrating Model Context Protocol (MCP) with LangChain, Zod, and related tools. Provides helpers for schema conversion, event streaming, and SDK usage.

91 lines (90 loc) 3.32 kB
import { JSONSchemaToZod } from '@dmitryrechkin/json-schema-to-zod'; import { DynamicStructuredTool } from '@langchain/core/tools'; import { z } from 'zod'; import { logger } from '../logging.js'; import { BaseAdapter } from './base.js'; function schemaToZod(schema) { try { return JSONSchemaToZod.convert(schema); } catch (err) { logger.warn(`Failed to convert JSON schema to Zod: ${err}`); return z.any(); } } function parseMcpToolResult(toolResult) { if (toolResult.isError) { throw new Error(`Tool execution failed: ${toolResult.content}`); } if (!toolResult.content || toolResult.content.length === 0) { throw new Error('Tool execution returned no content'); } let decoded = ''; for (const item of toolResult.content) { switch (item.type) { case 'text': { decoded += item.text; break; } case 'image': { decoded += item.data; break; } case 'resource': { const res = item.resource; if (res?.text !== undefined) { decoded += res.text; } else if (res?.blob !== undefined) { // eslint-disable-next-line node/prefer-global/buffer decoded += res.blob instanceof Uint8Array || res.blob instanceof Buffer // eslint-disable-next-line node/prefer-global/buffer ? Buffer.from(res.blob).toString('base64') : String(res.blob); } else { throw new Error(`Unexpected resource type: ${res?.type}`); } break; } default: throw new Error(`Unexpected content type: ${item.type}`); } } return decoded; } export class LangChainAdapter extends BaseAdapter { constructor(disallowedTools = []) { super(disallowedTools); } /** * Convert a single MCP tool specification into a LangChainJS structured tool. */ convertTool(mcpTool, connector) { // Filter out disallowed tools early. if (this.disallowedTools.includes(mcpTool.name)) { return null; } // Derive a strict Zod schema for the tool's arguments. const argsSchema = mcpTool.inputSchema ? schemaToZod(mcpTool.inputSchema) : z.object({}).optional(); const tool = new DynamicStructuredTool({ name: mcpTool.name ?? 'NO NAME', description: mcpTool.description ?? '', // Blank is acceptable but discouraged. schema: argsSchema, func: async (input) => { logger.debug(`MCP tool \"${mcpTool.name}\" received input: ${JSON.stringify(input)}`); try { const result = await connector.callTool(mcpTool.name, input); return parseMcpToolResult(result); } catch (err) { logger.error(`Error executing MCP tool: ${err}`); return `Error executing MCP tool: ${String(err)}`; } }, }); return tool; } }