Skip to content

MCP Server

Xora ships 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.

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.