Skip to main content
Glama

RunPod MCP Server

by Niel-RunPod
index.js20.3 kB
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod"; import fetch from "node-fetch"; // Base URL for RunPod API const API_BASE_URL = "https://rest.runpod.io/v1"; // Get API key from environment variable const API_KEY = process.env.RUNPOD_API_KEY; if (!API_KEY) { console.error("RUNPOD_API_KEY environment variable is required"); process.exit(1); } // Create an MCP server const server = new McpServer({ name: "RunPod API Server", version: "1.0.0", capabilities: { resources: {}, tools: {}, }, }); // Helper function to make authenticated API requests to RunPod async function runpodRequest(endpoint, method = "GET", body) { const url = `${API_BASE_URL}${endpoint}`; const headers = { Authorization: `Bearer ${API_KEY}`, "Content-Type": "application/json", }; const options = { method, headers, }; if (body && (method === "POST" || method === "PATCH")) { options.body = JSON.stringify(body); } try { const response = await fetch(url, options); if (!response.ok) { const errorText = await response.text(); throw new Error(`RunPod API Error: ${response.status} - ${errorText}`); } // Some endpoints might not return JSON const contentType = response.headers.get("content-type"); if (contentType && contentType.includes("application/json")) { return await response.json(); } return { success: true, status: response.status }; } catch (error) { console.error("Error calling RunPod API:", error); throw error; } } // ============== POD MANAGEMENT TOOLS ============== // List Pods server.tool("list-pods", { computeType: z .enum(["GPU", "CPU"]) .optional() .describe("Filter to only GPU or only CPU Pods"), gpuTypeId: z .array(z.string()) .optional() .describe("Filter to Pods with any of the listed GPU types"), dataCenterId: z .array(z.string()) .optional() .describe("Filter to Pods in any of the provided data centers"), name: z .string() .optional() .describe("Filter to Pods with the provided name"), includeMachine: z .boolean() .optional() .describe("Include information about the machine"), includeNetworkVolume: z .boolean() .optional() .describe("Include information about attached network volumes"), }, async (params) => { // Construct query parameters const queryParams = new URLSearchParams(); if (params.computeType) queryParams.append("computeType", params.computeType); if (params.gpuTypeId) params.gpuTypeId.forEach((type) => queryParams.append("gpuTypeId", type)); if (params.dataCenterId) params.dataCenterId.forEach((dc) => queryParams.append("dataCenterId", dc)); if (params.name) queryParams.append("name", params.name); if (params.includeMachine) queryParams.append("includeMachine", params.includeMachine.toString()); if (params.includeNetworkVolume) queryParams.append("includeNetworkVolume", params.includeNetworkVolume.toString()); const queryString = queryParams.toString() ? `?${queryParams.toString()}` : ""; const result = await runpodRequest(`/pods${queryString}`); return { content: [ { type: "text", text: JSON.stringify(result, null, 2), }, ], }; }); // Get Pod Details server.tool("get-pod", { podId: z.string().describe("ID of the pod to retrieve"), includeMachine: z .boolean() .optional() .describe("Include information about the machine"), includeNetworkVolume: z .boolean() .optional() .describe("Include information about attached network volumes"), }, async (params) => { // Construct query parameters const queryParams = new URLSearchParams(); if (params.includeMachine) queryParams.append("includeMachine", params.includeMachine.toString()); if (params.includeNetworkVolume) queryParams.append("includeNetworkVolume", params.includeNetworkVolume.toString()); const queryString = queryParams.toString() ? `?${queryParams.toString()}` : ""; const result = await runpodRequest(`/pods/${params.podId}${queryString}`); return { content: [ { type: "text", text: JSON.stringify(result, null, 2), }, ], }; }); // Create Pod server.tool("create-pod", { name: z.string().optional().describe("Name for the pod"), imageName: z.string().describe("Docker image to use"), cloudType: z .enum(["SECURE", "COMMUNITY"]) .optional() .describe("SECURE or COMMUNITY cloud"), gpuTypeIds: z .array(z.string()) .optional() .describe("List of acceptable GPU types"), gpuCount: z.number().optional().describe("Number of GPUs"), containerDiskInGb: z .number() .optional() .describe("Container disk size in GB"), volumeInGb: z.number().optional().describe("Volume size in GB"), volumeMountPath: z.string().optional().describe("Path to mount the volume"), ports: z .array(z.string()) .optional() .describe("Ports to expose (e.g., '8888/http', '22/tcp')"), env: z.record(z.string()).optional().describe("Environment variables"), dataCenterIds: z .array(z.string()) .optional() .describe("List of data centers"), }, async (params) => { const result = await runpodRequest("/pods", "POST", params); return { content: [ { type: "text", text: JSON.stringify(result, null, 2), }, ], }; }); // Update Pod server.tool("update-pod", { podId: z.string().describe("ID of the pod to update"), name: z.string().optional().describe("New name for the pod"), imageName: z.string().optional().describe("New Docker image"), containerDiskInGb: z .number() .optional() .describe("New container disk size in GB"), volumeInGb: z.number().optional().describe("New volume size in GB"), volumeMountPath: z .string() .optional() .describe("New path to mount the volume"), ports: z.array(z.string()).optional().describe("New ports to expose"), env: z.record(z.string()).optional().describe("New environment variables"), }, async (params) => { const { podId, ...updateParams } = params; const result = await runpodRequest(`/pods/${podId}`, "PATCH", updateParams); return { content: [ { type: "text", text: JSON.stringify(result, null, 2), }, ], }; }); // Start Pod server.tool("start-pod", { podId: z.string().describe("ID of the pod to start"), }, async (params) => { const result = await runpodRequest(`/pods/${params.podId}/start`, "POST"); return { content: [ { type: "text", text: JSON.stringify(result, null, 2), }, ], }; }); // Stop Pod server.tool("stop-pod", { podId: z.string().describe("ID of the pod to stop"), }, async (params) => { const result = await runpodRequest(`/pods/${params.podId}/stop`, "POST"); return { content: [ { type: "text", text: JSON.stringify(result, null, 2), }, ], }; }); // Delete Pod server.tool("delete-pod", { podId: z.string().describe("ID of the pod to delete"), }, async (params) => { const result = await runpodRequest(`/pods/${params.podId}`, "DELETE"); return { content: [ { type: "text", text: JSON.stringify(result, null, 2), }, ], }; }); // ============== ENDPOINT MANAGEMENT TOOLS ============== // List Endpoints server.tool("list-endpoints", { includeTemplate: z .boolean() .optional() .describe("Include template information"), includeWorkers: z .boolean() .optional() .describe("Include information about workers"), }, async (params) => { // Construct query parameters const queryParams = new URLSearchParams(); if (params.includeTemplate) queryParams.append("includeTemplate", params.includeTemplate.toString()); if (params.includeWorkers) queryParams.append("includeWorkers", params.includeWorkers.toString()); const queryString = queryParams.toString() ? `?${queryParams.toString()}` : ""; const result = await runpodRequest(`/endpoints${queryString}`); return { content: [ { type: "text", text: JSON.stringify(result, null, 2), }, ], }; }); // Get Endpoint Details server.tool("get-endpoint", { endpointId: z.string().describe("ID of the endpoint to retrieve"), includeTemplate: z .boolean() .optional() .describe("Include template information"), includeWorkers: z .boolean() .optional() .describe("Include information about workers"), }, async (params) => { // Construct query parameters const queryParams = new URLSearchParams(); if (params.includeTemplate) queryParams.append("includeTemplate", params.includeTemplate.toString()); if (params.includeWorkers) queryParams.append("includeWorkers", params.includeWorkers.toString()); const queryString = queryParams.toString() ? `?${queryParams.toString()}` : ""; const result = await runpodRequest(`/endpoints/${params.endpointId}${queryString}`); return { content: [ { type: "text", text: JSON.stringify(result, null, 2), }, ], }; }); // Create Endpoint server.tool("create-endpoint", { name: z.string().optional().describe("Name for the endpoint"), templateId: z.string().describe("Template ID to use"), computeType: z .enum(["GPU", "CPU"]) .optional() .describe("GPU or CPU endpoint"), gpuTypeIds: z .array(z.string()) .optional() .describe("List of acceptable GPU types"), gpuCount: z.number().optional().describe("Number of GPUs per worker"), workersMin: z.number().optional().describe("Minimum number of workers"), workersMax: z.number().optional().describe("Maximum number of workers"), dataCenterIds: z .array(z.string()) .optional() .describe("List of data centers"), }, async (params) => { const result = await runpodRequest("/endpoints", "POST", params); return { content: [ { type: "text", text: JSON.stringify(result, null, 2), }, ], }; }); // Update Endpoint server.tool("update-endpoint", { endpointId: z.string().describe("ID of the endpoint to update"), name: z.string().optional().describe("New name for the endpoint"), workersMin: z.number().optional().describe("New minimum number of workers"), workersMax: z.number().optional().describe("New maximum number of workers"), idleTimeout: z.number().optional().describe("New idle timeout in seconds"), scalerType: z .enum(["QUEUE_DELAY", "REQUEST_COUNT"]) .optional() .describe("Scaler type"), scalerValue: z.number().optional().describe("Scaler value"), }, async (params) => { const { endpointId, ...updateParams } = params; const result = await runpodRequest(`/endpoints/${endpointId}`, "PATCH", updateParams); return { content: [ { type: "text", text: JSON.stringify(result, null, 2), }, ], }; }); // Delete Endpoint server.tool("delete-endpoint", { endpointId: z.string().describe("ID of the endpoint to delete"), }, async (params) => { const result = await runpodRequest(`/endpoints/${params.endpointId}`, "DELETE"); return { content: [ { type: "text", text: JSON.stringify(result, null, 2), }, ], }; }); // ============== TEMPLATE MANAGEMENT TOOLS ============== // List Templates server.tool("list-templates", {}, async () => { const result = await runpodRequest("/templates"); return { content: [ { type: "text", text: JSON.stringify(result, null, 2), }, ], }; }); // Get Template Details server.tool("get-template", { templateId: z.string().describe("ID of the template to retrieve"), }, async (params) => { const result = await runpodRequest(`/templates/${params.templateId}`); return { content: [ { type: "text", text: JSON.stringify(result, null, 2), }, ], }; }); // Create Template server.tool("create-template", { name: z.string().describe("Name for the template"), imageName: z.string().describe("Docker image to use"), isServerless: z .boolean() .optional() .describe("Is this a serverless template"), ports: z.array(z.string()).optional().describe("Ports to expose"), dockerEntrypoint: z .array(z.string()) .optional() .describe("Docker entrypoint commands"), dockerStartCmd: z .array(z.string()) .optional() .describe("Docker start commands"), env: z.record(z.string()).optional().describe("Environment variables"), containerDiskInGb: z .number() .optional() .describe("Container disk size in GB"), volumeInGb: z.number().optional().describe("Volume size in GB"), volumeMountPath: z.string().optional().describe("Path to mount the volume"), readme: z.string().optional().describe("README content in markdown format"), }, async (params) => { const result = await runpodRequest("/templates", "POST", params); return { content: [ { type: "text", text: JSON.stringify(result, null, 2), }, ], }; }); // Update Template server.tool("update-template", { templateId: z.string().describe("ID of the template to update"), name: z.string().optional().describe("New name for the template"), imageName: z.string().optional().describe("New Docker image"), ports: z.array(z.string()).optional().describe("New ports to expose"), env: z.record(z.string()).optional().describe("New environment variables"), readme: z .string() .optional() .describe("New README content in markdown format"), }, async (params) => { const { templateId, ...updateParams } = params; const result = await runpodRequest(`/templates/${templateId}`, "PATCH", updateParams); return { content: [ { type: "text", text: JSON.stringify(result, null, 2), }, ], }; }); // Delete Template server.tool("delete-template", { templateId: z.string().describe("ID of the template to delete"), }, async (params) => { const result = await runpodRequest(`/templates/${params.templateId}`, "DELETE"); return { content: [ { type: "text", text: JSON.stringify(result, null, 2), }, ], }; }); // ============== NETWORK VOLUME MANAGEMENT TOOLS ============== // List Network Volumes server.tool("list-network-volumes", {}, async () => { const result = await runpodRequest("/networkvolumes"); return { content: [ { type: "text", text: JSON.stringify(result, null, 2), }, ], }; }); // Get Network Volume Details server.tool("get-network-volume", { networkVolumeId: z .string() .describe("ID of the network volume to retrieve"), }, async (params) => { const result = await runpodRequest(`/networkvolumes/${params.networkVolumeId}`); return { content: [ { type: "text", text: JSON.stringify(result, null, 2), }, ], }; }); // Create Network Volume server.tool("create-network-volume", { name: z.string().describe("Name for the network volume"), size: z.number().describe("Size in GB (1-4000)"), dataCenterId: z.string().describe("Data center ID"), }, async (params) => { const result = await runpodRequest("/networkvolumes", "POST", params); return { content: [ { type: "text", text: JSON.stringify(result, null, 2), }, ], }; }); // Update Network Volume server.tool("update-network-volume", { networkVolumeId: z.string().describe("ID of the network volume to update"), name: z.string().optional().describe("New name for the network volume"), size: z .number() .optional() .describe("New size in GB (must be larger than current)"), }, async (params) => { const { networkVolumeId, ...updateParams } = params; const result = await runpodRequest(`/networkvolumes/${networkVolumeId}`, "PATCH", updateParams); return { content: [ { type: "text", text: JSON.stringify(result, null, 2), }, ], }; }); // Delete Network Volume server.tool("delete-network-volume", { networkVolumeId: z.string().describe("ID of the network volume to delete"), }, async (params) => { const result = await runpodRequest(`/networkvolumes/${params.networkVolumeId}`, "DELETE"); return { content: [ { type: "text", text: JSON.stringify(result, null, 2), }, ], }; }); // ============== CONTAINER REGISTRY AUTH TOOLS ============== // List Container Registry Auths server.tool("list-container-registry-auths", {}, async () => { const result = await runpodRequest("/containerregistryauth"); return { content: [ { type: "text", text: JSON.stringify(result, null, 2), }, ], }; }); // Get Container Registry Auth Details server.tool("get-container-registry-auth", { containerRegistryAuthId: z .string() .describe("ID of the container registry auth to retrieve"), }, async (params) => { const result = await runpodRequest(`/containerregistryauth/${params.containerRegistryAuthId}`); return { content: [ { type: "text", text: JSON.stringify(result, null, 2), }, ], }; }); // Create Container Registry Auth server.tool("create-container-registry-auth", { name: z.string().describe("Name for the container registry auth"), username: z.string().describe("Registry username"), password: z.string().describe("Registry password"), }, async (params) => { const result = await runpodRequest("/containerregistryauth", "POST", params); return { content: [ { type: "text", text: JSON.stringify(result, null, 2), }, ], }; }); // Delete Container Registry Auth server.tool("delete-container-registry-auth", { containerRegistryAuthId: z .string() .describe("ID of the container registry auth to delete"), }, async (params) => { const result = await runpodRequest(`/containerregistryauth/${params.containerRegistryAuthId}`, "DELETE"); return { content: [ { type: "text", text: JSON.stringify(result, null, 2), }, ], }; }); // Start receiving messages on stdin and sending messages on stdout const transport = new StdioServerTransport(); server.connect(transport);

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Niel-RunPod/MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server