genkitx-mcp
Version:
A Genkit plugin that provides interoperability between Genkit and Model Context Protocol (MCP). Both client and server use cases are supported.
220 lines • 7.55 kB
JavaScript
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var server_exports = {};
__export(server_exports, {
GenkitMcpServer: () => GenkitMcpServer
});
module.exports = __toCommonJS(server_exports);
var import_genkit = require("genkit");
var import_schema = require("@genkit-ai/core/schema");
var import_logging = require("genkit/logging");
var import_tool = require("genkit/tool");
class GenkitMcpServer {
ai;
options;
server;
actionsResolved = false;
toolActions = [];
promptActions = [];
constructor(ai, options) {
this.ai = ai;
this.options = options;
this.setup();
}
async setup() {
if (this.actionsResolved) return;
const { Server } = await import("@modelcontextprotocol/sdk/server/index.js");
this.server = new Server(
{ name: this.options.name, version: this.options.version || "1.0.0" },
{
capabilities: {
prompts: {},
tools: {}
}
}
);
const {
CallToolRequestSchema,
GetPromptRequestSchema,
ListPromptsRequestSchema,
ListToolsRequestSchema
} = await import("@modelcontextprotocol/sdk/types.js");
this.server.setRequestHandler(
ListToolsRequestSchema,
this.listTools.bind(this)
);
this.server.setRequestHandler(
CallToolRequestSchema,
this.callTool.bind(this)
);
this.server.setRequestHandler(
ListPromptsRequestSchema,
this.listPrompts.bind(this)
);
this.server.setRequestHandler(
GetPromptRequestSchema,
this.getPrompt.bind(this)
);
const allActions = await this.ai.registry.listActions();
const toolList = [];
const promptList = [];
for (const k in allActions) {
if (k.startsWith("/tool/")) {
toolList.push(allActions[k]);
} else if (k.startsWith("/prompt/")) {
promptList.push(allActions[k]);
}
}
this.toolActions = toolList;
this.promptActions = promptList;
this.actionsResolved = true;
}
async listTools(req) {
await this.setup();
return {
tools: this.toolActions.map((t) => {
const def = (0, import_tool.toToolDefinition)(t);
return {
name: def.name,
inputSchema: def.inputSchema || { type: "object" },
description: def.description
};
})
};
}
async callTool(req) {
await this.setup();
const tool = this.toolActions.find(
(t) => t.__action.name === req.params.name
);
if (!tool)
throw new import_genkit.GenkitError({
status: "NOT_FOUND",
message: `Tried to call tool '${req.params.name}' but it could not be found.`
});
const result = await tool(req.params.arguments);
return { content: [{ type: "text", text: JSON.stringify(result) }] };
}
async listPrompts(req) {
await this.setup();
return {
prompts: this.promptActions.map((p) => {
return {
name: p.__action.name,
description: p.__action.description,
arguments: toMcpPromptArguments(p)
};
})
};
}
async getPrompt(req) {
await this.setup();
const prompt = this.promptActions.find(
(p) => p.__action.name === req.params.name
);
if (!prompt)
throw new import_genkit.GenkitError({
status: "NOT_FOUND",
message: `[@genkit-ai/mcp] Tried to call prompt '${req.params.name}' but it could not be found.`
});
const result = await prompt(req.params.arguments);
return {
description: prompt.__action.description,
messages: result.messages.map(toMcpPromptMessage)
};
}
async start(transport) {
if (!transport) {
const { StdioServerTransport } = await import("@modelcontextprotocol/sdk/server/stdio.js");
transport = new StdioServerTransport();
}
await this.setup();
await this.server.connect(transport);
import_logging.logger.info(
`[@genkit-ai/mcp] MCP server '${this.options.name}' started successfully.`
);
}
}
function toMcpPromptArguments(p) {
const jsonSchema = (0, import_schema.toJsonSchema)({
schema: p.__action.inputSchema,
jsonSchema: p.__action.inputJsonSchema
});
if (!jsonSchema) return void 0;
if (!jsonSchema.properties)
throw new import_genkit.GenkitError({
status: "FAILED_PRECONDITION",
message: "[@genkit-ai/mcp] MCP prompts must take objects as input schema."
});
const args = [];
for (const k in jsonSchema.properties) {
const { type, description } = jsonSchema.properties[k];
if (type !== "string" && (!Array.isArray(type) || !type.includes("string"))) {
throw new import_genkit.GenkitError({
status: "FAILED_PRECONDITION",
message: `[@genkit-ai/mcp] MCP prompts may only take string arguments, but ${p.__action.name} has property '${k}' of type '${type}'.`
});
}
args.push({
name: k,
description,
required: jsonSchema.required?.includes(k)
});
}
return args;
}
const ROLE_MAP = { model: "assistant", user: "user" };
function toMcpPromptMessage(messageData) {
if (messageData.role !== "model" && messageData.role !== "user") {
throw new import_genkit.GenkitError({
status: "UNIMPLEMENTED",
message: `[@genkit-ai/mcp] MCP prompt messages do not support role '${messageData.role}'. Only 'user' and 'model' messages are supported.`
});
}
const message = new import_genkit.Message(messageData);
const common = { role: ROLE_MAP[messageData.role] };
if (message.media) {
const { url, contentType } = message.media;
if (!url.startsWith("data:"))
throw new import_genkit.GenkitError({
status: "UNIMPLEMENTED",
message: `[@genkit-ai/mcp] MCP prompt messages only support base64 data images.`
});
const mimeType = contentType || url.substring(url.indexOf(":") + 1, url.indexOf(";"));
const data = url.substring(url.indexOf(",") + 1);
return { ...common, content: { type: "image", mimeType, data } };
} else {
return { ...common, content: { type: "text", text: message.text } };
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
GenkitMcpServer
});
//# sourceMappingURL=server.js.map
;