All posts
ffmpeg tool ai agent

Add an FFmpeg Tool to Your AI Agent (Claude Agent SDK, OpenAI Agents SDK, LangChain)

Give an AI agent an FFmpeg tool in a few lines: connect the Xora MCP server from the Claude Agent SDK, the OpenAI Agents SDK or LangChain, with code for each.

To add an FFmpeg tool to an AI agent, connect it to an MCP server that runs FFmpeg. With Xora, the server is https://api.xora.sh/v1/mcp with Authorization: Bearer YOUR_API_KEY, and the agent gets five tools: create_job, get_job, create_upload, list_recipes and cancel_job.

Below is the code for the Claude Agent SDK, the OpenAI Agents SDK and LangChain, a REST option for frameworks without MCP, and the instructions that make agents use the tools well. For clients such as Claude Code and Cursor, see FFmpeg for AI agents.

What the agent gets

ToolWhat it does
list_recipesLists the recipes (compress, trim, thumbnail, webReady and others) and their parameters.
create_jobStarts a job: a recipe, raw FFmpeg arguments, or a probe. Returns { id, state } at once.
get_jobReturns the state, the progress, and when complete, a signed URL for each output.
create_uploadGives a presigned URL for a local file that has no URL.
cancel_jobStops a job that is not finished.

Raw FFmpeg arguments go as a JSON array, so there is no shell, and -filter_complex, multiple inputs and codec flags pass through as written.

Claude Agent SDK

Pass the server in mcpServers with type: "http". Tools are named mcp__<server>__<tool>, so mcp__xora__* allows all Xora tools.

TypeScript — @anthropic-ai/claude-agent-sdk
import { query } from '@anthropic-ai/claude-agent-sdk'
for await (const message of query({
prompt: 'Make a 720p MP4 of https://example.com/talk.mov and give me the link.',
options: {
mcpServers: {
xora: {
type: 'http',
url: 'https://api.xora.sh/v1/mcp',
headers: { Authorization: `Bearer ${process.env.XORA_API_KEY}` },
},
},
allowedTools: ['mcp__xora__*'],
},
})) {
if (message.type === 'result' && message.subtype === 'success') console.log(message.result)
}
Python — claude_agent_sdk
import asyncio, os
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
options = ClaudeAgentOptions(
mcp_servers={
"xora": {
"type": "http",
"url": "https://api.xora.sh/v1/mcp",
"headers": {"Authorization": f"Bearer {os.environ['XORA_API_KEY']}"},
}
},
allowed_tools=["mcp__xora__*"],
)
async def main():
async for message in query(
prompt="Make a 720p MP4 of https://example.com/talk.mov and give me the link.",
options=options,
):
if isinstance(message, ResultMessage):
print(message.result)
asyncio.run(main())

Source: Claude Agent SDK MCP docs.

OpenAI Agents SDK

Use MCPServerStreamableHttp as an async context manager and attach it to the agent with mcp_servers.

Python — openai-agents
import asyncio, os
from agents import Agent, Runner
from agents.mcp import MCPServerStreamableHttp
async def main() -> None:
async with MCPServerStreamableHttp(
name="xora",
params={
"url": "https://api.xora.sh/v1/mcp",
"headers": {"Authorization": f"Bearer {os.environ['XORA_API_KEY']}"},
},
cache_tools_list=True,
) as xora:
agent = Agent(
name="Video assistant",
instructions="Use the Xora tools to process video. Poll get_job until the job ends.",
mcp_servers=[xora],
)
result = await Runner.run(agent, "Make a 720p MP4 of https://example.com/talk.mov and give me the link.")
print(result.final_output)
asyncio.run(main())

Source: OpenAI Agents SDK MCP docs.

LangChain

Current LangChain versions include MCP support in langchain[mcp] (beta). A URL target uses Streamable HTTP, and a string in auth is sent as a bearer token:

Python — langchain[mcp]
import asyncio, os
from fastmcp.client import Client
from langchain.agents import create_agent
from langchain.mcp import MCPAdapter
async def main():
client = Client("https://api.xora.sh/v1/mcp", auth=os.environ["XORA_API_KEY"])
async with MCPAdapter(client) as adapter:
tools = await adapter.list_tools()
agent = create_agent("anthropic:claude-sonnet-5-5", tools)
result = await agent.ainvoke(
{"messages": [{"role": "user", "content": "Make a 720p MP4 of https://example.com/talk.mov and give me the link."}]}
)
print(result["messages"][-1].content)
asyncio.run(main())

On older projects that still use langchain-mcp-adapters, the same server goes in MultiServerMCPClient with "transport": "http", the URL and a headers dict, and await client.get_tools() returns the tools. That package is now archived. Source: LangChain MCP docs.

Without MCP: a REST function tool

Any framework that can call a function can use the REST API. The tool starts the job, polls it, and returns the URL:

Python — a plain function tool
import os, time, requests
API = "https://api.xora.sh/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['XORA_API_KEY']}"}
def run_ffmpeg(input_url: str, args: list[str], output_name: str) -> dict:
"""Run FFmpeg args on input_url. Use {{in_1}} for the input and {{out_1}} for the output."""
job = requests.post(f"{API}/jobs", headers=HEADERS, json={
"mode": "ffmpeg",
"input_files": {"in_1": input_url},
"output_files": {"out_1": output_name},
"ffmpeg": {"args": args},
}).json()
while True:
status = requests.get(f"{API}/jobs/{job['id']}", headers=HEADERS).json()
if status["state"] in ("completed", "failed", "rejected", "cancelled"):
return status
time.sleep(3)

Register run_ffmpeg with your framework’s tool decorator. The OpenAPI spec and /llms.txt describe every field.

Instructions that help

Add a few lines to the agent’s instructions:

System prompt
You can process video and audio with the Xora tools.
- Before you write an FFmpeg command for a file you have not seen, run create_job with mode "probe".
- Prefer a recipe (call list_recipes once) when one fits. Use mode "ffmpeg" with an args array for anything else.
- Output file names use letters, numbers and underscores, plus an extension.
- Send an idempotencyKey with every create_job, and reuse it if you retry the same job.
- Poll get_job until the state is completed, failed, rejected or cancelled.
- If a job fails, read error.code and error.message, fix the request, and try again once.

More on why this works: LLMs write good FFmpeg commands.

Cost and limits

An agent’s job is a normal Xora job. It bills credits for machine time and output size, with the same plan limits as a REST request, and failed, rejected and cancelled jobs cost nothing. Give the agent its own API key, so you can see and limit what it uses. See pricing.

Next steps

Frequently asked questions

How do I give an AI agent an FFmpeg tool?

Connect a remote MCP server that runs FFmpeg, such as Xora at https://api.xora.sh/v1/mcp with an API key in the Authorization header. The agent then gets tools such as create_job and get_job, and the FFmpeg commands run in the cloud, not in the agent's process.

Which agent frameworks can use the Xora MCP server?

Any framework with an MCP client that supports Streamable HTTP. This guide shows the Claude Agent SDK (TypeScript and Python), the OpenAI Agents SDK (Python) and LangChain (Python). Frameworks without MCP can call the REST API from a normal function tool.

Why not run FFmpeg inside the agent's own process?

Video jobs need CPU, disk and time, and an agent's host or sandbox often has little of each. FFmpeg may not be installed, and running model-written commands through a shell is a security risk. A separate service takes an argument array, runs it in isolation and returns a URL.

How does the agent know when the job is done?

create_job returns at once with a job ID and the state queued. The agent calls get_job until the state is completed, failed, rejected or cancelled, then gives the user the signed URL of the output.

Ready to try Xora?

Replace your local FFmpeg binaries with a secure, high-performance cloud API.