@runpod/mcp-server 4.2.0 → 4.4.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 CHANGED
@@ -1,5 +1,65 @@
1
1
  # @runpod/mcp-server
2
2
 
3
+ ## 4.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - a58f9f1: New `search-docs` tool: searches Runpod documentation, curated support knowledge, the Runpod blog and runpod.io through the runpod-assistant knowledge index, and returns ranked passages with source URLs. The hosted server searches with its own service key and retries the index's capacity rejections with jittered backoff. Local installs call the hosted `POST /api/search` with the user's API key.
8
+
9
+ ### Patch Changes
10
+
11
+ - 4b53720: Hosted server: `tools/call` now answers as `application/json` too, so the CDN compresses tool results; only tools that hold their response open (`runsync-endpoint`, `get-job-status`, `stream-job`, `stream-pod-logs`, `stream-worker-logs`, `deploy-hub-repo`) keep SSE, declared with `CuratedTool.holdsResponse`.
12
+
13
+ ## 4.3.0
14
+
15
+ ### Minor Changes
16
+
17
+ - 39d296f: Add `describe-tool`, which returns any tool's full definition, and list the tools with large request bodies (create/update endpoint, template and cluster, update-pod, create/update secret) with their call shape only: the top-level arguments with their types, nested objects collapsed. What each tool accepts is unchanged: the full schema still gates every call and is one `describe-tool` call away. Every client handshake carries about a quarter fewer bytes.
18
+ - 40d9745: Resync the vendored v2 OpenAPI spec with production and update `@runpod/typescript-api-sdk` from 0.2.0 to 0.3.0 and `@runpod/plugin-knowledge` to 1.7.4. Adds the `list-global-volumes`, `get-global-volume`, `create-global-volume`, `update-global-volume`, `delete-global-volume` and `get-organization` tools, `global` mounts on `create-pod`, `mounts` on endpoints, and `pagination` on `list-clusters` and `list-network-volumes`. Those two list tools now return one page (default `limit` 1000); follow `pagination.nextCursor` until `hasNextPage` is false.
19
+
20
+ `tools/list` shrinks from 97 KB to 87 KB. `create-pod` is listed by its call shape, like `create-endpoint`; `describe-tool` serves its full schema. Tool annotations leave out `idempotentHint` when it is `false`, the MCP spec default. A description override on a composed schema is no longer repeated on each `allOf` member.
21
+
22
+ - d2d12ef: The installer runs without prompts and supports opencode and Pi.
23
+ `npx @runpod/mcp-server@latest add --client <ids>` configures the named clients
24
+ with no prompts (`--hosted` by default, `--local` to read the key from
25
+ `RUNPOD_API_KEY`), `remove --client <ids>` undoes it, and `add --list` shows
26
+ which clients are detected and where each config lives. Run with no
27
+ `--client` and no terminal, the installer now exits 2 and says nothing was
28
+ configured, instead of exiting 0 having written nothing. Exit codes: 0
29
+ configured, 1 a client failed, 2 bad usage. `--help` and `--version` work at
30
+ the top level and on `add`/`remove`.
31
+
32
+ New clients: opencode (`~/.config/opencode/opencode.json`, or an existing
33
+ `opencode.jsonc`, under `mcp` with opencode's `remote`/`local` entry schema)
34
+ and Pi (`~/.pi/agent/mcp.json`, honouring `PI_CODING_AGENT_DIR`). Both config
35
+ formats were checked by running opencode 1.19.0 and Pi 1.2.0 against the files
36
+ the installer writes.
37
+
38
+ ### Patch Changes
39
+
40
+ - 37dfc9b: Generated tool argument descriptions are compacted to what an agent needs: leading sentences up to a cap, constraints kept, REST paths replaced by tool names, response prose and status codes dropped. `tools/list` shrinks by roughly a fifth; a byte-budget test keeps it from regrowing.
41
+ - a388ccb: Hosted usage analytics now record which guide or concept was requested: the `id`, `concept`, `query`, `kind` and `limit` arguments of `list-guides`, `read-guide`, `lookup-concept` and `search-concepts`. `read-guide` events also carry `guide_kind` (skill, reference or golden-path). Guide resource reads (`resources/read`) are recorded as a new `runpod_mcp_resource_call` event with the guide URI, or `unknown` when nothing matched. Other tools still send no arguments, stdio still sends nothing, and `X-Runpod-Analytics: off` still opts out.
42
+ - a388ccb: The hosted server now breaks 404 loops: once a signed-in caller gets 50 404s from one tool within 10 minutes, that tool answers that caller with a retryable 429 for 1 hour. Counts live in the existing Convex sink, successful calls never touch it, and any sink failure lets calls through. Local (stdio) installs are unaffected. Each block emits one `runpod_mcp_loop_blocked` analytics event, and the 429s it serves carry `blocked_by: not_found_loop`.
43
+ - 19cae9f: Hosted server: every request except `tools/call` now answers as `application/json` instead of an SSE stream, so the CDN compresses it (`tools/list` drops from ~65 KB to ~13 KB on the wire per handshake). `tools/call` keeps SSE because clients read it under their long stream timeout and some tools hold a response longer than the JSON request timeout.
44
+
45
+ The per-request `mcp_request` log line is sampled (`MCP_REQUEST_LOG_SAMPLE_RATE`, default `0.1`; `MCP_VERBOSE_LOGS=true` logs all) and now records the response status, duration, JSON-RPC method (with tool name), the client's `initialize` name/version, user agent, and hashed caller key and address, so traffic can be attributed by client.
46
+
47
+ - c55d61a: Hosted server: the request body is validated once with the SDK's JSON-RPC schemas; `prefersJsonResponse` and `summarizeRpc` take the parsed messages, and the log line reports a client name/version only for a spec-valid `initialize`.
48
+ - 6efc1b3: Accept the argument shapes strict-schema clients send. Clients such as Codex
49
+ and opencode must send every property, so an optional query filter they mean
50
+ to leave out arrives as `null`, `""` or `[]`. Those are now treated as omitted:
51
+ `cudaVersions: []` next to `minCudaVersion` on `get-gpu-type` and
52
+ `list-gpu-types`, `lastN: null` next to an explicit range on the billing tools,
53
+ and `cursor: ""` on a first page no longer fail upstream. Numbers and booleans
54
+ a client stringified inside a request body (`disk: "20"`, `workers.max: "1"`)
55
+ are converted back where the body schema asks for one; string fields stay
56
+ strings.
57
+
58
+ A 400 hint now names the upstream cause instead of always saying "Input shape
59
+ mismatch": no capacity for the requested hardware, no account balance, or two
60
+ conflicting arguments. Real validation failures (a 422, or field errors) keep
61
+ the shape hint.
62
+
3
63
  ## 4.2.0
4
64
 
5
65
  ### Minor Changes
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Runpod MCP server
2
2
 
3
- The official Runpod Model Context Protocol (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.
3
+ The official Runpod Model Context Protocol (MCP) server. It lets MCP clients such as Claude Code, Claude Desktop, Cursor, Windsurf, VS Code, opencode, and Pi manage your Runpod Pods, Serverless endpoints, templates, network volumes, and more.
4
4
 
5
5
  **We host it for you at [`https://mcp.getrunpod.io/`](https://mcp.getrunpod.io/)** — point your client at that URL and sign in with Runpod. Nothing to install, no API key on disk. Or run it locally from npm as [`@runpod/mcp-server`](https://www.npmjs.com/package/@runpod/mcp-server).
6
6
 
@@ -23,6 +23,17 @@ To undo later:
23
23
  npx @runpod/mcp-server@latest remove
24
24
  ```
25
25
 
26
+ To skip the prompts (from a script, CI, or a coding agent's shell), name the clients. Supported ids are `claude-code`, `cursor`, `windsurf`, `claude-desktop`, `vscode`, `opencode`, and `pi`:
27
+
28
+ ```bash
29
+ npx @runpod/mcp-server@latest add --client opencode,pi # hosted, sign in with Runpod
30
+ npx @runpod/mcp-server@latest add --client cursor --local # local, key read from RUNPOD_API_KEY
31
+ npx @runpod/mcp-server@latest remove --client opencode
32
+ npx @runpod/mcp-server@latest add --list # what's detected, and where each config lives
33
+ ```
34
+
35
+ Without `--client` and without a terminal, the installer exits with code 2 and configures nothing. With flags it exits 0 when every client was configured and 1 when one failed.
36
+
26
37
  ### Or install the whole Runpod plugin
27
38
 
28
39
  For the full agent setup, the [official plugin marketplace](https://github.com/runpod/runpod-plugins-official) bundles this server with a router skill plus five more — `runpod-mcp`, `runpodctl`, `flash`, `runpod-usage`, and `companion-clis`:
@@ -73,9 +84,25 @@ An OAuth-capable client starts the "Sign in with Runpod" flow automatically on f
73
84
 
74
85
  > Prefer your own API key over OAuth? Append `--header "Authorization: Bearer YOUR_API_KEY"` to the `claude mcp add` command (or add a `headers` block in the JSON). The server forwards that key to the Runpod API directly.
75
86
 
87
+ ### If sign-in fails with HTTP 403
88
+
89
+ A `403 Forbidden` response with the header `X-Vercel-Mitigated: deny` means the hosted server's firewall has temporarily blocked your IP address, usually after a burst of unauthenticated requests from an MCP client. This happens most often with Codex, which sends many unauthenticated requests while it signs in. The block covers every path, including `/register` and requests that carry an API key, and lifts on its own within an hour. Wait for it to expire, then use one of these options so the next connection doesn't trip it again.
90
+
91
+ You can send your API key as a header instead of signing in with OAuth, as described above. Authenticated requests don't count toward the limit. In Codex, add the key to the server entry in `~/.codex/config.toml`:
92
+
93
+ ```toml
94
+ [mcp_servers.runpod]
95
+ url = "https://mcp.getrunpod.io/"
96
+ bearer_token_env_var = "RUNPOD_API_KEY"
97
+ ```
98
+
99
+ Then export `RUNPOD_API_KEY` in the shell that launches Codex.
100
+
101
+ You can also [run the server locally](#run-locally-with-npx). The local server calls the Runpod API directly, so the hosted firewall only affects its `search-docs` tool, which still searches through the hosted server.
102
+
76
103
  ### Usage analytics
77
104
 
78
- The hosted server records one anonymous event per tool call (tool name, status, duration, transport — never your API key, arguments, or any resource data; your identity is an irreversible salted hash). To opt out, send the header `X-Runpod-Analytics: off` — e.g. append `--header "X-Runpod-Analytics: off"` to the `claude mcp add` command. Running locally, nothing is ever sent.
105
+ The hosted server records one anonymous event per tool call (tool name, status, duration, transport) and per guide resource read (guide URI, or `unknown` on a miss), plus one event when it starts blocking a 404 loop (tool name and block length). It never records your API key or any resource data, and drops tool arguments except on the guide and concept tools (`list-guides`, `read-guide`, `lookup-concept`, `search-concepts`), where it keeps the guide id, concept name or search words, plus the kind of guide read. Your identity is an irreversible salted hash. To opt out, send the header `X-Runpod-Analytics: off` — e.g. append `--header "X-Runpod-Analytics: off"` to the `claude mcp add` command. Running locally, nothing is ever sent.
79
106
 
80
107
  ## Run locally with `npx`
81
108
 
@@ -16,11 +16,15 @@ function publicGraphqlBase(env) {
16
16
  function authedGraphqlBase(env) {
17
17
  return pick(env.RUNPOD_AUTHED_GRAPHQL_URL, "https://api.runpod.io/graphql");
18
18
  }
19
+ function hostedMcpBase(env) {
20
+ return pick(env.RUNPOD_MCP_URL, "https://mcp.getrunpod.io");
21
+ }
19
22
 
20
23
  export {
21
24
  sdkBase,
22
25
  serverlessBase,
23
26
  publicGraphqlBase,
24
- authedGraphqlBase
27
+ authedGraphqlBase,
28
+ hostedMcpBase
25
29
  };
26
- //# sourceMappingURL=chunk-DDX42UTT.mjs.map
30
+ //# sourceMappingURL=chunk-4GF3CMSH.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/_shared/hosts.ts"],"sourcesContent":["// Env-resolved API base URLs, extracted from the retired dual-version backend\n// resolver (backend.ts) when the spec-generated surface became the only one.\n// The credential preflight compares only active SDK and runtime destinations.\n\nexport type Env = Record<string, string | undefined>;\n\n// '' reads as unset everywhere: the wrong-environment guard already strips\n// empty vars before comparing, and every consumer (the credential checker's\n// probe URL, the GraphQL/log clients) must resolve identically or the\n// guard's \"checker and guard cannot disagree\" invariant breaks.\nfunction pick(value: string | undefined, fallback: string): string {\n return value?.trim().replace(/\\/+$/, '') || fallback;\n}\n\n// Generated paths include /v2, so the SDK base is the API origin.\nexport function sdkBase(env: Env): string {\n return pick(env.RUNPOD_API_BASE_URL, 'https://api.runpod.io');\n}\nexport function serverlessBase(env: Env): string {\n return pick(env.RUNPOD_SERVERLESS_API_URL, 'https://api.runpod.ai/v2');\n}\nexport function publicGraphqlBase(env: Env): string {\n return pick(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 pick(env.RUNPOD_AUTHED_GRAPHQL_URL, 'https://api.runpod.io/graphql');\n}\n"],"mappings":";;;AAUA,SAAS,KAAK,OAA2B,UAA0B;AACjE,SAAO,OAAO,KAAK,EAAE,QAAQ,QAAQ,EAAE,KAAK;AAC9C;AAGO,SAAS,QAAQ,KAAkB;AACxC,SAAO,KAAK,IAAI,qBAAqB,uBAAuB;AAC9D;AACO,SAAS,eAAe,KAAkB;AAC/C,SAAO,KAAK,IAAI,2BAA2B,0BAA0B;AACvE;AACO,SAAS,kBAAkB,KAAkB;AAClD,SAAO,KAAK,IAAI,2BAA2B,+BAA+B;AAC5E;AAKO,SAAS,kBAAkB,KAAkB;AAClD,SAAO,KAAK,IAAI,2BAA2B,+BAA+B;AAC5E;","names":[]}
1
+ {"version":3,"sources":["../src/_shared/hosts.ts"],"sourcesContent":["// Env-resolved API base URLs, extracted from the retired dual-version backend\n// resolver (backend.ts) when the spec-generated surface became the only one.\n// The credential preflight compares only active SDK and runtime destinations.\n\nexport type Env = Record<string, string | undefined>;\n\n// '' reads as unset everywhere: the wrong-environment guard already strips\n// empty vars before comparing, and every consumer (the credential checker's\n// probe URL, the GraphQL/log clients) must resolve identically or the\n// guard's \"checker and guard cannot disagree\" invariant breaks.\nfunction pick(value: string | undefined, fallback: string): string {\n return value?.trim().replace(/\\/+$/, '') || fallback;\n}\n\n// Generated paths include /v2, so the SDK base is the API origin.\nexport function sdkBase(env: Env): string {\n return pick(env.RUNPOD_API_BASE_URL, 'https://api.runpod.io');\n}\nexport function serverlessBase(env: Env): string {\n return pick(env.RUNPOD_SERVERLESS_API_URL, 'https://api.runpod.ai/v2');\n}\nexport function publicGraphqlBase(env: Env): string {\n return pick(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 pick(env.RUNPOD_AUTHED_GRAPHQL_URL, 'https://api.runpod.io/graphql');\n}\n/** The hosted MCP server: install target, and stdio's search-docs backend. */\nexport function hostedMcpBase(env: Env): string {\n return pick(env.RUNPOD_MCP_URL, 'https://mcp.getrunpod.io');\n}\n/** The runpod-assistant Convex site serving /v1/search. No default: unset\n * means search is not configured. */\nexport function knowledgeSearchBase(env: Env): string | undefined {\n return pick(env.KNOWLEDGE_SEARCH_URL, '') || undefined;\n}\n"],"mappings":";;;AAUA,SAAS,KAAK,OAA2B,UAA0B;AACjE,SAAO,OAAO,KAAK,EAAE,QAAQ,QAAQ,EAAE,KAAK;AAC9C;AAGO,SAAS,QAAQ,KAAkB;AACxC,SAAO,KAAK,IAAI,qBAAqB,uBAAuB;AAC9D;AACO,SAAS,eAAe,KAAkB;AAC/C,SAAO,KAAK,IAAI,2BAA2B,0BAA0B;AACvE;AACO,SAAS,kBAAkB,KAAkB;AAClD,SAAO,KAAK,IAAI,2BAA2B,+BAA+B;AAC5E;AAKO,SAAS,kBAAkB,KAAkB;AAClD,SAAO,KAAK,IAAI,2BAA2B,+BAA+B;AAC5E;AAEO,SAAS,cAAc,KAAkB;AAC9C,SAAO,KAAK,IAAI,gBAAgB,0BAA0B;AAC5D;","names":[]}