@transloadit/mcp-server 0.4.1 → 0.5.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.
Files changed (58) hide show
  1. package/README.md +246 -80
  2. package/dist/cli.js +48 -2
  3. package/dist/cli.js.map +1 -1
  4. package/dist/express.d.ts.map +1 -1
  5. package/dist/express.js +25 -12
  6. package/dist/express.js.map +1 -1
  7. package/dist/http-helpers.d.ts +88 -0
  8. package/dist/http-helpers.d.ts.map +1 -1
  9. package/dist/http-helpers.js +193 -3
  10. package/dist/http-helpers.js.map +1 -1
  11. package/dist/http-request-handler.d.ts +1 -0
  12. package/dist/http-request-handler.d.ts.map +1 -1
  13. package/dist/http-request-handler.js +9 -19
  14. package/dist/http-request-handler.js.map +1 -1
  15. package/dist/http.d.ts +2 -0
  16. package/dist/http.d.ts.map +1 -1
  17. package/dist/http.js +25 -49
  18. package/dist/http.js.map +1 -1
  19. package/dist/json.d.ts +5 -0
  20. package/dist/json.d.ts.map +1 -0
  21. package/dist/json.js +14 -0
  22. package/dist/json.js.map +1 -0
  23. package/dist/logger.d.ts.map +1 -1
  24. package/dist/logger.js +4 -1
  25. package/dist/logger.js.map +1 -1
  26. package/dist/options.d.ts +10 -0
  27. package/dist/options.d.ts.map +1 -0
  28. package/dist/options.js +26 -0
  29. package/dist/options.js.map +1 -0
  30. package/dist/request-transport.d.ts +21 -0
  31. package/dist/request-transport.d.ts.map +1 -0
  32. package/dist/request-transport.js +129 -0
  33. package/dist/request-transport.js.map +1 -0
  34. package/dist/server-card.d.ts +20 -7
  35. package/dist/server-card.d.ts.map +1 -1
  36. package/dist/server-card.js +41 -16
  37. package/dist/server-card.js.map +1 -1
  38. package/dist/server.d.ts +35 -0
  39. package/dist/server.d.ts.map +1 -1
  40. package/dist/server.js +419 -81
  41. package/dist/server.js.map +1 -1
  42. package/dist/tool-list.d.ts +9 -0
  43. package/dist/tool-list.d.ts.map +1 -0
  44. package/dist/tool-list.js +44 -0
  45. package/dist/tool-list.js.map +1 -0
  46. package/dist/tool-metadata.d.ts +53 -0
  47. package/dist/tool-metadata.d.ts.map +1 -0
  48. package/dist/tool-metadata.js +147 -0
  49. package/dist/tool-metadata.js.map +1 -0
  50. package/dist/ui/assembly-result-widget.d.ts +38 -0
  51. package/dist/ui/assembly-result-widget.d.ts.map +1 -0
  52. package/dist/ui/assembly-result-widget.js +415 -0
  53. package/dist/ui/assembly-result-widget.js.map +1 -0
  54. package/dist/upload-instructions.d.ts +29 -0
  55. package/dist/upload-instructions.d.ts.map +1 -0
  56. package/dist/upload-instructions.js +60 -0
  57. package/dist/upload-instructions.js.map +1 -0
  58. package/package.json +3 -2
package/README.md CHANGED
@@ -2,23 +2,134 @@
2
2
 
3
3
  Transloadit MCP Server (Streamable HTTP + stdio), built on top of `@transloadit/node`.
4
4
 
5
- ## Install
5
+ ## Connect by URL (recommended)
6
+
7
+ The hosted server lives at:
8
+
9
+ ```text
10
+ https://api2.transloadit.com/mcp
11
+ ```
12
+
13
+ Add it to your MCP client by URL. The client discovers API2 as the OAuth authorization server,
14
+ opens a browser consent page in the Transloadit Console, and keeps a short-lived token plus refresh
15
+ token for you. No API keys leave your Workspace.
16
+
17
+ The hosted endpoint asks you to sign in before any tool runs, Robot docs and linting included,
18
+ because MCP clients only start OAuth when the endpoint challenges them. Robot docs and linting ask
19
+ for no scopes. To use them without an account, run the server yourself (see Self-hosted).
20
+
21
+ ### Claude Code
6
22
 
7
23
  ```bash
8
- npm install @transloadit/mcp-server
24
+ claude mcp add --transport http transloadit https://api2.transloadit.com/mcp
25
+ claude mcp login transloadit
26
+ ```
27
+
28
+ For non-interactive runs (for example `claude -p`), explicitly allow MCP tools:
29
+
30
+ ```bash
31
+ claude -p "List templates" \
32
+ --allowedTools mcp__transloadit__* \
33
+ --output-format json
34
+ ```
35
+
36
+ ### Claude.ai and Claude Desktop
37
+
38
+ Settings → Connectors → Add custom connector → enter `https://api2.transloadit.com/mcp`. Claude
39
+ registers itself with API2 and opens the consent page.
40
+
41
+ ### ChatGPT
42
+
43
+ Settings → Apps & Connectors → Advanced → Developer mode → Create, then enter the URL above with
44
+ authentication set to OAuth. Files you attach in the chat are handed to
45
+ `transloadit_create_assembly` as `attachments`; results render in the Assembly result widget.
46
+
47
+ The plugin manifest for the ChatGPT and Codex catalog (`plugin.json`, `mcp.json` and the
48
+ `.codex-plugin/plugin.json` fallback) lives in this package directory. It points at the hosted
49
+ server and at the Agent Skills catalog at `https://transloadit.com/.well-known/skills/index.json`
50
+ instead of bundling skill files.
51
+
52
+ ### Codex
53
+
54
+ ```bash
55
+ codex mcp add transloadit --url https://api2.transloadit.com/mcp
56
+ ```
57
+
58
+ Codex opens the consent page right away. To sign in again later, run
59
+ `codex mcp login transloadit`.
60
+
61
+ Or in `~/.codex/config.toml`:
62
+
63
+ ```toml
64
+ [mcp_servers.transloadit]
65
+ url = "https://api2.transloadit.com/mcp"
66
+ ```
67
+
68
+ ### Cursor
69
+
70
+ `~/.cursor/mcp.json`:
71
+
72
+ ```json
73
+ {
74
+ "mcpServers": {
75
+ "transloadit": {
76
+ "url": "https://api2.transloadit.com/mcp"
77
+ }
78
+ }
79
+ }
80
+ ```
81
+
82
+ ### MCP Inspector
83
+
84
+ ```bash
85
+ npx @modelcontextprotocol/inspector --cli https://api2.transloadit.com/mcp
86
+ ```
87
+
88
+ ## CI and headless agents
89
+
90
+ Where no browser is available, mint a bearer token from an Auth Key and pass it as
91
+ `Authorization: Bearer <token>`:
92
+
93
+ ```bash
94
+ npx -y @transloadit/node auth token --aud mcp
9
95
  ```
10
96
 
11
- ## Quick start (self-hosted, recommended)
97
+ Generate this token in a trusted environment (backend, CI, or local shell), then hand it to the
98
+ agent runtime. You can mint it via:
99
+
100
+ - CLI: `npx -y @transloadit/node auth token --aud mcp`
101
+ - API: `POST https://api2.transloadit.com/token` (HTTP Basic Auth with key/secret)
102
+ - Node SDK: instantiate `Transloadit` with `authKey` + `authSecret`, then call
103
+ `client.mintBearerToken({ aud: 'mcp' })`
104
+
105
+ Interactive CLI sessions can also run `npx -y @transloadit/node auth login` (device flow) and reuse
106
+ the stored credentials.
107
+
108
+ Bearer tokens satisfy signature auth on API2 requests; signature checks apply to key/secret
109
+ requests.
110
+
111
+ ## Self-hosted
12
112
 
13
- For most teams, self-hosted MCP is the simplest happy path: run the server where your agent runs,
14
- set `TRANSLOADIT_KEY` and `TRANSLOADIT_SECRET`, and the server handles API auth automatically.
113
+ Run the server where your agent runs, set `TRANSLOADIT_KEY` and `TRANSLOADIT_SECRET`, and the server
114
+ handles API auth automatically.
15
115
 
16
- ### Stdio (recommended)
116
+ ### Install
117
+
118
+ ```bash
119
+ npm install @transloadit/mcp-server
120
+ ```
121
+
122
+ ### Stdio
17
123
 
18
124
  ```bash
19
125
  TRANSLOADIT_KEY=MY_AUTH_KEY TRANSLOADIT_SECRET=MY_SECRET_KEY npx -y @transloadit/mcp-server stdio
20
126
  ```
21
127
 
128
+ Auth Keys sign with one HMAC algorithm. Keys created in the Console with "Allow signing Smart CDN
129
+ URLs" (the default) require `sha256`, so add `TRANSLOADIT_SIGNATURE_ALGORITHM=sha256`, as the
130
+ Console's snippet for the key shows. Other keys use the default `sha384`. A mismatch fails with
131
+ `mcp_invalid_signature`, and its hint names the algorithm the key requires.
132
+
22
133
  ### HTTP
23
134
 
24
135
  ```bash
@@ -26,7 +137,8 @@ TRANSLOADIT_KEY=MY_AUTH_KEY TRANSLOADIT_SECRET=MY_SECRET_KEY \
26
137
  npx -y @transloadit/mcp-server http --host 127.0.0.1 --port 5723
27
138
  ```
28
139
 
29
- When binding HTTP mode to non-localhost hosts, `TRANSLOADIT_MCP_TOKEN` is required.
140
+ When binding HTTP mode to non-localhost hosts, `TRANSLOADIT_MCP_TOKEN` (or the hosted-mode
141
+ `TRANSLOADIT_MCP_RESOURCE_METADATA_URL`) is required.
30
142
 
31
143
  ### Docker
32
144
 
@@ -37,15 +149,19 @@ docker run -i --rm \
37
149
  ghcr.io/transloadit/mcp-server:latest
38
150
  ```
39
151
 
40
- For HTTP mode via Docker, expose the port:
152
+ For HTTP mode via Docker, override the `stdio` entrypoint, expose the port, and set a transport
153
+ token, which binding to `0.0.0.0` requires:
41
154
 
42
155
  ```bash
156
+ export TRANSLOADIT_MCP_TOKEN="$(openssl rand -hex 32)"
43
157
  docker run --rm \
44
158
  -e TRANSLOADIT_KEY=MY_AUTH_KEY \
45
159
  -e TRANSLOADIT_SECRET=MY_SECRET_KEY \
160
+ -e TRANSLOADIT_MCP_TOKEN \
46
161
  -p 5723:5723 \
162
+ --entrypoint transloadit-mcp \
47
163
  ghcr.io/transloadit/mcp-server:latest \
48
- transloadit-mcp http --host 0.0.0.0 --port 5723
164
+ http --host 0.0.0.0 --port 5723
49
165
  ```
50
166
 
51
167
  ### `TRANSLOADIT_MCP_TOKEN` explained
@@ -65,36 +181,11 @@ export TRANSLOADIT_MCP_TOKEN="$(openssl rand -hex 32)"
65
181
  npx -y @transloadit/mcp-server http --host 0.0.0.0 --port 5723
66
182
  ```
67
183
 
68
- ## Hosted endpoint
69
-
70
- If you cannot run `npx` where the agent runs, use the hosted endpoint:
71
-
72
- ```text
73
- https://api2.transloadit.com/mcp
74
- ```
75
-
76
- Use `Authorization: Bearer <token>`. Mint a token with:
77
-
78
- ```bash
79
- npx -y @transloadit/node auth token --aud mcp
80
- ```
81
-
82
- Generate this token in a trusted environment (backend, CI, or local shell), then hand it to the
83
- agent runtime. You can mint it via:
184
+ ### Self-hosted client setup
84
185
 
85
- - CLI: `npx -y @transloadit/node auth token --aud mcp`
86
- - API: `POST https://api2.transloadit.com/token` (HTTP Basic Auth with key/secret)
87
- - Node SDK: instantiate `Transloadit` with `authKey` + `authSecret`, then call
88
- `client.mintBearerToken({ aud: 'mcp' })`
186
+ Most self-hosted users add the server to their MCP client and let the client start it via stdio.
89
187
 
90
- Bearer tokens satisfy signature auth on API2 requests; signature checks apply to key/secret
91
- requests.
92
-
93
- ## Agent client setup
94
-
95
- Most users add the server to their MCP client and let the client start it automatically via stdio.
96
-
97
- ### Claude Code
188
+ #### Claude Code
98
189
 
99
190
  ```bash
100
191
  claude mcp add --transport stdio transloadit \
@@ -103,15 +194,7 @@ claude mcp add --transport stdio transloadit \
103
194
  -- npx -y @transloadit/mcp-server stdio
104
195
  ```
105
196
 
106
- For non-interactive runs (for example `claude -p`), explicitly allow MCP tools:
107
-
108
- ```bash
109
- claude -p "List templates" \
110
- --allowedTools mcp__transloadit__* \
111
- --output-format json
112
- ```
113
-
114
- ### Codex CLI
197
+ #### Codex CLI
115
198
 
116
199
  ```bash
117
200
  codex mcp add transloadit \
@@ -129,7 +212,7 @@ args = ["-y", "@transloadit/mcp-server", "stdio"]
129
212
  enabled_tools = ["transloadit_list_templates"]
130
213
  ```
131
214
 
132
- ### Gemini CLI
215
+ #### Gemini CLI
133
216
 
134
217
  ```bash
135
218
  gemini mcp add --scope user transloadit npx -y @transloadit/mcp-server stdio \
@@ -155,7 +238,7 @@ Allowlist tools in `~/.gemini/settings.json`:
155
238
  }
156
239
  ```
157
240
 
158
- ### Cursor
241
+ #### Cursor
159
242
 
160
243
  `~/.cursor/mcp.json`:
161
244
 
@@ -174,7 +257,7 @@ Allowlist tools in `~/.gemini/settings.json`:
174
257
  }
175
258
  ```
176
259
 
177
- ### OpenCode
260
+ #### OpenCode
178
261
 
179
262
  `~/.config/opencode/opencode.json`:
180
263
 
@@ -193,27 +276,31 @@ Allowlist tools in `~/.gemini/settings.json`:
193
276
  }
194
277
  ```
195
278
 
196
- ## Run the server manually
197
-
198
- HTTP:
199
-
200
- ```bash
201
- npx -y @transloadit/mcp-server http --host 127.0.0.1 --port 5723
202
- ```
203
-
204
- Stdio:
205
-
206
- ```bash
207
- npx -y @transloadit/mcp-server stdio
208
- ```
209
-
210
279
  ## Auth model
211
280
 
212
281
  ### Hosted (`https://api2.transloadit.com/mcp`)
213
282
 
214
- - Mint token via `POST https://api2.transloadit.com/token`.
215
- - Send `Authorization: Bearer <access_token>`.
216
- - Bearer auth satisfies signature auth; signature checks apply to key/secret requests.
283
+ - Requests without a bearer token get `401` with
284
+ `WWW-Authenticate: Bearer resource_metadata="https://api2.transloadit.com/.well-known/oauth-protected-resource/mcp"`.
285
+ MCP clients follow that document to API2's authorization server (authorization code + PKCE,
286
+ Dynamic Client Registration or Client ID Metadata Documents).
287
+ - This includes a bare `GET /mcp`, because some clients (Codex) discover the authorization server
288
+ from that probe. Directory health checks therefore see `401` instead of `200`; the JSON body
289
+ still carries `name`, `status` and `docs`. Self-hosted and unauthenticated deployments keep
290
+ answering the bare `GET` with `200`.
291
+ - Bearer tokens (OAuth or minted with `--aud mcp`) are forwarded to API2, which verifies them on
292
+ every call. A rejected or expired token yields a tool result with `isError` and
293
+ `_meta["mcp/www_authenticate"]`, so ChatGPT and Claude prompt you to reconnect.
294
+ - Each tool declares `securitySchemes` (top level and in `_meta`). Because the hosted endpoint
295
+ challenges every unauthenticated request, all tools declare `oauth2` there; the Robot docs and
296
+ linting tools ask for no scopes.
297
+ - A rejected or expired key/secret on a self-hosted server is reported as
298
+ `mcp_credentials_rejected` without an OAuth challenge, since only an operator can fix it.
299
+ - Browser requests must come from ChatGPT, Claude, Transloadit or loopback origins; requests without
300
+ an `Origin` header (CLIs, servers) are not restricted. Set `allowedOrigins` to change the list.
301
+ - `TRANSLOADIT_MCP_UPSTREAM_SECRET` is set by Transloadit's own deployment so API2 can tell that a
302
+ relayed `aud=mcp` token arrives from the hosted service; it is not needed for self-hosting.
303
+ Hosted mode refuses to start without it, because every authenticated call would fail.
217
304
 
218
305
  ### Self-hosted
219
306
 
@@ -229,7 +316,17 @@ npx -y @transloadit/mcp-server stdio
229
316
 
230
317
  - `TRANSLOADIT_KEY`
231
318
  - `TRANSLOADIT_SECRET`
319
+ - `TRANSLOADIT_SIGNATURE_ALGORITHM` (optional, `sha1`, `sha256` or `sha384`, default `sha384`;
320
+ must match the Auth Key)
232
321
  - `TRANSLOADIT_MCP_TOKEN`
322
+ - `TRANSLOADIT_MCP_RESOURCE_METADATA_URL` (hosted mode: protected-resource metadata URL to
323
+ advertise in `401` challenges)
324
+ - `TRANSLOADIT_MCP_UPSTREAM_SECRET` (hosted mode only, set by Transloadit's deployment; sent to
325
+ API2 as `Transloadit-Mcp-Upstream` next to forwarded bearer tokens)
326
+ - `TRANSLOADIT_MCP_RESULT_DOMAINS` (optional, comma-separated origins the result widget may load
327
+ previews from; default `https://*.transloadit.com,https://*.transloadit.net,https://*.r2.dev`)
328
+ - `TRANSLOADIT_MCP_CONSOLE_URL` (optional, default `https://transloadit.com`; Console origin for
329
+ widget deep links)
233
330
  - `TRANSLOADIT_ENDPOINT` (optional, default `https://api2.transloadit.com`)
234
331
  - `TRANSLOADIT_MCP_METRICS_PATH` (optional, default `/metrics`)
235
332
  - `TRANSLOADIT_MCP_METRICS_USER` (optional)
@@ -241,21 +338,50 @@ npx -y @transloadit/mcp-server stdio
241
338
  - `npx -y @transloadit/mcp-server http --endpoint https://api2.transloadit.com`
242
339
  - `npx -y @transloadit/mcp-server http --config path/to/config.json`
243
340
 
341
+ The JSON config accepts the same keys as `createTransloaditMcpHttpHandler()`, including
342
+ `allowedOrigins`, `resourceMetadataUrl`, `signatureAlgorithm`, `resultDomains` and `consoleUrl`.
343
+
244
344
  ## Tool surface
245
345
 
246
- - `transloadit_lint_assembly_instructions`
247
- - `transloadit_create_assembly`
248
- - `transloadit_get_assembly_status`
249
- - `transloadit_wait_for_assembly`
250
- - `transloadit_list_robots`
251
- - `transloadit_get_robot_help`
252
- - `transloadit_list_templates`
346
+ | Tool | Account | OAuth scopes | Notes |
347
+ | ---------------------------------------- | ------- | ------------------------------------ | ----------------------------------------------- |
348
+ | `transloadit_lint_assembly_instructions` | no | none | read-only |
349
+ | `transloadit_list_robots` | no | none | read-only |
350
+ | `transloadit_get_robot_help` | no | none | read-only |
351
+ | `transloadit_create_assembly` | yes | `assemblies:write`, `templates:read` | destructive, open-world (URL imports), widget |
352
+ | `transloadit_get_assembly_status` | yes | `assemblies:read` | read-only |
353
+ | `transloadit_wait_for_assembly` | yes | `assemblies:read` | read-only, result widget |
354
+ | `transloadit_list_templates` | yes | `templates:read` | read-only |
355
+ | `transloadit_get_profile` | yes | `assemblies:read`, `templates:read` | read-only, `_meta["openai/profile"]` |
356
+
357
+ Every tool carries `title`, `readOnlyHint`, `destructiveHint`, `idempotentHint` and
358
+ `openWorldHint` annotations. `transloadit_create_assembly` is the only destructive one: export
359
+ Robots such as `/s3/store` can overwrite files at their destination, so hosts should confirm it.
360
+
361
+ `securitySchemes` depend on how the server runs: hosted (`TRANSLOADIT_MCP_RESOURCE_METADATA_URL`)
362
+ declares `oauth2` with the scopes above for every tool; a server holding `TRANSLOADIT_KEY` and
363
+ `TRANSLOADIT_SECRET` declares `noauth` everywhere; otherwise the account tools declare `oauth2` and
364
+ the others `noauth`. `TRANSLOADIT_MCP_TOKEN` and `TRANSLOADIT_MCP_RESOURCE_METADATA_URL` cannot be
365
+ combined.
253
366
 
254
367
  `transloadit_list_templates` supports:
255
368
 
256
369
  - `include_builtin`: `all`, `latest`, `exclusively-all`, `exclusively-latest`
257
370
  - `include_content`: include parsed `steps` in each template item
258
371
 
372
+ `transloadit_get_profile` returns `{ id, name?, nickname? }` for the Workspace behind the current
373
+ credentials, derived from the Workspace's own Assemblies or Templates.
374
+
375
+ ### Result widget
376
+
377
+ `transloadit_create_assembly` and `transloadit_wait_for_assembly` link the MCP Apps resource
378
+ `ui://transloadit/assembly-result` (`_meta.ui.resourceUri`, also `_meta["openai/outputTemplate"]`).
379
+ Hosts that support MCP Apps render each Step's results with image, video and audio previews,
380
+ download links, an "Open in Console" link and a "Save as Template" shortcut. It speaks the MCP Apps
381
+ `2026-01-26` protocol (`ui/initialize` with `appInfo`) and also reads ChatGPT's `window.openai`.
382
+ Its CSP allows `https://*.transloadit.com`, `https://*.transloadit.net` and `https://*.r2.dev`
383
+ (result buckets); override the list with `TRANSLOADIT_MCP_RESULT_DOMAINS` or `resultDomains`.
384
+
259
385
  ## Input files
260
386
 
261
387
  ```ts
@@ -276,14 +402,57 @@ export type InputFile =
276
402
  }
277
403
  ```
278
404
 
405
+ Hosts that attach chat files (ChatGPT) pass them under `attachments` instead, as declared by
406
+ `_meta["openai/fileParams"]`:
407
+
408
+ ```ts
409
+ type Attachment = {
410
+ download_url: string
411
+ file_id: string
412
+ mime_type?: string
413
+ file_name?: string
414
+ }
415
+ ```
416
+
417
+ Each attachment becomes a URL input (`attachment_1`, `attachment_2`, …) and follows the URL rules
418
+ below.
419
+
420
+ ### Files that exist only locally or in your sandbox
421
+
422
+ If the file exists only locally or in your sandbox, call `transloadit_create_assembly` with
423
+ `expected_uploads` and run the returned `upload_instructions`; this needs outbound HTTPS from the
424
+ sandbox to Transloadit (Claude.ai: Settings → code execution network access must allow it). Hosts
425
+ such as Claude.ai do not hand chat attachments to connector tools, and base64 in tool arguments is
426
+ impractical for anything but tiny files, so the agent uploads the file itself:
427
+
428
+ 1. Call `transloadit_create_assembly` with your instructions and `expected_uploads: 1` (one per
429
+ file, at most 100 per call). The call returns right away, even with `wait_for_completion: true`,
430
+ because the Assembly now waits for those uploads.
431
+ 2. Each `upload_instructions` entry has the tus endpoint, the tus metadata (`assembly_url`,
432
+ `fieldname`) and a ready-to-run `curl` command. Set `FILE` to the file's path and run it in a
433
+ bash shell; it prints `201` once the file is uploaded (tus creation-with-upload, one request).
434
+ 3. Call `transloadit_wait_for_assembly` with the Assembly URL.
435
+
436
+ The commands contain no credentials: the Assembly URL is the only capability, and it lets the holder
437
+ add files to that one Assembly while it waits for uploads.
438
+
279
439
  ## Limits
280
440
 
281
441
  These limits apply to inline JSON/base64 payloads. For larger files, use a public URL or upload from
282
442
  your own machine with `npx -y @transloadit/node upload`.
283
443
 
284
- - Hosted default request body limit: **1 MB**
444
+ - Hosted default request body limit: **1 MiB**
285
445
  - Hosted `maxBase64Bytes`: **512,000** decoded bytes
286
- - Self-hosted default request body limit: **10 MB** (configurable)
446
+ - Self-hosted default request body limit: **10 MiB**
447
+
448
+ Set `maxRequestBodyBytes` (handler option or JSON config key) to change the body limit; larger
449
+ requests get HTTP 413 and are not buffered. Express apps that install their own body parser set
450
+ its limit there.
451
+
452
+ URL inputs that the server downloads (for templates that expect uploads) are capped at 1 GiB in
453
+ total per call and 10 minutes per download, redirects included; set `maxUrlDownloadBytes` and
454
+ `urlDownloadTimeoutMs` to change that. On the hosted
455
+ endpoint the caller's token is checked with API2 before anything is downloaded.
287
456
 
288
457
  ## URL inputs and template behavior
289
458
 
@@ -329,7 +498,8 @@ but this does not enable private-network URL file downloads.
329
498
  - Disable via `metricsPath: false`.
330
499
  - Optional metrics basic auth via `TRANSLOADIT_MCP_METRICS_USER` +
331
500
  `TRANSLOADIT_MCP_METRICS_PASSWORD` or `metricsAuth`.
332
- - Public discovery endpoint at `/.well-known/mcp/server-card.json`.
501
+ - Public discovery endpoint at `/.well-known/mcp/server-card.json`, listing every tool with its
502
+ annotations and security schemes and, in hosted mode, the OAuth resource metadata URL.
333
503
 
334
504
  ## MCP vs skills/CLI
335
505
 
@@ -388,7 +558,3 @@ corepack yarn --cwd packages/mcp-server test:e2e
388
558
  - Add or update tests with behavior changes.
389
559
  - Keep README and website docs aligned for user-facing behavior.
390
560
  - Open a PR in `transloadit/node-sdk`.
391
-
392
- ### Roadmap
393
-
394
- - Next.js Claude Web flow to mint and hand off bearer tokens for MCP.
package/dist/cli.js CHANGED
@@ -4,6 +4,7 @@ import { createServer } from 'node:http';
4
4
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
5
5
  import { createTransloaditMcpHttpHandler, createTransloaditMcpServer } from "./index.js";
6
6
  import { buildRedactor, getLogger } from "./logger.js";
7
+ import { signatureAlgorithmSchema } from "./server.js";
7
8
  const printHelp = () => {
8
9
  process.stdout.write(`transloadit-mcp
9
10
 
@@ -14,7 +15,12 @@ Usage:
14
15
  Environment:
15
16
  TRANSLOADIT_KEY
16
17
  TRANSLOADIT_SECRET
18
+ TRANSLOADIT_SIGNATURE_ALGORITHM (sha1, sha256 or sha384; must match the Auth Key)
17
19
  TRANSLOADIT_MCP_TOKEN
20
+ TRANSLOADIT_MCP_RESOURCE_METADATA_URL
21
+ TRANSLOADIT_MCP_UPSTREAM_SECRET
22
+ TRANSLOADIT_MCP_RESULT_DOMAINS (comma-separated origins for result previews)
23
+ TRANSLOADIT_MCP_CONSOLE_URL
18
24
  TRANSLOADIT_ENDPOINT
19
25
  TRANSLOADIT_MCP_METRICS_PATH
20
26
  TRANSLOADIT_MCP_METRICS_USER
@@ -66,6 +72,25 @@ const parseArgs = (args) => {
66
72
  }
67
73
  return { command, config };
68
74
  };
75
+ /** Reads the key/secret signature algorithm; an unknown value would only fail later per call. */
76
+ const parseSignatureAlgorithm = (value) => {
77
+ if (value === undefined || value === '')
78
+ return undefined;
79
+ const parsed = signatureAlgorithmSchema.safeParse(value);
80
+ if (!parsed.success) {
81
+ throw new Error('TRANSLOADIT_SIGNATURE_ALGORITHM must be one of sha1, sha256 or sha384.');
82
+ }
83
+ return parsed.data;
84
+ };
85
+ /** Accepts a JSON array (config file) or a comma-separated string (environment). */
86
+ const parseResultDomains = (value) => {
87
+ const entries = Array.isArray(value) ? value : typeof value === 'string' ? value.split(',') : [];
88
+ const domains = entries
89
+ .filter((entry) => typeof entry === 'string')
90
+ .map((entry) => entry.trim())
91
+ .filter(Boolean);
92
+ return domains.length > 0 ? domains : undefined;
93
+ };
69
94
  const isLocalHost = (host) => host === '127.0.0.1' || host === 'localhost' || host === '::1';
70
95
  const loadConfig = async (configPath) => {
71
96
  if (!configPath) {
@@ -100,9 +125,17 @@ const main = async () => {
100
125
  process.env.TRANSLOADIT_MCP_METRICS_PASSWORD);
101
126
  const endpoint = (config.endpoint ?? fileConfig.endpoint ?? process.env.TRANSLOADIT_ENDPOINT);
102
127
  const mcpToken = (fileConfig.mcpToken ?? process.env.TRANSLOADIT_MCP_TOKEN);
128
+ const resourceMetadataUrl = (fileConfig.resourceMetadataUrl ??
129
+ process.env.TRANSLOADIT_MCP_RESOURCE_METADATA_URL);
130
+ const upstreamSecret = (fileConfig.upstreamSecret ??
131
+ process.env.TRANSLOADIT_MCP_UPSTREAM_SECRET);
132
+ const consoleUrl = (fileConfig.consoleUrl ?? process.env.TRANSLOADIT_MCP_CONSOLE_URL);
133
+ const signatureAlgorithm = parseSignatureAlgorithm(fileConfig.signatureAlgorithm ?? process.env.TRANSLOADIT_SIGNATURE_ALGORITHM);
134
+ const resultDomains = parseResultDomains(fileConfig.resultDomains ?? process.env.TRANSLOADIT_MCP_RESULT_DOMAINS);
103
135
  const clientSuffix = process.env.TRANSLOADIT_CLIENT_SUFFIX;
104
- if (!isLocalHost(host) && !mcpToken) {
105
- throw new Error('TRANSLOADIT_MCP_TOKEN is required when binding to non-localhost host.');
136
+ // Hosted mode delegates token checks to API2, so it may bind publicly without a static token.
137
+ if (!isLocalHost(host) && !mcpToken && !resourceMetadataUrl) {
138
+ throw new Error('TRANSLOADIT_MCP_TOKEN or TRANSLOADIT_MCP_RESOURCE_METADATA_URL is required when binding to a non-localhost host.');
106
139
  }
107
140
  const handler = await createTransloaditMcpHttpHandler({
108
141
  authKey: (fileConfig.authKey ?? process.env.TRANSLOADIT_KEY),
@@ -110,6 +143,15 @@ const main = async () => {
110
143
  endpoint,
111
144
  clientSuffix,
112
145
  mcpToken,
146
+ resourceMetadataUrl,
147
+ upstreamSecret,
148
+ // Validated by the handler, which refuses anything but positive integers.
149
+ maxRequestBodyBytes: fileConfig.maxRequestBodyBytes,
150
+ maxUrlDownloadBytes: fileConfig.maxUrlDownloadBytes,
151
+ urlDownloadTimeoutMs: fileConfig.urlDownloadTimeoutMs,
152
+ signatureAlgorithm,
153
+ resultDomains,
154
+ consoleUrl,
113
155
  allowedOrigins: fileConfig.allowedOrigins,
114
156
  allowedHosts: fileConfig.allowedHosts,
115
157
  enableDnsRebindingProtection: fileConfig.enableDnsRebindingProtection,
@@ -136,7 +178,10 @@ const main = async () => {
136
178
  const server = createTransloaditMcpServer({
137
179
  authKey: process.env.TRANSLOADIT_KEY,
138
180
  authSecret: process.env.TRANSLOADIT_SECRET,
181
+ signatureAlgorithm: parseSignatureAlgorithm(process.env.TRANSLOADIT_SIGNATURE_ALGORITHM),
182
+ resultDomains: parseResultDomains(process.env.TRANSLOADIT_MCP_RESULT_DOMAINS),
139
183
  endpoint: process.env.TRANSLOADIT_ENDPOINT,
184
+ consoleUrl: process.env.TRANSLOADIT_MCP_CONSOLE_URL,
140
185
  clientSuffix: process.env.TRANSLOADIT_CLIENT_SUFFIX,
141
186
  });
142
187
  const transport = new StdioServerTransport();
@@ -148,6 +193,7 @@ main().catch((err) => {
148
193
  process.env.TRANSLOADIT_KEY,
149
194
  process.env.TRANSLOADIT_SECRET,
150
195
  process.env.TRANSLOADIT_MCP_TOKEN,
196
+ process.env.TRANSLOADIT_MCP_UPSTREAM_SECRET,
151
197
  ]);
152
198
  logger.err('MCP server failed: %s', redact(err));
153
199
  process.exit(1);
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"express.d.ts","sourceRoot":"","sources":["../src/express.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,WAAW,CAAA;AAU1D,MAAM,MAAM,4BAA4B,GAAG,yBAAyB,GAAG;IACrE,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,CAAA;AAED,wBAAgB,iCAAiC,CAAC,OAAO,GAAE,4BAAiC,8CA4F3F"}
1
+ {"version":3,"file":"express.d.ts","sourceRoot":"","sources":["../src/express.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,WAAW,CAAA;AAiB1D,MAAM,MAAM,4BAA4B,GAAG,yBAAyB,GAAG;IACrE,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,CAAA;AAED,wBAAgB,iCAAiC,CAAC,OAAO,GAAE,4BAAiC,8CAmG3F"}
package/dist/express.js CHANGED
@@ -1,19 +1,26 @@
1
- import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
2
1
  import express from 'express';
3
- import { isBasicAuthorized } from "./http-helpers.js";
2
+ import { applyCorsHeaders, assertHttpOptions, corsAllowHeaders, isBasicAuthorized, rejectMissingBearerToken, resolveAllowedOrigins, } from "./http-helpers.js";
4
3
  import { getMetrics, getMetricsContentType } from "./metrics.js";
4
+ import { createRequestTransport } from "./request-transport.js";
5
5
  import { createTransloaditMcpServer } from "./server.js";
6
6
  import { buildServerCard, serverCardPath } from "./server-card.js";
7
7
  export function createTransloaditMcpExpressRouter(options = {}) {
8
+ assertHttpOptions(options);
8
9
  const router = express.Router();
9
10
  const routePath = options.path ?? '/mcp';
10
11
  const metricsPath = options.metricsPath === false ? undefined : (options.metricsPath ?? '/metrics');
11
12
  const metricsAuth = options.metricsAuth;
12
- const serverCardJson = JSON.stringify(buildServerCard(routePath, { authKey: options.authKey, authSecret: options.authSecret }));
13
+ // Explicit `allowedOrigins` or hosted mode add an Origin policy here; embedders own CORS otherwise.
14
+ const allowedOrigins = resolveAllowedOrigins(options);
15
+ const serverCardJson = JSON.stringify(buildServerCard(routePath, {
16
+ authKey: options.authKey,
17
+ authSecret: options.authSecret,
18
+ resourceMetadataUrl: options.resourceMetadataUrl,
19
+ }));
13
20
  const sendServerCard = (res, includeBody) => {
14
21
  res.setHeader('Access-Control-Allow-Origin', '*');
15
22
  res.setHeader('Access-Control-Allow-Methods', 'GET,HEAD,OPTIONS');
16
- res.setHeader('Access-Control-Allow-Headers', 'Authorization,Content-Type,Mcp-Session-Id,Last-Event-ID');
23
+ res.setHeader('Access-Control-Allow-Headers', corsAllowHeaders);
17
24
  res.setHeader('Content-Type', 'application/json; charset=utf-8');
18
25
  res.setHeader('Cache-Control', 'public, max-age=3600');
19
26
  res.setHeader('X-Content-Type-Options', 'nosniff');
@@ -26,7 +33,7 @@ export function createTransloaditMcpExpressRouter(options = {}) {
26
33
  router.options(serverCardPath, (_req, res) => {
27
34
  res.setHeader('Access-Control-Allow-Origin', '*');
28
35
  res.setHeader('Access-Control-Allow-Methods', 'GET,HEAD,OPTIONS');
29
- res.setHeader('Access-Control-Allow-Headers', 'Authorization,Content-Type,Mcp-Session-Id,Last-Event-ID');
36
+ res.setHeader('Access-Control-Allow-Headers', corsAllowHeaders);
30
37
  res.status(204).end();
31
38
  });
32
39
  router.get(serverCardPath, (_req, res) => {
@@ -36,6 +43,17 @@ export function createTransloaditMcpExpressRouter(options = {}) {
36
43
  sendServerCard(res, false);
37
44
  });
38
45
  router.all(routePath, async (req, res) => {
46
+ if (allowedOrigins) {
47
+ if (!applyCorsHeaders(req, res, allowedOrigins))
48
+ return;
49
+ if (req.method === 'OPTIONS') {
50
+ res.status(204).end();
51
+ return;
52
+ }
53
+ }
54
+ // Any unauthenticated hosted method gets the OAuth challenge, so GET-probing clients find API2.
55
+ if (rejectMissingBearerToken(req, res, options.resourceMetadataUrl))
56
+ return;
39
57
  if (req.method !== 'POST') {
40
58
  res.status(405).json({
41
59
  jsonrpc: '2.0',
@@ -44,19 +62,14 @@ export function createTransloaditMcpExpressRouter(options = {}) {
44
62
  });
45
63
  return;
46
64
  }
47
- const transport = new StreamableHTTPServerTransport({
48
- sessionIdGenerator: undefined,
49
- allowedOrigins: options.allowedOrigins,
50
- allowedHosts: options.allowedHosts,
51
- enableDnsRebindingProtection: options.enableDnsRebindingProtection,
52
- });
65
+ const { transport, handle } = createRequestTransport(options);
53
66
  const server = createTransloaditMcpServer(options);
54
67
  res.on('close', () => {
55
68
  void transport.close();
56
69
  void server.close();
57
70
  });
58
71
  await server.connect(transport);
59
- await transport.handleRequest(req, res, req.body);
72
+ await handle(req, res, req.body);
60
73
  });
61
74
  if (metricsPath) {
62
75
  router.get(metricsPath, async (req, res) => {