UNPKG

@copilotkit/runtime

Version:

<img src="https://github.com/user-attachments/assets/0a6b64d9-e193-4940-a3f6-60334ac34084" alt="banner" style="border-radius: 12px; border: 2px solid #d6d4fa;" />

155 lines (151 loc) • 6.79 kB
require("reflect-metadata"); //#region src/lib/runtime/mcp-tools-utils.ts /** * Extracts CopilotKit-compatible parameters from an MCP tool schema. * @param toolOrSchema The schema object from an MCPTool or the full MCPTool object. * @returns An array of Parameter objects. */ function extractParametersFromSchema(toolOrSchema) { const parameters = []; const schema = "schema" in (toolOrSchema || {}) ? toolOrSchema.schema : toolOrSchema; const toolParameters = schema?.parameters?.jsonSchema || schema?.parameters; const properties = toolParameters?.properties; const requiredParams = new Set(toolParameters?.required || []); if (!properties) return parameters; for (const paramName in properties) if (Object.prototype.hasOwnProperty.call(properties, paramName)) { const paramDef = properties[paramName]; let type = paramDef.type || "string"; let description = paramDef.description || ""; if (type === "array" && paramDef.items) { const itemType = paramDef.items.type || "object"; if (itemType === "object" && paramDef.items.properties) { const itemProperties = Object.keys(paramDef.items.properties).join(", "); description = description + (description ? " " : "") + `Array of objects with properties: ${itemProperties}`; } else type = `array<${itemType}>`; } let enumValues; if (paramDef.enum && Array.isArray(paramDef.enum)) { enumValues = paramDef.enum.map(String); const enumDisplay = enumValues.join(" | "); description = description + (description ? " " : "") + `Allowed values: ${enumDisplay}`; } let attributes; if (type === "object" && paramDef.properties) { const objectProperties = Object.keys(paramDef.properties).join(", "); description = description + (description ? " " : "") + `Object with properties: ${objectProperties}`; attributes = extractParametersFromSchema({ parameters: { properties: paramDef.properties, required: paramDef.required || [] } }); } if (type === "array" && paramDef.items?.type === "object" && paramDef.items?.properties) attributes = extractParametersFromSchema({ parameters: { properties: paramDef.items.properties, required: paramDef.items.required || [] } }); const param = { name: paramName, type, description, required: requiredParams.has(paramName) }; if (type === "string" && enumValues) param.enum = enumValues; if (attributes && attributes.length > 0) { param.attributes = attributes; if (type === "array") param.type = "object[]"; } parameters.push(param); } return parameters; } /** * Converts a map of MCPTools into an array of CopilotKit Actions. * @param mcpTools A record mapping tool names to MCPTool objects. * @param mcpEndpoint The endpoint URL from which these tools were fetched. * @returns An array of Action<any> objects. */ function convertMCPToolsToActions(mcpTools, mcpEndpoint) { const actions = []; for (const [toolName, tool] of Object.entries(mcpTools)) { const parameters = extractParametersFromSchema(tool); const handler = async (params) => { try { const result = await tool.execute(params); return typeof result === "string" ? result : JSON.stringify(result); } catch (error) { console.error(`Error executing MCP tool '${toolName}' from endpoint ${mcpEndpoint}:`, error); throw new Error(`Execution failed for MCP tool '${toolName}': ${error instanceof Error ? error.message : String(error)}`, { cause: error }); } }; actions.push({ name: toolName, description: tool.description || `MCP tool: ${toolName} (from ${mcpEndpoint})`, parameters, handler, _isMCPTool: true, _mcpEndpoint: mcpEndpoint }); } return actions; } /** * Generate better instructions for using MCP tools * This is used to enhance the system prompt with tool documentation */ function generateMcpToolInstructions(toolsMap) { if (!toolsMap || Object.keys(toolsMap).length === 0) return ""; return `You have access to the following external tools provided by Model Context Protocol (MCP) servers: ${Object.entries(toolsMap).map(([name, tool]) => { let paramsDoc = " No parameters required"; try { if (tool.schema && typeof tool.schema === "object") { const schema = tool.schema; const toolParameters = schema.parameters?.jsonSchema || schema.parameters; const properties = toolParameters?.properties || schema.properties; const requiredParams = toolParameters?.required || schema.required || []; if (properties) { const paramsList = Object.entries(properties).map(([paramName, propSchema]) => { const propDetails = propSchema; const requiredMark = requiredParams.includes(paramName) ? "*" : ""; let typeInfo = propDetails.type || "any"; let description = propDetails.description ? ` - ${propDetails.description}` : ""; if (typeInfo === "array" && propDetails.items) { const itemType = propDetails.items.type || "object"; if (itemType === "object" && propDetails.items.properties) { const itemProps = Object.keys(propDetails.items.properties).join(", "); typeInfo = `array<object>`; description = description + (description ? " " : " - ") + `Array of objects with properties: ${itemProps}`; } else typeInfo = `array<${itemType}>`; } if (propDetails.enum && Array.isArray(propDetails.enum)) { const enumValues = propDetails.enum.join(" | "); description = description + (description ? " " : " - ") + `Allowed values: ${enumValues}`; } if (typeInfo === "object" && propDetails.properties) { const objectProps = Object.keys(propDetails.properties).join(", "); description = description + (description ? " " : " - ") + `Object with properties: ${objectProps}`; } return ` - ${paramName}${requiredMark} (${typeInfo})${description}`; }); if (paramsList.length > 0) paramsDoc = paramsList.join("\n"); } } } catch (e) { console.error(`Error parsing schema for tool ${name}:`, e); } return `- ${name}: ${tool.description || ""} ${paramsDoc}`; }).join("\n\n")} When using these tools: 1. Only provide valid parameters according to their type requirements 2. Required parameters are marked with * 3. For array parameters, provide data in the correct array format 4. For object parameters, include all required nested properties 5. For enum parameters, use only the allowed values listed 6. Format API calls correctly with the expected parameter structure 7. Always check tool responses to determine your next action`; } //#endregion exports.convertMCPToolsToActions = convertMCPToolsToActions; exports.extractParametersFromSchema = extractParametersFromSchema; exports.generateMcpToolInstructions = generateMcpToolInstructions; //# sourceMappingURL=mcp-tools-utils.cjs.map