Skip to content

Commit 9ad04d4

Browse files
committed
docs(mcp-server): clarify hosted vs local uploads
1 parent f4af03a commit 9ad04d4

2 files changed

Lines changed: 42 additions & 21 deletions

File tree

packages/mcp-server/README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,14 @@ the request body stays small and no extra MCP/LLM token budget is consumed.
8787
- If instructions already contain an `/http/import` step, the MCP server sets/overrides its `url`.
8888
- If multiple URLs and a single `/http/import` step exists, it supplies a `url` array.
8989
90+
## Local vs hosted file access
91+
92+
- `path` inputs only work when the MCP server can read the same filesystem (local/stdio).
93+
- Hosted MCP cannot access your disk. Use `url`/`base64` for small files, or upload locally with:
94+
`npx @transloadit/node upload ./file.ext <tus_url> --assembly <assembly_url> --field :original`
95+
- For remote flows, create the Assembly with `expected_uploads` so it stays open for out‑of‑band
96+
tus uploads.
97+
9098
## Resume behavior
9199
92100
If `assembly_url` is provided, the MCP server resumes uploads using Assembly status

packages/mcp-server/src/server.ts

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,9 @@ const createLiveClient = (
341341
const isRecord = (value: unknown): value is Record<string, unknown> =>
342342
typeof value === 'object' && value !== null
343343

344+
const isErrnoException = (value: unknown): value is NodeJS.ErrnoException =>
345+
isRecord(value) && typeof value.code === 'string'
346+
344347
const getAssemblyIdFromUrl = (assemblyUrl: string): string => {
345348
const match = assemblyUrl.match(/\/assemblies\/([^/?#]+)/)
346349
if (!match) {
@@ -551,28 +554,38 @@ export const createTransloaditMcpServer = (
551554
const uploadConcurrency = upload_concurrency
552555
const chunkSize = upload_chunk_size
553556

554-
const assembly = assembly_url
555-
? await client.resumeAssemblyUploads({
556-
assemblyUrl: assembly_url,
557-
files: filesMap,
558-
uploads: uploadsMap,
559-
waitForCompletion,
560-
timeout,
561-
uploadConcurrency,
562-
chunkSize,
563-
uploadBehavior,
564-
})
565-
: await client.createAssembly({
566-
params,
567-
files: filesMap,
568-
uploads: uploadsMap,
569-
waitForCompletion,
570-
timeout,
571-
uploadConcurrency,
572-
chunkSize,
573-
uploadBehavior,
574-
expectedUploads: expected_uploads,
557+
let assembly: Awaited<ReturnType<typeof client.createAssembly>>
558+
try {
559+
assembly = assembly_url
560+
? await client.resumeAssemblyUploads({
561+
assemblyUrl: assembly_url,
562+
files: filesMap,
563+
uploads: uploadsMap,
564+
waitForCompletion,
565+
timeout,
566+
uploadConcurrency,
567+
chunkSize,
568+
uploadBehavior,
569+
})
570+
: await client.createAssembly({
571+
params,
572+
files: filesMap,
573+
uploads: uploadsMap,
574+
waitForCompletion,
575+
timeout,
576+
uploadConcurrency,
577+
chunkSize,
578+
uploadBehavior,
579+
expectedUploads: expected_uploads,
580+
})
581+
} catch (error) {
582+
if (isErrnoException(error) && error.code === 'ENOENT') {
583+
return buildToolError('mcp_file_not_found', error.message, {
584+
hint: 'Path inputs only work when the MCP server can read local files. For hosted MCP, use url/base64 or upload via `npx @transloadit/node upload`.',
575585
})
586+
}
587+
throw error
588+
}
576589

577590
if (assembly_url) {
578591
uploadSummary.resumed = true

0 commit comments

Comments
 (0)