{"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      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(\n  p: PromptAction\n): Prompt['arguments'] | undefined {\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  return args;\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":[]}