@runpod/mcp-server 3.1.0 → 3.3.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 +80 -0
- package/dist/{chunk-OM6RHPQC.mjs → chunk-ICUS4KGX.mjs} +708 -100
- package/dist/chunk-ICUS4KGX.mjs.map +1 -0
- package/dist/http.cjs +747 -108
- package/dist/http.cjs.map +1 -1
- package/dist/http.mjs +41 -10
- package/dist/http.mjs.map +1 -1
- package/dist/stdio.cjs +1337 -213
- package/dist/stdio.cjs.map +1 -1
- package/dist/stdio.mjs +726 -108
- package/dist/stdio.mjs.map +1 -1
- package/dist/tools.cjs +707 -99
- package/dist/tools.cjs.map +1 -1
- package/dist/tools.d.cts +13 -1
- package/dist/tools.d.ts +13 -1
- package/dist/tools.mjs +1 -1
- package/dist/wizard-FBLOZ6YM.mjs +901 -0
- package/dist/wizard-FBLOZ6YM.mjs.map +1 -0
- package/package.json +2 -2
- package/dist/chunk-OM6RHPQC.mjs.map +0 -1
- package/dist/wizard-37ZJSVB5.mjs +0 -402
- package/dist/wizard-37ZJSVB5.mjs.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,85 @@
|
|
|
1
1
|
# @runpod/mcp-server
|
|
2
2
|
|
|
3
|
+
## 3.3.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- a62a663: `list-gpu-types` and `get-gpu-type` now always send `product` with their `include=AVAILABILITY` catalog requests, via a new optional `product` parameter (`POD` | `CLUSTER` | `SERVERLESS`, default `POD`). Availability is product-specific — the same GPU can be scarce for Pods and plentiful for Serverless — and the next v2 API release makes `product` required with availability (400 without it), so this keeps the availability lookups working and lets agents ask for the context they actually deploy to: pass `SERVERLESS` when picking a GPU for an endpoint, `CLUSTER` for Instant Clusters. When `includeAvailability` is false, `product` is not sent (the API also rejects `product` without `include=AVAILABILITY`). The CPU catalog tools never request availability, so they are unaffected.
|
|
8
|
+
- 7074c87: Add an `sshPublicKey` parameter to `create-pod` for full SSH access (#73), and fix v2 GPU pod creation failing without an explicit `gpuCount`.
|
|
9
|
+
|
|
10
|
+
The REST API has no SSH switch yet (the console and runpodctl set it via GraphQL `startSsh`), so Pods created through the MCP got a valid-looking port-22 mapping but no authorized key — direct SSH, SCP, SFTP, and rsync all failed. Passing `sshPublicKey` now merges the key into the `PUBLIC_KEY` environment variable and ensures `22/tcp` is exposed, which any image honoring the `PUBLIC_KEY` convention (all runpod/\* official images) turns into a running sshd with the key installed. Template deploys extend the template's ports and env rather than replacing them, and an existing `PUBLIC_KEY` is appended to rather than overwritten.
|
|
11
|
+
|
|
12
|
+
The key is validated before the Pod is created, because an unusable value would otherwise produce a Pod that looks SSH-ready and is not: `22/tcp` exposed, junk in `PUBLIC_KEY`, and a reply reporting SSH as configured. Rejected with a 400: a private key in any format (PEM in any case, or a PuTTY `.ppk`, which contains neither the words "private key" nor a public key line), a file path or SHA256 fingerprint passed instead of the `.pub` file's contents, a bare base64 blob with no key type, and an empty or whitespace-only value (omit the parameter to create a Pod without SSH). Accepted keys are normalized to one key per line with CRLF stripped, since a stray carriage return corrupts the `authorized_keys` entry it lands on. Error messages never echo the rejected value, which may itself be secret.
|
|
13
|
+
|
|
14
|
+
`create-pod` also now rejects a `gpuCount` below 1 or with a fractional part, which the v2 API answers with an opaque 422.
|
|
15
|
+
|
|
16
|
+
Separately, the v2 pod-create mapper omitted `gpu.count` when the caller passed no `gpuCount`, trusting the spec's documented server-side default of 1. In practice the scheduler matches zero machines without it and every create fails with a misleading "no instances available" error (verified live against both v2 hosts). The mapper now always emits `count`, defaulting to 1.
|
|
17
|
+
|
|
18
|
+
- 9176c78: Clamp long-poll tool budgets on the hosted HTTP server, which runs behind a 60-second Vercel function limit. `runsync-endpoint` waited 90 seconds by default (300 via `wait`) and `stream-job` polled for up to 5 minutes, so for a slow job the function was reaped mid-flight: the caller got a bare 504 and every chunk collected so far was discarded.
|
|
19
|
+
|
|
20
|
+
Over HTTP, `runsync-endpoint` now sends a `wait` capped at 45000 ms — a job that outlives it comes back as a job ID plus a non-terminal status to poll with `get-job-status`. `stream-job` stops after 45 seconds over HTTP and returns what it has with `pollingTimedOut: true`; `/stream` drains what it hands out, so calling again resumes rather than replaying. Its HTTP polls also send `wait=1000`, since the server otherwise holds an empty response for 10 seconds and the budget is only checked between polls. Both tool descriptions are now written per transport, so a caller is told the one budget that applies to them and where to go for more — `run-endpoint` + `get-job-status`, or the runtime API directly. The stdio server has no deadline and is unchanged.
|
|
21
|
+
|
|
22
|
+
- f20d987: Give every outbound request a client-side deadline — every tool call, the OAuth handshake on the hosted server, and the install wizard's key check. node-fetch applies no timeout of its own, so a Runpod host that accepted the connection and then went silent — a wedged worker, a load balancer holding the socket — left a tool call pending forever, and on the hosted server that ended as a bare 504 when Vercel reaped the function at its 60s limit.
|
|
23
|
+
|
|
24
|
+
Requests now abort after 30 seconds with a named `RequestTimeoutError` naming the API that went quiet, the deadline it was given, and what to do next. `runsync-endpoint` is the one call that legitimately asks the server to hold a connection open, so it derives its deadline from the `wait` it requested (the server's own 90-second default when `wait` is omitted) rather than being truncated. Successful tool output is unchanged.
|
|
25
|
+
|
|
26
|
+
On the hosted transport the cap is a single budget for the whole invocation rather than a fresh allowance per request, because several tools make more than one call — `get-job-status` adds a queued-job diagnosis, `deploy-hub-repo` and `set-endpoint-gpus` read before they write, `update-endpoint` reads the current scaler before patching it — and two full deadlines back to back outlived the platform even with each one bounded. Each request is clamped to what is left, so a stall anywhere in a handler surfaces as the named error instead of a 504. The queued-job diagnosis, which only decorates a status that is already in hand, is bounded at 5 seconds so it cannot spend a budget the reply itself needs.
|
|
27
|
+
|
|
28
|
+
`stream-job` bounds each poll by the wait the server was asked to hold rather than by its whole budget. A deadline set to the budget meant one wedged socket consumed the entire run in a single attempt — 45 seconds on the hosted server, five minutes on stdio — so the loop's retry path never ran and a stall returned nothing at all. Each poll now gets the hold plus a round trip, which both clears a reply already in flight and leaves the budget room to reconnect; a run that ends on the budget reports `pollingTimedOut` with the last error rather than discarding it.
|
|
29
|
+
|
|
30
|
+
The hosted OAuth routes are bounded too. `/token` polls the flash backend for an approval, and one silent socket there hung the whole handshake until the platform reaped it — the worst place for a blank error, since the user has no credential yet to retry with. Each backend call now has its own 10-second deadline (override with `MCP_FLASH_TIMEOUT_MS`), never exceeding what is left of a 45-second poll budget, and a stall is reported as a named error naming the operation, the host and the deadline. The `runpod-mcp install` wizard's key verification gets the same treatment, so it can no longer sit at "Verifying…" indefinitely.
|
|
31
|
+
|
|
32
|
+
A timed-out GraphQL read is also no longer described as a possible write. The advice keys off the HTTP method and GraphQL is always POST on the wire, so `list-gpu-types` timing out used to tell the agent the call may have landed and to "check with the matching list-/get- tool first" — which is the tool that just failed. Only actual mutations carry that warning now.
|
|
33
|
+
|
|
34
|
+
### Patch Changes
|
|
35
|
+
|
|
36
|
+
- 2b6480d: Refuse the standalone GET SSE stream with 405. The HTTP server is stateless and never sends server-initiated messages, so the GET "listen" stream has nothing to carry — but the SDK accepted it anyway and held the response open with nothing to send until the platform's maxDuration killed it, at which point every connected client immediately re-opened it. On the hosted deployment that loop was ~1.1M hung requests per day (90% of all traffic), each ending in a 60-second timeout, and it dominated the serverless bill. GET now gets the spec's answer for a server without an SSE stream: 405 Method Not Allowed with an `Allow: POST, DELETE` header and a JSON-RPC error body, before any auth work — a 401 there would send OAuth clients into a pointless re-auth flow. Clients per the MCP spec treat the 405 as "no server-initiated messages offered" and continue POST-only; tool calls are unaffected.
|
|
37
|
+
- 674fa2c: Fix Claude Code detection and registration in the install wizard on Windows (#56).
|
|
38
|
+
|
|
39
|
+
Detection used the POSIX-only `command -v claude` plus three POSIX install paths, so
|
|
40
|
+
Claude Code was undetectable on a standard Windows install. Windows now probes
|
|
41
|
+
`%USERPROFILE%\.local\bin\claude.exe` (native installer) and `%APPDATA%\npm\claude.cmd`
|
|
42
|
+
(global npm), and registration resolves the real entrypoint from the installed package
|
|
43
|
+
manifest instead of running the `.cmd` shim through `cmd.exe`. Candidates are
|
|
44
|
+
canonicalized and confined to their standard install roots, a PATH result resolving into
|
|
45
|
+
the current project is rejected, and Claude Code is spawned with `PATH`, `COMSPEC`,
|
|
46
|
+
`PATHEXT`, `NODE_OPTIONS`, and `NODE_PATH` sanitized, so nothing a project directory can
|
|
47
|
+
plant receives your API key. Custom npm prefixes and redirected roaming profiles are
|
|
48
|
+
still not auto-detected; when Claude Code is not found, the wizard now prints the exact
|
|
49
|
+
`claude mcp` command to register or remove the entry yourself.
|
|
50
|
+
|
|
51
|
+
Claude Code add and remove are now verified against its own `.claude.json` rather than
|
|
52
|
+
the CLI exit code, which reports success for writes it never made. Re-running the wizard
|
|
53
|
+
over an existing entry now says the entry was left unchanged instead of printing a bare
|
|
54
|
+
success, since the CLI does not update it and a rotated API key would otherwise look
|
|
55
|
+
applied. An entry shadowed by a local-scope one is called out with the command to clear
|
|
56
|
+
it.
|
|
57
|
+
|
|
58
|
+
For the clients that own a JSON config, an edit that would leave the file unparseable —
|
|
59
|
+
or land in a duplicated server block the client does not read — now fails with the
|
|
60
|
+
original file untouched instead of reporting success, and validity is judged by the
|
|
61
|
+
parser each client actually ships (Claude Desktop is strict JSON, Cursor and VS Code
|
|
62
|
+
accept JSONC, Windsurf's tolerance is unverified and disclosed rather than assumed).
|
|
63
|
+
Claude Desktop on Linux and VS Code now honour `XDG_CONFIG_HOME` instead of writing
|
|
64
|
+
where those clients never read, an empty or relative `APPDATA`/`XDG_CONFIG_HOME` no
|
|
65
|
+
longer resolves a config path against the current directory, configs this wizard creates
|
|
66
|
+
are `0600` because they hold a plaintext API key, and a key taken from the environment is
|
|
67
|
+
trimmed.
|
|
68
|
+
|
|
69
|
+
## 3.2.0
|
|
70
|
+
|
|
71
|
+
### Minor Changes
|
|
72
|
+
|
|
73
|
+
- 2fb68de: Default REST v2 base URL is now `https://api.runpod.io/v2` (the documented canonical host) instead of `https://v2-rest.runpod.io/v2`. Both hosts serve the same API; deployments that pin `RUNPOD_REST_V2_API_URL` are unaffected. Server instructions updated to match.
|
|
74
|
+
- 773a4ce: Add `get-capacity`: GPU capacity across host CUDA versions as one matrix call. Agents picking an endpoint's `allowedCudaVersions`/`minCudaVersion` (or diagnosing a capacity-starved endpoint) previously had to reverse-engineer per-version stock by calling the GraphQL `gpuTypes.lowestPrice` query once per CUDA version — an undocumented idiom nobody discovers organically. The default mode returns, per GPU type, overall stock plus AVAILABLE/UNAVAILABLE per host-reported CUDA version in a single credential-free catalog query; passing `cudaVersions` deep-probes those versions instead, returning graded stock (High/Medium/Low/Out) and the lowest on-demand price per version. Nothing is hidden by default — out-of-stock versions appear as explicit `Out` cells (set `includeUnavailable: false` to drop no-stock GPUs), and a transiently failing probe reports a per-version `probeErrors` entry instead of failing the whole call. Works on both v1 and v2 APIs — both use the public GraphQL catalog, since the v2 REST catalog's CUDA support is a `minCudaVersion` floor filter on availability, not the exact per-version breakdown, graded stock, or per-version pricing this tool returns.
|
|
75
|
+
- 14b1f88: Add server instructions (sent in the `initialize` response) pointing agents at the machine-readable API contracts: the REST v2 OpenAPI spec at api.runpod.io/v2/openapi.json and the GraphQL schema reference at graphql-spec.runpod.io. The MCP tools are curated projections of the underlying APIs; this gives agents a discoverable escape hatch when a tool doesn't expose the field or parameter they need, instead of a dead end. Also moves the `capabilities` object to the `ServerOptions` argument of the `McpServer` constructor, where the SDK actually reads it.
|
|
76
|
+
|
|
77
|
+
### Patch Changes
|
|
78
|
+
|
|
79
|
+
- 58c1218: `create-pod` now returns a clean local 400 when `name` is omitted on a v2 GPU create without a `templateId`, matching the v2 spec (`CreatePodRequest` requires `name`) instead of surfacing the API's raw 422. Template deploys (name inherited from the template) and CPU pods (routed to v1) are unaffected.
|
|
80
|
+
- cd52f94: Surface HTTP-level GraphQL failures by status instead of as parse errors. The GraphQL helper (behind `list-gpu-types`, `list-data-centers`, `list-hub-repos`, `list-public-endpoints`, `deploy-hub-repo`, and `set-endpoint-gpus`) previously called `response.json()` unconditionally, so a 429 or 5xx returning an HTML error page surfaced as an opaque `Unexpected token '<'` parse error. Non-OK responses now throw the same `HttpError` as the REST client — status and body named, with the `RateLimit` wait hint on 429 — completing the treatment the REST client received. A non-OK body that still carries a GraphQL `errors` array keeps the readable GraphQL message as an `HttpError` with the status attached (`Runpod GraphQL Error: 400 - <message>`), except on 401/429 where the re-auth and rate-limit hints take precedence. The 401 re-auth hint is now applied only by call sites that actually sent a credential (REST, authed GraphQL, the SSE log reader) — the credential-free public GraphQL path no longer advises re-authenticating for a 401 that cannot be about the caller's API key. `HttpError` messages now also cap embedded bodies at 2 KB (`.body` keeps the full text), so a large proxy/WAF error page can't flood an agent's context.
|
|
81
|
+
- deae681: Make 429s actionable. A bare "rate limit exceeded" invites an immediate retry — the worst possible agent response. On a 429 from the REST or serverless client, the error now names the exhausted quota window and how long to wait, read from the API's `Retry-After` and `RateLimit` headers, e.g. `(rate limited — the hour quota is exhausted; wait ~29 minutes (1724s) before retrying, and pace bulk operations)`. Several windows can report zero remaining at once, so the hint reports the longest wait either header justifies rather than the first or the nearest — answering a 30-minute lockout with "retry in 12s" is the failure this exists to prevent. When part of the header couldn't be read, the wait is qualified "at least" rather than presented as the answer. Falls back to generic back-off guidance when neither header is usable, as on the v1 REST API, which sends neither. The log-streaming tools, which build their own error, carry the same hint. GraphQL-backed tools (catalog, hub, public endpoints, endpoint GPUs) are unchanged — that helper doesn't inspect the response status yet. `HttpError.status`/`.body` are unchanged for programmatic callers.
|
|
82
|
+
|
|
3
83
|
## 3.1.0
|
|
4
84
|
|
|
5
85
|
### Minor Changes
|