Skip to content
Xora

FFmpeg MCP Server

The Xora FFmpeg MCP server gives an AI agent real FFmpeg as tool calls. The agent writes the FFmpeg arguments (or picks a recipe), Xora runs the job in the cloud, and the agent gets a signed URL for the output. Nothing needs to be installed where the agent runs.

The server is a remote MCP server at https://api.xora.sh/v1/mcp (Streamable HTTP). It authenticates with the same API keys as the REST API and its tools call the same job routes — plan limits, billing, and structured errors behave identically whether a job comes from curl or from an agent’s tool call. For an overview of every way an agent can reach Xora, see FFmpeg for AI agents.

Two ways to authenticate:

  • OAuth — clients with OAuth support (claude.ai custom connectors, Claude Desktop connectors) discover the flow automatically: add the endpoint URL, sign in with your Xora dashboard account, and approve the consent prompt.
  • API key — an Authorization: Bearer header carrying a Xora API key (create one in the dashboard), for headless agents, CI, and any client that can set a request header.

Settings → Connectors → Add custom connector, then paste:

https://api.xora.sh/v1/mcp

The OAuth flow starts automatically: you’ll sign in to your Xora dashboard (if you aren’t already) and approve the access prompt. No key to copy. Revoke any time from the consent screen’s dashboard link.

To verify a connection without writing code:

Terminal window
npx @modelcontextprotocol/inspector --cli https://api.xora.sh/v1/mcp \
--transport http \
--header "Authorization: Bearer YOUR_API_KEY" \
--method tools/list
ToolWhat it does
create_jobCreate an asynchronous job — mode: "recipe" (named operation), mode: "ffmpeg" (raw argument array with {{in_1}}/{{out_1}} placeholders), or mode: "probe" (ffprobe metadata only). Returns { id, state } immediately.
get_jobFetch a job by id: state, progress, signed download URLs when completed, probe metadata for probe jobs, structured error for failed or rejected jobs.
create_uploadGet a presigned URL for a local file that has no public address. Returns { uploadId, url, expiresAt, maxBytes }; the agent PUTs the bytes, then passes uploadId to create_job.
list_recipesStatic catalog of the nine recipes with parameters, constraints, and output formats. Costs nothing to call.
cancel_jobCancel a queued or running job.

The server also publishes instructions during the MCP handshake, so most agents discover the workflow on their own: call list_recipes once, create_job, then poll get_job until the state is terminal (completed | failed | rejected | cancelled).

create_job needs an input Xora can read. When the agent is holding a file path rather than a URL, create_upload provides the destination:

  1. Call create_upload with { "sizeBytes": 734003200, "filename": "interview.mov" }. The declared size is checked against the plan’s per-file limit up front.
  2. PUT the raw file bytes to the returned url — a plain HTTP request the agent makes itself, with no Authorization header and no form encoding. The URL is valid for one hour.
  3. Call create_job with "input": { "uploadId": "…" } in place of "input": { "url": … }.

Uploads survive for three days and can back any number of jobs in that window, so an agent producing several outputs from one source should upload once and reuse the id. See direct uploads for limits and the REST equivalent.

A typical create_job tool call:

{
"mode": "recipe",
"input": { "url": "https://example.com/interview.mov" },
"output": { "format": "mp4" },
"recipe": { "name": "compress", "crf": 23 }
}

…returns { "id": "01JXYZ…", "state": "queued" }. Polling get_job with that id eventually returns the terminal record:

{
"id": "01JXYZ1234ABCDEF56789000",
"state": "completed",
"progress": 100,
"output": {
"signedUrl": "https://cdn.xora.sh/...signed-url..."
}
}

Signed URLs expire, so agents should download promptly (or configure BYOB delivery so outputs land in your own bucket with nothing to collect). Pass webhookUrl on create_job to receive a webhook on the terminal state instead of polling.

Tool failures come back as MCP error results whose text is the API’s structured error JSON, plus the HTTP status:

{
"httpStatus": 402,
"error": {
"code": "LIMIT_EXCEEDED",
"message": "Plan credits exhausted",
"feature": "credits",
"retryable": false
}
}
error.codeHTTPMeaning
VALIDATION_ERROR400The request body is wrong — the message says which field.
LIMIT_EXCEEDED402Plan credits or storage exhausted; new jobs are refused until reset or upgrade.
PLAN_REQUIRED403The feature (for example BYOB) isn’t on the current plan.
NOT_FOUND404No job with that id on this account.

Failed and rejected jobs bill nothing — see error handling for the difference between the two.

For Claude specifically, there’s also an Agent Skill — judgment the tool schemas can’t carry: which recipe fits which ask, when to probe first, how to handle a local file, cost-saving habits like stageInput: false, and how to branch on error codes. It complements the MCP server (and covers plain REST when MCP isn’t connected).

Install it for Claude Code:

Terminal window
mkdir -p ~/.claude/skills/xora && \
curl -fsSL https://xora.sh/skills/xora/SKILL.md -o ~/.claude/skills/xora/SKILL.md

Use .claude/skills/xora/SKILL.md inside a repo to share it with a project instead, or upload it as a custom skill in claude.ai.

Yes. create_job with mode: "ffmpeg" takes a raw argument array, including -filter_complex and multiple inputs (input_files keyed in_1, in_2, …). Output file names in output_files use letters, numbers and underscores plus an extension, for example clip_720p.mp4. See custom FFmpeg args.

Which clients work with the Xora MCP server?

Section titled “Which clients work with the Xora MCP server?”

Any client that supports remote MCP servers over Streamable HTTP. The tabs above show Claude Code, claude.ai and Claude Desktop, Cursor, and the MCP TypeScript SDK.

No local server is needed: the agent only sends JSON, and FFmpeg runs on Xora. Clients that cannot connect to a remote server can call the REST API directly. /llms.txt describes the full workflow for agents.

No. A tool call creates the same job as POST /v1/jobs and bills the same credits. Failed, rejected and cancelled jobs cost nothing. See pricing.