genkitx-mcp
Version:
A Genkit plugin that provides interoperability between Genkit and Model Context Protocol (MCP). Both client and server use cases are supported.
1 lines • 11.9 kB
Source Map (JSON)
{"version":3,"sources":["../src/server.ts"],"sourcesContent":["/**\n * Copyright 2024 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n Genkit,\n GenkitError,\n Message,\n MessageData,\n PromptAction,\n} from 'genkit';\nimport type { McpServerOptions } from './index.js';\n\nimport { toJsonSchema } from '@genkit-ai/core/schema';\nimport type { Server } from '@modelcontextprotocol/sdk/server/index.js' with { 'resolution-mode': 'import' };\nimport type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js' with { 'resolution-mode': 'import' };\nimport type {\n CallToolRequest,\n CallToolResult,\n GetPromptRequest,\n GetPromptResult,\n ListPromptsRequest,\n ListPromptsResult,\n ListToolsRequest,\n ListToolsResult,\n Prompt,\n PromptMessage,\n Tool,\n} from '@modelcontextprotocol/sdk/types.js' with { 'resolution-mode': 'import' };\nimport { logger } from 'genkit/logging';\nimport { ToolAction, toToolDefinition } from 'genkit/tool';\nexport class GenkitMcpServer {\n ai: Genkit;\n options: McpServerOptions;\n server?: Server;\n actionsResolved: boolean = false;\n toolActions: ToolAction[] = [];\n promptActions: PromptAction[] = [];\n\n constructor(ai: Genkit, options: McpServerOptions) {\n this.ai = ai;\n this.options = options;\n this.setup();\n }\n\n async setup(): Promise<void> {\n if (this.actionsResolved) return;\n const { Server } = await import(\n '@modelcontextprotocol/sdk/server/index.js'\n );\n\n this.server = new Server(\n { name: this.options.name, version: this.options.version || '1.0.0' },\n {\n capabilities: {\n prompts: {},\n tools: {},\n },\n }\n );\n\n const {\n CallToolRequestSchema,\n GetPromptRequestSchema,\n ListPromptsRequestSchema,\n ListToolsRequestSchema,\n } = await import('@modelcontextprotocol/sdk/types.js');\n\n this.server.setRequestHandler(\n ListToolsRequestSchema,\n this.listTools.bind(this)\n );\n this.server.setRequestHandler(\n CallToolRequestSchema,\n this.callTool.bind(this)\n );\n this.server.setRequestHandler(\n ListPromptsRequestSchema,\n this.listPrompts.bind(this)\n );\n this.server.setRequestHandler(\n GetPromptRequestSchema,\n this.getPrompt.bind(this)\n );\n\n const allActions = await this.ai.registry.listActions();\n const toolList: ToolAction[] = [];\n const promptList: PromptAction[] = [];\n for (const k in allActions) {\n console.log('action:', k);\n if (k.startsWith('/tool/')) {\n toolList.push(allActions[k] as ToolAction);\n } else if (k.startsWith('/prompt/')) {\n promptList.push(allActions[k] as PromptAction);\n }\n }\n this.toolActions = toolList;\n this.promptActions = promptList;\n this.actionsResolved = true;\n }\n\n async listTools(req: ListToolsRequest): Promise<ListToolsResult> {\n await this.setup();\n return {\n tools: this.toolActions.map((t): Tool => {\n const def = toToolDefinition(t);\n return {\n name: def.name,\n inputSchema: (def.inputSchema as any) || { type: 'object' },\n description: def.description,\n };\n }),\n };\n }\n\n async callTool(req: CallToolRequest): Promise<CallToolResult> {\n await this.setup();\n const tool = this.toolActions.find(\n (t) => t.__action.name === req.params.name\n );\n if (!tool)\n throw new GenkitError({\n status: 'NOT_FOUND',\n message: `Tried to call tool '${req.params.name}' but it could not be found.`,\n });\n const result = await tool(req.params.arguments);\n return { content: [{ type: 'text', text: JSON.stringify(result) }] };\n }\n\n async listPrompts(req: ListPromptsRequest): Promise<ListPromptsResult> {\n await this.setup();\n return {\n prompts: this.promptActions.map((p): Prompt => {\n return {\n name: p.__action.name,\n description: p.__action.description,\n arguments: toMcpPromptArguments(p),\n };\n }),\n };\n }\n\n async getPrompt(req: GetPromptRequest): Promise<GetPromptResult> {\n await this.setup();\n const prompt = this.promptActions.find(\n (p) => p.__action.name === req.params.name\n );\n if (!prompt)\n throw new GenkitError({\n status: 'NOT_FOUND',\n message: `[@genkit-ai/mcp] Tried to call prompt '${req.params.name}' but it could not be found.`,\n });\n const result = await prompt(req.params.arguments);\n return {\n description: prompt.__action.description,\n messages: result.messages.map(toMcpPromptMessage),\n };\n }\n\n async start(transport?: Transport) {\n if (!transport) {\n const { StdioServerTransport } = await import(\n '@modelcontextprotocol/sdk/server/stdio.js'\n );\n transport = new StdioServerTransport();\n }\n await this.setup();\n await this.server!.connect(transport);\n logger.info(\n `[@genkit-ai/mcp] MCP server '${this.options.name}' started successfully.`\n );\n }\n}\n\nfunction toMcpPromptArguments(p: PromptAction): Prompt['arguments'] {\n const jsonSchema = toJsonSchema({\n schema: p.__action.inputSchema,\n jsonSchema: p.__action.inputJsonSchema,\n });\n\n if (!jsonSchema) return undefined;\n if (!jsonSchema.properties)\n throw new GenkitError({\n status: 'FAILED_PRECONDITION',\n message:\n '[@genkit-ai/mcp] MCP prompts must take objects as input schema.',\n });\n\n const args: Prompt['arguments'] = [];\n for (const k in jsonSchema.properties) {\n const { type, description } = jsonSchema.properties[k];\n if (\n type !== 'string' &&\n (!Array.isArray(type) || !type.includes('string'))\n ) {\n throw new GenkitError({\n status: 'FAILED_PRECONDITION',\n message: `[@genkit-ai/mcp] MCP prompts may only take string arguments, but ${p.__action.name} has property '${k}' of type '${type}'.`,\n });\n }\n args.push({\n name: k,\n description,\n required: jsonSchema.required?.includes(k),\n });\n }\n}\n\nconst ROLE_MAP = { model: 'assistant', user: 'user' } as const;\n\nfunction toMcpPromptMessage(messageData: MessageData): PromptMessage {\n if (messageData.role !== 'model' && messageData.role !== 'user') {\n throw new GenkitError({\n status: 'UNIMPLEMENTED',\n message: `[@genkit-ai/mcp] MCP prompt messages do not support role '${messageData.role}'. Only 'user' and 'model' messages are supported.`,\n });\n }\n const message = new Message(messageData);\n const common = { role: ROLE_MAP[messageData.role] };\n if (message.media) {\n const { url, contentType } = message.media;\n if (!url.startsWith('data:'))\n throw new GenkitError({\n status: 'UNIMPLEMENTED',\n message: `[@genkit-ai/mcp] MCP prompt messages only support base64 data images.`,\n });\n const mimeType =\n contentType || url.substring(url.indexOf(':')! + 1, url.indexOf(';'));\n const data = url.substring(url.indexOf(',') + 1);\n return { ...common, content: { type: 'image', mimeType, data } };\n } else {\n return { ...common, content: { type: 'text', text: message.text } };\n }\n}\n"],"mappings":"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","names":[]}