@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.
- package/README.md +246 -80
- package/dist/cli.js +48 -2
- package/dist/cli.js.map +1 -1
- package/dist/express.d.ts.map +1 -1
- package/dist/express.js +25 -12
- package/dist/express.js.map +1 -1
- package/dist/http-helpers.d.ts +88 -0
- package/dist/http-helpers.d.ts.map +1 -1
- package/dist/http-helpers.js +193 -3
- package/dist/http-helpers.js.map +1 -1
- package/dist/http-request-handler.d.ts +1 -0
- package/dist/http-request-handler.d.ts.map +1 -1
- package/dist/http-request-handler.js +9 -19
- package/dist/http-request-handler.js.map +1 -1
- package/dist/http.d.ts +2 -0
- package/dist/http.d.ts.map +1 -1
- package/dist/http.js +25 -49
- package/dist/http.js.map +1 -1
- package/dist/json.d.ts +5 -0
- package/dist/json.d.ts.map +1 -0
- package/dist/json.js +14 -0
- package/dist/json.js.map +1 -0
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +4 -1
- package/dist/logger.js.map +1 -1
- package/dist/options.d.ts +10 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +26 -0
- package/dist/options.js.map +1 -0
- package/dist/request-transport.d.ts +21 -0
- package/dist/request-transport.d.ts.map +1 -0
- package/dist/request-transport.js +129 -0
- package/dist/request-transport.js.map +1 -0
- package/dist/server-card.d.ts +20 -7
- package/dist/server-card.d.ts.map +1 -1
- package/dist/server-card.js +41 -16
- package/dist/server-card.js.map +1 -1
- package/dist/server.d.ts +35 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +419 -81
- package/dist/server.js.map +1 -1
- package/dist/tool-list.d.ts +9 -0
- package/dist/tool-list.d.ts.map +1 -0
- package/dist/tool-list.js +44 -0
- package/dist/tool-list.js.map +1 -0
- package/dist/tool-metadata.d.ts +53 -0
- package/dist/tool-metadata.d.ts.map +1 -0
- package/dist/tool-metadata.js +147 -0
- package/dist/tool-metadata.js.map +1 -0
- package/dist/ui/assembly-result-widget.d.ts +38 -0
- package/dist/ui/assembly-result-widget.d.ts.map +1 -0
- package/dist/ui/assembly-result-widget.js +415 -0
- package/dist/ui/assembly-result-widget.js.map +1 -0
- package/dist/upload-instructions.d.ts +29 -0
- package/dist/upload-instructions.d.ts.map +1 -0
- package/dist/upload-instructions.js +60 -0
- package/dist/upload-instructions.js.map +1 -0
- 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
|
-
##
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
14
|
-
|
|
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
|
-
###
|
|
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`
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
-
|
|
215
|
-
-
|
|
216
|
-
|
|
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
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
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
|
|
444
|
+
- Hosted default request body limit: **1 MiB**
|
|
285
445
|
- Hosted `maxBase64Bytes`: **512,000** decoded bytes
|
|
286
|
-
- Self-hosted default request body limit: **10
|
|
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
|
-
|
|
105
|
-
|
|
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":";
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/express.d.ts.map
CHANGED
|
@@ -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;
|
|
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
|
-
|
|
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',
|
|
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',
|
|
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 =
|
|
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
|
|
72
|
+
await handle(req, res, req.body);
|
|
60
73
|
});
|
|
61
74
|
if (metricsPath) {
|
|
62
75
|
router.get(metricsPath, async (req, res) => {
|