@runpod/mcp-server 1.1.0 → 1.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 CHANGED
@@ -1,5 +1,42 @@
1
1
  # @runpod/mcp-server
2
2
 
3
+ ## 1.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 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.
8
+ - 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`.
9
+ - 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`.
10
+ - 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).
11
+ - 3e6dedf: Address hosted OAuth review feedback:
12
+ - Remove the `MCP_OAUTH_ENABLED` flag — the hosted HTTP server always advertises the OAuth sign-in challenge. Callers that bring their own Runpod API key as the bearer token are unaffected (they never hit the challenge).
13
+ - Default `CONSOLE_BASE_URL` to the production console (`https://console.runpod.io`) so a deploy that forgets to set it doesn't silently redirect users to localhost.
14
+ - `/token` now polls for most of the function budget (~45s) instead of returning a non-retryable `authorization_pending` after ~10s, avoiding a dead-end when console→backend approval propagation lags.
15
+ - Caller-tracking falls back to the inbound HTTP `User-Agent` on the stateless HTTP transport, where the per-request server never sees the MCP `initialize` `clientInfo` (previously reported `client=unknown`).
16
+ - Stop advertising PKCE (`S256`) since it isn't enforced server-side; security rests on the `redirect_uri` allowlist and the single-use flash approval.
17
+ - Default the minted key name to `runpod-mcp` (`RUNPOD_API_KEY_NAME`), so hosted keys are identifiable/revocable. Set `RUNPOD_API_KEY_NAME=""` to suppress it for a backend that has not shipped the `apiKeyName` argument.
18
+
19
+ - 3e6dedf: Simplify hosted HTTP auth to pure token passthrough. The server now forwards the caller's Bearer token directly to the Runpod API and holds no credential of its own — there is no shared server-side key and no token translation. When `MCP_OAUTH_ENABLED=true`, unauthenticated requests return a `WWW-Authenticate` challenge so OAuth-capable clients start the "Sign in with Runpod" flow. Removes the `RUNPOD_HTTP_SHARED_API_KEY` environment variable and the `jose` dependency.
20
+
21
+ ### Patch Changes
22
+
23
+ - 3e6dedf: Support naming the minted Runpod API key in the OAuth flow. Set `RUNPOD_API_KEY_NAME` (e.g. `runpod-mcp`) to pass `apiKeyName` through to the flash backend's `createFlashAuthRequest`, so the key shows up under that name in the user's dashboard. It is omitted by default for compatibility with backends that don't yet support the argument.
24
+ - 3e6dedf: Address low-severity review nits on the hosted HTTP / OAuth path:
25
+ - Make the public discovery GraphQL host configurable via `RUNPOD_PUBLIC_GRAPHQL_URL` (was hardcoded to prod, so a dev deploy hit prod GraphQL).
26
+ - Report the real package version in the hosted server's outbound `User-Agent` (read from package.json at runtime, since tsup's build-time define doesn't run when Vercel compiles `api/index.ts`).
27
+ - Gate OAuth request-id / handoff-URL logging behind `MCP_VERBOSE_LOGS` (request ids are live, single-use auth codes).
28
+ - `stream-job` now surfaces the most recent polling error in its timeout payload instead of discarding it.
29
+ - Pass the parsed request body to the MCP transport explicitly; dispose the per-request server/transport on response close; guard `getBaseUrl` against a missing `Host`; handle a `Buffer` request body in the token endpoint.
30
+ - Single CORS source of truth (handler, not `vercel.json`); stop serving the whole repo as static assets; add an `oauth-e2e` npm script and `engines.pnpm`; fix docs that misattributed the OAuth routes and listed the new env vars.
31
+
32
+ ## 1.2.0
33
+
34
+ ### Minor Changes
35
+
36
+ - 7b715eb: Add list-gpu-types and list-data-centers tools using public GraphQL API for hardware and region discovery. Enhance list-templates with filter params (includeRunpodTemplates, includePublicTemplates, includeEndpointBoundTemplates). Add tool descriptions to create-pod and list-templates recommending Pytorch 2.8.0 as default template.
37
+ - ea2451b: Add Serverless endpoint runtime tools for invoking deployed workers. New tools: run-endpoint (async), runsync-endpoint (sync), get-job-status, stream-job, cancel-job, retry-job, endpoint-health, and purge-endpoint-queue. These use the Serverless API at api.runpod.ai/v2 with a new serverlessRequest helper.
38
+ - 34c0463: Add caller tracking headers to every outbound API call. Each request now carries a structured `User-Agent` (`runpod-mcp-server/<version> (caller=mcp; client=<mcp_client_name>; client_version=<mcp_client_version>; transport=<stdio|http>)`) and an anonymous per-process `X-Runpod-Session-Id` UUID. The MCP client identity is sourced from the `initialize` handshake's `clientInfo`. No tool behavior changes — observability only — so the Runpod platform can attribute traffic to specific MCP clients (Claude Code, Cursor, Codex, Gemini CLI, etc.) and count distinct agent sessions.
39
+
3
40
  ## 1.1.0
4
41
 
5
42
  ### Minor Changes
package/README.md CHANGED
@@ -1,101 +1,300 @@
1
- # Runpod MCP Server
1
+ # Runpod MCP server
2
+
2
3
  [![smithery badge](https://smithery.ai/badge/@runpod/runpod-mcp-ts)](https://smithery.ai/server/@runpod/runpod-mcp-ts)
3
4
 
4
- This Model Context Protocol (MCP) server enables you to interact with the Runpod REST API through Claude or other MCP-compatible clients.
5
+ This is the official Runpod Model Context Protocol (MCP) server, published to npm as `@runpod/mcp-server`.
6
+
7
+ It supports two deployment modes:
5
8
 
6
- ## Features
9
+ - 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.
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.
7
11
 
8
- The server provides tools for managing:
12
+ The server never holds a credential of its own and never shares one across users.
9
13
 
10
- - **Pods**: Create, list, get details, update, start, stop, and delete pods
11
- - **Endpoints**: Create, list, get details, update, and delete serverless endpoints
12
- - **Templates**: Create, list, get details, update, and delete templates
13
- - **Network Volumes**: Create, list, get details, update, and delete network volumes
14
- - **Container Registry Authentications**: Create, list, get details, and delete authentications
14
+ ## Requirements
15
15
 
16
- ## Quick Start
16
+ - Node.js 18 or higher.
17
+ - A Runpod account and API key: https://www.runpod.io/console/user/settings
17
18
 
18
- ### Prerequisites
19
+ ## Quick start
19
20
 
20
- - Node.js 18 or higher
21
- - A Runpod account and API key ([get your API key](https://www.runpod.io/console/user/settings))
21
+ ### Run locally with `npx`
22
22
 
23
- ### Running with npx
23
+ ```bash
24
+ RUNPOD_API_KEY=YOUR_API_KEY npx -y @runpod/mcp-server@latest
25
+ ```
24
26
 
25
- You can run the server directly without installation:
27
+ ### Install via Smithery
26
28
 
27
29
  ```bash
28
- RUNPOD_API_KEY=your_api_key_here npx @runpod/mcp-server@latest
30
+ npx -y @smithery/cli install @runpod/runpod-mcp-ts --client claude
29
31
  ```
30
32
 
31
- ### Installing via Smithery
33
+ ## Local MCP clients
34
+
35
+ Local MCP clients should use the default package entrypoint, which is the `stdio` server.
32
36
 
33
- To install for Claude Desktop automatically via [Smithery](https://smithery.ai/server/@runpod/runpod-mcp-ts):
37
+ ### Claude Code
34
38
 
35
39
  ```bash
36
- npx -y @smithery/cli install @runpod/runpod-mcp-ts --client claude
40
+ claude mcp add runpod -s user \
41
+ -e RUNPOD_API_KEY=YOUR_API_KEY \
42
+ -- npx -y @runpod/mcp-server@latest
37
43
  ```
38
44
 
39
- ## Setting up with Claude for Desktop
45
+ For a project-local server:
46
+
47
+ ```bash
48
+ claude mcp add runpod -s project \
49
+ -e RUNPOD_API_KEY=YOUR_API_KEY \
50
+ -- npx -y @runpod/mcp-server@latest
51
+ ```
52
+
53
+ Verify with `claude mcp list`. In an active session, use `/mcp` to reconnect.
54
+
55
+ ### Claude Desktop
56
+
57
+ Local MCP servers in Claude Desktop still use `claude_desktop_config.json`.
40
58
 
41
- 1. Open Claude for Desktop
42
- 2. Edit the config file:
43
- - macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
44
- - Windows: `%APPDATA%\Claude\claude_desktop_config.json`
45
- 3. Add the server configuration:
59
+ macOS:
60
+
61
+ `~/Library/Application Support/Claude/claude_desktop_config.json`
62
+
63
+ Windows:
64
+
65
+ `%APPDATA%\\Claude\\claude_desktop_config.json`
46
66
 
47
67
  ```json
48
68
  {
49
69
  "mcpServers": {
50
70
  "runpod": {
51
71
  "command": "npx",
52
- "args": ["@runpod/mcp-server@latest"],
72
+ "args": ["-y", "@runpod/mcp-server@latest"],
53
73
  "env": {
54
- "RUNPOD_API_KEY": "your_api_key_here"
74
+ "RUNPOD_API_KEY": "YOUR_API_KEY"
55
75
  }
56
76
  }
57
77
  }
58
78
  }
59
79
  ```
60
80
 
61
- 4. Restart Claude for Desktop
81
+ Restart Claude Desktop after saving.
62
82
 
63
- ## Usage Examples
83
+ ### Cursor
64
84
 
65
- ### List all pods
85
+ Add this to `.cursor/mcp.json` in your project or `~/.cursor/mcp.json` globally:
66
86
 
87
+ ```json
88
+ {
89
+ "mcpServers": {
90
+ "runpod": {
91
+ "command": "npx",
92
+ "args": ["-y", "@runpod/mcp-server@latest"],
93
+ "env": {
94
+ "RUNPOD_API_KEY": "YOUR_API_KEY"
95
+ }
96
+ }
97
+ }
98
+ }
67
99
  ```
68
- Can you list all my Runpod pods?
100
+
101
+ ### VS Code, Windsurf, Cline, JetBrains, and other local clients
102
+
103
+ Use the same pattern:
104
+
105
+ - command: `npx`
106
+ - args: `["-y", "@runpod/mcp-server@latest"]`
107
+ - env: `RUNPOD_API_KEY=YOUR_API_KEY`
108
+
109
+ For a broader list of MCP clients, see https://modelcontextprotocol.io/clients
110
+
111
+ ## Hosted HTTP deployment
112
+
113
+ The package also exports a Streamable HTTP entrypoint at `@runpod/mcp-server/http`, and this repo includes a Vercel function in `api/index.ts`.
114
+
115
+ The hosted transport is stateless:
116
+
117
+ - Each request creates a fresh MCP server instance.
118
+ - The caller must send `Authorization: Bearer <token>`.
119
+ - No credentials are cached or shared server-side.
120
+
121
+ ### Hosted auth
122
+
123
+ The server forwards the caller's Bearer token directly to the Runpod API as the credential for that request. There is no server-side or shared key.
124
+
125
+ The token can be either:
126
+
127
+ - a Runpod API key the caller configured manually, or
128
+ - a Runpod API key obtained through the OAuth "Sign in with Runpod" flow (see below).
129
+
130
+ 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. A caller that brings its own API key as the bearer token never hits that path.
131
+
132
+ ### Sign in with Runpod (authorize flow)
133
+
134
+ In OAuth mode the hosted server is itself the authorization server for Claude's connector. It advertises itself in `/.well-known/oauth-protected-resource` and `/.well-known/oauth-authorization-server`, pointing `authorization_endpoint` at its own `GET /authorize`, `token_endpoint` at its own `POST /token`, and `registration_endpoint` at its own `POST /register`.
135
+
136
+ The flow reuses the Runpod flash auth backend and mints a real Runpod API key:
137
+
138
+ 1. The client registers via `POST /register` (OAuth Dynamic Client Registration, RFC 7591) to obtain a `client_id`. This is a public client; no client secret is used.
139
+ 2. `GET /authorize` calls the guest `createFlashAuthRequest` mutation to get a request id (which serves as the OAuth authorization code), then `302`-redirects the browser to the console handoff page (`/integrations/mcp/login`), carrying the request id plus the client's `redirect_uri` and `state`.
140
+ 3. The user logs in and approves the request in the console. On approval the backend mints a Runpod API key for the request.
141
+ 4. The console returns the browser to the client's `redirect_uri` with `code=<request id>`.
142
+ 5. `POST /token` polls the guest `flashAuthRequestStatus` query for that id; once `APPROVED`, it returns the minted `apiKey` as the `access_token`. The client then sends that key as its bearer token on every MCP request, and the server forwards it to the Runpod API.
143
+
144
+ This flow uses these environment variables:
145
+
146
+ - `RUNPOD_GRAPHQL_URL`: flash auth backend endpoint (default `https://api.runpod.io/graphql`).
147
+ - `CONSOLE_BASE_URL`: base URL of the console that hosts the handoff login page (default `https://console.runpod.io`).
148
+ - `RUNPOD_REST_API_URL` / `RUNPOD_SERVERLESS_API_URL`: override the REST and Serverless API hosts so a deployment authenticating with non-production keys can target the matching environment.
149
+ - `RUNPOD_API_KEY_NAME`: name for the minted key as shown in the user's dashboard. Defaults to `runpod-mcp`. Set it to `""` to omit the name for a backend that does not support the `apiKeyName` argument (such backends reject the request when it is sent).
150
+ - `MCP_ALLOWED_REDIRECT_URIS`: comma-separated extra `redirect_uri` values to allow, in addition to the built-in Claude callbacks. Loopback addresses (`localhost`/`127.0.0.1`/`::1`, any port) are always allowed. `/authorize` and `/token` reject any `redirect_uri` not on this list, since the authorization code redeems into a real API key.
151
+
152
+ You can verify the entire flow end to end with `MCP_SERVER_URL=<deployment-url> npx tsx scripts/oauth-e2e.ts` (the harness uses a loopback callback).
153
+
154
+ Notes and current limitations:
155
+
156
+ - PKCE is not supported: `code_challenge` is neither advertised nor enforced (the flash flow has no place to bind it). Security relies on the `redirect_uri` allowlist and the single-use, short-lived flash approval.
157
+ - The minted key is named via `RUNPOD_API_KEY_NAME` (default `runpod-mcp`), which requires a flash backend that supports the `apiKeyName` argument. Against a backend without it, set `RUNPOD_API_KEY_NAME=""`.
158
+
159
+ ### Vercel
160
+
161
+ This repo already contains `vercel.json` and the Vercel handler.
162
+
163
+ Deploy with the Vercel CLI:
164
+
165
+ ```bash
166
+ vercel
167
+ vercel --prod
168
+ ```
169
+
170
+ After deploy, test the endpoint:
171
+
172
+ ```bash
173
+ curl -i https://YOUR-DEPLOYMENT.vercel.app/
174
+ ```
175
+
176
+ Unauthenticated requests should return `401`.
177
+
178
+ ### Hosted smoke test
179
+
180
+ ```bash
181
+ MCP_SERVER_URL=https://YOUR-DEPLOYMENT.vercel.app \
182
+ RUNPOD_API_KEY=YOUR_API_KEY \
183
+ pnpm smoke:http
184
+ ```
185
+
186
+ This validates:
187
+
188
+ - MCP initialization.
189
+ - `tools/list`.
190
+ - A public GraphQL-backed tool call.
191
+ - An authenticated REST-backed tool call.
192
+
193
+ ## Claude Desktop and hosted MCP
194
+
195
+ Use the local `stdio` integration for Claude Desktop today.
196
+
197
+ 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.
198
+
199
+ ## Local development
200
+
201
+ ```bash
202
+ git clone https://github.com/runpod/runpod-mcp.git
203
+ cd runpod-mcp
204
+ pnpm install
205
+ pnpm build
69
206
  ```
70
207
 
71
- ### Create a new pod
208
+ Run the local build directly:
72
209
 
210
+ ```bash
211
+ RUNPOD_API_KEY=YOUR_API_KEY node dist/stdio.mjs
73
212
  ```
74
- Create a new Runpod pod with the following specifications:
213
+
214
+ Or point a client at your local build:
215
+
216
+ ```json
217
+ {
218
+ "command": "node",
219
+ "args": ["/absolute/path/to/runpod-mcp/dist/stdio.mjs"],
220
+ "env": {
221
+ "RUNPOD_API_KEY": "YOUR_API_KEY"
222
+ }
223
+ }
224
+ ```
225
+
226
+ ### Local smoke test
227
+
228
+ ```bash
229
+ RUNPOD_API_KEY=YOUR_API_KEY pnpm build
230
+ RUNPOD_API_KEY=YOUR_API_KEY pnpm smoke:stdio
231
+ ```
232
+
233
+ ## Usage examples
234
+
235
+ ### List all Pods
236
+
237
+ ```text
238
+ Can you list all my Runpod Pods?
239
+ ```
240
+
241
+ ### Create a new Pod
242
+
243
+ ```text
244
+ Create a new Runpod Pod with the following specifications:
75
245
  - Name: test-pod
76
246
  - Image: runpod/pytorch:2.1.0-py3.10-cuda11.8.0-devel-ubuntu22.04
77
247
  - GPU Type: NVIDIA GeForce RTX 4090
78
248
  - GPU Count: 1
79
249
  ```
80
250
 
81
- ### Create a serverless endpoint
251
+ ### Create a Serverless endpoint
82
252
 
83
- ```
84
- Create a Runpod serverless endpoint with the following configuration:
253
+ ```text
254
+ Create a Runpod Serverless endpoint with the following configuration:
85
255
  - Name: my-endpoint
86
256
  - Template ID: 30zmvf89kd
87
257
  - Minimum workers: 0
88
258
  - Maximum workers: 3
89
259
  ```
90
260
 
91
- ## Security Considerations
261
+ ## Contributing
262
+
263
+ The source is now split by responsibility:
264
+
265
+ - `src/stdio.ts`: local `stdio` entrypoint.
266
+ - `src/http.ts`: bearer-token extraction and the per-request MCP session for the Streamable HTTP transport.
267
+ - `src/tools.ts`: all Runpod MCP tools.
268
+ - `src/server.ts`: shared server metadata and construction.
269
+ - `api/index.ts`: Vercel adapter and the OAuth authorization-server routes (`/.well-known/*`, `/register`, `/authorize`, `/token`).
270
+
271
+ After changes:
272
+
273
+ ```bash
274
+ pnpm type-check
275
+ pnpm lint
276
+ pnpm build
277
+ ```
278
+
279
+ For transport validation:
280
+
281
+ ```bash
282
+ pnpm smoke:stdio
283
+ pnpm smoke:http
284
+ ```
285
+
286
+ 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`.
287
+
288
+ See `CLAUDE.md` and `docs/context.md` for contributor guidance.
289
+
290
+ ## Security considerations
92
291
 
93
- This server requires your Runpod API key, which grants full access to your Runpod account. For security:
292
+ This server acts with the full permissions of the supplied `RUNPOD_API_KEY`.
94
293
 
95
- - Never share your API key
96
- - Be cautious about what operations you perform
97
- - Consider setting up a separate API key with limited permissions
98
- - Don't use this in a production environment without proper security measures
294
+ - Never share your API key.
295
+ - Be deliberate about destructive tools.
296
+ - Treat hosted deployments as sensitive infrastructure.
297
+ - Each request authenticates with its own caller-supplied token, which is forwarded to the Runpod API and never persisted server-side.
99
298
 
100
299
  ## License
101
300