@runpod/mcp-server 1.4.0 → 3.0.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.
- package/CHANGELOG.md +112 -2
- package/README.md +184 -54
- package/dist/chunk-GTBCNGHE.mjs +2878 -0
- package/dist/chunk-GTBCNGHE.mjs.map +1 -0
- package/dist/http.cjs +2554 -611
- package/dist/http.cjs.map +1 -1
- package/dist/http.d.cts +35 -2
- package/dist/http.d.ts +35 -2
- package/dist/http.mjs +247 -17
- package/dist/http.mjs.map +1 -1
- package/dist/stdio.cjs +2385 -600
- package/dist/stdio.cjs.map +1 -1
- package/dist/stdio.mjs +2388 -603
- package/dist/stdio.mjs.map +1 -1
- package/dist/tools.cjs +2303 -596
- package/dist/tools.cjs.map +1 -1
- package/dist/tools.d.cts +65 -3
- package/dist/tools.d.ts +65 -3
- package/dist/tools.mjs +1 -1
- package/package.json +3 -2
- package/dist/chunk-D4AEYJ2O.mjs +0 -1160
- package/dist/chunk-D4AEYJ2O.mjs.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,115 @@
|
|
|
1
1
|
# @runpod/mcp-server
|
|
2
2
|
|
|
3
|
+
## 3.0.0
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- 119f633: Resync the tool surface with the current v2 REST spec.
|
|
8
|
+
|
|
9
|
+
**Breaking:** removes the seven tag tools (`list-tags`, `get-tag`, `create-tag`, `update-tag`,
|
|
10
|
+
`delete-tag`, `attach-tag`, `detach-tag`). `/v2/tags` no longer exists — it returns
|
|
11
|
+
`404 "The requested path was not found."` on both the production and dev hosts — so the tools
|
|
12
|
+
could not succeed for any caller.
|
|
13
|
+
|
|
14
|
+
**New:** three AWS ECR delegation tools (`list-registry-delegations`,
|
|
15
|
+
`create-registry-delegation`, `delete-registry-delegation`) for `/v2/registries/delegations`.
|
|
16
|
+
Unlike `create-container-registry-auth`, this stores no credentials: you register an ECR
|
|
17
|
+
repository ARN and Runpod is granted scoped pull access. v2-only.
|
|
18
|
+
|
|
19
|
+
**New:** `create-network-volume` gains `volumeType` (`STANDARD` | `HIGH_PERFORMANCE`). The
|
|
20
|
+
field was in the spec but no tool exposed it, so high-performance volumes could not be created
|
|
21
|
+
here. Omit it for the data center default. Its documented size range is also corrected to
|
|
22
|
+
10–4096 GB (was 1–4000).
|
|
23
|
+
|
|
24
|
+
**Enabled:** `list-endpoint-releases` was implemented but left unregistered because
|
|
25
|
+
`GET /v2/serverless/{id}/releases` used to be dev-only. It now returns 200 on production.
|
|
26
|
+
|
|
27
|
+
`create-template` no longer sends `category: NVIDIA` when the caller omits it — v2 made the
|
|
28
|
+
field optional with that same server-side default, so the value is no longer invented
|
|
29
|
+
client-side. An explicit `category` still passes through.
|
|
30
|
+
|
|
31
|
+
### Minor Changes
|
|
32
|
+
|
|
33
|
+
- fbcf9b7: Add `RUNPOD_AUTHED_GRAPHQL_URL` to override the GraphQL host used by authenticated operations that have no REST equivalent (`deploy-hub-repo`, `set-endpoint-gpus`). These calls send the caller's API key as a Bearer token, so they no longer follow `RUNPOD_PUBLIC_GRAPHQL_URL` — that variable stays the credential-free discovery override, safe to point at a stub.
|
|
34
|
+
- 00e6ec2: Surface dead credentials as a proper HTTP 401 on the HTTP server so OAuth-capable MCP clients re-authenticate automatically.
|
|
35
|
+
|
|
36
|
+
Previously, when a bearer token was revoked mid-session (e.g. an OAuth-minted key), every upstream Runpod call failed with a 401 that the MCP SDK wrapped into a 200 JSON-RPC tool error — the client never saw an HTTP 401, never re-ran its auth flow, and the user was stuck with bare "Unauthorized" tool errors until they manually reconnected. The request handler now pre-flight verifies the bearer (one `myself` GraphQL query, cached ~60s valid / ~30s invalid by token hash, never the raw token) and answers `401` + `WWW-Authenticate` with the protected-resource metadata when the credential is dead. `WWW-Authenticate` is exposed via CORS so browser clients can read it, and a rejected credential carries `error="invalid_token"` to distinguish it from a request that sent none (RFC 6750 §3.1). `ToolContext` gains an optional `onUnauthorized` callback, invoked when an outbound call returns 401, which drops the cached verdict so the next request re-checks.
|
|
37
|
+
|
|
38
|
+
The check is deliberately conservative so it can never reject a working key:
|
|
39
|
+
- It fails **open** on anything indeterminate — auth-backend errors, 5xx, 403 (this host sits behind a WAF, and a block is not a revocation), a slow backend (time-bound), and a GraphQL response carrying an `errors` array (a resolver blip returns `myself: null` for everyone at once; treating that as invalid would 401 every valid key). Failing closed on any of these would make OAuth clients re-run the flow, minting a new API key per attempt — an unrecoverable loop.
|
|
40
|
+
- It runs only for the requests the transport would actually run a tool for: a `POST` whose `Content-Type` the SDK treats as JSON and whose body invokes a method (including inside a batch). Everything else is passed through unchecked.
|
|
41
|
+
- It self-disables (logging `skip_env_mismatch`) when the REST/Serverless hosts and the auth-GraphQL host disagree about environment in either direction, since it would otherwise validate a key against the wrong backend.
|
|
42
|
+
- Request bodies are capped at 4 MB (matching the SDK) on hosts that do not pre-parse them.
|
|
43
|
+
- The verdict cache is safe under load: eviction never disowns an in-flight check, and TTLs use a monotonic clock, so a burst of distinct tokens or a wall-clock adjustment cannot let a since-revoked key linger as `valid`.
|
|
44
|
+
|
|
45
|
+
Set `MCP_SKIP_CREDENTIAL_CHECK=true` to disable the pre-flight entirely.
|
|
46
|
+
|
|
47
|
+
Notes for consumers of the published `./http` export (not only the hosted deployment): the pre-flight adds one outbound `myself` call to the Runpod GraphQL host per checked request, and a new dependency on that host being reachable (it fails open if not). This does **not** close the pre-existing key-validity oracle — a caller who speaks MCP can still learn 401-vs-not for a token, one upstream call each, with no rate limiting; closing that needs rate limiting, which this does not add.
|
|
48
|
+
|
|
49
|
+
- f3b226b: Add a `deploy-hub-repo` tool that deploys a Runpod Hub repo's listed release as a new Serverless endpoint — the same operation as clicking Deploy on the Hub. Identify the repo by `repo` ("owner/name") or `hubReleaseId` (both from `list-hub-repos`); the release supplies the prebuilt image, container disk, CUDA constraints, and env-var defaults, with caller overrides for env vars, GPU pools, worker counts, scaling, and FlashBoot. Required env vars without a default fail fast with an actionable message before anything is created, as do POD listings and releases without a GPU pool when none is provided. Uses the authenticated GraphQL `saveEndpoint` mutation (Hub deploys have no REST home yet), so it behaves identically on v1 and v2. The tool runtime gains a `graphqlAuthed` helper (API-key Bearer + variables) to support it.
|
|
50
|
+
- 725b6cd: Surface realtime GPU availability on the v2 catalog. `list-gpu-types` now requests `?include=AVAILABILITY` by default, so each GPU carries an `availability` summary (HIGH/MEDIUM/LOW/NONE) and results are sorted highest-stock-first. The full catalog is still returned by default — nothing is hidden — so the tool stays complete for discovery and capacity/price surveys. `includeUnavailable` is now an opt-in _hide_: pass `includeUnavailable: false` to drop out-of-stock GPUs and list only currently-deployable ones. A new `includeAvailability` param (default true) can opt out of the stock lookup entirely. `get-gpu-type` returns the per-datacenter availability breakdown (and URL-encodes ids, which contain spaces) so callers can pick a `dataCenterIds` with stock before creating a pod. Falls back gracefully when the backend doesn't populate availability.
|
|
51
|
+
|
|
52
|
+
The v2 path also drops the `"unknown"` sentinel GPU (matching the v1 path) so it doesn't leak into the now-unhidden default list.
|
|
53
|
+
|
|
54
|
+
Behavior change to note: `list-gpu-types` still returns every GPU by default, but results are now sorted highest-stock-first rather than in a stable order. Nothing is hidden by default.
|
|
55
|
+
|
|
56
|
+
- 546a40f: Add a `list-hub-repos` tool for discovering the Runpod Hub catalog (prebuilt Serverless workers and Pod templates such as vLLM, ComfyUI, and Axolotl). Served by the public GraphQL endpoint — no auth required — and available on both v1 and v2. Each result includes the repo metadata (stars, deploys, category, tags) plus the currently listed release with its `hubReleaseId` and prebuilt `imageName`, the two values a Hub deploy is pinned to. Supports `searchTerm`, `category`, `type` (SERVERLESS/POD), and `repoOwner` filters (applied client-side), and an opt-in `includeConfig` that returns the release's parsed hardware/env-var config from `.runpod/hub.json`. Results are sorted most-deployed first and use the shared pagination envelope.
|
|
57
|
+
- e4fabd1: Add a `list-public-endpoints` tool for discovering Runpod Public Endpoints — the managed, pay-per-use model APIs (text, image, video, audio) that require no deployment. Served by the public GraphQL endpoint — no auth required — and available on both v1 and v2. Each result includes the `endpointId` to call with `run-endpoint`/`runsync-endpoint` (or directly at `https://api.runpod.ai/v2/{endpointId}`), plus the model name, modality, owner, and pricing parsed from the catalog metadata. Only live endpoints are listed by default (`includeOffline:true` to include the rest), with `searchTerm`, `modality`, and `owner` filters and the shared pagination envelope.
|
|
58
|
+
- cc0966c: Enable pod and serverless worker log streaming (v2). `stream-pod-logs` (GET /v2/pods/{id}/logs) is now registered — it was previously implemented but disabled while the endpoint was dev-only, and it is now live on prod. A new `stream-worker-logs` tool (GET /v2/serverless/{id}/workers/{workerId}/logs) streams a single worker's logs; get the workerId from `list-endpoint-workers`. Both read a bounded snapshot of the Server-Sent-Events stream (container and/or system) and support `source`, `tail`, `since`, and `maxWaitMs`; both return a 501 notice on the v1 API.
|
|
59
|
+
- 466a9d8: Add a `set-endpoint-gpus` tool that sets which GPUs any Serverless endpoint's workers run on — including pinning specific GPU SKUs, which the REST API cannot express (its pool-level `gpuPoolIds` has no exclusion concept). Callers pass either a raw `gpuIds` string or `pools` plus `excludeGpuTypeIds` (GPU type ids from `list-gpu-types`) and the exclusion string is built automatically; excluding all but one SKU in a pool pins that SKU exactly. Because the GraphQL `saveEndpoint` mutation resets omitted endpoint-level fields to server defaults (verified live), the tool reads the endpoint's current settings first and echoes every field back with only the GPU selection changed — workers, scaling, timeouts, FlashBoot, locations, network volumes, and the template are all preserved.
|
|
60
|
+
- d1f3719: create-pod template deploy improvements. Added a `containerRegistryAuthId` param to `create-pod` (private-image registry credential, a valid v2 ContainerConfig field). When deploying from a `templateId`, the template's registry credential is inherited as a default so a private-image template pulls correctly, `containerRegistryAuthId` overrides it, and passing an empty string opts out entirely (emits `registry: null`, which v2 accepts, clearing the template's credential). The template is fetched from v2 explicitly, so a split per-resource version override (e.g. templates pinned to v1) can't yield a v1-shaped template merged into a v2 pod body. Tool descriptions now state that template fields are applied whole-field as defaults (an explicitly-passed field replaces the template value rather than merging).
|
|
61
|
+
- 0b49b91: Fix two template gaps from the same ticket (API-385 / E-3717).
|
|
62
|
+
1. `create-template`/`update-template` were dropping the container start command on the v2 REST API. `dockerStartCmd` is now mapped to the v2 template's `args` field (a single string; a multi-element array is space-joined) instead of being discarded, so a template's startup command is persisted. `update-template` accepts `dockerStartCmd` now too. (v2 has no separate entrypoint field, so `dockerEntrypoint` is still not persisted on v2 — documented in the tool.)
|
|
63
|
+
2. `create-pod` can now deploy from a template. v2 `CreatePodRequest` has no `templateId`, so `create-pod` accepts a `templateId`, fetches the template, and spreads its container config (image, start command, ports, env, disk, volume, registry credential) into the pod body as defaults — any field you also pass explicitly overrides the template. `imageName` is now optional when `templateId` is given. Template-based deploy requires the v2 REST API and (for now) a GPU pod; clear errors are returned for v1, CPU, or when neither image nor template is supplied.
|
|
64
|
+
|
|
65
|
+
### Patch Changes
|
|
66
|
+
|
|
67
|
+
- e50409d: URL-encode the resource ids interpolated into the log-streaming request paths (`stream-pod-logs`, `stream-worker-logs`) so an id containing a URL-special character can't corrupt the request path. Opaque Runpod ids are unaffected in practice; this is defensive hardening.
|
|
68
|
+
- fb76883: Surface the configured `RUNPOD_REST_VERSION` in the MCP `serverInfo` version, e.g. `2.0.0 [RUNPOD_REST_VERSION=v2]` (or `RUNPOD_REST_VERSION unset (default v2)`). A plain `initialize` handshake now reveals whether a deployment is running v1 or v2 without inspecting the environment, and flags any per-resource overrides.
|
|
69
|
+
|
|
70
|
+
## 2.0.0
|
|
71
|
+
|
|
72
|
+
### Major Changes
|
|
73
|
+
|
|
74
|
+
- 2658e43: **Breaking:** default the REST version to **v2**, and migrate Serverless
|
|
75
|
+
endpoint CRUD to the v2 API.
|
|
76
|
+
|
|
77
|
+
With nothing set, all control-plane resources now use the v2 REST API
|
|
78
|
+
(`v2-rest.runpod.io/v2`); set `RUNPOD_REST_VERSION=v1` to pin the previous v1
|
|
79
|
+
behavior.
|
|
80
|
+
|
|
81
|
+
Why this is a major bump: `create-endpoint`/`update-endpoint` move from the v1
|
|
82
|
+
**template-based** model to the v2 **inline-config** model. On v2,
|
|
83
|
+
`create-endpoint` no longer accepts a `templateId` — it requires `imageName` +
|
|
84
|
+
`gpuPoolIds` (GPU pool names from `list-gpu-types`, e.g. `AMPERE_80`) plus
|
|
85
|
+
optional `workers`/`scaling`. So an existing integration that calls
|
|
86
|
+
`create-endpoint` with `{ templateId }` and no `RUNPOD_REST_VERSION` pin will
|
|
87
|
+
get a clean `400` after upgrading, with no code change on their side. To keep
|
|
88
|
+
the old behavior, pin `RUNPOD_REST_VERSION=v1` (templateId model preserved).
|
|
89
|
+
|
|
90
|
+
`jobs` still resolves to v1 (serverless runtime API, no v2 home). CPU pods are
|
|
91
|
+
still served by v1, and the `auto` stdio probe is unchanged. Version-sensitive
|
|
92
|
+
tests pin their version explicitly so the suite is independent of the default.
|
|
93
|
+
|
|
94
|
+
See the README "REST API version (v1 / v2)" section for the migration note.
|
|
95
|
+
|
|
96
|
+
### Minor Changes
|
|
97
|
+
|
|
98
|
+
- cdba19c: Add v2-only tools covering the rest of the v2 REST surface:
|
|
99
|
+
- **Tags** — `list-tags`, `get-tag`, `create-tag`, `update-tag`, `delete-tag`,
|
|
100
|
+
and `attach-tag` / `detach-tag` to associate a tag with a pod, network volume,
|
|
101
|
+
cluster, or serverless endpoint.
|
|
102
|
+
- **Billing** — `get-billing` returns time-bucketed spend, either aggregated or
|
|
103
|
+
broken down by resource type (`scope`), windowed by `startTime`/`endTime` or
|
|
104
|
+
`lastN`. The records array is capped via `limit`/`cursor`.
|
|
105
|
+
- **Endpoint workers** — `list-endpoint-workers` lists the workers behind a
|
|
106
|
+
serverless endpoint plus an aggregate summary (capped via `limit`/`cursor`).
|
|
107
|
+
- **Catalog by id** — `get-cpu-type` and `get-data-center` round out the catalog
|
|
108
|
+
alongside the existing `get-gpu-type`.
|
|
109
|
+
|
|
110
|
+
These resources exist only on the v2 REST API, so each returns a clean `501`
|
|
111
|
+
notice on v1 (set `RUNPOD_REST_VERSION=v2`).
|
|
112
|
+
|
|
3
113
|
## 1.4.0
|
|
4
114
|
|
|
5
115
|
### Minor Changes
|
|
@@ -22,7 +132,7 @@
|
|
|
22
132
|
|
|
23
133
|
### Minor Changes
|
|
24
134
|
|
|
25
|
-
- 3e6dedf: Add HTTP transport for hosted MCP server deployments. The package now exports three entrypoints: `@runpod/mcp-server` (stdio, unchanged), `@runpod/mcp-server/http` (streamable HTTP with per-request auth), and `@runpod/mcp-server/tools` (shared tool definitions). This enables deploying the MCP server on Vercel or any HTTP-capable host where each request carries its own
|
|
135
|
+
- 3e6dedf: Add HTTP transport for hosted MCP server deployments. The package now exports three entrypoints: `@runpod/mcp-server` (stdio, unchanged), `@runpod/mcp-server/http` (streamable HTTP with per-request auth), and `@runpod/mcp-server/tools` (shared tool definitions). This enables deploying the MCP server on Vercel or any HTTP-capable host where each request carries its own Runpod API key via the Authorization header. Existing stdio users are unaffected.
|
|
26
136
|
- 3e6dedf: Add a "Sign in with Runpod" OAuth flow to the hosted HTTP server so it can act as the authorization server for Claude's MCP connector. When `MCP_OAUTH_ENABLED=true`, the server advertises itself in the OAuth discovery metadata and exposes `GET /authorize` and `POST /token`. The flow reuses the Runpod flash auth backend: `/authorize` creates a guest `createFlashAuthRequest` and hands off to the Runpod console for approval, and `/token` polls `flashAuthRequestStatus` and returns the minted Runpod API key as the access token, which the server then forwards to the Runpod API. The backend endpoint and console base URL are configurable via `RUNPOD_GRAPHQL_URL` and `CONSOLE_BASE_URL`.
|
|
27
137
|
- 3e6dedf: Complete the hosted OAuth flow for real MCP clients. Add an OAuth 2.0 Dynamic Client Registration endpoint (`POST /register`, RFC 7591) and advertise it as `registration_endpoint`, so clients like Claude can register before signing in. Make the Runpod REST and Serverless API hosts configurable via `RUNPOD_REST_API_URL` and `RUNPOD_SERVERLESS_API_URL` so a deployment authenticating with non-production keys can target the matching environment. The console handoff path is `/integrations/mcp/login`.
|
|
28
138
|
- 3e6dedf: Validate the OAuth `redirect_uri` against an allowlist. Because the authorization code redeems into a real Runpod API key, `/authorize` and `/token` now reject any `redirect_uri` that is not an allowlisted client callback, preventing an attacker from crafting an authorize link that delivers the code (and key) to a host they control. Loopback addresses (`http://localhost` / `127.0.0.1` / `::1`, any port) are always allowed per RFC 8252; the hosted client callbacks default to Claude's, and the list is extendable via `MCP_ALLOWED_REDIRECT_URIS` (comma-separated).
|
|
@@ -59,4 +169,4 @@
|
|
|
59
169
|
|
|
60
170
|
### Minor Changes
|
|
61
171
|
|
|
62
|
-
- c49b2cc: Add npx support for running the MCP server directly without installation. Includes bin field in package.json, shebang in build output, and updated README with npx command. Also fixes branding consistency (
|
|
172
|
+
- c49b2cc: Add npx support for running the MCP server directly without installation. Includes bin field in package.json, shebang in build output, and updated README with npx command. Also fixes branding consistency (Runpod -> Runpod) and adds development conventions documentation.
|
package/README.md
CHANGED
|
@@ -2,33 +2,61 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://smithery.ai/server/@runpod/runpod-mcp-ts)
|
|
4
4
|
|
|
5
|
-
This is the official Runpod Model Context Protocol (MCP) server, published to npm as `@runpod/mcp-server`.
|
|
5
|
+
This is the official Runpod Model Context Protocol (MCP) server, published to npm as `@runpod/mcp-server`. It lets MCP clients such as Claude Code, Claude Desktop, Cursor, Windsurf, and VS Code manage your Runpod Pods, Serverless endpoints, templates, network volumes, and more.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## Quick start
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
- Hosted Streamable HTTP for Vercel or other HTTP-capable platforms. Each request carries its own `Authorization: Bearer <token>`, which the server forwards directly to the Runpod API. The token can be a Runpod API key or one obtained through the OAuth "Sign in with Runpod" flow.
|
|
9
|
+
The fastest way to get connected is the guided installer pointed at the **hosted Runpod MCP server at `https://mcp.getrunpod.io/`**. The installer detects the agents you have installed, asks which ones to configure, and writes the configuration for you:
|
|
11
10
|
|
|
12
|
-
|
|
11
|
+
```bash
|
|
12
|
+
npx @runpod/mcp-server@latest add
|
|
13
|
+
```
|
|
13
14
|
|
|
14
|
-
|
|
15
|
+
It supports **Claude Code, Claude Desktop, Cursor, Windsurf, and Visual Studio Code**, and offers two connection modes:
|
|
15
16
|
|
|
16
|
-
-
|
|
17
|
-
-
|
|
17
|
+
- **Hosted (recommended).** Points the agent at the hosted server and authenticates with the **"Sign in with Runpod"** OAuth flow, so **no API key is stored on disk**.
|
|
18
|
+
- **Local.** Runs the server through `npx` and stores a `RUNPOD_API_KEY` in the agent's config.
|
|
18
19
|
|
|
19
|
-
|
|
20
|
+
To undo the changes later, run:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npx @runpod/mcp-server@latest remove
|
|
24
|
+
```
|
|
20
25
|
|
|
21
|
-
###
|
|
26
|
+
### Connect to the hosted server manually
|
|
22
27
|
|
|
23
|
-
|
|
28
|
+
If you'd rather configure your client by hand, point it at the hosted server over HTTP (no local process, no API key stored).
|
|
29
|
+
|
|
30
|
+
**Claude Code** — add it as an HTTP server:
|
|
24
31
|
|
|
25
32
|
```bash
|
|
26
|
-
|
|
33
|
+
claude mcp add --transport http runpod -s user https://mcp.getrunpod.io/
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
**Other clients** (Cursor, VS Code, Claude Desktop connectors, …) — use a URL-based MCP entry:
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
{
|
|
40
|
+
"mcpServers": {
|
|
41
|
+
"runpod": {
|
|
42
|
+
"url": "https://mcp.getrunpod.io/"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
27
46
|
```
|
|
28
47
|
|
|
29
|
-
|
|
48
|
+
The hosted server uses the "Sign in with Runpod" OAuth flow for authentication, so no API key is stored. An OAuth-capable client starts the sign-in flow automatically on first connect. See [Sign in with Runpod (authorize flow)](#sign-in-with-runpod-authorize-flow) for details.
|
|
49
|
+
|
|
50
|
+
> Prefer your own API key instead of OAuth? Append `--header "Authorization: Bearer YOUR_API_KEY"` to the `claude mcp add` command (or add a `headers` block in the JSON), and the server forwards that key to the Runpod API directly.
|
|
30
51
|
|
|
31
|
-
###
|
|
52
|
+
### Requirements
|
|
53
|
+
|
|
54
|
+
- Node.js 18 or higher.
|
|
55
|
+
- A Runpod account and API key: https://www.runpod.io/console/user/settings
|
|
56
|
+
|
|
57
|
+
## Run locally with `npx`
|
|
58
|
+
|
|
59
|
+
To run the server as a local `stdio` process with your own API key:
|
|
32
60
|
|
|
33
61
|
```bash
|
|
34
62
|
RUNPOD_API_KEY=YOUR_API_KEY npx -y @runpod/mcp-server@latest
|
|
@@ -40,9 +68,9 @@ RUNPOD_API_KEY=YOUR_API_KEY npx -y @runpod/mcp-server@latest
|
|
|
40
68
|
npx -y @smithery/cli install @runpod/runpod-mcp-ts --client claude
|
|
41
69
|
```
|
|
42
70
|
|
|
43
|
-
## Local MCP
|
|
71
|
+
## Local MCP client setup
|
|
44
72
|
|
|
45
|
-
Local MCP clients should use the default package entrypoint, which is the `stdio` server.
|
|
73
|
+
Local MCP clients should use the default package entrypoint, which is the `stdio` server. The caller sets `RUNPOD_API_KEY` in the environment, and the server forwards it directly to the Runpod API.
|
|
46
74
|
|
|
47
75
|
### Claude Code
|
|
48
76
|
|
|
@@ -90,6 +118,8 @@ Windows:
|
|
|
90
118
|
|
|
91
119
|
Restart Claude Desktop after saving.
|
|
92
120
|
|
|
121
|
+
For remote clients such as Claude's connector, use the hosted HTTP server instead (the [Quick start](#quick-start) above). The client then runs the OAuth "Sign in with Runpod" flow, and the resulting Runpod API key is forwarded to the Runpod API on each request.
|
|
122
|
+
|
|
93
123
|
### Cursor
|
|
94
124
|
|
|
95
125
|
Add this to `.cursor/mcp.json` in your project or `~/.cursor/mcp.json` globally:
|
|
@@ -118,9 +148,42 @@ Use the same pattern:
|
|
|
118
148
|
|
|
119
149
|
For a broader list of MCP clients, see https://modelcontextprotocol.io/clients
|
|
120
150
|
|
|
151
|
+
## Usage examples
|
|
152
|
+
|
|
153
|
+
### List all Pods
|
|
154
|
+
|
|
155
|
+
```text
|
|
156
|
+
Can you list all my Runpod Pods?
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Create a new Pod
|
|
160
|
+
|
|
161
|
+
```text
|
|
162
|
+
Create a new Runpod Pod with the following specifications:
|
|
163
|
+
- Name: test-pod
|
|
164
|
+
- Image: runpod/pytorch:2.1.0-py3.10-cuda11.8.0-devel-ubuntu22.04
|
|
165
|
+
- GPU Type: NVIDIA GeForce RTX 4090
|
|
166
|
+
- GPU Count: 1
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Create a Serverless endpoint
|
|
170
|
+
|
|
171
|
+
```text
|
|
172
|
+
Create a Runpod Serverless endpoint with the following configuration:
|
|
173
|
+
- Name: my-endpoint
|
|
174
|
+
- Image: runpod/test-output:0.0.1
|
|
175
|
+
- GPU pool: AMPERE_80 (a "pool" value from list-gpu-types)
|
|
176
|
+
- Minimum workers: 0
|
|
177
|
+
- Maximum workers: 3
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
On the v2 API (the default) endpoints are image-based — pass an image and a GPU
|
|
181
|
+
pool, not a template. To use the legacy template-based model, pin
|
|
182
|
+
`RUNPOD_REST_VERSION=v1` and provide a `Template ID` instead.
|
|
183
|
+
|
|
121
184
|
## Hosted HTTP deployment
|
|
122
185
|
|
|
123
|
-
The package also exports a Streamable HTTP entrypoint at `@runpod/mcp-server/http`, and this repo includes a Vercel function in `api/index.ts`.
|
|
186
|
+
The package also exports a Streamable HTTP entrypoint at `@runpod/mcp-server/http`, and this repo includes a Vercel function in `api/index.ts`. This is what powers the hosted server at `https://mcp.getrunpod.io/`.
|
|
124
187
|
|
|
125
188
|
The hosted transport is stateless:
|
|
126
189
|
|
|
@@ -137,7 +200,9 @@ The token can be either:
|
|
|
137
200
|
- a Runpod API key the caller configured manually, or
|
|
138
201
|
- a Runpod API key obtained through the OAuth "Sign in with Runpod" flow (see below).
|
|
139
202
|
|
|
140
|
-
An unauthenticated request receives a `401` with a `WWW-Authenticate` header pointing at the protected-resource metadata, which tells an OAuth-capable client (such as Claude) to start the sign-in flow.
|
|
203
|
+
An unauthenticated request receives a `401` with a `WWW-Authenticate` header pointing at the protected-resource metadata, which tells an OAuth-capable client (such as Claude) to start the sign-in flow.
|
|
204
|
+
|
|
205
|
+
A request whose bearer token is _rejected_ — a revoked key, whether OAuth-minted or supplied by the caller — gets the same `401`, plus `error="invalid_token"` to distinguish it from having sent no credential at all. The token is verified once and the verdict cached briefly. If a credential dies mid-session while a "valid" verdict is still cached, the first call afterward can still surface the upstream 401 as a `200` tool error; that call drops the cached verdict, so the next request re-checks and surfaces a real HTTP `401` that triggers re-authentication. Set `MCP_SKIP_CREDENTIAL_CHECK=true` to disable that verification; it also self-disables when the REST/Serverless hosts and the auth GraphQL host are pointed at different environments, since it would otherwise validate the key against the wrong backend.
|
|
141
206
|
|
|
142
207
|
### Sign in with Runpod (authorize flow)
|
|
143
208
|
|
|
@@ -200,12 +265,6 @@ This validates:
|
|
|
200
265
|
- A public GraphQL-backed tool call.
|
|
201
266
|
- An authenticated REST-backed tool call.
|
|
202
267
|
|
|
203
|
-
## Claude Desktop and hosted MCP
|
|
204
|
-
|
|
205
|
-
Use the local `stdio` integration for Claude Desktop today.
|
|
206
|
-
|
|
207
|
-
For remote clients such as Claude's connector, deploy the hosted HTTP server. The client then runs the OAuth "Sign in with Runpod" flow, and the resulting Runpod API key is forwarded to the Runpod API on each request.
|
|
208
|
-
|
|
209
268
|
## Local development
|
|
210
269
|
|
|
211
270
|
```bash
|
|
@@ -240,42 +299,20 @@ RUNPOD_API_KEY=YOUR_API_KEY pnpm build
|
|
|
240
299
|
RUNPOD_API_KEY=YOUR_API_KEY pnpm smoke:stdio
|
|
241
300
|
```
|
|
242
301
|
|
|
243
|
-
## Usage examples
|
|
244
|
-
|
|
245
|
-
### List all Pods
|
|
246
|
-
|
|
247
|
-
```text
|
|
248
|
-
Can you list all my Runpod Pods?
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
### Create a new Pod
|
|
252
|
-
|
|
253
|
-
```text
|
|
254
|
-
Create a new Runpod Pod with the following specifications:
|
|
255
|
-
- Name: test-pod
|
|
256
|
-
- Image: runpod/pytorch:2.1.0-py3.10-cuda11.8.0-devel-ubuntu22.04
|
|
257
|
-
- GPU Type: NVIDIA GeForce RTX 4090
|
|
258
|
-
- GPU Count: 1
|
|
259
|
-
```
|
|
260
|
-
|
|
261
|
-
### Create a Serverless endpoint
|
|
262
|
-
|
|
263
|
-
```text
|
|
264
|
-
Create a Runpod Serverless endpoint with the following configuration:
|
|
265
|
-
- Name: my-endpoint
|
|
266
|
-
- Template ID: 30zmvf89kd
|
|
267
|
-
- Minimum workers: 0
|
|
268
|
-
- Maximum workers: 3
|
|
269
|
-
```
|
|
270
|
-
|
|
271
302
|
## Contributing
|
|
272
303
|
|
|
273
304
|
The source is now split by responsibility:
|
|
274
305
|
|
|
275
|
-
- `src/stdio.ts`: local `stdio` entrypoint.
|
|
306
|
+
- `src/stdio.ts`: local `stdio` entrypoint (runs the v2 probe at startup for `auto` mode).
|
|
276
307
|
- `src/http.ts`: bearer-token extraction and the per-request MCP session for the Streamable HTTP transport.
|
|
277
|
-
- `src/tools.ts`:
|
|
308
|
+
- `src/tools.ts`: thin orchestrator — builds the shared runtime and calls each per-resource registrar.
|
|
309
|
+
- `src/tools/<resource>.ts`: the tools for one resource (`pods`, `endpoints`, `jobs`, `templates`, `network-volumes`, `registries`, `catalog`), each with a description + MCP annotations.
|
|
310
|
+
- `src/tools/runtime.ts`: the shared per-server runtime (caller-tracking, the authenticated REST/Serverless/GraphQL clients, the v1/v2 backend resolver) threaded into every registrar.
|
|
278
311
|
- `src/server.ts`: shared server metadata and construction.
|
|
312
|
+
- `src/_shared/backend.ts`: v1/v2 routing adapter — version resolution, per-resource paths, list-envelope unwrap, and the v2 probe.
|
|
313
|
+
- `src/_shared/http.ts`: unified authenticated JSON client + `HttpError`.
|
|
314
|
+
- `src/_shared/tracking.ts`: caller-tracking header construction.
|
|
315
|
+
- `src/_shared/mappers.ts`: v1→v2 request-body mappers.
|
|
279
316
|
- `api/index.ts`: Vercel adapter and the OAuth authorization-server routes (`/.well-known/*`, `/register`, `/authorize`, `/token`).
|
|
280
317
|
|
|
281
318
|
After changes:
|
|
@@ -283,9 +320,27 @@ After changes:
|
|
|
283
320
|
```bash
|
|
284
321
|
pnpm type-check
|
|
285
322
|
pnpm lint
|
|
323
|
+
pnpm test
|
|
286
324
|
pnpm build
|
|
287
325
|
```
|
|
288
326
|
|
|
327
|
+
`pnpm test` runs the offline unit suite (outbound-request goldens, adapter, mappers, http client) — no network or API key required.
|
|
328
|
+
|
|
329
|
+
### v2 spec parity gate
|
|
330
|
+
|
|
331
|
+
`tests/spec-parity.test.ts` walks every operation in the vendored v2 OpenAPI spec (`tests/fixtures/v2-openapi.yaml`) and fails if a v2 endpoint has no MCP tool covering it (and isn't explicitly allowlisted) — the drift gate that flags when the API grows an endpoint we don't expose yet. It also runs the reverse check (no tool is left unaccounted for). It's part of `pnpm test`, hermetic (parses the committed spec; no network, no API key).
|
|
332
|
+
|
|
333
|
+
Refresh the vendored spec when the v2 API changes:
|
|
334
|
+
|
|
335
|
+
```bash
|
|
336
|
+
pnpm tsx scripts/fetch-v2-spec.ts # re-fetch tests/fixtures/v2-openapi.yaml
|
|
337
|
+
pnpm test # parity test shows any newly-uncovered endpoint
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
The serverless runtime tools (`run-endpoint`, `get-job-status`, …) target `api.runpod.ai/v2`, which is a different service from the v2 REST control plane, so they are allowlisted as intentionally spec-unmapped. The spec has no logs/artifacts endpoints, so there are no such tools.
|
|
341
|
+
|
|
342
|
+
An optional live shape check (skipped by default) verifies the live endpoints still return the envelopes the list tools unwrap; run it with `MCP_LIVE_V2_KEY=<dev-key> pnpm test` (optionally `MCP_LIVE_V2_BASE`).
|
|
343
|
+
|
|
289
344
|
For transport validation:
|
|
290
345
|
|
|
291
346
|
```bash
|
|
@@ -293,10 +348,85 @@ pnpm smoke:stdio
|
|
|
293
348
|
pnpm smoke:http
|
|
294
349
|
```
|
|
295
350
|
|
|
351
|
+
To exercise a real create→get→delete lifecycle against a **dev account** (free resources only — templates and registry auths — with fail-closed teardown):
|
|
352
|
+
|
|
353
|
+
```bash
|
|
354
|
+
RUNPOD_API_KEY=YOUR_DEV_KEY \
|
|
355
|
+
RUNPOD_REST_V2_API_URL=https://v2-rest.runpod.dev/v2 \
|
|
356
|
+
pnpm smoke:crud v1 v2
|
|
357
|
+
```
|
|
358
|
+
|
|
296
359
|
This project uses [changesets](https://github.com/changesets/changesets) for versioning and npm publishing. Every PR with user-facing changes needs a changeset file at `.changeset/DESCRIPTIVE_NAME.md`.
|
|
297
360
|
|
|
298
361
|
See `CLAUDE.md` and `docs/context.md` for contributor guidance.
|
|
299
362
|
|
|
363
|
+
## Reference
|
|
364
|
+
|
|
365
|
+
### Deployment modes
|
|
366
|
+
|
|
367
|
+
The server supports two deployment modes:
|
|
368
|
+
|
|
369
|
+
- Local `stdio` for Claude Desktop, Claude Code, Cursor, VS Code, and other MCP clients that launch a local process. The caller sets `RUNPOD_API_KEY` in the environment.
|
|
370
|
+
- Hosted Streamable HTTP for Vercel or other HTTP-capable platforms. Each request carries its own `Authorization: Bearer <token>`, which the server forwards directly to the Runpod API. The token can be a Runpod API key or one obtained through the OAuth "Sign in with Runpod" flow.
|
|
371
|
+
|
|
372
|
+
The server never holds a credential of its own and never shares one across users.
|
|
373
|
+
|
|
374
|
+
### REST API version (v1 / v2)
|
|
375
|
+
|
|
376
|
+
The server can target either the v1 REST API (`rest.runpod.io/v1`) or the newer v2 REST API (`v2-rest.runpod.io/v2`). It **defaults to v2**; set `RUNPOD_REST_VERSION=v1` to pin the previous v1 behavior. These environment variables are read once at startup:
|
|
377
|
+
|
|
378
|
+
| Variable | Values | Default | Effect |
|
|
379
|
+
| -------------------------------- | ---------------------- | ------------------------------ | ----------------------------------------------------------------------------------------------------- |
|
|
380
|
+
| `RUNPOD_REST_VERSION` | `v1` \| `v2` \| `auto` | `v2` | Version used for all resources. |
|
|
381
|
+
| `RUNPOD_REST_VERSION_<RESOURCE>` | `v1` \| `v2` \| `auto` | — | Per-resource override (e.g. `RUNPOD_REST_VERSION_PODS=v2`). Takes precedence over the global setting. |
|
|
382
|
+
| `RUNPOD_REST_V2_API_URL` | URL | `https://v2-rest.runpod.io/v2` | v2 base URL. Override to target a non-prod host. |
|
|
383
|
+
| `RUNPOD_REST_API_URL` | URL | `https://rest.runpod.io/v1` | v1 base URL. |
|
|
384
|
+
| `RUNPOD_SERVERLESS_API_URL` | URL | `https://api.runpod.ai/v2` | Serverless runtime base URL. |
|
|
385
|
+
|
|
386
|
+
> **⚠️ Migration note — `create-endpoint` / `update-endpoint` changed shape in v2.** Serverless endpoints now use the v2 API (`/v2/serverless`) with an **inline config** instead of a `templateId`. On v2, `create-endpoint` requires `imageName` + `gpuPoolIds` (GPU **pool** names from `list-gpu-types` — the `pool` field, e.g. `AMPERE_80`), plus optional `workersMin`/`workersMax`, `scalerType`/`scalerValue`/`idleTimeout`, `containerDiskInGb`, `env`, `flashboot`, etc. It no longer accepts `templateId`. **If you previously called `create-endpoint` with `{ templateId }` and have no `RUNPOD_REST_VERSION` set, that call now returns a clean `400` after upgrading** — switch to the inline fields, or pin `RUNPOD_REST_VERSION=v1` to keep the legacy template-based model.
|
|
387
|
+
|
|
388
|
+
Notes:
|
|
389
|
+
|
|
390
|
+
- **Default is v2** — with nothing set, every control-plane resource uses the v2 REST API. Set `RUNPOD_REST_VERSION=v1` to pin the previous v1 behavior.
|
|
391
|
+
- **Pinning a deployment** — the env var is read once at startup, so set `RUNPOD_REST_VERSION` (`v1` or `v2`) in the host's environment (e.g. a Vercel project env var) and redeploy; no code change. Hosted HTTP honors this default like any other transport.
|
|
392
|
+
- **What `auto` does:** it probes v2 once at startup and falls back to v1 — but **only on the `stdio` transport** (one process = one key). On hosted HTTP `auto` resolves to **v1**, because a warm instance serves many users and a cached probe verdict could leak across them. `auto` is a stdio-only convenience; on HTTP, rely on the default or pin the version explicitly.
|
|
393
|
+
- `jobs` (serverless runtime) always uses v1 regardless of the setting — it has no v2 REST home (it targets `api.runpod.ai/v2`, a different service).
|
|
394
|
+
- The v2-only tools (`list-cpu-types`, `get-gpu-type`, `restart-pod`, and the three `*-registry-delegation(s)` tools) return a clear "v2 only" notice when called under v1.
|
|
395
|
+
- `create-pod` for a **CPU pod** (`computeType: "CPU"`) on v2 is transparently served by the **v1** API — v2 has no CPU pods yet — and the reply is flagged `_servedBy: "v1"`. Because that fallback hits the **v1 base**, set `RUNPOD_REST_API_URL` to match your environment when running v2 against a non-prod host (otherwise CPU creates land on v1 **prod**). On v2 a create with neither `gpuTypeIds` nor `computeType` is rejected — absence is never silently turned into a CPU pod.
|
|
396
|
+
|
|
397
|
+
### Private image pull: credentials vs ECR delegation
|
|
398
|
+
|
|
399
|
+
Two ways to let Runpod pull a private image, and they are not interchangeable:
|
|
400
|
+
|
|
401
|
+
- **`create-container-registry-auth`** — stores a username + password/token. Works for any registry (Docker Hub, GHCR, Quay, a self-hosted one). Available on v1 and v2. Reference the resulting id from `create-pod` / `create-endpoint` via `containerRegistryAuthId`.
|
|
402
|
+
- **`create-registry-delegation`** — **AWS ECR only, v2-only, no credentials stored.** You register an ECR repository ARN and Runpod is granted scoped pull access to it; the reply carries a `dockerRegistryUri` plus the resolved repository, tag, and AWS region. Manage with `list-registry-delegations` and revoke with `delete-registry-delegation`.
|
|
403
|
+
|
|
404
|
+
Prefer the delegation for ECR — nothing long-lived is stored on Runpod's side.
|
|
405
|
+
|
|
406
|
+
Example (stdio client config) — v2 against prod:
|
|
407
|
+
|
|
408
|
+
```json
|
|
409
|
+
"env": {
|
|
410
|
+
"RUNPOD_API_KEY": "YOUR_API_KEY",
|
|
411
|
+
"RUNPOD_REST_VERSION": "v2"
|
|
412
|
+
}
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
Targeting a **non-prod (dev) environment** — point **both** bases at it (the v1 base matters even in v2 mode, for the CPU-pod fallback above):
|
|
416
|
+
|
|
417
|
+
```json
|
|
418
|
+
"env": {
|
|
419
|
+
"RUNPOD_API_KEY": "YOUR_DEV_KEY",
|
|
420
|
+
"RUNPOD_REST_VERSION": "v2",
|
|
421
|
+
"RUNPOD_REST_V2_API_URL": "https://v2-rest.runpod.dev/v2",
|
|
422
|
+
"RUNPOD_REST_API_URL": "https://rest.runpod.dev/v1"
|
|
423
|
+
}
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
### Large tool output
|
|
427
|
+
|
|
428
|
+
Resource **lists** are paginated (default 20 items, `nextCursor`), so a big account can't flood the agent's context. But **serverless job output** — `run-endpoint`, `runsync-endpoint`, `get-job-status`, and especially `stream-job` (which accumulates every chunk) — is returned **as-is and is not size-capped**. It's a single opaque payload, not a list, so there's no cursor to page. A very large or long-streaming result can exceed the context window. If output may be huge, have the agent **write it to a file** instead of returning it inline, or set `s3Config` on the job so large outputs go to object storage.
|
|
429
|
+
|
|
300
430
|
## Security considerations
|
|
301
431
|
|
|
302
432
|
This server acts with the full permissions of the supplied `RUNPOD_API_KEY`.
|