@runpod/mcp-server 2.0.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/tools/runtime.ts","../src/_shared/http.ts","../src/_shared/tracking.ts","../src/tools/logs.ts","../src/_shared/mappers.ts","../src/_shared/backend.ts","../src/tools/catalog.ts","../src/pagination.ts","../src/tools/hub.ts","../src/tools/public-endpoints.ts","../src/tools/endpoint-gpus.ts","../src/tools/pods.ts","../src/tools/endpoints.ts","../src/tools/jobs.ts","../src/tools/templates.ts","../src/tools/network-volumes.ts","../src/tools/registries.ts","../src/tools/billing.ts","../src/tools.ts"],"sourcesContent":["import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport fetch from 'node-fetch';\nimport { randomUUID } from 'node:crypto';\nimport { createHttpClient } from '../_shared/http.js';\nimport { buildTrackingHeaders } from '../_shared/tracking.js';\nimport { readSseSnapshot, type SseFetch } from './logs.js';\nimport {\n resolveBackend,\n restV1Base,\n serverlessBase,\n publicGraphqlBase,\n authedGraphqlBase,\n type Env,\n type Backend,\n type Resource,\n} from '../_shared/backend.js';\n\n// ============== TOOL RUNTIME (shared per-server wiring) ==============\n// The per-resource tool modules (src/tools/<resource>.ts) are pure registration\n// functions: each takes the MCP server + this runtime and calls server.tool(...).\n// Everything that depends on the live server instance or the caller's API key —\n// caller-tracking, the authenticated request clients, the v1/v2 backend resolver\n// — is built ONCE here by createToolRuntime and threaded in, so the resource\n// modules stay free of wiring and are individually testable.\n\n// Base URLs are resolved LIVE per call (via restV1Base/serverlessBase/\n// publicGraphqlBase reading process.env), not frozen at module import — so they\n// match callRestUrl's behavior and a test/env change takes effect without a\n// module reload. The defaults live in _shared/backend.ts. Three distinct\n// GraphQL hosts: publicGraphqlBase (credential-free), authedGraphqlBase (the\n// only one this module sends the caller's API key to), and RUNPOD_GRAPHQL_URL\n// (flash OAuth flow in api/index.ts only).\n\n// ============== CALLER TRACKING ==============\n// Adds structured caller identification to every outbound API call so the\n// Runpod platform can attribute traffic to a specific MCP client (Claude Code,\n// Cursor, Codex, Gemini CLI, etc.) and count distinct agent sessions. Pure\n// observability — no tool behavior changes.\n//\n// `__PACKAGE_VERSION__` is replaced at build time by tsup's `define` with the\n// current `version` from package.json. Falls back to `'dev'` when the\n// substitution doesn't happen (e.g. `pnpm dev` via tsx).\ndeclare const __PACKAGE_VERSION__: string;\nconst MCP_SERVER_VERSION =\n typeof __PACKAGE_VERSION__ !== 'undefined' ? __PACKAGE_VERSION__ : 'dev';\n\n// One session ID per server process. Anonymous; lets the data side count\n// distinct agent sessions without per-user attribution.\nconst SESSION_ID = randomUUID();\n\n/**\n * Context passed to every tool handler. Contains the API key used to\n * authenticate against the Runpod REST and Serverless APIs, the transport the\n * server is running under, and (for stateless HTTP) the inbound client\n * User-Agent — all used for outbound caller-tracking headers.\n */\nexport interface ToolContext {\n apiKey: string;\n transport: 'stdio' | 'http';\n clientUserAgent?: string;\n serverVersion?: string;\n // Called when an outbound call answers 401, i.e. the credential just died.\n // The hosted server uses it to drop the cached pre-flight verdict so the very\n // next request re-checks and can emit the 401 + WWW-Authenticate that makes a\n // client re-authenticate, instead of waiting out the cache TTL.\n onUnauthorized?: () => void;\n}\n\n/**\n * Builds the headers that identify the calling MCP client and session on every\n * outbound HTTP call. Client identity comes from the `initialize` handshake's\n * `clientInfo` (exposed by the SDK via `server.server.getClientVersion()`),\n * which works for the long-lived stdio server. In stateless HTTP that handshake\n * is on a different request, so we fall back to the inbound HTTP User-Agent.\n *\n * Resolution of clientInfo → fallback happens here (the SDK touch); the pure\n * string formatting lives in `_shared/tracking.ts`.\n */\nfunction trackingHeaders(\n server: McpServer,\n ctx: ToolContext\n): Record<string, string> {\n const info = server.server.getClientVersion();\n return buildTrackingHeaders({\n clientName: info?.name || ctx.clientUserAgent || 'unknown',\n clientVersion: info?.version || 'unknown',\n transport: ctx.transport,\n // Prefer a server version supplied by the caller (the hosted entrypoint reads\n // it from package.json at runtime, since tsup's build-time define does not\n // run when Vercel compiles api/index.ts). Fall back to the build-time value.\n serverVersion: ctx.serverVersion || MCP_SERVER_VERSION,\n sessionId: SESSION_ID,\n });\n}\n\n// The fetch implementation the unified client uses. Defaults to node-fetch;\n// tests inject a fake to capture outbound requests offline (the A4 seam).\nexport type HttpFetch = Parameters<typeof createHttpClient>[0]['fetch'];\nconst defaultFetch = fetch as HttpFetch;\n\n// Wrap a unified-client call with the legacy `console.error(label) + re-throw`\n// the pre-adapter runpodRequest/serverlessRequest helpers had. Centralizes the\n// identical try/catch blocks into one place.\nasync function withApiErrorLog<T>(\n label: string,\n call: () => Promise<T>\n): Promise<T> {\n try {\n return await call();\n } catch (error) {\n console.error(label, error);\n throw error;\n }\n}\n\n// The standard MCP tool reply: a single text block holding pretty-printed JSON.\n// Every tool returns this shape.\nexport function jsonReply(result: unknown) {\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }],\n };\n}\n\n// Shared MCP tool-annotation presets (advisory hints clients use to label tools\n// and gate confirmations). `openWorldHint` is true on all of these — every tool\n// talks to the external Runpod API. READ_ONLY = pure reads; WRITE = creates/\n// mutations; DESTRUCTIVE = deletes (also idempotent: re-deleting a gone resource\n// is a no-op). Spread a preset and add a per-tool `title`.\nexport const READ_ONLY = { readOnlyHint: true, openWorldHint: true };\nexport const WRITE = { readOnlyHint: false, openWorldHint: true };\nexport const DESTRUCTIVE = {\n readOnlyHint: false,\n destructiveHint: true,\n idempotentHint: true,\n openWorldHint: true,\n};\n\n// Optional test seam: inject a fake fetch to capture outbound requests offline.\n// Production passes nothing → node-fetch. `v2Available` is the already-resolved\n// stdio `auto`-probe verdict (see backend.resolveVersion); omitted → `auto`\n// resolves to v1.\nexport interface ToolDeps {\n fetch?: HttpFetch;\n v2Available?: boolean;\n // Test seam for the SSE log stream (stream-pod-logs). Production builds a\n // node-fetch reader; tests inject a fake returning canned event-stream text.\n streamSse?: StreamSse;\n // Lower-level seam: the fetch the SSE reader uses. `streamSse` replaces the\n // whole reader (and so bypasses the 401 observer); this replaces only its\n // transport, which is what lets a test drive an SSE 401 through the observer.\n sseFetch?: SseFetch;\n}\n\n// A bounded Server-Sent-Events read. Returns the raw accumulated stream text\n// (caller parses frames) plus whether the byte cap truncated it. Time-bounded\n// by maxWaitMs (the stream may stay open for live tail), so a clean timeout is\n// a normal end, not an error.\nexport interface StreamSseResult {\n raw: string;\n truncated: boolean;\n}\nexport type StreamSse = (\n url: string,\n opts: { maxWaitMs: number; maxBytes: number }\n) => Promise<StreamSseResult>;\n\n/**\n * The shared, server-instance-bound runtime threaded into every per-resource\n * registrar. Built once by createToolRuntime.\n */\nexport interface ToolRuntime {\n // Pretty-printed JSON reply helper (re-exported for convenience).\n jsonReply: typeof jsonReply;\n // Public, no-auth GraphQL query against the Runpod GraphQL endpoint.\n graphql: <T>(query: string) => Promise<T>;\n // Authenticated GraphQL operation (API-key Bearer) against the same endpoint,\n // with variables support — the authenticated path accepts them (the public,\n // unauthenticated path does not). Used for console-only operations that have\n // no REST home yet (e.g. deploying a Hub release via saveEndpoint).\n graphqlAuthed: <T>(\n query: string,\n variables?: Record<string, unknown>\n ) => Promise<T>;\n // Authenticated v1 REST call, path-relative to the v1 base (e.g. `/endpoints`).\n runpodRequest: (\n endpoint: string,\n method?: string,\n body?: Record<string, unknown>\n ) => Promise<unknown>;\n // Authenticated Serverless runtime call (api.runpod.ai/v2/{endpointId}{path}).\n serverlessRequest: (\n endpointId: string,\n path: string,\n method?: string,\n body?: Record<string, unknown>\n ) => Promise<unknown>;\n // Authenticated REST call to a fully-resolved URL (the adapter builds the URL).\n callRestUrl: (\n url: string,\n method?: string,\n body?: Record<string, unknown>\n ) => Promise<unknown>;\n // Resolve a resource's v1/v2 backend descriptor for the current env/transport.\n backendFor: (resource: Resource) => Backend;\n // Bounded SSE reader (stream-pod-logs). Authenticated + tracked; reads a\n // text/event-stream until the byte cap or the time bound, returning the raw\n // accumulated text. Throws HttpError on a non-OK response.\n streamSse: StreamSse;\n // Pod state transition (v1 subpaths vs v2 unified /action).\n podAction: (\n podId: string,\n action: 'start' | 'stop' | 'restart'\n ) => Promise<unknown>;\n // The process env, exposed for the few handlers that resolve base URLs\n // directly (e.g. create-pod's CPU → v1 fallback).\n env: Env;\n}\n\n// Helper to make GraphQL requests to Runpod (public, no auth required). Bound to\n// the per-request tracking headers AND the injected fetch by createToolRuntime —\n// it must use the same `httpFetch` seam as the REST clients, NOT the module-level\n// node-fetch, or test fakes wouldn't intercept the v1 catalog (list-gpu-types /\n// list-data-centers) GraphQL calls and those \"offline\" goldens would hit the net.\nasync function graphqlRequest<T>(\n query: string,\n tracking: () => Record<string, string>,\n fetchImpl: HttpFetch,\n url: string,\n options?: {\n variables?: Record<string, unknown>;\n apiKey?: string;\n }\n): Promise<T> {\n const response = await fetchImpl(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...(options?.apiKey ? { Authorization: `Bearer ${options.apiKey}` } : {}),\n ...tracking(),\n },\n body: JSON.stringify({\n query,\n ...(options?.variables ? { variables: options.variables } : {}),\n }),\n });\n\n const result = (await response.json()) as {\n data?: T;\n errors?: Array<{ message: string }>;\n };\n\n if (result.errors && result.errors.length > 0) {\n throw new Error(\n `GraphQL Error: ${result.errors.map((e) => e.message).join(', ')}`\n );\n }\n\n if (!result.data) {\n throw new Error('No data returned from GraphQL query');\n }\n\n return result.data;\n}\n\n/**\n * Build the shared runtime once per registerTools call. Constructs the\n * caller-tracking closure, the authenticated REST/Serverless/GraphQL clients,\n * and the version-aware backend resolver — all from the live server + context.\n */\nexport function createToolRuntime(\n server: McpServer,\n ctx: ToolContext,\n deps: ToolDeps = {}\n): ToolRuntime {\n const tracking = () => trackingHeaders(server, ctx);\n\n // Report a 401 once, at the transport boundary, instead of at each of the ~30\n // call sites. Applied to BOTH outbound fetch seams: the JSON clients (REST\n // v1/v2, serverless, GraphQL) and the SSE reader, which binds its own fetch\n // and would otherwise let stream-pod-logs / stream-worker-logs 401s go\n // unreported. Pass-through when no observer is registered (stdio).\n function observeUnauthorized<\n A extends unknown[],\n R extends { status: number },\n >(fn: (...args: A) => Promise<R>): (...args: A) => Promise<R> {\n const notify = ctx.onUnauthorized;\n if (!notify) return fn;\n return async (...args: A) => {\n const response = await fn(...args);\n if (response.status === 401) notify();\n return response;\n };\n }\n\n // Only the AUTHENTICATED seams are observed. The public GraphQL query sends no\n // Authorization header at all, so a 401 from that host (a WAF block, say) says\n // nothing about the caller's credential — observing it would drop a good verdict\n // and force every caller back through the pre-flight.\n const rawFetch = deps.fetch ?? defaultFetch;\n const httpFetch = observeUnauthorized(rawFetch);\n\n // v1 REST client (path-relative to the v1 base).\n const v1Client = createHttpClient({\n apiKey: ctx.apiKey,\n fetch: httpFetch,\n tracking,\n errorPrefix: 'Runpod API Error',\n });\n const runpodRequest = (\n endpoint: string,\n method: string = 'GET',\n body?: Record<string, unknown>\n ) =>\n withApiErrorLog('Error calling Runpod API:', () =>\n v1Client(`${restV1Base(process.env as Env)}${endpoint}`, method, body)\n );\n\n // Serverless runtime client (endpointId + path against the serverless base).\n const serverlessClient = createHttpClient({\n apiKey: ctx.apiKey,\n fetch: httpFetch,\n tracking,\n errorPrefix: 'Runpod Serverless API Error',\n });\n const serverlessRequest = (\n endpointId: string,\n path: string,\n method: string = 'GET',\n body?: Record<string, unknown>\n ) =>\n withApiErrorLog('Error calling Runpod Serverless API:', () =>\n serverlessClient(\n `${serverlessBase(process.env as Env)}/${endpointId}${path}`,\n method,\n body\n )\n );\n\n // v2-aware REST routing (keystone): a full-URL REST client (the adapter\n // resolves base+path per version) used by all adapter-routed resources.\n const restClient = createHttpClient({\n apiKey: ctx.apiKey,\n fetch: httpFetch,\n tracking,\n errorPrefix: 'Runpod API Error',\n });\n const callRestUrl = (\n url: string,\n method: string = 'GET',\n body?: Record<string, unknown>\n ): Promise<unknown> =>\n withApiErrorLog('Error calling Runpod API:', () =>\n restClient(url, method, body)\n );\n\n // Bounded SSE reader for stream-pod-logs / stream-worker-logs. Uses node-fetch\n // directly (not the JSON client) so the response body is read incrementally and\n // stopped on the byte cap or the time bound. The read loop itself lives in\n // logs.ts (readSseSnapshot) so it is unit-testable against a mock Response; here\n // we just bind it to node-fetch + the authenticated headers. Overridable via\n // deps for offline handler tests.\n const sseFetch = observeUnauthorized(\n deps.sseFetch ?? (fetch as unknown as SseFetch)\n );\n const streamSse: StreamSse =\n deps.streamSse ??\n ((url, opts) =>\n readSseSnapshot(\n sseFetch,\n url,\n {\n Authorization: `Bearer ${ctx.apiKey}`,\n Accept: 'text/event-stream',\n ...tracking(),\n },\n opts\n ));\n\n const backendFor = (resource: Resource): Backend =>\n resolveBackend({\n resource,\n env: process.env as Env,\n ctx: { transport: ctx.transport },\n v2Available: deps.v2Available,\n });\n\n // B4: pod state transition. v1 has dedicated subpaths (/start, /stop); v2\n // unifies them under POST /pods/{id}/action with an `{action}` body.\n const podAction = async (\n podId: string,\n action: 'start' | 'stop' | 'restart'\n ): Promise<unknown> => {\n const backend = backendFor('pods');\n const podPath = backend.get!(podId);\n if (backend.version === 'v2') {\n return callRestUrl(`${backend.base}${podPath}/action`, 'POST', {\n action,\n });\n }\n return callRestUrl(`${backend.base}${podPath}/${action}`, 'POST');\n };\n\n return {\n jsonReply,\n graphql: <T>(query: string) =>\n graphqlRequest<T>(\n query,\n tracking,\n // rawFetch, not httpFetch: this call carries no credential (see above).\n rawFetch,\n publicGraphqlBase(process.env as Env)\n ),\n graphqlAuthed: <T>(query: string, variables?: Record<string, unknown>) =>\n graphqlRequest<T>(\n query,\n tracking,\n httpFetch,\n // NOT publicGraphqlBase: this call carries the caller's API key.\n authedGraphqlBase(process.env as Env),\n { variables, apiKey: ctx.apiKey }\n ),\n runpodRequest,\n serverlessRequest,\n callRestUrl,\n backendFor,\n streamSse,\n podAction,\n env: process.env as Env,\n };\n}\n","// ============== UNIFIED HTTP CLIENT (REST + Serverless) ==============\n// One authenticated JSON client that replaces the byte-identical\n// `runpodRequest` + `serverlessRequest` helpers. The adapter\n// (src/_shared/backend.ts) resolves the full URL, so this client takes a\n// resolved URL — the old `endpointId`-split shape collapses into the path.\n//\n// GraphQL is intentionally NOT routed through here: it sends no Authorization\n// header and has its own `{data,errors}` envelope + error prefix. It stays a\n// separate helper through Phase A.\n//\n// `fetch` and `tracking` are injected so this is unit-testable offline with no\n// network and no MCP SDK.\n\n// The shape of a `fetch` request init this client builds. Named so the client's\n// internal `init` literal can't drift from what `FetchLike` actually accepts.\ninterface RequestInitLike {\n method: string;\n headers: Record<string, string>;\n body?: string;\n}\n\ntype FetchLike = (url: string, init: RequestInitLike) => Promise<HttpResponseLike>;\n\ninterface HttpResponseLike {\n ok: boolean;\n status: number;\n text(): Promise<string>;\n json(): Promise<unknown>;\n headers: { get(name: string): string | null };\n}\n\n// Thrown on any non-OK response. Carries `status` + `body` so callers can\n// branch (e.g. create-pod maps a 501 to a clean \"CPU pods not yet supported\"\n// message) without parsing the message string. Because it still THROWS, loops\n// that count consecutive errors (e.g. stream-job) keep working — a 501 mid-poll\n// is surfaced as an error, not swallowed.\nexport class HttpError extends Error {\n readonly status: number;\n readonly body: string;\n constructor(prefix: string, status: number, body: string) {\n // A 401 means the credential itself is dead (expired/revoked key), not\n // that the request was wrong. Say so — a bare \"401 - Unauthorized\" gives\n // an agent nothing actionable, and on stdio (env-var API key) there is no\n // HTTP layer to convert this into a re-auth signal.\n const hint =\n status === 401\n ? ' (the Runpod API rejected the credential — the API key may be expired or revoked; re-authenticate or update RUNPOD_API_KEY)'\n : '';\n super(`${prefix}: ${status} - ${body}${hint}`);\n this.name = 'HttpError';\n this.status = status;\n this.body = body;\n }\n}\n\n// A response whose content-type marks it as JSON — including v2's RFC-9457\n// `application/problem+json` error bodies. We match the `+json`/`/json` shape,\n// NOT the literal substring `application/json` (which `problem+json` does not\n// contain), so v2 error bodies are parsed rather than swallowed.\nfunction isJsonContentType(contentType: string | null): boolean {\n if (!contentType) return false;\n const ct = contentType.toLowerCase();\n return ct.includes('application/json') || ct.includes('+json');\n}\n\n// Body-carrying methods. This is now the single unified client for all REST\n// calls, so include PUT — otherwise a future tool passing method='PUT' with a\n// body would have the payload silently dropped (request sent with no body, no\n// error). GET/DELETE never carry a body.\nfunction methodSendsBody(method: string): boolean {\n return method === 'POST' || method === 'PATCH' || method === 'PUT';\n}\n\n// The auth + content-type + caller-tracking headers sent on every request.\nfunction buildRequestHeaders(\n apiKey: string,\n tracking: () => Record<string, string>\n): Record<string, string> {\n return {\n Authorization: `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n ...tracking(),\n };\n}\n\nexport interface HttpClient {\n (\n url: string,\n method?: string,\n body?: Record<string, unknown>\n ): Promise<unknown>;\n}\n\nexport function createHttpClient(deps: {\n apiKey: string;\n fetch: FetchLike;\n tracking: () => Record<string, string>;\n // Distinct per backend so error messages stay attributable\n // (\"Runpod API Error\" / \"Runpod Serverless API Error\").\n errorPrefix: string;\n}): HttpClient {\n return async function request(\n url: string,\n method: string = 'GET',\n body?: Record<string, unknown>\n ): Promise<unknown> {\n const init: RequestInitLike = {\n method,\n headers: buildRequestHeaders(deps.apiKey, deps.tracking),\n };\n if (body && methodSendsBody(method)) {\n init.body = JSON.stringify(body);\n }\n\n const response = await deps.fetch(url, init);\n\n if (!response.ok) {\n throw new HttpError(\n deps.errorPrefix,\n response.status,\n await response.text()\n );\n }\n\n // 204 / empty / non-JSON → a uniform success marker (matches today's helpers\n // and covers pod-action responses that return no JSON body).\n return isJsonContentType(response.headers.get('content-type'))\n ? response.json()\n : { success: true, status: response.status };\n };\n}\n","// ============== CALLER TRACKING (pure header construction) ==============\n// The structured User-Agent + session id that identify the calling MCP client\n// on every outbound API call. Pure functions here so they're unit-testable\n// without the MCP SDK; the SDK-touching part (reading clientInfo off the\n// handshake) stays at the call site and is reduced to plain strings before\n// reaching `buildTrackingHeaders`.\n\n// Sanitizes a value for inclusion in a User-Agent token. RFC 7230 reserves\n// parens and a few other chars; strip them so the structured UA stays\n// parseable, and bound the length so a hostile client can't blow up a header.\nexport function sanitizeUaToken(value: string): string {\n return value.replace(/[()<>@,;:\\\\\"/[\\]?={}\\s]/g, '_').slice(0, 64);\n}\n\nexport interface TrackingInput {\n // Client identity resolved from the MCP `initialize` handshake's clientInfo,\n // or the inbound HTTP User-Agent as a fallback (stateless HTTP).\n clientName?: string;\n clientVersion?: string;\n transport: 'stdio' | 'http';\n serverVersion: string;\n sessionId: string;\n}\n\n// Builds the `User-Agent` + `X-Runpod-Session-Id` headers. The clientInfo →\n// fallback → 'unknown' resolution is the caller's job (it owns the SDK handle);\n// this function just sanitizes and formats whatever identity it's given.\nexport function buildTrackingHeaders(\n input: TrackingInput\n): Record<string, string> {\n const name = sanitizeUaToken(input.clientName || 'unknown');\n const version = sanitizeUaToken(input.clientVersion || 'unknown');\n const userAgent = `runpod-mcp-server/${input.serverVersion} (caller=mcp; client=${name}; client_version=${version}; transport=${input.transport})`;\n return {\n 'User-Agent': userAgent,\n 'X-Runpod-Session-Id': input.sessionId,\n };\n}\n","import { z } from 'zod';\nimport { HttpError } from '../_shared/http.js';\nimport type { Backend, Resource } from '../_shared/backend.js';\nimport type { StreamSse, ToolRuntime } from './runtime.js';\n\n// ============== SHARED LOG STREAMING ==============\n// Pod logs (GET /v2/pods/{id}/logs) and worker logs\n// (GET /v2/serverless/{id}/workers/{workerId}/logs) are the same feature on two\n// resources: an SSE stream of `data: {source,line,ts}` frames. This module holds\n// everything they share — the frame parser, the param schema, the bounded read,\n// and the tool handler — so each tool registration is just a name + a URL.\n\n// One parsed log frame. A payload that isn't JSON is kept verbatim under `raw`.\nexport interface LogEntry {\n source?: string;\n line?: string;\n ts?: string;\n raw?: string;\n}\n\n// Parse SSE text into log frames. Pure, so it's unit-tested without a network.\n// Events are separated by a blank line; only `data:` fields are read (`id:`,\n// `event:`, and `:` comments are ignored). A `data:` field may span several lines.\nexport function parseLogSse(raw: string): LogEntry[] {\n const items: LogEntry[] = [];\n for (const block of raw.split(/\\r?\\n\\r?\\n/)) {\n const dataLines = block.split(/\\r?\\n/).filter((l) => l.startsWith('data:'));\n if (!dataLines.length) continue;\n // Drop the `data:` prefix and one optional leading space from each line.\n const payload = dataLines\n .map((l) => l.slice(5).replace(/^ /, ''))\n .join('\\n');\n if (!payload.trim()) continue;\n try {\n const parsed: unknown = JSON.parse(payload);\n // A log frame is a JSON object; a bare primitive/array/null (`data: 42`)\n // is not a LogEntry, so keep it verbatim under `raw` rather than pushing a\n // value that violates the LogEntry shape.\n items.push(\n parsed !== null && typeof parsed === 'object' && !Array.isArray(parsed)\n ? (parsed as LogEntry)\n : { raw: payload }\n );\n } catch {\n items.push({ raw: payload });\n }\n }\n return items;\n}\n\n// How long to hold the stream open, and the byte cap that flips `truncated`.\nexport const LOG_STREAM_DEFAULT_WAIT_MS = 5000;\nexport const LOG_STREAM_MAX_BYTES = 256 * 1024;\n\n// Minimal structural shape of the fetch response the SSE reader consumes. Kept\n// deliberately narrow so both node-fetch (production) and a test fake satisfy it\n// without pulling in a full Response type.\nexport interface SseResponse {\n ok: boolean;\n status: number;\n text(): Promise<string>;\n body: AsyncIterable<Buffer> | null;\n}\nexport type SseFetch = (\n url: string,\n init: { method: string; headers: Record<string, string>; signal: AbortSignal }\n) => Promise<SseResponse>;\n\n// The real bounded SSE reader, extracted so it can be unit-tested against a mock\n// Response (production wires it to node-fetch in createToolRuntime). Time-bounded\n// by maxWaitMs (the stream may stay open to tail live output) and byte-bounded by\n// maxBytes; whichever fires first aborts and returns what was collected so far.\n// A timeout/cap abort is a NORMAL end of a bounded snapshot — whether it fires\n// while CONNECTING (thrown from the `await fetchImpl`) or mid body read, keep the\n// collected bytes rather than throwing. Only a non-OK HTTP status throws\n// (HttpError). Buffers are concatenated and decoded ONCE at the end so a UTF-8\n// char split across two network chunks is never corrupted.\nexport async function readSseSnapshot(\n fetchImpl: SseFetch,\n url: string,\n headers: Record<string, string>,\n opts: { maxWaitMs: number; maxBytes: number }\n): Promise<{ raw: string; truncated: boolean }> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), opts.maxWaitMs);\n const chunks: Buffer[] = [];\n let bytes = 0;\n let truncated = false;\n try {\n const res = await fetchImpl(url, {\n method: 'GET',\n headers,\n signal: controller.signal,\n });\n if (!res.ok) {\n throw new HttpError(\n 'Runpod API Error',\n res.status,\n await res.text().catch(() => '')\n );\n }\n for await (const chunk of (res.body ?? []) as AsyncIterable<Buffer>) {\n chunks.push(chunk);\n bytes += chunk.length;\n if (bytes >= opts.maxBytes) {\n truncated = true;\n controller.abort();\n break;\n }\n }\n } catch (err) {\n // Abort (timeout or byte-cap) is a clean end of a bounded read — keep what we\n // have. Anything else (incl. HttpError on a non-OK status) propagates.\n if (!(err instanceof Error && err.name === 'AbortError')) throw err;\n } finally {\n clearTimeout(timer);\n }\n return { raw: Buffer.concat(chunks).toString('utf8'), truncated };\n}\n\n// Zod params shared by both log tools; spread in alongside the resource id.\nexport const logStreamParams = {\n source: z\n .enum(['container', 'system', 'both'])\n .optional()\n .describe('Which log source to read (default: both)'),\n tail: z\n .number()\n .int()\n .min(0)\n .max(5000)\n .optional()\n .describe(\n 'Historical lines to backfill before live output (API default 100, max 5000; 0 = live only). Ignored when `since` is set.'\n ),\n since: z\n .string()\n .optional()\n .describe('RFC3339 timestamp to resume from; when set, `tail` is ignored.'),\n maxWaitMs: z\n .number()\n .int()\n .min(500)\n .max(30000)\n .optional()\n .describe('How long to read the stream, in ms (default 5000, max 30000)'),\n} as const;\n\nexport interface LogStreamParams {\n source?: 'container' | 'system' | 'both';\n tail?: number;\n since?: string;\n maxWaitMs?: number;\n}\n\n// Read a bounded snapshot of a log endpoint and return the parsed frames.\n// `source: 'both'` (or omitted) sends no `source` param — the endpoint returns\n// both streams when it's absent (the wire enum is only container|system).\n// Throws HttpError on a non-OK response.\nexport async function collectLogSnapshot(\n streamSse: StreamSse,\n logsUrl: string,\n params: LogStreamParams\n): Promise<{ items: LogEntry[]; count: number; truncated: boolean }> {\n const qs = new URLSearchParams();\n if (params.source && params.source !== 'both')\n qs.append('source', params.source);\n if (params.tail !== undefined) qs.append('tail', String(params.tail));\n if (params.since) qs.append('since', params.since);\n const query = qs.toString() ? `?${qs}` : '';\n const { raw, truncated } = await streamSse(`${logsUrl}${query}`, {\n maxWaitMs: params.maxWaitMs ?? LOG_STREAM_DEFAULT_WAIT_MS,\n maxBytes: LOG_STREAM_MAX_BYTES,\n });\n const items = parseLogSse(raw);\n // A byte-cap truncation almost always slices the final frame mid-line, so the\n // last parsed entry is a partial (typically garbage half-JSON kept under\n // `raw`). Drop it when truncated so callers never see a corrupt trailing\n // frame; `truncated: true` already signals output was cut.\n //\n // The pop is unconditional: in the rare case the cap lands exactly on a frame\n // boundary (or the final bytes were a non-`data:` block that produced no\n // entry), this drops one *valid* trailing line instead of a garbage one. That\n // over-trim is acceptable — `truncated: true` already tells the caller output\n // was cut, so losing one more line at the boundary is not misleading.\n if (truncated) items.pop();\n return { items, count: items.length, truncated };\n}\n\n// The full handler for a log tool: resolve the backend, gate v2-only, stream a\n// snapshot, and map an HTTP error to a JSON reply. `logsUrl` builds the endpoint\n// URL from the resolved backend (the resource id is closed over by the caller).\nexport async function streamLogsReply(\n rt: Pick<ToolRuntime, 'jsonReply' | 'backendFor' | 'streamSse'>,\n tool: {\n name: string;\n resource: Resource;\n logsUrl: (backend: Backend) => string;\n },\n params: LogStreamParams\n) {\n const backend = rt.backendFor(tool.resource);\n if (backend.version === 'v1') {\n return rt.jsonReply({\n error: `${tool.name} is only available on the v2 REST API. Set RUNPOD_REST_VERSION=v2.`,\n status: 501,\n });\n }\n try {\n return rt.jsonReply(\n await collectLogSnapshot(rt.streamSse, tool.logsUrl(backend), params)\n );\n } catch (error) {\n if (error instanceof HttpError) {\n return rt.jsonReply({ error: error.message, status: error.status });\n }\n throw error;\n }\n}\n","// ============== v1 → v2 REQUEST BODY MAPPERS ==============\n// Pure functions that translate the v1-shaped tool params (what the MCP tool\n// schemas accept today) into v2 REST request bodies. Isolated here so the v2\n// shape is a one-file change when the spec moves.\n//\n// These mappers target the vendored v2 spec snapshot under tests/fixtures and are\n// pinned by committed fixtures. When the live spec changes, update the mapper AND\n// its fixture in one commit.\n//\n// Two older mid-flight questions this file carried ARE now settled, and their\n// workarounds are gone: `cloud` dropped `ALL` (the tool never offered it), and\n// template `category` became optional with a documented server-side `NVIDIA`\n// default, so the mapper no longer forces a value.\n//\n// `/v2/serverless` writes now match the vendored spec: `type` is a create field,\n// `scaling` is a union keyed on it, and `idleTimeout` sits under `workers`. Note the\n// spec-parity gate cannot police this — it checks operationId-to-tool coverage and\n// never validates a request body against a schema, so the mapper tests in\n// tests/mappers.test.ts are the only guard on the emitted shape.\n\n// v1 params accepted by the create-pod / update-pod tool schemas (the fields the\n// mapper knows how to translate). Unknown keys are intentionally dropped.\ninterface V1PodParams {\n name?: string;\n imageName?: string;\n cloudType?: 'SECURE' | 'COMMUNITY';\n gpuTypeIds?: string[];\n gpuCount?: number;\n containerDiskInGb?: number;\n volumeInGb?: number;\n volumeMountPath?: string;\n ports?: string[];\n env?: Record<string, string>;\n dataCenterIds?: string[];\n containerRegistryAuthId?: string;\n}\n\n// Drop undefined entries so we never emit explicit `undefined`/`null` the API\n// would reject; keeps the body minimal and the fixtures clean.\nfunction compact<T extends Record<string, unknown>>(obj: T): Partial<T> {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(obj)) {\n if (v !== undefined) out[k] = v;\n }\n return out as Partial<T>;\n}\n\n// volumeInGb / volumeMountPath → mounts.persistent.{size,path}.\n// v2 PersistentMount requires BOTH size and path (additionalProperties:false,\n// 422 on a partial). So only emit the mount when both are present; a partial\n// v1 input (size-only or path-only) yields `undefined` and is dropped rather\n// than producing a body the API rejects. (Tool-schema validation should require\n// both together.)\ntype PersistentMount = { persistent: { size: number; path: string } };\nfunction persistentMount(\n size?: number,\n path?: string\n): PersistentMount | undefined {\n if (size === undefined || path === undefined) return undefined;\n return { persistent: { size, path } };\n}\n\n// dockerStartCmd[] → v2 `args` (single string). Space-joined (lossy, but v2 has\n// only `args`). Empty/undefined → no `args` key, so we never overwrite with \"\".\nfunction joinStartCmd(cmd?: string[]): string | undefined {\n return cmd && cmd.length ? cmd.join(' ') : undefined;\n}\n\n// ---- ContainerConfig flatten shared by pod + template create/update ----\nfunction containerConfigToV2(p: {\n imageName?: string;\n containerDiskInGb?: number;\n volumeInGb?: number;\n volumeMountPath?: string;\n ports?: string[];\n env?: Record<string, string>;\n}): Record<string, unknown> {\n return compact({\n image: p.imageName,\n disk: p.containerDiskInGb,\n ports: p.ports,\n env: p.env,\n mounts: persistentMount(p.volumeInGb, p.volumeMountPath),\n });\n}\n\n// gpuTypeIds[] + gpuCount → gpu: { id, count }. v2 GpuConfig requires `id`, so\n// return undefined for a count-only input — an idless gpu would be rejected\n// (422). count is optional (defaults to 1 server-side).\nfunction gpuConfigToV2(\n gpuTypeIds?: string[],\n gpuCount?: number\n): Record<string, unknown> | undefined {\n const id = gpuTypeIds?.[0];\n if (id === undefined) return undefined;\n return compact({ id, count: gpuCount });\n}\n\nexport function mapPodCreateToV2(params: V1PodParams): Record<string, unknown> {\n return compact({\n ...containerConfigToV2(params),\n name: params.name,\n // Private-image registry credential (v2 ContainerConfig `registry`). When\n // deploying from a template, this spreads over the template's registry, so\n // passing it overrides the inherited credential. An empty string is an\n // explicit opt-out: emit `registry: null` (v2 accepts null) to CLEAR a\n // template's inherited credential. Undefined is dropped by compact, so an\n // omitted param leaves the template's registry in place.\n registry:\n params.containerRegistryAuthId === ''\n ? null\n : params.containerRegistryAuthId,\n cloud: params.cloudType,\n // v2 CreatePodRequest takes `dataCenterIds` as an ARRAY (preferred data\n // centers; omit/empty = scheduler chooses). Pass the v1 list straight\n // through — the earlier singular `dataCenter` key did not exist on the pod\n // schema, so placement was being silently dropped. GPU, by contrast, IS\n // singular on v2 (`gpu.id`): gpuConfigToV2 takes the first id; the\n // create-pod handler warns when more than one gpuTypeId was supplied.\n dataCenterIds: params.dataCenterIds?.length\n ? params.dataCenterIds\n : undefined,\n gpu: gpuConfigToV2(params.gpuTypeIds, params.gpuCount),\n });\n}\n\nexport function mapPodUpdateToV2(params: V1PodParams): Record<string, unknown> {\n // Update has no gpu/cloud/dataCenter; just name + ContainerConfig fields.\n return {\n ...containerConfigToV2(params),\n ...compact({ name: params.name }),\n };\n}\n\n// ---- Endpoint (serverless) create/update → v2 /v2/serverless body ----\n// v1 create-endpoint is templateId-based (a fundamentally different model); v2\n// takes an INLINE container + compute config (image, gpu.pools, workers, scaling)\n// and has NO templateId. So this mapper translates the v2-shaped tool params into\n// the nested v2 body. It deliberately does NOT reuse containerConfigToV2 — that\n// helper emits `mounts` (a pod/template concept), which the endpoint schema\n// rejects; endpoints attach storage via `networkVolumes` instead.\n//\n// Required by v2 CreateEndpointRequest: `name`, `image`, `gpu` (with `gpu.pools`\n// minItems 1), `type` and `scaling`. The create-endpoint handler guards the first\n// three before calling, so a missing field yields a clean 400 rather than a raw\n// 422 from the API; the last two are always emitted, defaulted below.\n\ninterface V2EndpointParams {\n name?: string;\n imageName?: string;\n args?: string;\n endpointType?: EndpointType;\n gpuPoolIds?: string[];\n gpuCount?: number;\n workersMin?: number;\n workersMax?: number;\n scalerType?: ScalerType;\n scalerValue?: number;\n idleTimeout?: number;\n dataCenterIds?: string[];\n networkVolumeIds?: string[];\n executionTimeoutMs?: number;\n flashboot?: 'OFF' | 'FLASHBOOT' | 'PRIORITY_FLASHBOOT';\n containerDiskInGb?: number;\n ports?: string[];\n env?: Record<string, string>;\n containerRegistryAuthId?: string;\n}\n\ntype EndpointType = 'QUEUE' | 'LOAD_BALANCER';\ntype ScalerType = 'QUEUE_DELAY' | 'REQUEST_COUNT';\n\n// `type` and `scaling` are required on create, so something must be sent. These are\n// what the API used to apply server-side, so a caller that passes neither keeps\n// getting the endpoint it always got.\n//\n// DEFAULT_ENDPOINT_TYPE is create-only — update never sends `type`. DEFAULT_SCALER_VALUE\n// applies on BOTH: the scaling union requires a target next to its discriminator, so\n// `scalerType` alone still has to carry a value.\nconst DEFAULT_ENDPOINT_TYPE: EndpointType = 'QUEUE';\nconst DEFAULT_SCALER_VALUE = 4;\n\n// The scaler each endpoint type uses when the caller does not name one. Queue\n// endpoints may use either signal; load-balancing endpoints have no queue, so\n// REQUEST_COUNT is their only legal choice.\nfunction defaultScalerType(endpointType: EndpointType): ScalerType {\n return endpointType === 'LOAD_BALANCER' ? 'REQUEST_COUNT' : 'QUEUE_DELAY';\n}\n\n// `scaling` is a union discriminated on `type`, with the target carried under a\n// per-variant key rather than a shared `value`.\nfunction endpointScaling(\n scalerType: ScalerType,\n value: number\n): Record<string, unknown> {\n return scalerType === 'REQUEST_COUNT'\n ? { type: 'REQUEST_COUNT', requestCount: value }\n : { type: 'QUEUE_DELAY', queueDelay: value };\n}\n\n// gpu requires `pools` (minItems 1) — return undefined when no pools so the\n// handler's guard, not the API, reports the omission.\nfunction endpointGpuConfig(\n pools?: string[],\n count?: number\n): Record<string, unknown> | undefined {\n if (!pools?.length) return undefined;\n return compact({ pools, count });\n}\n\n// `workers` absorbed `idleTimeout` from `scaling`. Returns undefined when the caller\n// set none of the three, so we never send an empty `workers: {}`.\nfunction endpointWorkers(\n params: V2EndpointParams\n): Record<string, unknown> | undefined {\n const workers = compact({\n min: params.workersMin,\n max: params.workersMax,\n idleTimeout: params.idleTimeout,\n });\n return Object.keys(workers).length ? workers : undefined;\n}\n\n// The half of the body shared by create and update: container config, compute,\n// placement and workers. Only `type` and `scaling` differ between the two.\nfunction endpointCommonToV2(params: V2EndpointParams): Record<string, unknown> {\n return compact({\n name: params.name,\n image: params.imageName,\n args: params.args,\n disk: params.containerDiskInGb,\n ports: params.ports,\n env: params.env,\n registry: params.containerRegistryAuthId,\n gpu: endpointGpuConfig(params.gpuPoolIds, params.gpuCount),\n workers: endpointWorkers(params),\n dataCenterIds: params.dataCenterIds?.length\n ? params.dataCenterIds\n : undefined,\n networkVolumes: params.networkVolumeIds?.length\n ? params.networkVolumeIds\n : undefined,\n timeout: params.executionTimeoutMs,\n flashboot: params.flashboot,\n });\n}\n\n// CREATE. `type` and `scaling` are required, so both are always emitted.\nexport function mapEndpointCreateToV2(\n params: V2EndpointParams\n): Record<string, unknown> {\n const endpointType = params.endpointType ?? DEFAULT_ENDPOINT_TYPE;\n return compact({\n ...endpointCommonToV2(params),\n type: endpointType,\n scaling: endpointScaling(\n params.scalerType ?? defaultScalerType(endpointType),\n params.scalerValue ?? DEFAULT_SCALER_VALUE\n ),\n });\n}\n\n// UPDATE. Only provided fields change, so nothing is defaulted into existence —\n// except the scaler target, which the union requires alongside its `type`\n// discriminator (so `scalerType` alone implies the default value). `type` is never\n// sent: the API rejects it on PATCH (\"additional properties 'type' not allowed\") —\n// an endpoint's routing model is fixed at creation.\nexport function mapEndpointUpdateToV2(\n params: V2EndpointParams\n): Record<string, unknown> {\n return compact({\n ...endpointCommonToV2(params),\n scaling: params.scalerType\n ? endpointScaling(\n params.scalerType,\n params.scalerValue ?? DEFAULT_SCALER_VALUE\n )\n : undefined,\n });\n}\n\n// ---- Network volume: dataCenterId → dataCenter (only field change) ----\ninterface V1NetworkVolumeCreate {\n name?: string;\n size?: number;\n dataCenterId?: string;\n // Storage tier. Optional on v2 — omitted means the data center's default\n // (primary) tier. Immutable after creation, so there is no update equivalent.\n volumeType?: 'STANDARD' | 'HIGH_PERFORMANCE';\n}\nexport function mapNetworkVolumeCreateToV2(\n params: V1NetworkVolumeCreate\n): Record<string, unknown> {\n return compact({\n name: params.name,\n size: params.size,\n dataCenter: params.dataCenterId,\n type: params.volumeType,\n });\n}\n\n// ---- Template: imageName→image, isServerless→serverless, dockerStartCmd→args,\n// ContainerConfig flatten. `dockerEntrypoint` and `readme` are dropped (no v2\n// equivalent — v2 ContainerConfig has only `args`, no separate entrypoint). ----\ninterface V1TemplateCreate {\n name?: string;\n imageName?: string;\n isServerless?: boolean;\n ports?: string[];\n env?: Record<string, string>;\n containerDiskInGb?: number;\n volumeInGb?: number;\n volumeMountPath?: string;\n // Startup command; joinStartCmd collapses the array into v2's `args` string.\n dockerStartCmd?: string[];\n // Template category (CPU/NVIDIA/AMD). Optional on v2, which defaults it to\n // NVIDIA server-side — so an omitted category is left unsent rather than\n // filled in here.\n category?: 'CPU' | 'NVIDIA' | 'AMD';\n // Container registry credential for pulling a private image. v1's field is\n // `containerRegistryAuthId`; v2 ContainerConfig calls it `registry`.\n containerRegistryAuthId?: string;\n}\nexport function mapTemplateCreateToV2(\n params: V1TemplateCreate\n): Record<string, unknown> {\n return {\n ...containerConfigToV2(params),\n ...compact({\n name: params.name,\n serverless: params.isServerless,\n registry: params.containerRegistryAuthId,\n args: joinStartCmd(params.dockerStartCmd),\n // No longer required by v2 (it defaults to NVIDIA server-side), so an\n // unset category is dropped by compact instead of being forced here.\n category: params.category,\n }),\n };\n}\n\n// ---- Template → pod create body (client-side template-based deploy) ----\n// v2 CreatePodRequest has no `templateId`, so create-pod can't deploy from a\n// template the way v1 did. Bridge on the MCP side: copy the template's container\n// config into the pod body as DEFAULTS; the caller's explicit params override\n// them. `registry` is included so a private-image template deploys with its\n// credential — the caller can override it via create-pod's containerRegistryAuthId\n// param. Template-only fields (id, serverless, public, category) and null values\n// are dropped.\nexport function podBodyFromTemplate(\n template: Record<string, unknown>\n): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n const keys = [\n 'name',\n 'image',\n 'args',\n 'disk',\n 'ports',\n 'env',\n 'mounts',\n 'registry',\n ];\n for (const key of keys) {\n const value = template[key];\n if (value !== undefined && value !== null) out[key] = value;\n }\n return out;\n}\n\ninterface V1TemplateUpdate {\n name?: string;\n imageName?: string;\n ports?: string[];\n env?: Record<string, string>;\n dockerStartCmd?: string[];\n containerRegistryAuthId?: string;\n // readme has no v2 equivalent — dropped.\n}\n// Update has no required `category`; flatten ContainerConfig + name. Maps\n// imageName→image (v2 expects `image`) and dockerStartCmd→args like create.\nexport function mapTemplateUpdateToV2(\n params: V1TemplateUpdate\n): Record<string, unknown> {\n return {\n ...containerConfigToV2(params),\n ...compact({\n name: params.name,\n registry: params.containerRegistryAuthId,\n args: joinStartCmd(params.dockerStartCmd),\n }),\n };\n}\n","// ============== BACKEND ADAPTER (v1/v2 routing core) ==============\n// Pure routing layer that lets tools stay version-agnostic. A tool asks for a\n// resource backend; the adapter decides v1 vs v2, resolves the base URL + path,\n// normalizes the list response shape (`unwrapList`), and maps request bodies.\n//\n// This module is intentionally pure and side-effect free: env, transport, and\n// the v2 probe are all passed in, so every function is unit-testable offline\n// with no network and no MCP SDK. The HTTP client (src/_shared/http.ts) and the\n// per-resource tool handlers (src/tools/<resource>.ts) consume this.\n\nimport {\n mapPodCreateToV2,\n mapPodUpdateToV2,\n mapTemplateCreateToV2,\n mapTemplateUpdateToV2,\n mapNetworkVolumeCreateToV2,\n mapEndpointCreateToV2,\n mapEndpointUpdateToV2,\n} from './mappers.js';\n\n// One canonical resource union used by unwrapList, resolveVersion, and\n// resolveBackend alike — so the steps don't each invent a spelling. The v2\n// list-envelope key happens to equal the resource name.\nexport type Resource =\n | 'pods'\n | 'templates'\n | 'networkVolumes'\n | 'registries'\n | 'gpus'\n | 'cpus'\n | 'dataCenters'\n | 'endpoints'\n | 'jobs'\n | 'workers'\n | 'billing';\n\nexport type RestVersion = 'v1' | 'v2';\n\n// Resources that have no v2 REST home and stay on v1 regardless of any flag.\n// - jobs: serverless runtime, lives on api.runpod.ai/v2 (a different service)\n// (endpoints now route to v2 at /v2/serverless — see V2_REST_PATHS/V2_MAPPERS.)\nconst V1_ONLY: ReadonlySet<Resource> = new Set<Resource>(['jobs']);\n\n// The key each v2 list response is wrapped in: `{ pods: [...] }`, etc.\n// `billing` wraps its rows under `records` (not the resource name); `workers`\n// under `workers`.\nconst V2_UNWRAP_KEY: Record<Resource, string> = {\n pods: 'pods',\n templates: 'templates',\n networkVolumes: 'networkVolumes',\n registries: 'registries',\n gpus: 'gpus',\n cpus: 'cpus',\n dataCenters: 'dataCenters',\n endpoints: 'endpoints',\n jobs: 'jobs',\n workers: 'workers',\n billing: 'records',\n};\n\n// Env-var suffix for the per-resource version override (RUNPOD_REST_VERSION_<KEY>).\nconst RESOURCE_ENV_KEY: Record<Resource, string> = {\n pods: 'PODS',\n templates: 'TEMPLATES',\n networkVolumes: 'NETWORK_VOLUMES',\n registries: 'REGISTRIES',\n gpus: 'GPUS',\n cpus: 'CPUS',\n dataCenters: 'DATA_CENTERS',\n endpoints: 'ENDPOINTS',\n jobs: 'JOBS',\n workers: 'WORKERS',\n billing: 'BILLING',\n};\n\n// ---- Base URLs (resolved from env, with the same defaults tools.ts uses) ----\n\nexport type Env = Record<string, string | undefined>;\n\nexport function restV1Base(env: Env): string {\n return env.RUNPOD_REST_API_URL ?? 'https://rest.runpod.io/v1';\n}\nexport function restV2Base(env: Env): string {\n return env.RUNPOD_REST_V2_API_URL ?? 'https://v2-rest.runpod.io/v2';\n}\nexport function serverlessBase(env: Env): string {\n return env.RUNPOD_SERVERLESS_API_URL ?? 'https://api.runpod.ai/v2';\n}\nexport function publicGraphqlBase(env: Env): string {\n return env.RUNPOD_PUBLIC_GRAPHQL_URL ?? 'https://api.runpod.io/graphql';\n}\n// A separate var from publicGraphqlBase despite the identical default:\n// RUNPOD_PUBLIC_GRAPHQL_URL is the documented credential-free discovery\n// override and gets pointed at stubs freely, so routing authed calls through it\n// would turn \"point this anywhere\" into \"send the caller's API key there\".\nexport function authedGraphqlBase(env: Env): string {\n return env.RUNPOD_AUTHED_GRAPHQL_URL ?? 'https://api.runpod.io/graphql';\n}\n\n// ---- A0: unwrap a list response into a plain array ----\n// v1 returns a bare array; v2 wraps it in a per-resource envelope. Either way\n// we hand `capListResult` a plain array. Anything unexpected → [] (never throws\n// in an agent's face, and never passes a non-array through to the cap).\nexport function unwrapList(\n resource: Resource,\n version: RestVersion,\n raw: unknown\n): unknown[] {\n if (version === 'v1') return Array.isArray(raw) ? raw : [];\n if (raw === null || typeof raw !== 'object') return [];\n const arr = (raw as Record<string, unknown>)[V2_UNWRAP_KEY[resource]];\n return Array.isArray(arr) ? arr : [];\n}\n\n// ---- A1: resolve which version a given resource call should use ----\n// Pure: env, transport, and the already-resolved v2 probe verdict are injected.\n// Precedence: v1-only resources → v1; else RUNPOD_REST_VERSION_<RESOURCE> →\n// RUNPOD_REST_VERSION → default 'v2'. `auto` probes only on stdio (one process =\n// one key); on hosted HTTP `auto` is treated as v1 (a warm instance serves many\n// keys, so a cached probe verdict would leak across users).\n//\n// `v2Available` is a *resolved boolean*, NOT a thunk or a promise: the caller\n// awaits createV2Prober() once at startup (stdio only) and passes the boolean\n// in. This is deliberate — a `() => Promise<boolean>` would be truthy even when\n// the probe failed, silently forcing v2. Keeping it a plain boolean removes that\n// footgun. When omitted under `auto`, we conservatively resolve to v1.\nexport interface VersionCtx {\n transport: 'stdio' | 'http';\n}\n\nexport function resolveVersion(opts: {\n resource: Resource;\n env: Env;\n ctx: VersionCtx;\n v2Available?: boolean;\n}): RestVersion {\n const { resource, env, ctx, v2Available } = opts;\n if (V1_ONLY.has(resource)) return 'v1';\n\n const perResource = env[`RUNPOD_REST_VERSION_${RESOURCE_ENV_KEY[resource]}`];\n const setting = (\n perResource ??\n env.RUNPOD_REST_VERSION ??\n 'v2'\n ).toLowerCase();\n\n if (setting === 'v2') return 'v2';\n if (setting === 'auto') {\n if (ctx.transport === 'http') return 'v1';\n return v2Available === true ? 'v2' : 'v1';\n }\n return 'v1';\n}\n\n// True if any version setting (global or per-resource) is `auto` — i.e. the\n// stdio entrypoint should run the v2 probe once at startup. Pure.\nexport function wantsAutoProbe(env: Env): boolean {\n return Object.entries(env).some(\n ([k, v]) =>\n k.startsWith('RUNPOD_REST_VERSION') && (v ?? '').toLowerCase() === 'auto'\n );\n}\n\n// Human-readable summary of how RUNPOD_REST_VERSION is configured, surfaced in\n// the MCP serverInfo version so a plain `initialize` reveals whether the server\n// is pinned to v1/v2/auto (default v2) without inspecting the deployment env.\n// Echoes the global var's value (or \"unset (default v2)\") and flags how many\n// per-resource overrides (RUNPOD_REST_VERSION_<RESOURCE>) are set. Pure.\nexport function restVersionSummary(env: Env): string {\n const raw = (env.RUNPOD_REST_VERSION ?? '').trim().toLowerCase();\n const base = raw\n ? `RUNPOD_REST_VERSION=${raw}`\n : 'RUNPOD_REST_VERSION unset (default v2)';\n const overrides = Object.keys(env).filter(\n (k) => k.startsWith('RUNPOD_REST_VERSION_') && (env[k] ?? '').trim() !== ''\n ).length;\n return overrides > 0 ? `${base}, +${overrides} per-resource` : base;\n}\n\n// ---- A1b: the real `auto` probe (decision logic, injected fetch) ----\n// Returns an async resolver that probes once and memoizes the verdict for the\n// process. The startup wiring (stdio only) awaits this once, then passes the\n// resulting boolean to resolveVersion as `v2Available`. Never wire into the HTTP\n// path (see resolveVersion).\n//\n// Only *definitive* verdicts are cached: a reachable endpoint (any non-5xx\n// response) pins true/false, but a transient failure (thrown error or 5xx) is\n// NOT cached — it returns false for this call and re-probes next time, so a\n// one-time startup network blip doesn't pin the process to v1 forever.\n// Exported so the stdio entrypoint can type its node-fetch adapter against the\n// exact shape the prober needs (just `{ status }`), instead of casting.\n// Named `ProbeFetch` (not `FetchLike`) to avoid colliding with the unrelated,\n// stricter `FetchLike` in _shared/http.ts (which requires method+headers) — the\n// two model different contracts and the distinct name keeps that obvious.\nexport type ProbeFetch = (\n url: string,\n init?: {\n method?: string;\n headers?: Record<string, string>;\n signal?: AbortSignal;\n }\n) => Promise<{ status: number }>;\n\nexport interface ProbeDeps {\n fetch: ProbeFetch;\n baseUrl: string;\n apiKey: string;\n timeoutMs?: number;\n // Optional, injected — called when the probe falls back to v1 for a TRANSIENT\n // reason (timeout / network error / 5xx / 401-403), so an operator who set\n // `auto` and silently got v1 has a signal. Kept as an injected callback\n // (defaulting to no-op) rather than a direct console.* so this module stays\n // pure/side-effect-free and unit tests stay silent. NOT called on a definitive\n // 404 (v2 genuinely not deployed) — that's the expected answer, not a blip.\n warn?: (message: string) => void;\n}\n\n// Bound the startup probe so a slow-but-reachable v2 host can't hang stdio\n// startup forever — an abort throws, which runV2Probe degrades to a transient.\nexport const PROBE_TIMEOUT_MS = 4000;\n\n// Classify a probe response status into a definitive verdict, or `undefined` for\n// a transient failure that must NOT be cached (so the next call re-probes).\n// Transient = 5xx AND 401/403: an auth failure during a rollout, or a key whose\n// v2 scope is later expanded, must not pin the process to v1 for its lifetime\n// with no recovery short of restart. A 2xx pins true; any other definitive 4xx\n// (e.g. 404 = no v2 endpoint) pins false.\nfunction classifyProbeStatus(status: number): boolean | undefined {\n if (status >= 500) return undefined;\n if (status === 401 || status === 403) return undefined;\n return status >= 200 && status < 300;\n}\n\n// One probe attempt. Returns a definitive verdict, or `undefined` when the\n// attempt was transient (network throw / timeout / 5xx) and should be retried.\nasync function runV2Probe(deps: ProbeDeps): Promise<boolean | undefined> {\n try {\n const res = await deps.fetch(`${deps.baseUrl}/catalog/gpus`, {\n method: 'GET',\n headers: { Authorization: `Bearer ${deps.apiKey}` },\n signal: AbortSignal.timeout(deps.timeoutMs ?? PROBE_TIMEOUT_MS),\n });\n const verdict = classifyProbeStatus(res.status);\n if (verdict === undefined) {\n deps.warn?.(\n `v2 auto-probe: ${deps.baseUrl} returned ${res.status} (transient) — using v1 for now; will re-probe. Pin RUNPOD_REST_VERSION=v2 to force v2.`\n );\n }\n return verdict;\n } catch {\n // Thrown = timeout (AbortSignal) or network error — transient, not cached.\n deps.warn?.(\n `v2 auto-probe: ${deps.baseUrl} unreachable (timed out after ${\n deps.timeoutMs ?? PROBE_TIMEOUT_MS\n }ms or network error) — using v1 for now; will re-probe. Pin RUNPOD_REST_VERSION=v2 to force v2.`\n );\n return undefined;\n }\n}\n\n// Memoizing v2 prober: probes once, caches only a *definitive* verdict, and\n// coalesces concurrent first-calls onto a single in-flight probe. A transient\n// attempt resolves to false for this call but leaves the cache unset, so the\n// next call re-probes (a one-time startup blip can't pin the process to v1).\nexport function createV2Prober(deps: ProbeDeps): () => Promise<boolean> {\n let cached: boolean | undefined;\n let inFlight: Promise<boolean> | undefined;\n\n const probeOnce = async (): Promise<boolean> => {\n const verdict = await runV2Probe(deps);\n if (verdict !== undefined) cached = verdict;\n return verdict ?? false;\n };\n\n return () => {\n if (cached !== undefined) return Promise.resolve(cached);\n if (!inFlight) {\n inFlight = probeOnce().finally(() => {\n inFlight = undefined;\n });\n }\n return inFlight;\n };\n}\n\n// ---- A2: resolve the backend descriptor for a resource ----\n// `kind` distinguishes a normal REST resource from the GraphQL-backed catalog\n// (v1) and the serverless-runtime jobs base. mapCreate/mapUpdate default to\n// identity under v1; Phase B fills the v2 half (paths + body mappers + unwrap).\nexport type BackendKind = 'rest' | 'graphql';\n\nexport interface Backend {\n kind: BackendKind;\n version: RestVersion;\n base: string;\n list?: string;\n get?: (id: string) => string;\n unwrap: (raw: unknown) => unknown[];\n mapCreate: (body: unknown) => unknown;\n mapUpdate: (body: unknown) => unknown;\n}\n\nconst identity = (body: unknown): unknown => body;\n\n// v1 REST paths, exactly as tools.ts uses them today.\nconst V1_REST_PATHS: Partial<\n Record<Resource, { list: string; get: (id: string) => string }>\n> = {\n pods: { list: '/pods', get: (id) => `/pods/${id}` },\n templates: { list: '/templates', get: (id) => `/templates/${id}` },\n networkVolumes: {\n list: '/networkvolumes',\n get: (id) => `/networkvolumes/${id}`,\n },\n registries: {\n list: '/containerregistryauth',\n get: (id) => `/containerregistryauth/${id}`,\n },\n endpoints: { list: '/endpoints', get: (id) => `/endpoints/${id}` },\n};\n\nconst CATALOG: ReadonlySet<Resource> = new Set<Resource>([\n 'gpus',\n 'cpus',\n 'dataCenters',\n]);\n\n// Resources that exist ONLY on v2 REST — no v1 REST path and no v1 GraphQL\n// equivalent. Under v1 they resolve to a stub backend (version 'v1', no paths)\n// so the tool emits a clean \"v2 only\" 501 notice instead of throwing on a\n// missing path table entry (mirrors how get-gpu-type/list-cpu-types degrade).\nconst V2_ONLY: ReadonlySet<Resource> = new Set<Resource>([\n 'workers',\n 'billing',\n]);\n\n// v2 REST paths (the control-plane resources). Paths are relative to the v2\n// base which ALREADY includes `/v2` (restV2Base → https://v2-rest.runpod.io/v2),\n// so they do NOT repeat the `/v2` prefix — `base + list` = `.../v2/pods`. (The\n// prober relies on the same convention: `base + /catalog/gpus`.)\n// Renames vs v1: network-volumes (hyphen), registries (was containerregistryauth),\n// catalog/*. Catalog `datacenters` is intentionally NOT hyphenated (matches the spec).\nconst V2_REST_PATHS: Partial<\n Record<Resource, { list: string; get?: (id: string) => string }>\n> = {\n pods: { list: '/pods', get: (id) => `/pods/${id}` },\n templates: { list: '/templates', get: (id) => `/templates/${id}` },\n networkVolumes: {\n list: '/network-volumes',\n get: (id) => `/network-volumes/${id}`,\n },\n registries: { list: '/registries', get: (id) => `/registries/${id}` },\n gpus: { list: '/catalog/gpus', get: (id) => `/catalog/gpus/${id}` },\n cpus: { list: '/catalog/cpus', get: (id) => `/catalog/cpus/${id}` },\n dataCenters: {\n list: '/catalog/datacenters',\n get: (id) => `/catalog/datacenters/${id}`,\n },\n // Endpoints live under /v2/serverless on v2 (NOT /v2/endpoints). The v2 list\n // response wraps rows under `endpoints` (see V2_UNWRAP_KEY), so the existing\n // unwrap key stays correct.\n endpoints: { list: '/serverless', get: (id) => `/serverless/${id}` },\n // workers/billing build their own sub-paths in the tool from `base`; the\n // list entry just satisfies buildV2Backend (which requires a paths entry).\n workers: { list: '/serverless' },\n billing: { list: '/billing' },\n};\n\n// v2 request-body mappers per resource (identity where v1==v2, e.g. registries).\nconst V2_MAPPERS: Partial<\n Record<\n Resource,\n {\n create: (body: unknown) => unknown;\n update: (body: unknown) => unknown;\n }\n >\n> = {\n pods: {\n create: (b) =>\n mapPodCreateToV2(b as Parameters<typeof mapPodCreateToV2>[0]),\n update: (b) =>\n mapPodUpdateToV2(b as Parameters<typeof mapPodUpdateToV2>[0]),\n },\n templates: {\n create: (b) =>\n mapTemplateCreateToV2(b as Parameters<typeof mapTemplateCreateToV2>[0]),\n update: (b) =>\n mapTemplateUpdateToV2(b as Parameters<typeof mapTemplateUpdateToV2>[0]),\n },\n networkVolumes: {\n create: (b) =>\n mapNetworkVolumeCreateToV2(\n b as Parameters<typeof mapNetworkVolumeCreateToV2>[0]\n ),\n update: identity,\n },\n registries: { create: identity, update: identity },\n endpoints: {\n create: (b) =>\n mapEndpointCreateToV2(b as Parameters<typeof mapEndpointCreateToV2>[0]),\n update: (b) =>\n mapEndpointUpdateToV2(b as Parameters<typeof mapEndpointUpdateToV2>[0]),\n },\n};\n\n// The unwrap closure is built once in resolveBackend and threaded into whichever\n// builder runs, so the per-version builders stay free of unwrap plumbing.\ntype Unwrap = Backend['unwrap'];\n\n// jobs never reaches here (pinned v1 by resolveVersion). Endpoints DO reach here\n// on v2 → /v2/serverless via V2_REST_PATHS + V2_MAPPERS. Catalog v2 is REST (not\n// GraphQL); CRUD resources use their v2 paths + body mappers.\nfunction buildV2Backend(resource: Resource, env: Env, unwrap: Unwrap): Backend {\n const paths = V2_REST_PATHS[resource];\n if (!paths) throw new Error(`no v2 REST paths for resource \"${resource}\"`);\n const mappers = V2_MAPPERS[resource];\n return {\n kind: 'rest',\n version: 'v2',\n base: restV2Base(env),\n list: paths.list,\n get: paths.get,\n unwrap,\n mapCreate: mappers?.create ?? identity,\n mapUpdate: mappers?.update ?? identity,\n };\n}\n\nfunction buildV1Backend(resource: Resource, env: Env, unwrap: Unwrap): Backend {\n // jobs: serverless runtime base; no list/get/path table entry.\n if (resource === 'jobs') {\n return {\n kind: 'rest',\n version: 'v1',\n base: serverlessBase(env),\n unwrap,\n mapCreate: identity,\n mapUpdate: identity,\n };\n }\n // v2-only resources have no v1 home: return a stub so the tool sees\n // version 'v1' and returns a clean 501 (it never reads list/get on this).\n if (V2_ONLY.has(resource)) {\n return {\n kind: 'rest',\n version: 'v1',\n base: restV1Base(env),\n unwrap,\n mapCreate: identity,\n mapUpdate: identity,\n };\n }\n // v1 catalog is GraphQL via a separate helper (kept out of the unified REST\n // client through Phase A); folds into REST at Step B5.\n if (CATALOG.has(resource)) {\n return {\n kind: 'graphql',\n version: 'v1',\n base: publicGraphqlBase(env),\n unwrap,\n mapCreate: identity,\n mapUpdate: identity,\n };\n }\n const paths = V1_REST_PATHS[resource];\n if (!paths) throw new Error(`no v1 REST paths for resource \"${resource}\"`);\n return {\n kind: 'rest',\n version: 'v1',\n base: restV1Base(env),\n list: paths.list,\n get: paths.get,\n unwrap,\n mapCreate: identity,\n mapUpdate: identity,\n };\n}\n\nexport function resolveBackend(opts: {\n resource: Resource;\n env: Env;\n ctx: VersionCtx;\n v2Available?: boolean;\n}): Backend {\n const { resource, env } = opts;\n const version = resolveVersion(opts);\n const unwrap: Unwrap = (raw) => unwrapList(resource, version, raw);\n return version === 'v2'\n ? buildV2Backend(resource, env, unwrap)\n : buildV1Backend(resource, env, unwrap);\n}\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\nimport { capListResult, listPaginationParams } from '../pagination.js';\nimport { READ_ONLY, type ToolRuntime } from './runtime.js';\n\n// ============== INFRASTRUCTURE / CATALOG TOOLS ==============\n// GPU types, data centers, CPU types. v1 reads these over GraphQL; v2 has a REST\n// catalog (GET /v2/catalog/*). The adapter picks the backend; v2-only entries\n// return a 501 notice on v1.\n\nexport function registerCatalogTools(server: McpServer, rt: ToolRuntime): void {\n const { jsonReply, graphql, callRestUrl, backendFor } = rt;\n\n // List GPU Types\n server.tool(\n 'list-gpu-types',\n 'List available GPU types with stock/pricing and capability filters (minimum VRAM, secure/community cloud, name search). Use this to discover valid gpuTypeIds before creating a pod or endpoint. By default the full catalog is returned: each result includes an `availability` summary (HIGH/MEDIUM/LOW/NONE) and results are sorted with the most-available GPUs first, but nothing is hidden. Set includeUnavailable:false to drop out-of-stock GPUs and list only deployable ones (set includeAvailability:false to skip the stock lookup entirely). For per-datacenter availability (to pick a dataCenterIds), use get-gpu-type.',\n {\n ...listPaginationParams,\n minMemoryGb: z\n .number()\n .optional()\n .describe('Filter to GPUs with at least this much VRAM in GB'),\n secureCloudOnly: z\n .boolean()\n .optional()\n .describe('Filter to only GPUs available in secure cloud'),\n communityCloudOnly: z\n .boolean()\n .optional()\n .describe('Filter to only GPUs available in community cloud'),\n searchTerm: z\n .string()\n .optional()\n .describe(\n \"Search term to filter GPUs by name (e.g., 'A100', 'RTX 4090')\"\n ),\n includeUnavailable: z\n .boolean()\n .optional()\n .describe(\n 'Out-of-stock GPUs are included by default (annotated availability:NONE and sorted last). Set false to hide them and list only currently-deployable GPUs.'\n ),\n includeAvailability: z\n .boolean()\n .optional()\n .describe(\n 'Request realtime stock and annotate each GPU with an availability summary (HIGH/MEDIUM/LOW/NONE). Default true. Set false to skip the availability lookup — then out-of-stock GPUs cannot be filtered.'\n ),\n },\n { title: 'List GPU types', ...READ_ONLY },\n async (params) => {\n const backend = backendFor('gpus');\n if (backend.version === 'v2') {\n // v2 REST: GET /v2/catalog/gpus?include=AVAILABILITY → { gpus: [...] },\n // each with an `availability` summary (HIGH/MEDIUM/LOW/NONE) and a\n // per-datacenter `dataCenters` breakdown. Filters re-applied against v2\n // field names. Opt out with includeAvailability:false (then the\n // filter/sort below no-op, since there's no data).\n const wantAvailability = params.includeAvailability !== false;\n const raw = await callRestUrl(\n `${backend.base}${backend.list}${\n wantAvailability ? '?include=AVAILABILITY' : ''\n }`\n );\n let gpus = backend.unwrap(raw) as Array<Record<string, unknown>>;\n // Drop the \"unknown\" sentinel (matches the v1 path). It's a NONE-stock\n // placeholder that used to be masked by the default hide; now that the\n // full catalog shows by default it would otherwise leak into the list.\n gpus = gpus.filter((g) => g.id !== 'unknown');\n if (params.minMemoryGb !== undefined)\n gpus = gpus.filter(\n (g) => Number(g.memory ?? 0) >= params.minMemoryGb!\n );\n if (params.secureCloudOnly) gpus = gpus.filter((g) => g.secure);\n if (params.communityCloudOnly) gpus = gpus.filter((g) => g.community);\n if (params.searchTerm) {\n const t = params.searchTerm.toLowerCase();\n gpus = gpus.filter(\n (g) =>\n String(g.id ?? '')\n .toLowerCase()\n .includes(t) ||\n String(g.name ?? '')\n .toLowerCase()\n .includes(t)\n );\n }\n // Full catalog by default; only includeUnavailable:false filters down to\n // deployable GPUs. A GPU with no `availability` from the backend is\n // treated as available, so the opt-in never over-filters.\n if (params.includeUnavailable === false)\n gpus = gpus.filter((g) => g.availability !== 'NONE');\n // Highest stock first so the best pick is at the top.\n const rank: Record<string, number> = {\n HIGH: 3,\n MEDIUM: 2,\n LOW: 1,\n NONE: 0,\n };\n gpus.sort(\n (a, b) =>\n (rank[String(b.availability)] ?? 0) -\n (rank[String(a.availability)] ?? 0)\n );\n // Drop the bulky per-datacenter breakdown from the list; keep the\n // `availability` summary. get-gpu-type returns the full detail.\n gpus = gpus.map(({ dataCenters: _dataCenters, ...rest }) => rest);\n return capListResult(gpus, {\n limit: params.limit,\n cursor: params.cursor,\n });\n }\n\n interface GpuTypesResponse {\n gpuTypes: Array<{\n id: string;\n displayName: string;\n memoryInGb: number;\n secureCloud: boolean;\n communityCloud: boolean;\n lowestPrice?: { stockStatus: string | null } | null;\n }>;\n }\n\n const data = await graphql<GpuTypesResponse>(`\n query {\n gpuTypes {\n id\n displayName\n memoryInGb\n secureCloud\n communityCloud\n lowestPrice(input: { gpuCount: 1 }) {\n stockStatus\n }\n }\n }\n `);\n\n const stockPriority: Record<string, number> = {\n High: 3,\n Medium: 2,\n Low: 1,\n };\n\n const isAvailable = (gpu: GpuTypesResponse['gpuTypes'][number]) => {\n const status = gpu.lowestPrice?.stockStatus;\n return !!status && status !== 'Out';\n };\n\n let gpuTypes = data.gpuTypes.filter((gpu) => gpu.id !== 'unknown');\n\n // Full catalog by default; opt in (includeUnavailable:false) to hide out-of-stock.\n if (params.includeUnavailable === false) {\n gpuTypes = gpuTypes.filter(isAvailable);\n }\n if (params.minMemoryGb) {\n gpuTypes = gpuTypes.filter(\n (gpu) => gpu.memoryInGb >= params.minMemoryGb!\n );\n }\n if (params.secureCloudOnly) {\n gpuTypes = gpuTypes.filter((gpu) => gpu.secureCloud);\n }\n if (params.communityCloudOnly) {\n gpuTypes = gpuTypes.filter((gpu) => gpu.communityCloud);\n }\n if (params.searchTerm) {\n const term = params.searchTerm.toLowerCase();\n gpuTypes = gpuTypes.filter(\n (gpu) =>\n gpu.id.toLowerCase().includes(term) ||\n gpu.displayName.toLowerCase().includes(term)\n );\n }\n\n gpuTypes.sort((a, b) => {\n const aP = stockPriority[a.lowestPrice?.stockStatus || ''] || 0;\n const bP = stockPriority[b.lowestPrice?.stockStatus || ''] || 0;\n if (bP !== aP) return bP - aP;\n return b.memoryInGb - a.memoryInGb;\n });\n\n const result = gpuTypes.map((gpu) => ({\n id: gpu.id,\n displayName: gpu.displayName,\n memoryGb: gpu.memoryInGb,\n secureCloud: gpu.secureCloud,\n communityCloud: gpu.communityCloud,\n stockStatus: gpu.lowestPrice?.stockStatus || 'unavailable',\n available: isAvailable(gpu),\n }));\n\n return capListResult(result, {\n limit: params.limit,\n cursor: params.cursor,\n });\n }\n );\n\n // List Data Centers\n server.tool(\n 'list-data-centers',\n 'List Runpod data centers (id, name, region/location). Use this to discover valid dataCenterIds for placing pods, endpoints, or network volumes.',\n {\n ...listPaginationParams,\n region: z\n .string()\n .optional()\n .describe(\n \"Filter by region/location (e.g., 'United States', 'Europe', 'Canada')\"\n ),\n },\n { title: 'List data centers', ...READ_ONLY },\n async (params) => {\n const backend = backendFor('dataCenters');\n if (backend.version === 'v2') {\n // v2 REST: GET /v2/catalog/datacenters → { dataCenters: [...] }. v2 uses\n // a `region` enum (vs v1 free-text `location`); region filter matches it.\n const raw = await callRestUrl(`${backend.base}${backend.list}`);\n let dcs = backend.unwrap(raw) as Array<Record<string, unknown>>;\n if (params.region) {\n const t = params.region.toLowerCase();\n dcs = dcs.filter((dc) =>\n String(dc.region ?? '')\n .toLowerCase()\n .includes(t)\n );\n }\n return capListResult(dcs, {\n limit: params.limit,\n cursor: params.cursor,\n });\n }\n\n interface DataCentersResponse {\n dataCenters: Array<{\n id: string;\n name: string;\n location: string;\n }>;\n }\n\n const data = await graphql<DataCentersResponse>(`\n query {\n dataCenters {\n id\n name\n location\n }\n }\n `);\n\n let dataCenters = data.dataCenters;\n\n if (params.region) {\n const term = params.region.toLowerCase();\n dataCenters = dataCenters.filter((dc) =>\n dc.location.toLowerCase().includes(term)\n );\n }\n\n return capListResult(dataCenters, {\n limit: params.limit,\n cursor: params.cursor,\n });\n }\n );\n\n // List CPU Types (v2-only — v2 catalog REST has no v1/GraphQL equivalent)\n server.tool(\n 'list-cpu-types',\n 'List available CPU flavor types for CPU pods/endpoints. v2-only — returns a 501 notice on the v1 API.',\n { ...listPaginationParams },\n { title: 'List CPU types', ...READ_ONLY },\n async (params) => {\n const backend = backendFor('cpus');\n if (backend.version === 'v1') {\n return jsonReply({\n error:\n 'list-cpu-types is only available on the v2 REST API. Set RUNPOD_REST_VERSION=v2.',\n status: 501,\n });\n }\n const raw = await callRestUrl(`${backend.base}${backend.list}`);\n return capListResult(backend.unwrap(raw), {\n limit: params.limit,\n cursor: params.cursor,\n });\n }\n );\n\n // Get GPU Type by id (v2-only — GET /v2/catalog/gpus/{id})\n server.tool(\n 'get-gpu-type',\n 'Get details for a single GPU type by id, including per-datacenter availability. v2-only — returns a 501 notice on the v1 API (use list-gpu-types there). Use the returned dataCenters[].availability to pick a dataCenterIds with stock before creating a pod.',\n {\n gpuTypeId: z.string().describe('ID of the GPU type to retrieve'),\n includeAvailability: z\n .boolean()\n .optional()\n .describe(\n 'Include realtime per-datacenter availability (HIGH/MEDIUM/LOW/NONE). Default true.'\n ),\n },\n { title: 'Get GPU type', ...READ_ONLY },\n async (params) => {\n const backend = backendFor('gpus');\n if (backend.version === 'v1') {\n return jsonReply({\n error:\n 'get-gpu-type is only available on the v2 REST API. Set RUNPOD_REST_VERSION=v2 (or use list-gpu-types on v1).',\n status: 501,\n });\n }\n // GPU ids contain spaces (e.g. \"NVIDIA GeForce RTX 4090\"), so encode the\n // path segment. Availability on by default — it's the point of a single GPU.\n const path = backend.get!(encodeURIComponent(params.gpuTypeId));\n const query =\n params.includeAvailability === false ? '' : '?include=AVAILABILITY';\n const result = await callRestUrl(`${backend.base}${path}${query}`);\n return jsonReply(result);\n }\n );\n\n // Get CPU Type by id (v2-only — GET /v2/catalog/cpus/{id})\n server.tool(\n 'get-cpu-type',\n 'Get details for a single CPU flavor type by id. v2-only — returns a 501 notice on the v1 API (use list-cpu-types there).',\n {\n cpuTypeId: z.string().describe('ID of the CPU type to retrieve'),\n },\n { title: 'Get CPU type', ...READ_ONLY },\n async (params) => {\n const backend = backendFor('cpus');\n if (backend.version === 'v1') {\n return jsonReply({\n error:\n 'get-cpu-type is only available on the v2 REST API. Set RUNPOD_REST_VERSION=v2.',\n status: 501,\n });\n }\n const result = await callRestUrl(\n `${backend.base}${backend.get!(params.cpuTypeId)}`\n );\n return jsonReply(result);\n }\n );\n\n // Get Data Center by id (v2-only — GET /v2/catalog/datacenters/{id})\n server.tool(\n 'get-data-center',\n 'Get details for a single data center by id. v2-only — returns a 501 notice on the v1 API (use list-data-centers there).',\n {\n dataCenterId: z.string().describe('ID of the data center to retrieve'),\n },\n { title: 'Get data center', ...READ_ONLY },\n async (params) => {\n const backend = backendFor('dataCenters');\n if (backend.version === 'v1') {\n return jsonReply({\n error:\n 'get-data-center is only available on the v2 REST API. Set RUNPOD_REST_VERSION=v2.',\n status: 501,\n });\n }\n const result = await callRestUrl(\n `${backend.base}${backend.get!(params.dataCenterId)}`\n );\n return jsonReply(result);\n }\n );\n}\n","// ============== LIST RESULT PAGINATION / TOKEN CAPS ==============\n// The REST list endpoints do not yet support server-side pagination, so a\n// large account can return a payload many times the size of an LLM's context\n// window (e.g. list-templates has been observed at ~15x Claude Code's window),\n// which ends the agent session. Until the REST API ships cursor pagination,\n// the MCP caps list responses client-side: it returns at most `limit` items\n// and reports how many were omitted so the agent knows to narrow its query.\n//\n// The `limit` and `cursor` parameters are shaped to match the cursor-based\n// pagination the REST API will add, so the tool signatures do not change when\n// server-side pagination lands; the MCP will simply forward them and surface a\n// real `nextCursor` instead of the client-side offset used here.\n\nimport { z } from 'zod';\n\n// Default and maximum number of items returned by a list tool in a single\n// call. The cap is what protects the agent's context; `limit` lets a caller\n// ask for fewer (or more, up to the ceiling) when they know what they want.\nexport const DEFAULT_LIST_LIMIT = 20;\nexport const MAX_LIST_LIMIT = 100;\n\n// Shared Zod parameters added to every list-* tool. Optional so existing\n// callers that pass nothing keep working (they get the default page).\nexport const listPaginationParams = {\n limit: z\n .number()\n .int()\n .positive()\n .max(MAX_LIST_LIMIT)\n .optional()\n .describe(\n `Maximum number of items to return (default ${DEFAULT_LIST_LIMIT}, max ${MAX_LIST_LIMIT}). Use the returned nextCursor to fetch the next page.`\n ),\n cursor: z\n .string()\n .optional()\n .describe(\n 'Opaque pagination cursor from a previous response (nextCursor). Omit to start from the beginning.'\n ),\n};\n\n// Decodes the opaque cursor into a numeric offset. The cursor is currently a\n// base64-encoded offset; when the REST API ships real cursors this becomes a\n// passthrough. Invalid cursors are treated as the start so a bad value never\n// throws in an agent's face.\nexport function decodeCursorOffset(cursor: string | undefined): number {\n if (!cursor) return 0;\n try {\n const decoded = Buffer.from(cursor, 'base64').toString('utf8');\n const offset = Number.parseInt(decoded, 10);\n return Number.isFinite(offset) && offset >= 0 ? offset : 0;\n } catch {\n return 0;\n }\n}\n\nexport function encodeCursorOffset(offset: number): string {\n return Buffer.from(String(offset), 'utf8').toString('base64');\n}\n\n// Caps a list response to `limit` items starting at `cursor`, returning an\n// envelope that tells the agent how much it is seeing and how to get the rest.\n// Only arrays are paginated; any other shape is passed through untouched.\n//\n// `extra` merges sibling fields alongside `items`/`pagination` (e.g. billing\n// `metadata`, an endpoint-workers `summary`) so a capped list response can still\n// carry the small aggregate fields that accompany the array. Reserved keys\n// (`items`, `pagination`) in `extra` are ignored so they can't shadow the cap.\nexport function capListResult(\n result: unknown,\n options: { limit?: number; cursor?: string },\n extra?: Record<string, unknown>\n): { content: Array<{ type: 'text'; text: string }> } {\n const limit = Math.min(options.limit ?? DEFAULT_LIST_LIMIT, MAX_LIST_LIMIT);\n const offset = decodeCursorOffset(options.cursor);\n\n if (!Array.isArray(result)) {\n return {\n content: [\n { type: 'text' as const, text: JSON.stringify(result, null, 2) },\n ],\n };\n }\n\n const total = result.length;\n const page = result.slice(offset, offset + limit);\n const nextOffset = offset + page.length;\n const hasMore = nextOffset < total;\n\n const { items: _i, pagination: _p, ...safeExtra } = extra ?? {};\n void _i;\n void _p;\n\n const envelope = {\n ...safeExtra,\n items: page,\n pagination: {\n total,\n returned: page.length,\n offset,\n truncated: hasMore,\n nextCursor: hasMore ? encodeCursorOffset(nextOffset) : null,\n note: hasMore\n ? `Showing ${page.length} of ${total}. Pass cursor=nextCursor to fetch more, or narrow the query with filters.`\n : undefined,\n },\n };\n\n return {\n content: [\n { type: 'text' as const, text: JSON.stringify(envelope, null, 2) },\n ],\n };\n}\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\nimport { capListResult, listPaginationParams } from '../pagination.js';\nimport { READ_ONLY, WRITE, type ToolRuntime } from './runtime.js';\n\n// ============== HUB TOOLS ==============\n// Read-only discovery of Runpod Hub listings (prebuilt serverless workers and\n// pod templates published from GitHub repos, e.g. worker-vllm, worker-comfyui).\n// Served by the public GraphQL endpoint — no auth required — like the v1\n// catalog tools. There is no REST home for the Hub yet, so this is\n// version-agnostic: the same GraphQL path is used on v1 and v2.\n//\n// The `listings(input: {})` query returns the full public catalog; the\n// endpoint does not accept GraphQL variables on the public path, so filters\n// (search, category, type, owner) are applied client-side, matching the\n// list-gpu-types v1 pattern. Each listing carries its currently listed\n// release, whose id (`hubReleaseId`) and built image are what a Hub deploy is\n// pinned to.\n\ninterface HubBuild {\n id: string;\n imageName: string;\n}\n\ninterface HubRelease {\n id: string;\n name: string;\n tagName: string;\n createdAt: string;\n config?: string | null;\n build?: HubBuild | null;\n}\n\ninterface HubListing {\n id: string;\n repoId: string;\n title: string;\n description: string | null;\n repoName: string;\n repoOwner: string;\n createdAt: string;\n updatedAt: string;\n views: number;\n stars: number;\n deploys: number;\n language: string | null;\n category: string | null;\n tags: string[] | null;\n type: string;\n listedRelease?: HubRelease | null;\n}\n\ninterface ListingsResponse {\n listings: HubListing[];\n}\n\n// The release `config` is the repo's .runpod/hub.json config serialized as a\n// JSON string (hardware requirements + the env-var input schema). It can be\n// tens of KB per listing, so it is only requested when includeConfig is set.\nfunction parseReleaseConfig(config: string | null | undefined): unknown {\n if (!config) return undefined;\n try {\n return JSON.parse(config);\n } catch {\n return config;\n }\n}\n\n// Typed view of the parts of the release config a deploy consumes. Everything\n// is optional — the config is repo-authored and defensively read.\ninterface HubReleaseConfig {\n runsOn?: string;\n containerDiskInGb?: number;\n gpuIds?: string;\n gpuCount?: number;\n allowedCudaVersions?: string[];\n env?: Array<{\n key: string;\n input?: {\n name?: string;\n type?: string;\n default?: unknown;\n required?: boolean;\n trueValue?: string;\n falseValue?: string;\n };\n }>;\n}\n\n// The one listings query both hub tools share. `withConfig` pulls in the\n// (large) release config only when the caller needs it.\nfunction listingsQuery(withConfig: boolean): string {\n return `\n query {\n listings(input: {}) {\n id\n repoId\n title\n description\n repoName\n repoOwner\n createdAt\n updatedAt\n views\n stars\n deploys\n language\n category\n tags\n type\n listedRelease {\n id\n name\n tagName\n createdAt${withConfig ? '\\n config' : ''}\n build {\n id\n imageName\n }\n }\n }\n }\n `;\n}\n\n// Serializes a boolean through the schema's trueValue/falseValue. Applied to\n// caller values too: an agent naturally passes 'true' where the schema declares\n// trueValue '1', so the worker would get a value its own schema calls invalid.\n// Only exact 'true'/'false' map; anything else is a deliberate literal.\nfunction serializeBoolean(\n value: string,\n input: { type?: string; trueValue?: string; falseValue?: string }\n): string {\n if (value === 'true') return input.trueValue ?? 'true';\n if (value === 'false') return input.falseValue ?? 'false';\n return value;\n}\n\n// Builds the template env array a Hub deploy submits: every key from the\n// release's env schema with its default (booleans serialized through\n// trueValue/falseValue), overridden by caller-provided values. Caller keys not\n// in the schema are appended verbatim. Returns the missing required keys so\n// the tool can fail with an actionable message instead of a broken endpoint.\nexport function buildHubEnv(\n config: HubReleaseConfig,\n overrides: Record<string, string>\n): {\n env: Array<{ key: string; value: string }>;\n missingRequired: string[];\n} {\n const env: Array<{ key: string; value: string }> = [];\n const missingRequired: string[] = [];\n const remaining = { ...overrides };\n\n for (const entry of config.env ?? []) {\n const input = entry.input ?? {};\n const override = entry.key in remaining ? remaining[entry.key] : undefined;\n delete remaining[entry.key];\n\n // An override present but EMPTY is not a value. Checking `key in remaining`\n // alone let `env: { MODEL_NAME: '' }` satisfy a required key, so fail-fast\n // passed and the deploy produced a broken worker.\n if (override !== undefined && override !== '') {\n env.push({\n key: entry.key,\n value:\n input.type === 'boolean'\n ? serializeBoolean(override, input)\n : override,\n });\n continue;\n }\n\n if (input.default !== undefined && input.default !== null) {\n env.push({\n key: entry.key,\n value:\n typeof input.default === 'boolean'\n ? input.default\n ? (input.trueValue ?? 'true')\n : (input.falseValue ?? 'false')\n : String(input.default),\n });\n continue;\n }\n\n if (input.required) {\n missingRequired.push(entry.key);\n // Still submitted so the key is visible on the endpoint, though the tool\n // aborts on a non-empty missingRequired before the caller sees it.\n env.push({ key: entry.key, value: '' });\n continue;\n }\n\n // Optional, no default, nothing supplied: OMIT the key rather than send ''.\n // os.environ.get('X', 'fb') returns '' when X='', shadowing the fallback.\n }\n\n for (const [key, value] of Object.entries(remaining)) {\n env.push({ key, value });\n }\n\n return { env, missingRequired };\n}\n\n// Lowest entry of the config's allowedCudaVersions (numeric-aware compare, so\n// '12.10' > '12.9'). The console submits this as minCudaVersion.\nexport function minCudaVersion(versions: string[] | undefined): string | null {\n if (!versions || versions.length === 0) return null;\n const compare = (a: string, b: string) => {\n const pa = a.split('.').map(Number);\n const pb = b.split('.').map(Number);\n for (let i = 0; i < Math.max(pa.length, pb.length); i++) {\n const d = (pa[i] ?? 0) - (pb[i] ?? 0);\n if (d !== 0) return d;\n }\n return 0;\n };\n return [...versions].sort(compare)[0];\n}\n\nfunction randomSuffix(): string {\n return Math.random().toString(36).slice(2, 8);\n}\n\nexport function registerHubTools(server: McpServer, rt: ToolRuntime): void {\n const { graphql, graphqlAuthed, jsonReply } = rt;\n\n server.tool(\n 'list-hub-repos',\n 'List repos published to the Runpod Hub (prebuilt Serverless workers and Pod templates, e.g. vLLM, ComfyUI). Public catalog — no auth required. Each result includes the currently listed release with its hubReleaseId and prebuilt image name. Results are sorted by deploy count (most popular first). Set includeConfig:true to also return the release config (hardware requirements and environment-variable schema) — it is large, so prefer requesting it for a single repo via the repoOwner/searchTerm filters.',\n {\n ...listPaginationParams,\n searchTerm: z\n .string()\n .optional()\n .describe(\n \"Case-insensitive search across title, description, repo name, owner, and tags (e.g. 'vllm', 'comfyui', 'fine-tuning')\"\n ),\n category: z\n .string()\n .optional()\n .describe(\n \"Filter by category (e.g. 'language', 'image', 'audio', 'video', 'embedding')\"\n ),\n type: z\n .enum(['SERVERLESS', 'POD'])\n .optional()\n .describe(\n 'Filter by listing type: SERVERLESS (endpoint workers) or POD (pod templates)'\n ),\n repoOwner: z\n .string()\n .optional()\n .describe(\n \"Filter to listings from this GitHub owner/org (e.g. 'runpod-workers', 'axolotl-ai-cloud')\"\n ),\n includeConfig: z\n .boolean()\n .optional()\n .describe(\n 'Include the listed release config (hardware requirements + env-var input schema, parsed from .runpod/hub.json). Large — off by default.'\n ),\n },\n { title: 'List Hub repos', ...READ_ONLY },\n async (params) => {\n const data = await graphql<ListingsResponse>(\n listingsQuery(params.includeConfig === true)\n );\n\n let listings = data.listings;\n\n if (params.type) {\n listings = listings.filter(\n (l) => (l.type ?? '').toUpperCase() === params.type\n );\n }\n if (params.category) {\n const term = params.category.toLowerCase();\n listings = listings.filter(\n (l) => (l.category ?? '').toLowerCase() === term\n );\n }\n if (params.repoOwner) {\n const term = params.repoOwner.toLowerCase();\n listings = listings.filter(\n (l) => (l.repoOwner ?? '').toLowerCase() === term\n );\n }\n if (params.searchTerm) {\n const term = params.searchTerm.toLowerCase();\n listings = listings.filter((l) =>\n [\n l.title,\n l.description,\n l.repoName,\n l.repoOwner,\n ...(l.tags ?? []),\n ].some((field) => (field ?? '').toLowerCase().includes(term))\n );\n }\n\n // Most-deployed first so well-known workers surface at the top, id as\n // tiebreak. The tiebreak is load-bearing: each page re-fetches the whole\n // catalog and `listings(input: {})` promises no order, so ties move\n // between requests and paging silently skips and duplicates.\n listings = [...listings].sort(\n (a, b) =>\n (b.deploys ?? 0) - (a.deploys ?? 0) || a.id.localeCompare(b.id)\n );\n\n const result = listings.map((l) => ({\n id: l.id,\n repo: `${l.repoOwner}/${l.repoName}`,\n title: l.title,\n description: l.description,\n type: l.type,\n category: l.category,\n tags: l.tags,\n language: l.language,\n stars: l.stars,\n deploys: l.deploys,\n views: l.views,\n githubUrl: `https://github.com/${l.repoOwner}/${l.repoName}`,\n hubUrl: `https://console.runpod.io/hub/${l.repoOwner}/${l.repoName}`,\n createdAt: l.createdAt,\n updatedAt: l.updatedAt,\n listedRelease: l.listedRelease\n ? {\n hubReleaseId: l.listedRelease.id,\n name: l.listedRelease.name,\n tagName: l.listedRelease.tagName,\n createdAt: l.listedRelease.createdAt,\n imageName: l.listedRelease.build?.imageName,\n ...(params.includeConfig\n ? { config: parseReleaseConfig(l.listedRelease.config) }\n : {}),\n }\n : null,\n }));\n\n return capListResult(result, {\n limit: params.limit,\n cursor: params.cursor,\n });\n }\n );\n\n server.tool(\n 'deploy-hub-repo',\n \"Deploy a Runpod Hub repo's listed release as a new Serverless endpoint (the same as clicking Deploy on the Hub). Identify the repo by `repo` (\\\"owner/name\\\" from list-hub-repos) or by `hubReleaseId`. The release supplies the prebuilt image, container disk, CUDA constraints, and env-var defaults; pass `env` to override or fill in values (required keys without a default must be provided — check list-hub-repos with includeConfig:true for the schema). GPU selection comes from the release config when it specifies one; otherwise pass gpuIds (GPU pool names, e.g. 'ADA_24' or 'ADA_80_PRO,AMPERE_80'). Uses the authenticated GraphQL API (no REST home for Hub deploys yet), so it works the same on v1 and v2.\",\n {\n repo: z\n .string()\n .optional()\n .describe(\n 'The Hub repo to deploy as \"owner/name\" (e.g. \\'runpod-workers/worker-comfyui\\'). Deploys its currently listed release. Provide this or hubReleaseId.'\n ),\n hubReleaseId: z\n .string()\n .optional()\n .describe(\n 'The Hub release ID to deploy (from list-hub-repos listedRelease.hubReleaseId). Provide this or repo.'\n ),\n name: z\n .string()\n .optional()\n .describe(\n \"Name for the new endpoint. Defaults to '<listing title> <release tag>'.\"\n ),\n env: z\n .record(z.string())\n .optional()\n .describe(\n 'Environment variable overrides, merged over the release config defaults. Keys not in the release schema are passed through as-is.'\n ),\n gpuIds: z\n .string()\n .optional()\n .describe(\n \"Comma-separated GPU pool names for workers (e.g. 'ADA_24' or 'ADA_80_PRO,AMPERE_80'). To pin specific GPU SKUs within a pool, append exclusions prefixed with '-' using GPU type ids from list-gpu-types (e.g. 'AMPERE_16,-NVIDIA RTX 2000 Ada Generation,-NVIDIA RTX A4500' allows only the pool's remaining SKUs). Defaults to the release config's gpuIds; required when the config does not specify one.\"\n ),\n gpuCount: z\n .number()\n .int()\n .positive()\n .optional()\n .describe('GPUs per worker. Defaults to the release config (or 1).'),\n containerDiskInGb: z\n .number()\n .int()\n .positive()\n .optional()\n .describe('Container disk size in GB. Defaults to the release config.'),\n workersMin: z\n .number()\n .int()\n .min(0)\n .optional()\n .describe('Minimum workers (default 0 — scale to zero).'),\n workersMax: z\n .number()\n .int()\n .positive()\n .optional()\n .describe('Maximum workers (default: account default).'),\n idleTimeout: z\n .number()\n .int()\n .positive()\n .optional()\n .describe('Seconds a worker idles before scaling down (default 5).'),\n scalerType: z\n .enum(['QUEUE_DELAY', 'REQUEST_COUNT'])\n .optional()\n .describe('Autoscaler type (default QUEUE_DELAY).'),\n scalerValue: z\n .number()\n .optional()\n .describe('Autoscaler target value (default 4).'),\n executionTimeoutMs: z\n .number()\n .int()\n .positive()\n .optional()\n .describe('Per-job execution timeout in ms (default 600000).'),\n flashboot: z\n .enum(['OFF', 'FLASHBOOT', 'PRIORITY_FLASHBOOT'])\n .optional()\n .describe('FlashBoot mode (default FLASHBOOT).'),\n },\n { title: 'Deploy Hub repo', ...WRITE },\n async (params) => {\n if (!params.repo && !params.hubReleaseId) {\n return jsonReply({\n error:\n 'Provide either repo (\"owner/name\") or hubReleaseId. Use list-hub-repos to discover both.',\n });\n }\n\n // Resolve the listing + release from the public catalog. The catalog only\n // exposes each repo's currently LISTED release, so a hubReleaseId must\n // match one of those (which is also the only state the console deploys).\n const catalog = await graphql<ListingsResponse>(listingsQuery(true));\n let listing: HubListing | undefined;\n if (params.hubReleaseId) {\n listing = catalog.listings.find(\n (l) => l.listedRelease?.id === params.hubReleaseId\n );\n } else {\n const repoKey = params.repo!.toLowerCase();\n listing = catalog.listings.find(\n (l) => `${l.repoOwner}/${l.repoName}`.toLowerCase() === repoKey\n );\n }\n if (!listing) {\n return jsonReply({\n error: `No Hub listing found for ${\n params.hubReleaseId\n ? `hubReleaseId \"${params.hubReleaseId}\" (only each repo's currently listed release is deployable)`\n : `repo \"${params.repo}\"`\n }. Use list-hub-repos to see the catalog.`,\n });\n }\n const release = listing.listedRelease;\n if (!release?.build?.imageName) {\n return jsonReply({\n error: `Hub repo ${listing.repoOwner}/${listing.repoName} has no listed release with a built image, so it cannot be deployed.`,\n });\n }\n if ((listing.type ?? '').toUpperCase() !== 'SERVERLESS') {\n return jsonReply({\n error: `Hub repo ${listing.repoOwner}/${listing.repoName} is a ${listing.type} listing — only SERVERLESS listings deploy as endpoints.`,\n });\n }\n\n const config = (parseReleaseConfig(release.config) ??\n {}) as HubReleaseConfig;\n\n const gpuIds = params.gpuIds ?? config.gpuIds;\n if (!gpuIds) {\n return jsonReply({\n error:\n 'This release does not specify a GPU pool — pass gpuIds (comma-separated pool names, e.g. \"ADA_80_PRO,AMPERE_80\"; see the pool field on list-gpu-types).',\n });\n }\n\n const { env, missingRequired } = buildHubEnv(config, params.env ?? {});\n if (missingRequired.length > 0) {\n return jsonReply({\n error: `Missing required environment variables for this release: ${missingRequired.join(\n ', '\n )}. Pass them via the env parameter.`,\n });\n }\n\n const endpointName = params.name ?? `${listing.title} ${release.tagName}`;\n const minCuda = minCudaVersion(config.allowedCudaVersions);\n\n const input: Record<string, unknown> = {\n name: endpointName,\n hubReleaseId: release.id,\n type: 'QB',\n gpuIds,\n gpuCount: params.gpuCount ?? config.gpuCount ?? 1,\n workersMin: params.workersMin ?? 0,\n workersMax: params.workersMax ?? null,\n idleTimeout: params.idleTimeout ?? 5,\n scalerType: params.scalerType ?? 'QUEUE_DELAY',\n scalerValue: params.scalerValue ?? 4,\n executionTimeoutMs: params.executionTimeoutMs ?? 600000,\n flashBootType: params.flashboot ?? 'FLASHBOOT',\n locations: null,\n networkVolumeIds: null,\n compliance: [],\n modelReferences: [],\n ...(minCuda\n ? {\n minCudaVersion: minCuda,\n allowedCudaVersions: config.allowedCudaVersions!.join(','),\n }\n : {}),\n template: {\n name: `${endpointName}__template__${randomSuffix()}`,\n imageName: release.build.imageName,\n containerDiskInGb:\n params.containerDiskInGb ?? config.containerDiskInGb ?? 20,\n containerRegistryAuthId: '',\n dockerArgs: '',\n startScript: '',\n ports: '',\n env,\n },\n };\n\n interface SaveEndpointResponse {\n saveEndpoint: {\n id: string;\n name: string;\n gpuIds: string;\n gpuCount: number;\n workersMin: number;\n workersMax: number | null;\n idleTimeout: number;\n scalerType: string;\n scalerValue: number;\n flashBootType: string;\n templateId: string;\n };\n }\n\n const data = await graphqlAuthed<SaveEndpointResponse>(\n `\n mutation saveEndpoint($input: EndpointInput!) {\n saveEndpoint(input: $input) {\n id\n name\n gpuIds\n gpuCount\n workersMin\n workersMax\n idleTimeout\n scalerType\n scalerValue\n flashBootType\n templateId\n }\n }\n `,\n { input }\n );\n\n return jsonReply({\n endpoint: data.saveEndpoint,\n deployed: {\n repo: `${listing.repoOwner}/${listing.repoName}`,\n release: release.tagName,\n hubReleaseId: release.id,\n imageName: release.build.imageName,\n },\n note: `Endpoint created. Submit jobs with run-endpoint/runsync-endpoint using endpointId \"${data.saveEndpoint.id}\".`,\n });\n }\n );\n}\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\nimport { capListResult, listPaginationParams } from '../pagination.js';\nimport { READ_ONLY, type ToolRuntime } from './runtime.js';\n\n// ============== PUBLIC ENDPOINT TOOLS ==============\n// Read-only discovery of Runpod Public Endpoints — the managed, pay-per-use\n// model APIs (e.g. Kimi, Hailuo, Veo) that need no deployment. Served by the\n// public GraphQL endpoint (allAiApiPublicConfigs) — no auth required — like\n// the Hub catalog, and version-agnostic (no REST home yet).\n//\n// A public endpoint is invoked like any Serverless endpoint using its\n// `endpointId` (the aiApiId), so results here feed directly into\n// run-endpoint / runsync-endpoint.\n\ninterface PublicEndpointConfig {\n id: string;\n aiApiId: string;\n modelName: string;\n displayName: string;\n description: string | null;\n metadata: string | null;\n isLive: boolean;\n createdAt: string;\n updatedAt: string;\n}\n\ninterface PublicEndpointsResponse {\n allAiApiPublicConfigs: PublicEndpointConfig[];\n}\n\n// `metadata` is a JSON string carrying pricing and classification (cost,\n// owner, source/modality, tag, priceString). Parsed defensively — a malformed\n// value falls back to undefined fields rather than a crash.\ninterface PublicEndpointMetadata {\n cost?: number;\n owner?: string;\n source?: string;\n tag?: string;\n priceString?: string;\n}\n\nfunction parseMetadata(\n metadata: string | null | undefined\n): PublicEndpointMetadata {\n if (!metadata) return {};\n try {\n const parsed = JSON.parse(metadata) as unknown;\n return parsed && typeof parsed === 'object'\n ? (parsed as PublicEndpointMetadata)\n : {};\n } catch {\n return {};\n }\n}\n\nexport function registerPublicEndpointTools(\n server: McpServer,\n rt: ToolRuntime\n): void {\n const { graphql } = rt;\n\n server.tool(\n 'list-public-endpoints',\n 'List Runpod Public Endpoints — managed, pay-per-use model APIs (text, image, video, audio) that require no deployment. Public catalog, no auth required. Each result includes the endpointId to call with run-endpoint/runsync-endpoint (or via https://api.runpod.ai/v2/{endpointId}), the model name, modality, owner, and pricing. Only live endpoints are returned by default; set includeOffline:true to also list ones that are not currently live.',\n {\n ...listPaginationParams,\n searchTerm: z\n .string()\n .optional()\n .describe(\n \"Case-insensitive search across display name, model name, endpoint id, description, owner, and tag (e.g. 'kimi', 'video', 'flux')\"\n ),\n modality: z\n .string()\n .optional()\n .describe(\n \"Filter by modality/category (the metadata source field, e.g. 'language', 'image', 'video', 'audio')\"\n ),\n owner: z\n .string()\n .optional()\n .describe(\n \"Filter by model owner (e.g. 'moonshot', 'minimax', 'google')\"\n ),\n includeOffline: z\n .boolean()\n .optional()\n .describe(\n 'Include endpoints that are not currently live (isLive:false). Default false — only live endpoints are listed.'\n ),\n },\n { title: 'List public endpoints', ...READ_ONLY },\n async (params) => {\n const data = await graphql<PublicEndpointsResponse>(`\n query {\n allAiApiPublicConfigs {\n id\n aiApiId\n modelName\n displayName\n description\n metadata\n isLive\n createdAt\n updatedAt\n }\n }\n `);\n\n let configs = data.allAiApiPublicConfigs.map((c) => ({\n config: c,\n meta: parseMetadata(c.metadata),\n }));\n\n if (!params.includeOffline) {\n configs = configs.filter(({ config }) => config.isLive);\n }\n if (params.modality) {\n const term = params.modality.toLowerCase();\n configs = configs.filter(\n ({ meta }) => (meta.source ?? '').toLowerCase() === term\n );\n }\n if (params.owner) {\n const term = params.owner.toLowerCase();\n configs = configs.filter(\n ({ meta }) => (meta.owner ?? '').toLowerCase() === term\n );\n }\n if (params.searchTerm) {\n const term = params.searchTerm.toLowerCase();\n configs = configs.filter(({ config, meta }) =>\n [\n config.displayName,\n config.modelName,\n config.aiApiId,\n config.description,\n meta.owner,\n meta.tag,\n meta.source,\n ].some((field) => (field ?? '').toLowerCase().includes(term))\n );\n }\n\n // Stable, scannable order for the catalog.\n configs = [...configs].sort((a, b) =>\n a.config.displayName.localeCompare(b.config.displayName)\n );\n\n const result = configs.map(({ config, meta }) => ({\n endpointId: config.aiApiId,\n displayName: config.displayName,\n modelName: config.modelName,\n description: config.description,\n modality: meta.source,\n tag: meta.tag,\n owner: meta.owner,\n pricing: meta.priceString,\n isLive: config.isLive,\n baseUrl: `https://api.runpod.ai/v2/${config.aiApiId}`,\n createdAt: config.createdAt,\n updatedAt: config.updatedAt,\n }));\n\n return capListResult(result, {\n limit: params.limit,\n cursor: params.cursor,\n });\n }\n );\n}\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\nimport { WRITE, type ToolRuntime } from './runtime.js';\n\n// ============== ENDPOINT GPU PINNING ==============\n// Sets which GPUs a Serverless endpoint's workers run on, including pinning\n// specific GPU SKUs — a capability the REST API cannot express (its\n// gpuPoolIds field has no SKU exclusion concept). The GraphQL `gpuIds` string\n// is \"POOL[,POOL...][,-<GPU type id>...]\": pool names allow every SKU in the\n// pool, and '-'-prefixed GPU type ids (from list-gpu-types) exclude SKUs, so\n// a pool minus all-but-one SKU pins that SKU exactly.\n//\n// saveEndpoint is NOT a sparse update. Measured live with an\n// id+name+gpuIds-only update: workersMax 7→3, idleTimeout 42→10, scalerValue\n// 9→4 all reset to server defaults. Everything else held — including templateId,\n// the CUDA fields, compliance and modelReferences. So the reset set is narrower\n// than \"every omitted field\", but it is undocumented server behavior and could\n// widen, so this tool reads the endpoint and echoes every field back with only\n// gpuIds (and gpuCount) changed.\n//\n// Read shapes are not write shapes: networkVolumeIds reads as `NetworkVolumeIds`\n// (networkVolumeId + dataCenterId) but writes as `NetworkVolumeIdsInput`\n// (networkVolumeId ONLY), so echoing it verbatim gives `Field \"dataCenterId\" is\n// not defined by type \"NetworkVolumeIdsInput\"` and breaks every volume-bearing\n// endpoint.\n\ninterface EndpointSnapshot {\n id: string;\n name: string;\n gpuIds: string;\n gpuCount: number;\n workersMin: number;\n workersMax: number;\n idleTimeout: number;\n scalerType: string;\n scalerValue: number;\n executionTimeoutMs: number;\n flashBootType: string;\n type: string;\n locations: string | null;\n templateId: string | null;\n // A comma-separated String on read AND write, not a list.\n allowedCudaVersions: string | null;\n minCudaVersion: string | null;\n // A [Compliance] ENUM on input, not [String] — the server rejects 'gdpr' and\n // suggests 'GDPR'. Read values are already enum names: pass back verbatim.\n compliance: string[] | null;\n modelReferences: string[] | null;\n networkVolumeIds: Array<{\n networkVolumeId: string;\n dataCenterId: string | null;\n }> | null;\n}\n\ninterface MyEndpointsResponse {\n myself: { endpoints: EndpointSnapshot[] };\n}\n\nexport function registerEndpointGpuTools(\n server: McpServer,\n rt: ToolRuntime\n): void {\n const { graphqlAuthed, jsonReply } = rt;\n\n server.tool(\n 'set-endpoint-gpus',\n \"Set which GPUs a Serverless endpoint's workers run on — including pinning specific GPU SKUs, which create-endpoint/update-endpoint cannot express. Provide either a raw gpuIds string, or pools plus optional excludeGpuTypeIds (GPU type ids from list-gpu-types) and the exclusion string is built for you: a pool allows every SKU in it, and excluding all but one SKU pins that SKU exactly (e.g. pools:['AMPERE_16'], excludeGpuTypeIds:['NVIDIA RTX 2000 Ada Generation','NVIDIA RTX 4000 Ada Generation','NVIDIA RTX A4500'] pins RTX A4000). All other endpoint settings (workers, scaling, timeouts, template) are read first and preserved. Works on any Serverless endpoint via the authenticated GraphQL API.\",\n {\n endpointId: z\n .string()\n .describe('ID of the Serverless endpoint to update'),\n gpuIds: z\n .string()\n .optional()\n .describe(\n \"Raw gpuIds string, e.g. 'ADA_24' or 'AMPERE_16,-NVIDIA RTX A4500'. Takes precedence over pools/excludeGpuTypeIds.\"\n ),\n pools: z\n .array(z.string())\n .optional()\n .describe(\n \"GPU pool names workers may use (e.g. ['ADA_80_PRO','AMPERE_80']). The pool field from list-gpu-types.\"\n ),\n excludeGpuTypeIds: z\n .array(z.string())\n .optional()\n .describe(\n \"GPU type ids to exclude from the allowed pools (e.g. ['NVIDIA H100 NVL']). Use with pools to pin specific SKUs.\"\n ),\n gpuCount: z\n .number()\n .int()\n .positive()\n .optional()\n .describe('GPUs per worker. Omit to keep the current value.'),\n minCudaVersion: z\n .string()\n .optional()\n .describe(\n \"Minimum host CUDA version workers may run on (e.g. '12.4'). Omit to keep the current value.\"\n ),\n allowedCudaVersions: z\n .string()\n .optional()\n .describe(\n \"Comma-separated allowed host CUDA versions (e.g. '12.8,12.7,12.6'). Omit to keep the current value. CUDA compatibility is part of GPU selection — a narrow list can leave an endpoint unable to schedule workers.\"\n ),\n },\n { title: 'Set endpoint GPUs', ...WRITE, idempotentHint: true },\n async (params) => {\n const gpuIds =\n params.gpuIds ??\n (params.pools && params.pools.length > 0\n ? [\n ...params.pools,\n ...(params.excludeGpuTypeIds ?? []).map((id) => `-${id}`),\n ].join(',')\n : undefined);\n if (!gpuIds) {\n return jsonReply({\n error:\n 'Provide gpuIds (raw string) or pools (with optional excludeGpuTypeIds). See list-gpu-types for pool names and GPU type ids.',\n });\n }\n\n // Read the endpoint's current settings — saveEndpoint resets omitted\n // endpoint-level fields to defaults, so everything must be echoed back.\n const data = await graphqlAuthed<MyEndpointsResponse>(`\n query {\n myself {\n endpoints {\n id\n name\n gpuIds\n gpuCount\n workersMin\n workersMax\n idleTimeout\n scalerType\n scalerValue\n executionTimeoutMs\n flashBootType\n type\n locations\n templateId\n allowedCudaVersions\n minCudaVersion\n compliance\n modelReferences\n networkVolumeIds {\n networkVolumeId\n dataCenterId\n }\n }\n }\n }\n `);\n const current = data.myself.endpoints.find(\n (e) => e.id === params.endpointId\n );\n if (!current) {\n return jsonReply({\n error: `No Serverless endpoint found with id \"${params.endpointId}\". Use list-endpoints to see your endpoints.`,\n });\n }\n\n const input: Record<string, unknown> = {\n id: current.id,\n name: current.name,\n gpuIds,\n gpuCount: params.gpuCount ?? current.gpuCount,\n workersMin: current.workersMin,\n workersMax: current.workersMax,\n idleTimeout: current.idleTimeout,\n scalerType: current.scalerType,\n scalerValue: current.scalerValue,\n executionTimeoutMs: current.executionTimeoutMs,\n flashBootType: current.flashBootType,\n type: current.type,\n locations: current.locations,\n networkVolumeIds:\n current.networkVolumeIds && current.networkVolumeIds.length > 0\n ? // Drop dataCenterId: NetworkVolumeIdsInput takes networkVolumeId\n // ONLY, and the read shape is rejected outright.\n current.networkVolumeIds.map((v) => ({\n networkVolumeId: v.networkVolumeId,\n }))\n : null,\n };\n\n // Echoed only when set. Omitting a field that currently reads null resets\n // it to a default that is already null, while an explicit null risks a\n // server-side type rejection for no gain.\n for (const [key, value] of Object.entries({\n templateId: current.templateId,\n allowedCudaVersions:\n params.allowedCudaVersions ?? current.allowedCudaVersions,\n minCudaVersion: params.minCudaVersion ?? current.minCudaVersion,\n compliance: current.compliance,\n modelReferences: current.modelReferences,\n })) {\n if (value !== null && value !== undefined) input[key] = value;\n }\n\n interface SaveEndpointResponse {\n saveEndpoint: {\n id: string;\n name: string;\n gpuIds: string;\n gpuCount: number;\n workersMin: number;\n workersMax: number;\n };\n }\n\n const result = await graphqlAuthed<SaveEndpointResponse>(\n `\n mutation saveEndpoint($input: EndpointInput!) {\n saveEndpoint(input: $input) {\n id\n name\n gpuIds\n gpuCount\n workersMin\n workersMax\n }\n }\n `,\n { input }\n );\n\n return jsonReply({\n endpoint: result.saveEndpoint,\n previousGpuIds: current.gpuIds,\n });\n }\n );\n}\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\nimport { capListResult, listPaginationParams } from '../pagination.js';\nimport { HttpError } from '../_shared/http.js';\nimport { restV1Base, restV2Base } from '../_shared/backend.js';\nimport { podBodyFromTemplate } from '../_shared/mappers.js';\nimport { READ_ONLY, WRITE, DESTRUCTIVE, type ToolRuntime } from './runtime.js';\nimport { logStreamParams, streamLogsReply } from './logs.js';\n\n// ============== POD MANAGEMENT TOOLS ==============\n\nexport function registerPodTools(server: McpServer, rt: ToolRuntime): void {\n const { jsonReply, callRestUrl, backendFor, podAction, env } = rt;\n\n // List Pods\n server.tool(\n 'list-pods',\n 'List your pods (running and stopped) with optional filters — compute type, GPU type, data center, name — plus machine/network-volume expansion. Paginated via limit/cursor.',\n {\n ...listPaginationParams,\n computeType: z\n .enum(['GPU', 'CPU'])\n .optional()\n .describe('Filter to only GPU or only CPU Pods'),\n gpuTypeId: z\n .array(z.string())\n .optional()\n .describe('Filter to Pods with any of the listed GPU types'),\n dataCenterId: z\n .array(z.string())\n .optional()\n .describe('Filter to Pods in any of the provided data centers'),\n name: z\n .string()\n .optional()\n .describe('Filter to Pods with the provided name'),\n includeMachine: z\n .boolean()\n .optional()\n .describe('Include information about the machine'),\n includeNetworkVolume: z\n .boolean()\n .optional()\n .describe('Include information about attached network volumes'),\n },\n { title: 'List pods', ...READ_ONLY },\n async (params) => {\n const backend = backendFor('pods');\n\n // v1 supports query-param filters; v2 has none (the spec declares no query\n // params and ignores them), so we only build the query string under v1.\n let queryString = '';\n if (backend.version === 'v1') {\n const queryParams = new URLSearchParams();\n if (params.computeType)\n queryParams.append('computeType', params.computeType);\n if (params.gpuTypeId)\n params.gpuTypeId.forEach((type) =>\n queryParams.append('gpuTypeId', type)\n );\n if (params.dataCenterId)\n params.dataCenterId.forEach((dc) =>\n queryParams.append('dataCenterId', dc)\n );\n if (params.name) queryParams.append('name', params.name);\n if (params.includeMachine)\n queryParams.append(\n 'includeMachine',\n params.includeMachine.toString()\n );\n if (params.includeNetworkVolume)\n queryParams.append(\n 'includeNetworkVolume',\n params.includeNetworkVolume.toString()\n );\n queryString = queryParams.toString()\n ? `?${queryParams.toString()}`\n : '';\n }\n\n const result = await callRestUrl(\n `${backend.base}${backend.list}${queryString}`\n );\n\n return capListResult(backend.unwrap(result), {\n limit: params.limit,\n cursor: params.cursor,\n });\n }\n );\n\n // Get Pod Details\n server.tool(\n 'get-pod',\n 'Get full details for one pod by id, optionally expanding machine and attached network-volume info.',\n {\n podId: z.string().describe('ID of the pod to retrieve'),\n includeMachine: z\n .boolean()\n .optional()\n .describe('Include information about the machine'),\n includeNetworkVolume: z\n .boolean()\n .optional()\n .describe('Include information about attached network volumes'),\n },\n { title: 'Get pod', ...READ_ONLY },\n async (params) => {\n const backend = backendFor('pods');\n\n // v1-only expansion query params (v2 has no query params on get).\n let queryString = '';\n if (backend.version === 'v1') {\n const queryParams = new URLSearchParams();\n if (params.includeMachine)\n queryParams.append(\n 'includeMachine',\n params.includeMachine.toString()\n );\n if (params.includeNetworkVolume)\n queryParams.append(\n 'includeNetworkVolume',\n params.includeNetworkVolume.toString()\n );\n queryString = queryParams.toString()\n ? `?${queryParams.toString()}`\n : '';\n }\n\n const result = await callRestUrl(\n `${backend.base}${backend.get!(params.podId)}${queryString}`\n );\n return jsonReply(result);\n }\n );\n\n // Create Pod\n server.tool(\n 'create-pod',\n 'Create a new GPU/CPU pod on Runpod. Pass gpuTypeIds for a GPU pod, or computeType:\"CPU\" for a CPU pod (CPU pods are served by the v1 API for now). Pass either imageName or templateId (templateId deploys from an existing template — its name, image, start command, ports, env, disk, volume, and registry credential are used as defaults, and any field you also pass explicitly replaces the template value for that field, e.g. passing env replaces the whole env set rather than merging; pass containerRegistryAuthId to override or supply a private-image credential, or an empty string to deploy with none). If the user specifies neither an image nor a template, recommend the \"Runpod Pytorch 2.8.0\" image (runpod/pytorch:1.0.2-cu1281-torch280-ubuntu2404) as the default — it has the most up-to-date CUDA and PyTorch versions.',\n {\n name: z.string().optional().describe('Name for the pod'),\n imageName: z\n .string()\n .optional()\n .describe('Docker image to use. Optional when templateId is provided.'),\n templateId: z\n .string()\n .optional()\n .describe(\n 'Deploy from an existing template (see list-templates / get-template). The template supplies name, image, start command, ports, env, disk, volume, and registry credential as defaults; any field you also pass replaces the template value for that field (whole-field, not a merge). Override the registry credential with containerRegistryAuthId. Requires the v2 REST API. Still pass gpuTypeIds or computeType to choose the compute — a template does not pin the pod compute.'\n ),\n computeType: z\n .enum(['GPU', 'CPU'])\n .optional()\n .describe(\n \"Pod type. On v2, required when not passing gpuTypeIds. 'CPU' is served by the v1 API for now (v2 has no CPU pods yet).\"\n ),\n cloudType: z\n .enum(['SECURE', 'COMMUNITY'])\n .optional()\n .describe('SECURE or COMMUNITY cloud'),\n gpuTypeIds: z\n .array(z.string())\n .optional()\n .describe('List of acceptable GPU types'),\n gpuCount: z.number().optional().describe('Number of GPUs'),\n containerDiskInGb: z\n .number()\n .optional()\n .describe('Container disk size in GB'),\n volumeInGb: z.number().optional().describe('Volume size in GB'),\n volumeMountPath: z\n .string()\n .optional()\n .describe('Path to mount the volume'),\n ports: z\n .array(z.string())\n .optional()\n .describe(\"Ports to expose (e.g., '8888/http', '22/tcp')\"),\n env: z.record(z.string()).optional().describe('Environment variables'),\n containerRegistryAuthId: z\n .string()\n .optional()\n .describe(\n 'Container registry credential ID for pulling a private image (see list-container-registry-auths). When deploying from a templateId, this overrides the credential the template carries; pass an empty string to deploy with NO credential (clears a template’s inherited registry).'\n ),\n dataCenterIds: z\n .array(z.string())\n .optional()\n .describe('List of data centers'),\n },\n { title: 'Create pod', ...WRITE },\n async (params) => {\n const backend = backendFor('pods');\n\n // Template deploy is v2-only: v2 CreatePodRequest has no templateId, so we\n // fetch the template and spread its container config into the body below.\n // Only v2 templates are ContainerConfig-shaped.\n if (params.templateId && backend.version !== 'v2') {\n return jsonReply({\n error:\n 'Deploying a pod from a templateId is only supported on the v2 REST API. Set RUNPOD_REST_VERSION=v2, or pass imageName instead.',\n status: 501,\n });\n }\n // Image comes from either imageName or the template; require one of them.\n if (!params.imageName && !params.templateId) {\n return jsonReply({\n error:\n 'Provide imageName, or templateId to deploy from an existing template.',\n status: 400,\n });\n }\n\n // Pod type is decided by STATED intent, never inferred from the absence of\n // GPU fields (absence used to silently downgrade a misspecified GPU request\n // into a CPU pod). On v2 we require an explicit, non-contradictory choice;\n // v1 keeps its passthrough behavior (it validates the body itself).\n const hasGpuTypes = (params.gpuTypeIds?.length ?? 0) > 0;\n const hasGpuCount = (params.gpuCount ?? 0) > 0;\n const wantsCpu = params.computeType === 'CPU';\n const wantsGpu =\n hasGpuTypes || hasGpuCount || params.computeType === 'GPU';\n\n if (backend.version === 'v2') {\n if (wantsGpu && wantsCpu) {\n return jsonReply({\n error:\n \"Specify a GPU pod (gpuTypeIds or computeType:'GPU') OR a CPU pod (computeType:'CPU'), not both.\",\n status: 400,\n });\n }\n if (!wantsGpu && !wantsCpu) {\n return jsonReply({\n error:\n \"No pod type specified. Pass gpuTypeIds (see list-gpu-types) for a GPU pod, or computeType:'CPU' for a CPU pod.\",\n status: 400,\n });\n }\n if (wantsGpu && !hasGpuTypes) {\n return jsonReply({\n error:\n 'A GPU pod needs gpuTypeIds (see list-gpu-types); gpuCount or computeType alone is under-specified.',\n status: 400,\n });\n }\n // v2 has no CPU pods yet (AE-2991): serve a CPU pod from v1 (which supports\n // them) instead of failing, and tell the caller which API answered.\n if (wantsCpu) {\n // CPU pods route to v1, but the template fetch/merge below is v2-only;\n // rather than silently ignore the template, tell the caller.\n if (params.templateId) {\n return jsonReply({\n error:\n 'Template-based deploy is currently supported only for GPU pods on the v2 API. Create the CPU pod with an explicit imageName instead.',\n status: 400,\n });\n }\n // v1 is a passthrough (mapCreate is identity there), so the raw tool\n // params are the correct v1 body — `computeType` is a valid v1 field.\n // Wrap the call so a v1 error surfaces as a clean message, not a raw\n // throw (matching the GPU/v2 path's error handling below).\n try {\n const result = (await callRestUrl(\n `${restV1Base(env)}/pods`,\n 'POST',\n params as Record<string, unknown>\n )) as Record<string, unknown>;\n return jsonReply({\n ...result,\n _servedBy: 'v1',\n _note:\n 'CPU pod: created on the v1 API, because the v2 REST API does not support CPU pods yet.',\n });\n } catch (error) {\n if (error instanceof HttpError) {\n return jsonReply({\n error: error.message,\n status: error.status,\n _servedBy: 'v1',\n _note: 'CPU pod create was routed to the v1 API and failed.',\n });\n }\n throw error;\n }\n }\n }\n\n let body = backend.mapCreate(params) as Record<string, unknown>;\n\n // Template-based deploy (guaranteed v2 here). Fetch the template and use its\n // container config as the base; the mapped pod params spread ON TOP so an\n // explicitly-passed field (image, ports, disk, …) still wins.\n if (params.templateId) {\n // Fetch the template from v2 EXPLICITLY (not via backendFor('templates'),\n // whose independent version resolution could return a v1 shape under a\n // split override like RUNPOD_REST_VERSION_TEMPLATES=v1 → merged body with\n // `imageName` not `image` → 422). Template deploy is v2-only, so pin v2.\n let template: Record<string, unknown>;\n try {\n template = (await callRestUrl(\n `${restV2Base(env)}/templates/${params.templateId}`\n )) as Record<string, unknown>;\n } catch (error) {\n if (error instanceof HttpError) {\n return jsonReply({\n error: `Failed to load template ${params.templateId}: ${error.message}`,\n status: error.status,\n });\n }\n throw error;\n }\n // Template config as defaults; caller-passed fields spread on top and win\n // (including registry, overridable via containerRegistryAuthId).\n body = { ...podBodyFromTemplate(template), ...body };\n }\n\n try {\n const result = (await callRestUrl(\n `${backend.base}${backend.list}`,\n 'POST',\n body\n )) as Record<string, unknown>;\n // v2 accepts a single GPU type (`gpu.id`); v1's gpuTypeIds is \"any of\n // these\". If the caller offered several, only the first was sent — say\n // so in the reply so the narrowing isn't silent.\n if (backend.version === 'v2' && (params.gpuTypeIds?.length ?? 0) > 1) {\n return jsonReply({\n ...result,\n _warning: `v2 accepts one GPU type per pod; used \"${params.gpuTypeIds![0]}\" and ignored ${\n params.gpuTypeIds!.length - 1\n } other(s): ${params.gpuTypeIds!.slice(1).join(', ')}.`,\n });\n }\n return jsonReply(result);\n } catch (error) {\n if (error instanceof HttpError) {\n // Surface any API rejection (4xx/429/5xx/501) as a clean {error, status}\n // carrying the API's own message, instead of throwing a raw stack.\n //\n // Do NOT special-case 501 as \"CPU not supported\" here: CPU pods route to\n // v1 above and never reach this v2 POST, so a 501 here is a GPU request\n // hitting an unimplemented path — that CPU guidance lives on the CPU branch.\n return jsonReply({ error: error.message, status: error.status });\n }\n throw error;\n }\n }\n );\n\n // Update Pod\n server.tool(\n 'update-pod',\n \"Update a pod's mutable fields (name, image, container disk, volume, ports, env). Only the fields you provide change.\",\n {\n podId: z.string().describe('ID of the pod to update'),\n name: z.string().optional().describe('New name for the pod'),\n imageName: z.string().optional().describe('New Docker image'),\n containerDiskInGb: z\n .number()\n .optional()\n .describe('New container disk size in GB'),\n volumeInGb: z.number().optional().describe('New volume size in GB'),\n volumeMountPath: z\n .string()\n .optional()\n .describe('New path to mount the volume'),\n ports: z.array(z.string()).optional().describe('New ports to expose'),\n env: z\n .record(z.string())\n .optional()\n .describe('New environment variables'),\n },\n { title: 'Update pod', ...WRITE, idempotentHint: true },\n async (params) => {\n const { podId, ...updateParams } = params;\n const backend = backendFor('pods');\n const body = backend.mapUpdate(updateParams) as Record<string, unknown>;\n const result = await callRestUrl(\n `${backend.base}${backend.get!(podId)}`,\n 'PATCH',\n body\n );\n return jsonReply(result);\n }\n );\n\n // Start Pod — v1: POST /pods/{id}/start ; v2: POST /pods/{id}/action {action:'start'}\n server.tool(\n 'start-pod',\n 'Start a stopped pod (resumes the same pod and its billing).',\n {\n podId: z.string().describe('ID of the pod to start'),\n },\n { title: 'Start pod', ...WRITE, idempotentHint: true },\n async (params) => {\n const result = await podAction(params.podId, 'start');\n return jsonReply(result);\n }\n );\n\n // Stop Pod — v1: POST /pods/{id}/stop ; v2: POST /pods/{id}/action {action:'stop'}\n server.tool(\n 'stop-pod',\n 'Stop a running pod. The pod and its disk persist; GPU billing stops.',\n {\n podId: z.string().describe('ID of the pod to stop'),\n },\n { title: 'Stop pod', ...WRITE, idempotentHint: true },\n async (params) => {\n const result = await podAction(params.podId, 'stop');\n return jsonReply(result);\n }\n );\n\n // Restart Pod — v2-only state transition (PodAction enum). The v1 REST API has\n // no restart endpoint, so under v1 we return a clean message instead of firing\n // a request that would 404 (mirrors the create-pod 501 handling).\n server.tool(\n 'restart-pod',\n 'Restart a running pod (single PodAction call). v2-only — on the v1 API returns a 501 notice (stop then start the pod instead).',\n {\n podId: z.string().describe('ID of the pod to restart'),\n },\n { title: 'Restart pod', ...WRITE },\n async (params) => {\n const backend = backendFor('pods');\n if (backend.version === 'v1') {\n return jsonReply({\n error:\n 'restart-pod is only available on the v2 REST API. Set RUNPOD_REST_VERSION=v2 (or stop then start the pod on v1).',\n status: 501,\n });\n }\n const result = await podAction(params.podId, 'restart');\n return jsonReply(result);\n }\n );\n\n // Stream Pod Logs (v2-only — GET /v2/pods/{id}/logs, Server-Sent Events).\n // Stream Pod Logs (v2-only — GET /v2/pods/{id}/logs). See streamLogsReply.\n server.tool(\n 'stream-pod-logs',\n \"Fetch a bounded snapshot of a pod's live logs (container and/or system) via Server-Sent Events. v2-only — returns a 501 notice on the v1 API. Reads for up to maxWaitMs (default 5s) and returns the collected log lines; use `tail` to backfill recent lines first. Large output is truncated (see the `truncated` flag).\",\n {\n podId: z.string().describe('ID of the pod whose logs to stream'),\n ...logStreamParams,\n },\n { title: 'Stream pod logs', ...READ_ONLY },\n (params) =>\n streamLogsReply(\n rt,\n {\n name: 'stream-pod-logs',\n resource: 'pods',\n logsUrl: (backend) =>\n `${backend.base}${backend.get!(encodeURIComponent(params.podId))}/logs`,\n },\n params\n )\n );\n\n // Delete Pod\n server.tool(\n 'delete-pod',\n 'Permanently delete a pod and its data. This cannot be undone.',\n {\n podId: z.string().describe('ID of the pod to delete'),\n },\n { title: 'Delete pod', ...DESTRUCTIVE },\n async (params) => {\n const backend = backendFor('pods');\n const result = await callRestUrl(\n `${backend.base}${backend.get!(params.podId)}`,\n 'DELETE'\n );\n return jsonReply(result);\n }\n );\n}\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\nimport { capListResult, listPaginationParams } from '../pagination.js';\nimport { READ_ONLY, WRITE, DESTRUCTIVE, type ToolRuntime } from './runtime.js';\nimport { logStreamParams, streamLogsReply } from './logs.js';\n\n// ============== ENDPOINT MANAGEMENT TOOLS ==============\n// Serverless endpoint CRUD, version-aware via the backend adapter.\n// v2 (default): endpoints live at /v2/serverless with an INLINE config —\n// image + gpu.pools + workers + scaling (NO templateId).\n// v1: the legacy /endpoints model — templateId-based.\n// list/get/delete route through the adapter on both versions; create/update\n// branch on backend.version because the request model differs fundamentally.\n\n// Autoscaling bounds, mirroring the v2 spec so a bad value is a clean client-side\n// error instead of a server 422. `scalerValue` feeds two different union variants\n// with different bounds — QUEUE_DELAY takes a float >= 0.5, REQUEST_COUNT an\n// integer >= 1 — so the schema can only enforce the looser floor. The\n// REQUEST_COUNT half is checked per-call by scalerValueError() below, which needs\n// the resolved scaler type.\nconst MIN_QUEUE_DELAY = 0.5;\nconst MIN_REQUEST_COUNT = 1;\nconst MIN_IDLE_TIMEOUT = 1;\nconst MAX_IDLE_TIMEOUT = 3600;\n\n// Returns a message when scalerValue is illegal for the scaler it will be sent as,\n// or undefined when it is fine (including when either input is absent — the\n// mapper's defaults are always in range).\nfunction scalerValueError(\n scalerType: 'QUEUE_DELAY' | 'REQUEST_COUNT' | undefined,\n scalerValue: number | undefined\n): string | undefined {\n if (scalerType !== 'REQUEST_COUNT' || scalerValue === undefined) return;\n if (!Number.isInteger(scalerValue) || scalerValue < MIN_REQUEST_COUNT) {\n return `REQUEST_COUNT scales on whole in-flight requests per worker, so scalerValue must be an integer >= ${MIN_REQUEST_COUNT} (got ${scalerValue}). For a fractional target use scalerType QUEUE_DELAY, which takes seconds >= ${MIN_QUEUE_DELAY}.`;\n }\n return;\n}\n\nexport function registerEndpointTools(\n server: McpServer,\n rt: ToolRuntime\n): void {\n const { jsonReply, callRestUrl, backendFor } = rt;\n\n // List Endpoints — v1 supports includeTemplate/includeWorkers query params;\n // v2 (GET /v2/serverless) declares none, so we only build the query under v1.\n server.tool(\n 'list-endpoints',\n 'List your Serverless endpoints, optionally expanding template and worker details (v1 only). Paginated via limit/cursor. On v2 each endpoint carries its request routing in `type` and the URLs to call it in `requestUrls`.',\n {\n ...listPaginationParams,\n includeTemplate: z\n .boolean()\n .optional()\n .describe('Include template information (v1 only)'),\n includeWorkers: z\n .boolean()\n .optional()\n .describe('Include information about workers (v1 only)'),\n },\n { title: 'List endpoints', ...READ_ONLY },\n async (params) => {\n const backend = backendFor('endpoints');\n\n let queryString = '';\n if (backend.version === 'v1') {\n const queryParams = new URLSearchParams();\n if (params.includeTemplate)\n queryParams.append(\n 'includeTemplate',\n params.includeTemplate.toString()\n );\n if (params.includeWorkers)\n queryParams.append(\n 'includeWorkers',\n params.includeWorkers.toString()\n );\n queryString = queryParams.toString()\n ? `?${queryParams.toString()}`\n : '';\n }\n\n const result = await callRestUrl(\n `${backend.base}${backend.list}${queryString}`\n );\n\n return capListResult(backend.unwrap(result), {\n limit: params.limit,\n cursor: params.cursor,\n });\n }\n );\n\n // Get Endpoint Details\n server.tool(\n 'get-endpoint',\n 'Get one Serverless endpoint by id, optionally expanding template and worker details (v1 only). On v2 the reply carries `type` (queue-based vs load-balancing routing) and `requestUrls` — the run/runsync/status/... URLs for a queue endpoint, or the base + health URLs for a load-balancing one. Read those rather than constructing endpoint URLs by hand.',\n {\n endpointId: z.string().describe('ID of the endpoint to retrieve'),\n includeTemplate: z\n .boolean()\n .optional()\n .describe('Include template information (v1 only)'),\n includeWorkers: z\n .boolean()\n .optional()\n .describe('Include information about workers (v1 only)'),\n },\n { title: 'Get endpoint', ...READ_ONLY },\n async (params) => {\n const backend = backendFor('endpoints');\n\n let queryString = '';\n if (backend.version === 'v1') {\n const queryParams = new URLSearchParams();\n if (params.includeTemplate)\n queryParams.append(\n 'includeTemplate',\n params.includeTemplate.toString()\n );\n if (params.includeWorkers)\n queryParams.append(\n 'includeWorkers',\n params.includeWorkers.toString()\n );\n queryString = queryParams.toString()\n ? `?${queryParams.toString()}`\n : '';\n }\n\n const result = await callRestUrl(\n `${backend.base}${backend.get!(params.endpointId)}${queryString}`\n );\n\n return jsonReply(result);\n }\n );\n\n // Create Endpoint — model differs by version:\n // v2: inline config. Requires imageName + gpuPoolIds (gpu.pools minItems 1).\n // v1: templateId-based.\n server.tool(\n 'create-endpoint',\n 'Create a Serverless endpoint. On v2 (default), pass an inline config: imageName + gpuPoolIds (GPU pool names from list-gpu-types — the `pool` field, e.g. AMPERE_80/ADA_24) plus optional workers/scaling/disk/env. On v1, pass a templateId instead. Worker min/max set autoscaling bounds (min 0 = scale to zero). Use endpointType to pick queue-based (default) or load-balancing request routing; the response `requestUrls` carries the URLs to call the endpoint with.',\n {\n name: z.string().optional().describe('Name for the endpoint'),\n // --- v2 inline-config fields ---\n imageName: z\n .string()\n .optional()\n .describe('Docker image (v2). Required on v2 instead of a templateId.'),\n endpointType: z\n .enum(['QUEUE', 'LOAD_BALANCER'])\n .optional()\n .describe(\n 'How requests reach the workers (v2). QUEUE (default) = submit jobs through the managed queue (run/runsync/status/...). LOAD_BALANCER = send HTTP requests straight to worker-defined paths, and forces scalerType REQUEST_COUNT. Fixed at creation — update-endpoint cannot change it.'\n ),\n gpuPoolIds: z\n .array(z.string())\n .optional()\n .describe(\n 'GPU pool names (v2, required). The `pool` field from list-gpu-types, e.g. [\"AMPERE_80\"]. NOT GPU type ids.'\n ),\n gpuCount: z.number().optional().describe('GPUs per worker (v2)'),\n args: z.string().optional().describe('Container start command/args (v2)'),\n containerDiskInGb: z\n .number()\n .optional()\n .describe('Container disk size in GB (v2)'),\n ports: z\n .array(z.string())\n .optional()\n .describe(\"Ports to expose (v2), e.g. ['8000/http']\"),\n env: z\n .record(z.string())\n .optional()\n .describe('Environment variables (v2)'),\n containerRegistryAuthId: z\n .string()\n .optional()\n .describe('Container registry auth id for a private image (v2)'),\n networkVolumeIds: z\n .array(z.string())\n .optional()\n .describe('Network volume ids to attach (v2)'),\n executionTimeoutMs: z\n .number()\n .optional()\n .describe('Per-job execution timeout in ms (v2)'),\n flashboot: z\n .enum(['OFF', 'FLASHBOOT', 'PRIORITY_FLASHBOOT'])\n .optional()\n .describe('FlashBoot mode (v2)'),\n // --- v1 template-based fields ---\n templateId: z\n .string()\n .optional()\n .describe('Template ID (v1). Required on v1.'),\n computeType: z\n .enum(['GPU', 'CPU'])\n .optional()\n .describe('GPU or CPU endpoint (v1)'),\n gpuTypeIds: z\n .array(z.string())\n .optional()\n .describe('List of acceptable GPU types (v1)'),\n // --- shared autoscaling fields ---\n workersMin: z.number().optional().describe('Minimum number of workers'),\n workersMax: z.number().optional().describe('Maximum number of workers'),\n scalerType: z\n .enum(['QUEUE_DELAY', 'REQUEST_COUNT'])\n .optional()\n .describe(\n 'Autoscaler signal. QUEUE_DELAY scales on how long requests wait in the queue (queue endpoints only); REQUEST_COUNT scales on in-flight requests per worker. Defaults to QUEUE_DELAY for QUEUE endpoints and REQUEST_COUNT for LOAD_BALANCER ones.'\n ),\n scalerValue: z\n .number()\n .min(MIN_QUEUE_DELAY)\n .optional()\n .describe(\n 'Autoscaler target for the chosen scalerType — seconds of queue delay (min 0.5) or in-flight requests per worker (integer, min 1). Defaults to 4.'\n ),\n idleTimeout: z\n .number()\n .int()\n .min(MIN_IDLE_TIMEOUT)\n .max(MAX_IDLE_TIMEOUT)\n .optional()\n .describe(\n 'Idle timeout in seconds before scaling a worker down (1-3600). Does not apply to QUEUE endpoints scaling on REQUEST_COUNT.'\n ),\n dataCenterIds: z\n .array(z.string())\n .optional()\n .describe('List of preferred data centers'),\n },\n { title: 'Create endpoint', ...WRITE },\n async (params) => {\n const backend = backendFor('endpoints');\n\n if (backend.version === 'v2') {\n // Guard the v2-required fields before calling, so the caller gets a\n // clean 400 rather than a raw 422 from the API (mirrors create-pod).\n // v2 CreateEndpointRequest marks `name` required too — guard it so an\n // omitted name is a clean 400, not an opaque 422.\n if (!params.name) {\n return jsonReply({\n error: 'On the v2 REST API, create-endpoint requires a name.',\n status: 400,\n });\n }\n if (!params.imageName) {\n return jsonReply({\n error:\n 'On the v2 REST API, create-endpoint needs an imageName (v2 endpoints are image-based, not template-based). To use a templateId, set RUNPOD_REST_VERSION=v1.',\n status: 400,\n });\n }\n if (!params.gpuPoolIds?.length) {\n return jsonReply({\n error:\n 'create-endpoint needs gpuPoolIds on v2 (GPU pool names from list-gpu-types — the `pool` field, e.g. [\"AMPERE_80\"]).',\n status: 400,\n });\n }\n // A load balancer has no request queue, so there is no queue delay to\n // scale on. The API rejects this too, but catching it here costs a round\n // trip less and names the reason directly.\n if (\n params.endpointType === 'LOAD_BALANCER' &&\n params.scalerType === 'QUEUE_DELAY'\n ) {\n return jsonReply({\n error:\n 'LOAD_BALANCER endpoints have no request queue, so they cannot scale on QUEUE_DELAY. Use scalerType REQUEST_COUNT (the default for this endpoint type), or create a QUEUE endpoint instead.',\n status: 400,\n });\n }\n // REQUEST_COUNT is the default scaler for a load balancer, so the value\n // has to be checked against the scaler that will actually be sent, not\n // just the one the caller named.\n const scalerError = scalerValueError(\n params.scalerType ??\n (params.endpointType === 'LOAD_BALANCER'\n ? 'REQUEST_COUNT'\n : undefined),\n params.scalerValue\n );\n if (scalerError) {\n return jsonReply({ error: scalerError, status: 400 });\n }\n const body = backend.mapCreate(params) as Record<string, unknown>;\n const result = await callRestUrl(\n `${backend.base}${backend.list}`,\n 'POST',\n body\n );\n return jsonReply(result);\n }\n\n // v1: legacy /endpoints, templateId-based. Guard the v1-required field.\n if (!params.templateId) {\n return jsonReply({\n error:\n 'On the v1 REST API, create-endpoint needs a templateId. (On v2 — the default — pass imageName + gpuPoolIds instead.)',\n status: 400,\n });\n }\n // Send ONLY v1-relevant fields — the tool schema is a v1+v2 union, so\n // forwarding the raw params would also send v2-only keys (gpuPoolIds,\n // flashboot, networkVolumeIds, …) to the v1 API. Harmless today (v1 ignores\n // unknowns) but imprecise; filter explicitly.\n const v1Body: Record<string, unknown> = {};\n for (const k of [\n 'templateId',\n 'name',\n 'computeType',\n 'gpuTypeIds',\n 'gpuCount',\n 'workersMin',\n 'workersMax',\n 'dataCenterIds',\n ] as const) {\n if (params[k] !== undefined) v1Body[k] = params[k];\n }\n const result = await callRestUrl(\n `${backend.base}${backend.list}`,\n 'POST',\n v1Body\n );\n return jsonReply(result);\n }\n );\n\n // Update Endpoint — only provided fields change. v2 maps to the nested\n // /v2/serverless body; v1 passes the flat fields through.\n server.tool(\n 'update-endpoint',\n \"Update a Serverless endpoint's config. On v2 you can change image/disk/env/ports/registry/workers/scaling/networkVolumes/timeout/flashboot; on v1, scaling fields (worker min/max, idle timeout, scaler type/value, name). Only provided fields change. An endpoint's request routing (queue vs load balancer) is fixed at creation and cannot be changed here — recreate the endpoint instead.\",\n {\n endpointId: z.string().describe('ID of the endpoint to update'),\n name: z.string().optional().describe('New name for the endpoint'),\n workersMin: z\n .number()\n .optional()\n .describe('New minimum number of workers'),\n workersMax: z\n .number()\n .optional()\n .describe('New maximum number of workers'),\n idleTimeout: z\n .number()\n .int()\n .min(MIN_IDLE_TIMEOUT)\n .max(MAX_IDLE_TIMEOUT)\n .optional()\n .describe(\n 'New idle timeout in seconds (1-3600). Does not apply to queue endpoints scaling on REQUEST_COUNT.'\n ),\n scalerType: z\n .enum(['QUEUE_DELAY', 'REQUEST_COUNT'])\n .optional()\n .describe(\n 'New autoscaler signal. Switchable on queue endpoints; load-balancing endpoints only accept REQUEST_COUNT.'\n ),\n scalerValue: z\n .number()\n .min(MIN_QUEUE_DELAY)\n .optional()\n .describe(\n \"New autoscaler target — seconds of queue delay (min 0.5) or in-flight requests per worker (integer, min 1). Applies to the endpoint's current scalerType unless you also pass a new one.\"\n ),\n // --- v2-only inline-config fields ---\n imageName: z.string().optional().describe('New Docker image (v2)'),\n gpuPoolIds: z\n .array(z.string())\n .optional()\n .describe('New GPU pool names (v2), e.g. [\"AMPERE_80\"]'),\n gpuCount: z.number().optional().describe('New GPUs per worker (v2)'),\n args: z.string().optional().describe('New container args (v2)'),\n containerDiskInGb: z\n .number()\n .optional()\n .describe('New container disk size in GB (v2)'),\n ports: z.array(z.string()).optional().describe('New ports (v2)'),\n env: z\n .record(z.string())\n .optional()\n .describe('New environment variables (v2)'),\n containerRegistryAuthId: z\n .string()\n .optional()\n .describe('New container registry auth id (v2)'),\n networkVolumeIds: z\n .array(z.string())\n .optional()\n .describe('New network volume ids (v2)'),\n executionTimeoutMs: z\n .number()\n .optional()\n .describe('New per-job execution timeout in ms (v2)'),\n flashboot: z\n .enum(['OFF', 'FLASHBOOT', 'PRIORITY_FLASHBOOT'])\n .optional()\n .describe('New FlashBoot mode (v2)'),\n },\n { title: 'Update endpoint', ...WRITE, idempotentHint: true },\n async (params) => {\n const { endpointId, ...updateParams } = params;\n const backend = backendFor('endpoints');\n const url = `${backend.base}${backend.get!(endpointId)}`;\n\n if (backend.version !== 'v2') {\n const body = backend.mapUpdate(updateParams) as Record<string, unknown>;\n return jsonReply(await callRestUrl(url, 'PATCH', body));\n }\n\n // `scaling` is a union keyed on the scaler type, so a bare \"change the target\n // to N\" has no expressible form without knowing which scaler is in effect.\n // Rather than reject the call, read the endpoint's current scaler and keep\n // it — which is what such a request has always meant.\n let scalerType = updateParams.scalerType;\n if (scalerType === undefined && updateParams.scalerValue !== undefined) {\n const current = (await callRestUrl(url)) as\n | { scaling?: { type?: string } }\n | undefined;\n scalerType =\n current?.scaling?.type === 'REQUEST_COUNT'\n ? 'REQUEST_COUNT'\n : 'QUEUE_DELAY';\n }\n\n // Checked against the resolved scaler, so `scalerValue` alone on an endpoint\n // already scaling on REQUEST_COUNT is still held to the integer bound.\n const scalerError = scalerValueError(\n scalerType,\n updateParams.scalerValue\n );\n if (scalerError) {\n return jsonReply({ error: scalerError, status: 400 });\n }\n\n const body = backend.mapUpdate({\n ...updateParams,\n scalerType,\n }) as Record<string, unknown>;\n return jsonReply(await callRestUrl(url, 'PATCH', body));\n }\n );\n\n // Delete Endpoint\n server.tool(\n 'delete-endpoint',\n 'Permanently delete a Serverless endpoint. This cannot be undone.',\n {\n endpointId: z.string().describe('ID of the endpoint to delete'),\n },\n { title: 'Delete endpoint', ...DESTRUCTIVE },\n async (params) => {\n const backend = backendFor('endpoints');\n const result = await callRestUrl(\n `${backend.base}${backend.get!(params.endpointId)}`,\n 'DELETE'\n );\n return jsonReply(result);\n }\n );\n\n // List Endpoint Releases — GET /v2/serverless/{id}/releases. v2-only; v1 has no\n // equivalent, hence the 501 notice.\n server.tool(\n 'list-endpoint-releases',\n \"List a Serverless endpoint's release history and current rollout status (workers on the latest version). v2-only — returns a 501 notice on the v1 API. Paginated via limit/cursor.\",\n {\n ...listPaginationParams,\n endpointId: z\n .string()\n .describe('ID of the Serverless endpoint whose releases to list'),\n },\n { title: 'List endpoint releases', ...READ_ONLY },\n async (params) => {\n const backend = backendFor('endpoints');\n if (backend.version === 'v1') {\n return jsonReply({\n error:\n 'list-endpoint-releases is only available on the v2 REST API. Set RUNPOD_REST_VERSION=v2.',\n status: 501,\n });\n }\n const raw = (await callRestUrl(\n `${backend.base}/serverless/${params.endpointId}/releases`\n )) as Record<string, unknown> | undefined;\n const releases = Array.isArray(raw?.releases) ? raw!.releases : [];\n return capListResult(\n releases,\n { limit: params.limit, cursor: params.cursor },\n { rollout: raw?.rollout, endpointVersion: raw?.endpointVersion }\n );\n }\n );\n\n // List Endpoint Workers (v2-only — GET /v2/serverless/{id}/workers)\n // Returns the workers backing an endpoint plus an aggregate summary. v2-only:\n // returns a 501 notice on the v1 API. The workers array is capped via\n // limit/cursor; the `summary` and `endpointVersion` are preserved alongside.\n server.tool(\n 'list-endpoint-workers',\n 'List the workers backing a Serverless endpoint, with their status and an aggregate summary. v2-only — returns a 501 notice on the v1 API. An UNHEALTHY worker usually means the container is crash-looping (repeated starts that exit before the handler runs) — jobs on the endpoint will sit IN_QUEUE even though this is a worker failure, not a capacity shortage; inspect it with stream-worker-logs. Zero workers while jobs queue means the endpoint is waiting for GPU capacity. Paginated via limit/cursor.',\n {\n ...listPaginationParams,\n endpointId: z\n .string()\n .describe('ID of the Serverless endpoint whose workers to list'),\n },\n { title: 'List endpoint workers', ...READ_ONLY },\n async (params) => {\n const backend = backendFor('workers');\n if (backend.version === 'v1') {\n return jsonReply({\n error:\n 'list-endpoint-workers is only available on the v2 REST API. Set RUNPOD_REST_VERSION=v2 (on v1, use get-endpoint with includeWorkers).',\n status: 501,\n });\n }\n const raw = (await callRestUrl(\n `${backend.base}/serverless/${params.endpointId}/workers`\n )) as Record<string, unknown> | undefined;\n return capListResult(\n backend.unwrap(raw),\n { limit: params.limit, cursor: params.cursor },\n { summary: raw?.summary, endpointVersion: raw?.endpointVersion }\n );\n }\n );\n\n // Stream Worker Logs (v2-only — GET /v2/serverless/{id}/workers/{workerId}/logs).\n // Same feature as stream-pod-logs; see streamLogsReply.\n server.tool(\n 'stream-worker-logs',\n \"Fetch a bounded snapshot of a serverless worker's live logs (container and/or system) via Server-Sent Events. v2-only — returns a 501 notice on the v1 API. Get the workerId from list-endpoint-workers. Use this to diagnose UNHEALTHY workers: repeated `start container` system lines with no container output is the crash-loop signature (the container exits before the handler runs). Reads for up to maxWaitMs (default 5s) and returns the collected log lines; use `tail` to backfill recent lines first. Large output is truncated (see the `truncated` flag).\",\n {\n endpointId: z\n .string()\n .describe('ID of the Serverless endpoint the worker belongs to'),\n workerId: z\n .string()\n .describe(\n 'ID of the worker whose logs to stream (from list-endpoint-workers)'\n ),\n ...logStreamParams,\n },\n { title: 'Stream worker logs', ...READ_ONLY },\n (params) =>\n streamLogsReply(\n rt,\n {\n name: 'stream-worker-logs',\n resource: 'workers',\n logsUrl: (backend) =>\n `${backend.base}/serverless/${encodeURIComponent(params.endpointId)}/workers/${encodeURIComponent(params.workerId)}/logs`,\n },\n params\n )\n );\n}\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\nimport { READ_ONLY, WRITE, type ToolRuntime } from './runtime.js';\n\n// ============== SERVERLESS RUNTIME TOOLS ==============\n// Job submission and lifecycle against the Serverless runtime API\n// (api.runpod.ai/v2/{endpointId}/...). Distinct from endpoint CRUD.\n\n// Agents poll get-job-status in a tight loop while a job is queued, and each\n// IN_QUEUE poll would otherwise refetch the same worker list — dozens of\n// identical diagnoses for one queued job. Worker state changes on the order of\n// tens of seconds (scheduling, container starts), so a short-lived cache keyed\n// by endpoint keeps the amplification at one extra call per endpoint per TTL.\n// Module-level so it survives across per-request tool registries on a warm\n// hosted instance; bounded so one-off endpoint ids cannot grow it unbounded.\nconst DIAGNOSIS_TTL_MS = 15_000;\nconst MAX_DIAGNOSIS_ENTRIES = 500;\ninterface CachedDiagnosis {\n value: { workerHealth: unknown; hint: string };\n expiresAt: number;\n}\nconst diagnosisCache = new Map<string, CachedDiagnosis>();\n// Test seam: module-level state would otherwise leak between test cases.\nexport function clearQueuedJobDiagnosisCache(): void {\n diagnosisCache.clear();\n}\n\nexport function registerJobTools(server: McpServer, rt: ToolRuntime): void {\n const { jsonReply, serverlessRequest, backendFor, callRestUrl } = rt;\n\n // A job stuck IN_QUEUE has two very different causes that its status alone\n // cannot distinguish: no host has the endpoint's GPU available (capacity),\n // or a worker DID spin up and is crash-looping — the platform marks it\n // UNHEALTHY while the job stays queued forever. Field experience shows\n // agents (and humans) read the endless IN_QUEUE as \"no capacity\" and stop\n // digging. So when get-job-status sees IN_QUEUE, it best-effort attaches the\n // endpoint's worker summary and a plain-language hint pointing at the next\n // diagnostic step. v2-only (the workers listing has no v1 REST home);\n // never fails the status call itself.\n interface WorkerSummary {\n idle?: number;\n initializing?: number;\n running?: number;\n throttled?: number;\n total?: number;\n unhealthy?: number;\n }\n\n async function diagnoseQueuedJob(\n endpointId: string\n ): Promise<{ workerHealth: WorkerSummary; hint: string } | null> {\n const cached = diagnosisCache.get(endpointId);\n if (cached && cached.expiresAt > Date.now()) {\n return cached.value as { workerHealth: WorkerSummary; hint: string };\n }\n diagnosisCache.delete(endpointId);\n try {\n const backend = backendFor('workers');\n if (backend.version !== 'v2') return null;\n const raw = (await callRestUrl(\n `${backend.base}/serverless/${endpointId}/workers`\n )) as\n | {\n summary?: WorkerSummary;\n workers?: Array<{ id: string; status?: string }>;\n }\n | undefined;\n const summary = raw?.summary;\n const workers = raw?.workers ?? [];\n if (!summary) return null;\n\n const remember = (value: {\n workerHealth: WorkerSummary;\n hint: string;\n }) => {\n if (diagnosisCache.size >= MAX_DIAGNOSIS_ENTRIES) {\n const oldest = diagnosisCache.keys().next().value;\n if (oldest !== undefined) diagnosisCache.delete(oldest);\n }\n diagnosisCache.set(endpointId, {\n value,\n expiresAt: Date.now() + DIAGNOSIS_TTL_MS,\n });\n return value;\n };\n\n if ((summary.unhealthy ?? 0) > 0) {\n const badIds = workers\n .filter((w) => w.status === 'UNHEALTHY')\n .map((w) => w.id)\n .join(', ');\n return remember({\n workerHealth: summary,\n hint: `${summary.unhealthy} of ${summary.total} worker(s) on this endpoint are UNHEALTHY — the container is likely crash-looping (repeated starts that exit before the handler runs). The job can stay IN_QUEUE indefinitely; this is a worker failure, NOT a capacity shortage. Inspect the logs with stream-worker-logs${\n badIds ? ` (workerId: ${badIds})` : ''\n }.`,\n });\n }\n if ((summary.total ?? 0) === 0) {\n return remember({\n workerHealth: summary,\n hint: 'No workers are scheduled for this endpoint yet — it may simply be scaling up from zero (normal for the first seconds of a cold start), or it is waiting for GPU capacity / its GPU-CUDA constraints exclude the currently-available hosts. If this persists, check availability with list-gpu-types or widen the gpuIds/CUDA settings.',\n });\n }\n if ((summary.throttled ?? 0) > 0 && (summary.running ?? 0) === 0) {\n return remember({\n workerHealth: summary,\n hint: 'Workers exist but are throttled — the hosts are at capacity right now; the job should start when capacity frees up.',\n });\n }\n if ((summary.initializing ?? 0) > 0) {\n return remember({\n workerHealth: summary,\n hint: 'A worker is initializing — likely a cold start (image pull / model load); the job should start soon.',\n });\n }\n return remember({ workerHealth: summary, hint: '' });\n } catch {\n return null; // diagnosis is best-effort — never break the status call\n }\n }\n\n // Shared schemas for serverless tools\n const endpointIdSchema = z\n .string()\n .regex(/^[a-zA-Z0-9_-]+$/, 'Invalid endpoint ID format');\n\n const jobIdSchema = z\n .string()\n .regex(/^[a-zA-Z0-9_-]+$/, 'Invalid job ID format');\n\n const inputSchema = z\n .record(z.unknown())\n .describe(\n 'Input payload for the worker handler. The expected fields depend on the deployed model or worker.'\n );\n\n const webhookSchema = z\n .string()\n .url()\n .optional()\n .describe(\n 'Webhook URL to receive job completion notifications instead of polling'\n );\n\n const policySchema = z\n .object({\n executionTimeout: z\n .number()\n .optional()\n .describe('Maximum execution time in milliseconds'),\n lowPriority: z\n .boolean()\n .optional()\n .describe('Submit as a low-priority job'),\n ttl: z\n .number()\n .optional()\n .describe('Time-to-live for the job result in milliseconds'),\n })\n .optional()\n .describe('Execution policy options');\n\n const s3ConfigSchema = z\n .object({\n accessId: z.string().describe('S3 access key ID'),\n accessSecret: z.string().describe('S3 secret access key'),\n bucketName: z.string().describe('S3 bucket name'),\n endpointUrl: z.string().describe('S3 endpoint URL'),\n })\n .optional()\n .describe('S3-compatible storage config for large outputs');\n\n // Run Endpoint (Async)\n server.tool(\n 'run-endpoint',\n 'Submit an asynchronous job to a Serverless endpoint. Returns a job ID immediately — use get-job-status to poll for results. Async results are available for 30 minutes after completion.',\n {\n endpointId: endpointIdSchema.describe(\n 'ID of the Serverless endpoint to run'\n ),\n input: inputSchema,\n webhook: webhookSchema,\n policy: policySchema,\n s3Config: s3ConfigSchema,\n },\n { title: 'Run endpoint (async)', ...WRITE },\n async (params) => {\n const { endpointId, ...body } = params;\n const result = await serverlessRequest(\n endpointId,\n '/run',\n 'POST',\n body as Record<string, unknown>\n );\n\n return jsonReply(result);\n }\n );\n\n // Run Endpoint Sync\n server.tool(\n 'runsync-endpoint',\n 'Submit a synchronous job to a Serverless endpoint and wait for the result. Best for tasks completing within 90 seconds. If processing exceeds 90 seconds, the response returns a job ID to poll with get-job-status. Max payload: 20 MB. Results expire after 1 minute. Use the wait parameter to extend the server-side wait up to 5 minutes (300000 ms).',\n {\n endpointId: endpointIdSchema.describe(\n 'ID of the Serverless endpoint to run synchronously'\n ),\n input: inputSchema,\n wait: z\n .number()\n .min(1000)\n .max(300000)\n .optional()\n .describe(\n 'How long in milliseconds the server should wait for a result before returning a job ID to poll (1000–300000). Defaults to 90000 (90 seconds).'\n ),\n webhook: webhookSchema,\n policy: policySchema,\n s3Config: s3ConfigSchema,\n },\n { title: 'Run endpoint (sync)', ...WRITE },\n async (params) => {\n const { endpointId, wait, ...body } = params;\n const path = wait ? `/runsync?wait=${wait}` : '/runsync';\n const result = await serverlessRequest(\n endpointId,\n path,\n 'POST',\n body as Record<string, unknown>\n );\n\n return jsonReply(result);\n }\n );\n\n // Get Job Status\n server.tool(\n 'get-job-status',\n 'Check the status of an asynchronous Serverless job. Returns the current status and output when complete. Job statuses: IN_QUEUE, IN_PROGRESS, COMPLETED, FAILED, CANCELLED, TIMED_OUT. IMPORTANT: a job stuck IN_QUEUE does not necessarily mean a capacity shortage — a worker may have spun up and crash-looped (the platform marks it UNHEALTHY while the job stays queued). When the job is IN_QUEUE this tool attaches a workerHealth summary and a hint; to dig deeper, call list-endpoint-workers (look for UNHEALTHY) and stream-worker-logs.',\n {\n endpointId: endpointIdSchema.describe(\n 'ID of the Serverless endpoint the job belongs to'\n ),\n jobId: jobIdSchema.describe('ID of the job to check'),\n },\n { title: 'Get job status', ...READ_ONLY },\n async (params) => {\n const result = await serverlessRequest(\n params.endpointId,\n `/status/${params.jobId}`\n );\n\n if (\n result &&\n typeof result === 'object' &&\n (result as { status?: string }).status === 'IN_QUEUE'\n ) {\n const diagnosis = await diagnoseQueuedJob(params.endpointId);\n if (diagnosis) {\n return jsonReply({\n ...(result as Record<string, unknown>),\n workerHealth: diagnosis.workerHealth,\n ...(diagnosis.hint ? { hint: diagnosis.hint } : {}),\n });\n }\n }\n\n return jsonReply(result);\n }\n );\n\n // Stream Job Results\n server.tool(\n 'stream-job',\n 'Retrieve all streaming output from a Serverless job by polling until the job reaches a terminal state. The worker must support streaming output. Polls /stream/{jobId} repeatedly and collects every chunk until status is COMPLETED, FAILED, CANCELLED, or TIMED_OUT.',\n {\n endpointId: endpointIdSchema.describe(\n 'ID of the Serverless endpoint the job belongs to'\n ),\n jobId: jobIdSchema.describe('ID of the job to stream results from'),\n },\n { title: 'Stream job', ...READ_ONLY },\n async (params) => {\n const TERMINAL_STATUSES = new Set([\n 'COMPLETED',\n 'FAILED',\n 'CANCELLED',\n 'TIMED_OUT',\n ]);\n const MAX_POLL_TIME_MS = 5 * 60 * 1000; // 5 minutes\n const POLL_INTERVAL_MS = 1000;\n const MAX_CONSECUTIVE_ERRORS = 5;\n const allChunks: unknown[] = [];\n let finalResult: Record<string, unknown> = {};\n let consecutiveErrors = 0;\n let lastError: string | undefined;\n const startTime = Date.now();\n\n while (true) {\n try {\n const result = (await serverlessRequest(\n params.endpointId,\n `/stream/${params.jobId}`\n )) as Record<string, unknown>;\n\n consecutiveErrors = 0;\n\n if (Array.isArray(result.stream)) {\n allChunks.push(...result.stream);\n }\n\n finalResult = result;\n\n if (TERMINAL_STATUSES.has(result.status as string)) {\n break;\n }\n } catch (error) {\n consecutiveErrors++;\n lastError = error instanceof Error ? error.message : String(error);\n if (consecutiveErrors >= MAX_CONSECUTIVE_ERRORS) {\n finalResult.error = `Polling aborted after ${MAX_CONSECUTIVE_ERRORS} consecutive errors: ${lastError}`;\n break;\n }\n }\n\n if (Date.now() - startTime > MAX_POLL_TIME_MS) {\n finalResult.pollingTimedOut = true;\n finalResult.note =\n 'Polling timed out after 5 minutes. Use get-job-status to check the job later.';\n // Surface the most recent error (if any) instead of discarding it —\n // the last poll may have been failing (e.g. job expired) even though\n // earlier polls succeeded.\n if (lastError) finalResult.lastError = lastError;\n break;\n }\n\n await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));\n }\n\n return jsonReply({ ...finalResult, stream: allChunks });\n }\n );\n\n // Cancel Job\n server.tool(\n 'cancel-job',\n 'Cancel a Serverless job that is queued or in progress.',\n {\n endpointId: endpointIdSchema.describe(\n 'ID of the Serverless endpoint the job belongs to'\n ),\n jobId: jobIdSchema.describe('ID of the job to cancel'),\n },\n { title: 'Cancel job', ...WRITE, idempotentHint: true },\n async (params) => {\n const result = await serverlessRequest(\n params.endpointId,\n `/cancel/${params.jobId}`,\n 'POST'\n );\n\n return jsonReply(result);\n }\n );\n\n // Retry Job\n server.tool(\n 'retry-job',\n 'Retry a failed or timed-out Serverless job. Only works for jobs with FAILED or TIMED_OUT status. The previous output is removed and the job is requeued.',\n {\n endpointId: endpointIdSchema.describe(\n 'ID of the Serverless endpoint the job belongs to'\n ),\n jobId: jobIdSchema.describe('ID of the job to retry'),\n },\n { title: 'Retry job', ...WRITE },\n async (params) => {\n const result = await serverlessRequest(\n params.endpointId,\n `/retry/${params.jobId}`,\n 'POST'\n );\n\n return jsonReply(result);\n }\n );\n\n // Endpoint Health\n server.tool(\n 'endpoint-health',\n 'Get the health and operational status of a Serverless endpoint, including worker counts and job statistics. Use this when jobs are stuck IN_QUEUE: unhealthy workers mean a crash-looping container (a worker failure — inspect with stream-worker-logs), while zero workers means the endpoint is waiting for GPU capacity.',\n {\n endpointId: endpointIdSchema.describe(\n 'ID of the Serverless endpoint to check health for'\n ),\n },\n { title: 'Endpoint health', ...READ_ONLY },\n async (params) => {\n const result = await serverlessRequest(params.endpointId, '/health');\n\n return jsonReply(result);\n }\n );\n\n // Purge Endpoint Queue\n server.tool(\n 'purge-endpoint-queue',\n 'Remove all pending jobs from a Serverless endpoint queue. Only affects queued jobs — in-progress jobs continue running. Use this for error recovery or clearing outdated requests.',\n {\n endpointId: endpointIdSchema.describe(\n 'ID of the Serverless endpoint to purge the queue for'\n ),\n },\n { title: 'Purge endpoint queue', ...WRITE, idempotentHint: true },\n async (params) => {\n const result = await serverlessRequest(\n params.endpointId,\n '/purge-queue',\n 'POST'\n );\n\n return jsonReply(result);\n }\n );\n}\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\nimport { capListResult, listPaginationParams } from '../pagination.js';\nimport { READ_ONLY, WRITE, DESTRUCTIVE, type ToolRuntime } from './runtime.js';\n\n// ============== TEMPLATE MANAGEMENT TOOLS ==============\n\nexport function registerTemplateTools(\n server: McpServer,\n rt: ToolRuntime\n): void {\n const { jsonReply, callRestUrl, backendFor } = rt;\n\n // List Templates\n server.tool(\n 'list-templates',\n 'List available templates. By default returns only the user\\'s own templates. Use includeRunpodTemplates to also include official Runpod templates. The recommended default template for new pods is \"Runpod Pytorch 2.8.0\" (ID: runpod-torch-v280) — it has the latest CUDA and PyTorch versions.',\n {\n ...listPaginationParams,\n includeRunpodTemplates: z\n .boolean()\n .optional()\n .describe('Include official Runpod templates in the response'),\n includePublicTemplates: z\n .boolean()\n .optional()\n .describe('Include community-made public templates in the response'),\n includeEndpointBoundTemplates: z\n .boolean()\n .optional()\n .describe(\n 'Include templates bound to Serverless endpoints in the response'\n ),\n },\n { title: 'List templates', ...READ_ONLY },\n async (params) => {\n const backend = backendFor('templates');\n let query = '';\n if (backend.version === 'v1') {\n const queryParams = new URLSearchParams();\n if (params.includeRunpodTemplates)\n queryParams.set('includeRunpodTemplates', 'true');\n if (params.includePublicTemplates)\n queryParams.set('includePublicTemplates', 'true');\n if (params.includeEndpointBoundTemplates)\n queryParams.set('includeEndpointBoundTemplates', 'true');\n query = queryParams.toString() ? `?${queryParams.toString()}` : '';\n }\n const result = await callRestUrl(\n `${backend.base}${backend.list}${query}`\n );\n\n return capListResult(backend.unwrap(result), {\n limit: params.limit,\n cursor: params.cursor,\n });\n }\n );\n\n // Get Template Details\n server.tool(\n 'get-template',\n 'Get one template by id (image, env, ports, disk/volume config).',\n {\n templateId: z.string().describe('ID of the template to retrieve'),\n },\n { title: 'Get template', ...READ_ONLY },\n async (params) => {\n const backend = backendFor('templates');\n const result = await callRestUrl(\n `${backend.base}${backend.get!(params.templateId)}`\n );\n return jsonReply(result);\n }\n );\n\n // Create Template\n server.tool(\n 'create-template',\n 'Create a reusable pod/endpoint template (image, ports, env, disk/volume). Category is optional and defaults to NVIDIA.',\n {\n name: z.string().describe('Name for the template'),\n imageName: z.string().describe('Docker image to use'),\n isServerless: z\n .boolean()\n .optional()\n .describe('Is this a serverless template'),\n ports: z.array(z.string()).optional().describe('Ports to expose'),\n dockerEntrypoint: z\n .array(z.string())\n .optional()\n .describe(\n 'Docker entrypoint commands. Note: not persisted on the v2 REST API, which has no separate entrypoint field (only a start command).'\n ),\n dockerStartCmd: z\n .array(z.string())\n .optional()\n .describe(\n 'Container start command. On v2 this is stored as the template\\'s `args` string; a multi-element array is joined with spaces (e.g. [\"python\",\"-u\",\"app.py\"] → \"python -u app.py\"). The join is lossy: an element that itself contains spaces is NOT preserved as one argument — e.g. [\"sh\",\"-c\",\"echo hi\"] becomes \"sh -c echo hi\", so pass a shell command as a single pre-quoted element if that distinction matters. Omit or pass an empty array to leave the command unset (never overwrites with \"\").'\n ),\n env: z.record(z.string()).optional().describe('Environment variables'),\n containerDiskInGb: z\n .number()\n .optional()\n .describe('Container disk size in GB'),\n volumeInGb: z.number().optional().describe('Volume size in GB'),\n volumeMountPath: z\n .string()\n .optional()\n .describe('Path to mount the volume'),\n readme: z\n .string()\n .optional()\n .describe('README content in markdown format'),\n category: z\n .enum(['CPU', 'NVIDIA', 'AMD'])\n .optional()\n .describe(\n 'How the template is grouped and filtered in the Runpod console — it does NOT affect hardware selection, scheduling, or billing. Optional; defaults to NVIDIA. Set CPU or AMD only to file the template correctly in the console.'\n ),\n containerRegistryAuthId: z\n .string()\n .optional()\n .describe(\n 'ID of a container registry credential (from create-container-registry-auth / list-container-registry-auths) used to pull a private image. Required when imageName points at a private registry; without it serverless workers fail the image pull.'\n ),\n },\n { title: 'Create template', ...WRITE },\n async (params) => {\n const backend = backendFor('templates');\n const body = backend.mapCreate(params) as Record<string, unknown>;\n const result = await callRestUrl(\n `${backend.base}${backend.list}`,\n 'POST',\n body\n );\n return jsonReply(result);\n }\n );\n\n // Update Template\n server.tool(\n 'update-template',\n \"Update a template's mutable fields (name, image, ports, env, start command, registry auth). Only provided fields change; omitted fields are left untouched.\",\n {\n templateId: z.string().describe('ID of the template to update'),\n name: z.string().optional().describe('New name for the template'),\n imageName: z.string().optional().describe('New Docker image'),\n dockerStartCmd: z\n .array(z.string())\n .optional()\n .describe(\n \"New container start command. On v2 stored as the template's `args` string; a multi-element array is joined with spaces (lossy — an element containing spaces is split into separate tokens). Note: this can only set a command, not clear one — an empty or absent array is ignored so the existing command is preserved.\"\n ),\n ports: z.array(z.string()).optional().describe('New ports to expose'),\n env: z\n .record(z.string())\n .optional()\n .describe('New environment variables'),\n readme: z\n .string()\n .optional()\n .describe('New README content in markdown format'),\n containerRegistryAuthId: z\n .string()\n .optional()\n .describe(\n 'ID of a container registry credential (from create-container-registry-auth / list-container-registry-auths) used to pull a private image. Set this to attach a credential to a template referencing a private registry.'\n ),\n },\n { title: 'Update template', ...WRITE, idempotentHint: true },\n async (params) => {\n const { templateId, ...updateParams } = params;\n const backend = backendFor('templates');\n const body = backend.mapUpdate(updateParams) as Record<string, unknown>;\n const result = await callRestUrl(\n `${backend.base}${backend.get!(templateId)}`,\n 'PATCH',\n body\n );\n return jsonReply(result);\n }\n );\n\n // Delete Template\n server.tool(\n 'delete-template',\n 'Permanently delete a template. This cannot be undone.',\n {\n templateId: z.string().describe('ID of the template to delete'),\n },\n { title: 'Delete template', ...DESTRUCTIVE },\n async (params) => {\n const backend = backendFor('templates');\n const result = await callRestUrl(\n `${backend.base}${backend.get!(params.templateId)}`,\n 'DELETE'\n );\n return jsonReply(result);\n }\n );\n}\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\nimport { capListResult, listPaginationParams } from '../pagination.js';\nimport { READ_ONLY, WRITE, DESTRUCTIVE, type ToolRuntime } from './runtime.js';\n\n// ============== NETWORK VOLUME MANAGEMENT TOOLS ==============\n\nexport function registerNetworkVolumeTools(\n server: McpServer,\n rt: ToolRuntime\n): void {\n const { jsonReply, callRestUrl, backendFor } = rt;\n\n // List Network Volumes\n server.tool(\n 'list-network-volumes',\n 'List your network volumes (persistent storage attachable to pods). Paginated via limit/cursor.',\n listPaginationParams,\n { title: 'List network volumes', ...READ_ONLY },\n async (params) => {\n const backend = backendFor('networkVolumes');\n const result = await callRestUrl(`${backend.base}${backend.list}`);\n\n return capListResult(backend.unwrap(result), {\n limit: params.limit,\n cursor: params.cursor,\n });\n }\n );\n\n // Get Network Volume Details\n server.tool(\n 'get-network-volume',\n 'Get one network volume by id (name, size, data center).',\n {\n networkVolumeId: z\n .string()\n .describe('ID of the network volume to retrieve'),\n },\n { title: 'Get network volume', ...READ_ONLY },\n async (params) => {\n const backend = backendFor('networkVolumes');\n const result = await callRestUrl(\n `${backend.base}${backend.get!(params.networkVolumeId)}`\n );\n return jsonReply(result);\n }\n );\n\n // Create Network Volume\n server.tool(\n 'create-network-volume',\n 'Create a persistent network volume in a data center (size 10–4096 GB) that pods can mount. Pass volumeType to pick a storage tier; omit it to get the data center default.',\n {\n name: z.string().describe('Name for the network volume'),\n // Bounds mirror the v2 spec (integer, minimum 10, maximum 4096). Enforced\n // here as well as described, so an out-of-range value fails locally\n // instead of costing an API roundtrip.\n size: z.number().int().min(10).max(4096).describe('Size in GB (10-4096)'),\n dataCenterId: z\n .string()\n .describe('Data center ID (see list-data-centers)'),\n volumeType: z\n .enum(['STANDARD', 'HIGH_PERFORMANCE'])\n .optional()\n .describe(\n \"Storage tier. Omit for the data center's default (primary) tier. HIGH_PERFORMANCE provisions an HPS volume. Immutable after creation — update-network-volume cannot change it.\"\n ),\n },\n { title: 'Create network volume', ...WRITE },\n async (params) => {\n const backend = backendFor('networkVolumes');\n const body = backend.mapCreate(params) as Record<string, unknown>;\n const result = await callRestUrl(\n `${backend.base}${backend.list}`,\n 'POST',\n body\n );\n return jsonReply(result);\n }\n );\n\n // Update Network Volume\n server.tool(\n 'update-network-volume',\n 'Update a network volume (rename, or grow size — the new size must exceed the current size). Only provided fields change.',\n {\n networkVolumeId: z\n .string()\n .describe('ID of the network volume to update'),\n name: z.string().optional().describe('New name for the network volume'),\n // Same absolute bounds as create. \"Larger than current\" stays server-side —\n // we do not hold the current size here, so only the range is checked.\n size: z\n .number()\n .int()\n .min(10)\n .max(4096)\n .optional()\n .describe('New size in GB, 10-4096 (must be larger than current)'),\n },\n { title: 'Update network volume', ...WRITE, idempotentHint: true },\n async (params) => {\n const { networkVolumeId, ...updateParams } = params;\n const backend = backendFor('networkVolumes');\n const body = backend.mapUpdate(updateParams) as Record<string, unknown>;\n const result = await callRestUrl(\n `${backend.base}${backend.get!(networkVolumeId)}`,\n 'PATCH',\n body\n );\n return jsonReply(result);\n }\n );\n\n // Delete Network Volume\n server.tool(\n 'delete-network-volume',\n 'Permanently delete a network volume and its data. This cannot be undone.',\n {\n networkVolumeId: z\n .string()\n .describe('ID of the network volume to delete'),\n },\n { title: 'Delete network volume', ...DESTRUCTIVE },\n async (params) => {\n const backend = backendFor('networkVolumes');\n const result = await callRestUrl(\n `${backend.base}${backend.get!(params.networkVolumeId)}`,\n 'DELETE'\n );\n return jsonReply(result);\n }\n );\n}\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\nimport { capListResult, listPaginationParams } from '../pagination.js';\nimport { READ_ONLY, WRITE, DESTRUCTIVE, type ToolRuntime } from './runtime.js';\n\n// ============== CONTAINER REGISTRY TOOLS ==============\n// Two related things live here, both under the v2 `registries` resource:\n//\n// 1. Container registry auths (`/v2/registries`) — a stored username +\n// password used to pull a private image. Available on v1 and v2.\n// 2. ECR delegations (`/v2/registries/delegations`) — a different mechanism\n// for the same goal, specific to AWS ECR: instead of storing credentials,\n// you register an ECR repository ARN and Runpod is granted scoped pull\n// access to it, handing back a `dockerRegistryUri` to pull from. v2-only.\n//\n// The delegation sub-paths are built from the registries backend's own base +\n// list path, so they need no separate Resource entry in the adapter.\n\nconst DELEGATIONS = '/delegations';\n\nexport function registerRegistryTools(\n server: McpServer,\n rt: ToolRuntime\n): void {\n const { jsonReply, callRestUrl, backendFor } = rt;\n\n // ECR delegation is a v2-only concept — v1 has no equivalent endpoint, so the\n // tools return a clean 501 notice there rather than calling a v1 path that\n // does not exist (mirrors list-endpoint-workers / stream-pod-logs).\n const delegationsV2OnlyNotice = (tool: string) => ({\n error: `${tool} is only available on the v2 REST API. Set RUNPOD_REST_VERSION=v2.`,\n status: 501,\n });\n\n // List Container Registry Auths\n server.tool(\n 'list-container-registry-auths',\n 'List your saved container-registry credentials (private image-pull auth). Paginated via limit/cursor.',\n listPaginationParams,\n { title: 'List container registry auths', ...READ_ONLY },\n async (params) => {\n const backend = backendFor('registries');\n const result = await callRestUrl(`${backend.base}${backend.list}`);\n\n return capListResult(backend.unwrap(result), {\n limit: params.limit,\n cursor: params.cursor,\n });\n }\n );\n\n // Get Container Registry Auth Details\n server.tool(\n 'get-container-registry-auth',\n 'Get one saved container-registry credential by id (the secret/password is not returned).',\n {\n containerRegistryAuthId: z\n .string()\n .describe('ID of the container registry auth to retrieve'),\n },\n { title: 'Get container registry auth', ...READ_ONLY },\n async (params) => {\n const backend = backendFor('registries');\n const result = await callRestUrl(\n `${backend.base}${backend.get!(params.containerRegistryAuthId)}`\n );\n return jsonReply(result);\n }\n );\n\n // Create Container Registry Auth\n server.tool(\n 'create-container-registry-auth',\n 'Save container-registry credentials (username + password/token) so pods and endpoints can pull private images.',\n {\n name: z.string().describe('Name for the container registry auth'),\n username: z.string().describe('Registry username'),\n password: z\n .string()\n .describe('Registry password or access token (stored as a secret)'),\n },\n { title: 'Create container registry auth', ...WRITE },\n async (params) => {\n const backend = backendFor('registries');\n const body = backend.mapCreate(params) as Record<string, unknown>;\n const result = await callRestUrl(\n `${backend.base}${backend.list}`,\n 'POST',\n body\n );\n return jsonReply(result);\n }\n );\n\n // Delete Container Registry Auth\n server.tool(\n 'delete-container-registry-auth',\n 'Permanently delete a saved container-registry credential. This cannot be undone.',\n {\n containerRegistryAuthId: z\n .string()\n .describe('ID of the container registry auth to delete'),\n },\n { title: 'Delete container registry auth', ...DESTRUCTIVE },\n async (params) => {\n const backend = backendFor('registries');\n const result = await callRestUrl(\n `${backend.base}${backend.get!(params.containerRegistryAuthId)}`,\n 'DELETE'\n );\n return jsonReply(result);\n }\n );\n\n // ============== ECR DELEGATION TOOLS (v2-only) ==============\n\n // List ECR Delegations\n server.tool(\n 'list-registry-delegations',\n 'List your AWS ECR delegations — ECR repositories Runpod has been granted scoped pull access to, so private ECR images can be pulled without storing AWS credentials. Each entry includes the `dockerRegistryUri` to pull from. v2-only — returns a 501 notice on the v1 API. Paginated via limit/cursor.',\n listPaginationParams,\n { title: 'List registry delegations', ...READ_ONLY },\n async (params) => {\n const backend = backendFor('registries');\n if (backend.version === 'v1') {\n return jsonReply(delegationsV2OnlyNotice('list-registry-delegations'));\n }\n // The response envelope is `{delegations:[…]}`, not the `{registries:[…]}`\n // that backend.unwrap expects for this resource, so read the key directly.\n const raw = (await callRestUrl(\n `${backend.base}${backend.list}${DELEGATIONS}`\n )) as Record<string, unknown> | undefined;\n const delegations = Array.isArray(raw?.delegations)\n ? raw.delegations\n : [];\n return capListResult(delegations, {\n limit: params.limit,\n cursor: params.cursor,\n });\n }\n );\n\n // Create ECR Delegation\n server.tool(\n 'create-registry-delegation',\n 'Register an AWS ECR repository so Runpod can pull private images from it without stored credentials. Pass the repository ARN; the reply carries the `dockerRegistryUri`, resolved repository/tag, and AWS region. v2-only — returns a 501 notice on the v1 API. For a non-ECR private registry use create-container-registry-auth instead.',\n {\n resource: z\n .string()\n .min(1)\n .describe(\n 'ECR resource ARN, e.g. \"arn:aws:ecr:us-east-2:123456789012:repository/my-org/my-image\"'\n ),\n name: z\n .string()\n .optional()\n .describe('Optional human-readable name for the delegation'),\n },\n { title: 'Create registry delegation', ...WRITE },\n async (params) => {\n const backend = backendFor('registries');\n if (backend.version === 'v1') {\n return jsonReply(delegationsV2OnlyNotice('create-registry-delegation'));\n }\n // CreateDelegationRequest is additionalProperties:false — send only the\n // two documented keys, and omit `name` entirely when unset rather than\n // sending null.\n const body: Record<string, unknown> = { resource: params.resource };\n if (params.name !== undefined) body.name = params.name;\n const result = await callRestUrl(\n `${backend.base}${backend.list}${DELEGATIONS}`,\n 'POST',\n body\n );\n return jsonReply(result);\n }\n );\n\n // Revoke ECR Delegation\n server.tool(\n 'delete-registry-delegation',\n \"Revoke an AWS ECR delegation, withdrawing Runpod's pull access to that repository. Existing workers keep running; future pulls fail. v2-only — returns a 501 notice on the v1 API. This cannot be undone.\",\n {\n delegationId: z\n .string()\n .describe(\n 'ID of the delegation to revoke (from list-registry-delegations)'\n ),\n },\n { title: 'Revoke registry delegation', ...DESTRUCTIVE },\n async (params) => {\n const backend = backendFor('registries');\n if (backend.version === 'v1') {\n return jsonReply(delegationsV2OnlyNotice('delete-registry-delegation'));\n }\n const result = await callRestUrl(\n `${backend.base}${backend.list}${DELEGATIONS}/${encodeURIComponent(\n params.delegationId\n )}`,\n 'DELETE'\n );\n return jsonReply(result);\n }\n );\n}\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\nimport { capListResult, listPaginationParams } from '../pagination.js';\nimport { READ_ONLY, type ToolRuntime } from './runtime.js';\n\n// ============== BILLING TOOLS (v2-only) ==============\n// Read-only, time-bucketed spend history. v2-only — returns a 501 notice on the\n// v1 API. The records array can be large (buckets × resources), so it is capped\n// via limit/cursor; the aggregate `metadata` is preserved alongside the page.\n\n// scope → URL sub-path. 'all' is the aggregate /v2/billing; the rest are\n// per-resource breakdowns. Values match the v2 spec sub-paths exactly\n// (note: 'networkvolumes' has no hyphen here, unlike the /v2/network-volumes\n// resource path).\nconst BILLING_SCOPE_PATH: Record<string, string> = {\n all: '/billing',\n pods: '/billing/pods',\n serverless: '/billing/serverless',\n endpoints: '/billing/endpoints',\n networkvolumes: '/billing/networkvolumes',\n clusters: '/billing/clusters',\n};\n\nexport function registerBillingTools(server: McpServer, rt: ToolRuntime): void {\n const { jsonReply, callRestUrl, backendFor } = rt;\n\n server.tool(\n 'get-billing',\n 'Get time-bucketed Runpod spend history, either aggregated across all resources or broken down by resource type (pods, serverless, endpoints, network volumes, clusters). v2-only — returns a 501 notice on the v1 API. Records are capped via limit/cursor; narrow the window with startTime/endTime or lastN.',\n {\n ...listPaginationParams,\n scope: z\n .enum([\n 'all',\n 'pods',\n 'serverless',\n 'endpoints',\n 'networkvolumes',\n 'clusters',\n ])\n .optional()\n .describe(\n 'Which billing breakdown to fetch. \"all\" (default) is the aggregate across every resource.'\n ),\n startTime: z\n .string()\n .optional()\n .describe(\n 'Start of the period (RFC 3339, e.g. 2026-05-01T00:00:00Z). Defaults to 30 days ago. Mutually exclusive with lastN.'\n ),\n endTime: z\n .string()\n .optional()\n .describe(\n 'End of the period (RFC 3339), exclusive. Defaults to now. Mutually exclusive with lastN.'\n ),\n bucketSize: z\n .enum(['hour', 'day', 'week', 'month', 'year'])\n .optional()\n .describe('Length of each time bucket. Defaults to day.'),\n lastN: z\n .number()\n .int()\n .positive()\n .optional()\n .describe(\n 'Return the last N buckets of bucketSize, ending with the current one. Mutually exclusive with startTime/endTime.'\n ),\n },\n { title: 'Get billing history', ...READ_ONLY },\n async (params) => {\n const backend = backendFor('billing');\n if (backend.version === 'v1') {\n return jsonReply({\n error:\n 'get-billing is only available on the v2 REST API. Set RUNPOD_REST_VERSION=v2.',\n status: 501,\n });\n }\n\n const subPath = BILLING_SCOPE_PATH[params.scope ?? 'all'];\n const query = new URLSearchParams();\n if (params.startTime) query.set('startTime', params.startTime);\n if (params.endTime) query.set('endTime', params.endTime);\n if (params.bucketSize) query.set('bucketSize', params.bucketSize);\n // lastN is mutually exclusive with startTime/endTime; if a window was\n // given, ignore lastN so we never forward a contradictory request.\n if (\n params.lastN !== undefined &&\n !params.startTime &&\n !params.endTime\n )\n query.set('lastN', String(params.lastN));\n const qs = query.toString() ? `?${query.toString()}` : '';\n\n const raw = (await callRestUrl(`${backend.base}${subPath}${qs}`)) as\n | Record<string, unknown>\n | undefined;\n // Cap the (potentially large) records array but keep the aggregate\n // `metadata` alongside the page so totals aren't lost to truncation.\n return capListResult(\n backend.unwrap(raw),\n { limit: params.limit, cursor: params.cursor },\n { metadata: raw?.metadata }\n );\n }\n );\n}\n","import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport {\n createToolRuntime,\n type ToolContext,\n type ToolDeps,\n} from './tools/runtime.js';\nimport { registerCatalogTools } from './tools/catalog.js';\nimport { registerHubTools } from './tools/hub.js';\nimport { registerPublicEndpointTools } from './tools/public-endpoints.js';\nimport { registerEndpointGpuTools } from './tools/endpoint-gpus.js';\nimport { registerPodTools } from './tools/pods.js';\nimport { registerEndpointTools } from './tools/endpoints.js';\nimport { registerJobTools } from './tools/jobs.js';\nimport { registerTemplateTools } from './tools/templates.js';\nimport { registerNetworkVolumeTools } from './tools/network-volumes.js';\nimport { registerRegistryTools } from './tools/registries.js';\nimport { registerBillingTools } from './tools/billing.js';\n\n// Re-export so existing importers (entrypoints, tests) keep their import path.\nexport type { ToolContext } from './tools/runtime.js';\n\n/**\n * Register all Runpod tools on the given MCP server instance.\n *\n * The tool surface is split by resource under `src/tools/<resource>.ts`; this\n * function builds the shared runtime (caller-tracking, authenticated REST/\n * Serverless/GraphQL clients, the v1/v2 backend resolver) once and threads it\n * into each per-resource registrar.\n *\n * @param ctx supplies the API key the request helpers authenticate with.\n * @param deps optional test seam (inject a fake fetch / the resolved v2-probe\n * verdict). Production passes nothing.\n */\nexport function registerTools(\n server: McpServer,\n ctx: ToolContext,\n deps: ToolDeps = {}\n): void {\n const rt = createToolRuntime(server, ctx, deps);\n\n registerCatalogTools(server, rt);\n registerHubTools(server, rt);\n registerPublicEndpointTools(server, rt);\n registerPodTools(server, rt);\n registerEndpointTools(server, rt);\n registerEndpointGpuTools(server, rt);\n registerJobTools(server, rt);\n registerTemplateTools(server, rt);\n registerNetworkVolumeTools(server, rt);\n registerRegistryTools(server, rt);\n registerBillingTools(server, rt);\n}\n"],"mappings":"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","names":["z","z","jsonReply","z","z","jsonReply","z","z","z","z","jsonReply","z","z","jsonReply","z","z","jsonReply","z","result","body","z","jsonReply","z","z","jsonReply","z","z","jsonReply","z","z","jsonReply","z","z","jsonReply","z"]}