UNPKG

@paddle/paddle-mcp

Version:
86 lines (85 loc) 3.81 kB
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import PaddleAPI from "./api.js"; import tools from "./tools.js"; function isMetricsTool(tool) { return tool.actions.metrics !== undefined; } class PaddleMCPServer extends McpServer { _paddle; constructor({ apiKey, environment, toolFilter = { mode: "non-destructive" } }) { super({ name: "paddle", version: "0.1.3", }); this._paddle = new PaddleAPI(apiKey, environment); // Validate tools let requestedTools; if (toolFilter.mode === "specific" && toolFilter.tools) { requestedTools = new Set(toolFilter.tools); const availableTools = new Set(tools.map((tool) => tool.method)); const invalidTools = toolFilter.tools.filter((method) => !availableTools.has(method)); if (invalidTools.length > 0) { throw new Error(`Invalid tool value(s) provided: ${invalidTools.join(", ")}. ` + `Accepted values are all, read-only, non-destructive, or a comma-separated list of valid tools: ${Array.from(availableTools).sort().join(", ")}`); } } // Register tools let registeredCount = 0; const isWriteTool = (tool) => Object.values(tool.actions).some((action) => action.write === true); const isDestructiveTool = (tool) => Object.values(tool.actions).some((action) => action.delete === true || action.update === true); tools.forEach((tool) => { const write = isWriteTool(tool); const destructive = isDestructiveTool(tool); let shouldRegister = false; if (toolFilter.mode === "all") { shouldRegister = true; } else if (toolFilter.mode === "read-only") { shouldRegister = !write; } else if (toolFilter.mode === "non-destructive") { shouldRegister = !destructive; } else if (toolFilter.mode === "specific") { shouldRegister = requestedTools?.has(tool.method) ?? false; } if (!shouldRegister) { return; } if (environment === "sandbox" && isMetricsTool(tool)) { return; } const annotations = { readOnlyHint: !write, destructiveHint: write ? destructive : undefined, }; this.tool(tool.method, tool.description, tool.parameters.shape, annotations, async (arg, _extra) => { const result = await this._paddle.run(tool.method, arg); return { content: [ { type: "text", text: String(result), }, ], }; }); registeredCount++; }); if (registeredCount === 0) { const sandboxMetricsHint = environment === "sandbox" ? " Metrics tools are omitted in sandbox because they only work with production data; add other tools to your filter or set the environment to production." : ""; throw new Error("No tools were registered with the current filter settings. " + "The value of the --tools parameter must be 'all', 'read-only', 'non-destructive', or a comma-separated list of valid tools." + sandboxMetricsHint); } this.server.oninitialized = () => { const clientVersion = this.server.getClientVersion(); if (clientVersion) { this._paddle.setClientInfo(clientVersion); } }; } } export default PaddleMCPServer;