claude-media-mcp
Routes provider requests through Cloudflare AI Gateway, optionally using an authenticated gateway via CF_AIG_GATEWAY and CF_AIG_TOKEN.
Generates images and audio via Cloudflare Workers AI models, including @cf/black-forest-labs/flux-1-schnell for images and @cf/deepgram/aura-1 for audio.
Generates and edits images with gemini-3-pro-image (Nano Banana Pro), video with veo-3.1-generate-preview, and WAV audio with gemini-3.8-flash-tts.
Generates images with gpt-image-2 (including editing), video with sora-2, and audio with gpt-4o-mini-tts, with optional model overrides and provider-specific options.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@claude-media-mcpgenerate a 16:9 image of a cozy cabin in snowy mountains at sunset"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
claude-media-mcp
An MCP server that lets any MCP-capable chat or agent (Claude Code, Claude Desktop, Codex, VS Code, Antigravity, Cursor, claude.ai connectors and others) generate images, video and audio through OpenAI, Google Gemini, fal.ai and Cloudflare Workers AI. You can also send every request through your Cloudflare AI Gateway.
One Python file, three dependencies, one .env for all your clients.
Image | Video | Audio | |
OpenAI |
|
|
|
Gemini |
|
|
|
fal.ai |
|
|
|
Cloudflare Workers AI |
| - |
|
Every tool also takes a model override, so any model the provider offers works.
Quick start
Requires uv and Python 3.11+.
git clone https://github.com/righttechsoft/claude-media-mcp.git
cd claude-media-mcp
uv sync
cp .env.example .env # then fill in the keys you haveOnly providers whose key is set are used. .env sits next to server.py and is read on every start; real environment variables take precedence.
Related MCP server: media-gen-mcp
Connect a client
The server speaks MCP over stdio. Every client launches the same command:
uv run --directory /path/to/claude-media-mcp server.pyOr, to skip uv at launch time, the project's virtualenv Python directly: /path/to/claude-media-mcp/.venv/bin/python /path/to/claude-media-mcp/server.py (on Windows: .venv\Scripts\python.exe).
Claude Code (all projects):
claude mcp add -s user media -- uv run --directory /path/to/claude-media-mcp server.pyClaude Desktop (claude_desktop_config.json), Antigravity (~/.gemini/antigravity/mcp_config.json), Cursor (~/.cursor/mcp.json):
{
"mcpServers": {
"media": {
"command": "uv",
"args": ["run", "--directory", "/path/to/claude-media-mcp", "server.py"]
}
}
}Codex (~/.codex/config.toml):
[mcp_servers.media]
command = "uv"
args = ["run", "--directory", "/path/to/claude-media-mcp", "server.py"]VS Code (user mcp.json):
{
"servers": {
"media": {
"type": "stdio",
"command": "uv",
"args": ["run", "--directory", "/path/to/claude-media-mcp", "server.py"]
}
}
}GUI apps sometimes don't see your shell PATH. If a client can't find uv, use its absolute path or the virtualenv Python shown above.
Tools
All tools take optional provider (default: the first configured one in the order listed), model and options. options is merged into the provider's request, so you can pass any model-specific parameter (quality, seed, resolution, negative prompt and so on).
Files are saved to MEDIA_OUTPUT_DIR (default ~/claude-media) as YYYYmmdd-HHMMSS-provider-id.ext. Each result has the absolute path. In HTTP mode it also has a download link.
generate_image(prompt, provider, model, aspect_ratio, input_images, options)
Order: openai, gemini, fal, cloudflare. Returns the full-size file plus a JPEG preview (max 1024px) the chat can see inline.
aspect_ratiolike16:9. OpenAI maps it to the closest supported size.input_images: local paths, URLs or data URIs, used for editing or as references. Not supported on Cloudflare.
start_video(prompt, provider, model, aspect_ratio, duration_seconds, input_image, options) and check_video(job_id, wait_seconds=45)
Order: openai, gemini, fal. Video takes minutes, longer than most clients wait for one tool call, so it is split in two:
start_videosubmits the job and returns ajob_idimmediately.check_videowaits up towait_seconds(max 300). If the video is done it saves it and returns the path. If not, it returns the current status, and the chat calls it again.
The job_id contains the provider's own job reference, so a job started in one session can be collected in another. On fal, duration is model-specific: pass it via options, for example {"duration": "8s"}.
generate_audio(text, provider, model, voice, options)
Order: openai, gemini, fal, cloudflare. Text-to-speech by default. Prompt-based fal models (music, sound effects) take options={"prompt": "..."}.
Configuration
Variable | Purpose |
| OpenAI |
| Gemini |
| fal.ai |
| Cloudflare Workers AI |
| Cloudflare AI Gateway id. With |
| Optional, for authenticated gateways ( |
| Output folder, default |
| HTTP mode bind address, default |
| HTTP mode secret: the endpoint becomes |
| Public base URL used in file download links, for example behind a tunnel |
With the AI Gateway enabled, each provider still needs its own key. Gateway-stored keys (BYOK) without a local key are not supported yet.
HTTP mode (remote clients)
uv run server.py --httpServes streamable HTTP at http://127.0.0.1:47213/mcp and generated files at /files/<name>. To reach it from claude.ai or another machine, set MCP_TOKEN and MCP_PUBLIC_URL, put it behind a tunnel (for example Cloudflare Tunnel), and add https://your-host/{MCP_TOKEN}/mcp as a custom connector.
The server spends your API credits, so it refuses to bind to a non-loopback address without MCP_TOKEN. Treat the token like a password.
Development
uv run python test_server.pyOffline checks only: no API calls, no keys needed.
mcp is pinned below 2.0 because the mcp.server.fastmcp API this server uses was removed in the 2.x SDK.
License
Available Tools
4 toolscheck_videoA
Wait for a video job started by start_video. Polls for up to wait_seconds (0-300, default 45). When the video is ready, saves it to disk and returns its path. If it is still running, returns a status message with the job_id; call check_video again with the same job_id until the path is returned. Failures raise an error.
| Name | Required | Description | Default |
|---|---|---|---|
| job_id | Yes | ||
| wait_seconds | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does well: it discloses blocking/wait behavior (poll up to 0-300s), a real side effect (saves the video to disk and returns its path), the non-terminal return shape (status message plus job_id), and error behavior ('failures raise an error'). It omits file naming/location and any auth or rate-limit context, so it is strong but not exhaustive.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four tight sentences, front-loaded with purpose and timing, then the success path, then the retry path, then failures. Every sentence adds an actionable fact with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema and no annotations, so the description correctly explains the return values (file path vs. status message with job_id) and the error case. It is nearly complete for a two-parameter polling tool; only the saved file's destination/naming convention is left unstated.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate, and it does for the key parameter by giving wait_seconds' range and default (0-300, default 45) beyond the schema's bare default. job_id's meaning and its reuse across polls are implied rather than defined, which is the only real gap.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Wait for a video job started by start_video') and names the sibling that must precede it, so an agent can immediately place it in the video pipeline rather than confusing it with generate_image or generate_audio.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a clear precondition (only after start_video) and an explicit repeated-call loop ('call check_video again with the same job_id until the path is returned'). It does not need to name alternatives since none of the other siblings poll a job, but it stops short of stating any when-not condition or termination limit on retries.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
generate_audioA
Text-to-speech (and prompt-based audio on fal). Saves the audio file to disk and returns its path.
provider (default: first configured of openai, gemini, fal, cloudflare):
openai: default gpt-4o-mini-tts, voice default alloy, mp3 output. options merged into the request (e.g. instructions, speed, response_format).
gemini: default gemini-3.8-flash-tts, voice default Kore (prebuilt voice name). options shallow-update generationConfig. Output is WAV.
fal: default fal-ai/elevenlabs/tts/turbo-v2.5. Input {text, voice} updated with options. Prompt-based fal audio models (music, sound effects) take options={"prompt": "..."}; any model id works.
cloudflare: default @cf/deepgram/aura-1. Body {text, speaker=voice} updated with options.
| Name | Required | Description | Default |
|---|---|---|---|
| text | Yes | ||
| model | No | ||
| voice | No | ||
| options | No | ||
| provider | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does disclose the critical trait an agent needs: this writes an audio file to disk and returns its path rather than returning bytes. It also documents per-provider output formats (mp3, WAV) and how each backend's payload is mutated. It stops short of auth/error/rate-limit behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose and side effect are front-loaded in one sentence, followed by a tight provider-by-provider list where every line adds actionable detail. There is no filler or repetition of the schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 5-parameter, no-output-schema tool at 0% schema coverage, this covers the essentials including return value and per-provider behavior. Marginal gaps remain: it does not clarify how the required `text` field interacts with fal prompt-based (music/SFX) models, nor what happens when no provider is configured.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, and the description compensates thoroughly: it explains the default provider resolution order, the default model and voice per provider, and precisely how the opaque `options` object is applied (merged into the request, shallow-updates generationConfig, becomes {prompt} for fal prompt-based audio). That is meaning the schema cannot convey.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource ('Text-to-speech ... Saves the audio file to disk and returns its path'), naming both the operation and its side effect. It is trivially distinguishable from generate_image, start_video, and check_video by modality.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The provider breakdown gives concrete selection guidance (which backend is default, what each accepts, what output format results), so an agent knows how to pick a route. What is missing is an explicit when-to-use/when-not statement or a named alternative for overlapping cases (e.g. fal prompt-based music/SFX vs speech).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
generate_imageA
Generate or edit an image. Saves full-resolution files to disk and returns paths plus a JPEG preview.
provider (default: first configured of openai, gemini, fal, cloudflare):
openai: default model gpt-image-2. aspect_ratio maps to size (1:1 -> 1024x1024; 16:9/3:2/4:3 -> 1536x1024; 9:16/2:3/3:4 -> 1024x1536). options merged into the request body (e.g. quality, background, n, output_format); options["size"] wins. input_images switches to /images/edits.
gemini: default gemini-3-pro-image (Nano Banana Pro). aspect_ratio -> imageConfig.aspectRatio (e.g. 16:9). options shallow-update generationConfig (e.g. imageConfig with imageSize).
fal: default fal-ai/nano-banana-pro. Input {prompt, aspect_ratio, image_urls} updated with options (model-specific params such as num_images, resolution, image_size). Any model id works.
cloudflare: default @cf/black-forest-labs/flux-1-schnell. Body {prompt} updated with options (e.g. steps, seed). No input_images.
input_images: local file paths, http(s) URLs or data URIs, used as edit targets or references.
| Name | Required | Description | Default |
|---|---|---|---|
| model | No | ||
| prompt | Yes | ||
| options | No | ||
| provider | No | ||
| aspect_ratio | No | ||
| input_images | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does disclose the key side effect: files are written to disk and a preview plus paths are returned, so the agent knows this is not a read-only call. It also discloses the non-obvious branch where input_images switches openai to /images/edits. It omits auth requirements, cost, and failure modes for a paid generation endpoint.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose and return behavior, then a scannable per-provider bullet list. The density is justified by the zero schema coverage, though the provider bullets are heavy enough that an agent must read the whole block rather than skim.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 6-parameter tool with no annotations, no output schema, and 0% schema description coverage, the description covers the provider/model/aspect_ratio/options/input_images surface and states what is returned. Gaps remain around error behavior, cost, and what happens when multiple providers are configured beyond the 'first configured' rule.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must compensate, and it largely does: aspect_ratio is given explicit per-provider mappings (1:1 -> 1024x1024, 16:9/3:2/4:3 -> 1536x1024), options merge semantics are spelled out including precedence ('options["size"] wins'), model defaults are named per provider, and input_images formats (paths, URLs, data URIs) and roles (edit target vs reference) are defined.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource ('Generate or edit an image') and immediately states the observable side effect and return shape ('Saves full-resolution files to disk and returns paths plus a JPEG preview'). This clearly separates it from siblings generate_audio, start_video, and check_video without needing their schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides clear selection context by documenting the provider default ('first configured of openai, gemini, fal, cloudflare') and the per-provider defaults (gpt-image-2, gemini-3-pro-image, fal-ai/nano-banana-pro, flux-1-schnell), plus when input_images switches to an edit path for openai. There is no explicit when-not guidance or cost/limit exclusion, but the provider routing context is unusually strong.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
start_videoA
Start a video generation job (text-to-video, or image-to-video with input_image) and return its job_id immediately. Then call check_video(job_id) to wait for and fetch the result.
provider (default: first configured of openai, gemini, fal):
openai: default sora-2. aspect_ratio 16:9 -> 1280x720, 9:16 -> 720x1280. duration_seconds -> seconds. options merged into the request (e.g. size overrides). input_image sent as input_reference.
gemini: default veo-3.1-generate-preview. aspect_ratio and duration_seconds go to parameters.aspectRatio / durationSeconds; options merged into parameters (e.g. resolution, negativePrompt, personGeneration).
fal: default fal-ai/veo3.1/fast. Input {prompt, aspect_ratio, image_url} updated with options. Duration is model-specific on fal (e.g. "8s" vs "5"), so pass it via options such as {"duration": "8s"}; duration_seconds is rejected for fal.
input_image: local path, http(s) URL or data URI.
| Name | Required | Description | Default |
|---|---|---|---|
| model | No | ||
| prompt | Yes | ||
| options | No | ||
| provider | No | ||
| input_image | No | ||
| aspect_ratio | No | ||
| duration_seconds | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and largely meets it: it discloses the asynchronous job_id contract, provider defaults, how duration_seconds and aspect_ratio are re-mapped per provider, that duration_seconds is *rejected* for fal, and that options are merged into the provider request. It omits auth requirements, rate limits, and prompt constraints, so not a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The first sentence front-loads the action and the async contract, followed by compact per-provider bullets. It is dense but every line carries operative detail; only minor trimming is possible.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 7-parameter, no-annotation mutation tool this is thorough, and the job_id/polling contract plus provider quirks are covered. An output schema exists so return values need not be described, but there is no mention of validation limits or failure behavior, keeping it just short of complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must compensate, and it does: provider enumerates the three backends with defaults, aspect_ratio/duration_seconds translation is spelled out per provider, duration_seconds' fal constraint is documented, options is defined as provider-specific merged keys with examples, and input_image's accepted formats (path/URL/data URI) are given. This adds meaning far beyond the bare schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Start a video generation job') and immediately distinguishes the two modalities (text-to-video vs image-to-video via input_image). It also names the sibling it hands off to (check_video), so an agent can separate start from poll without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit workflow guidance: this tool returns a job_id immediately and check_video(job_id) must be called to wait for the result. It also provides per-provider selection guidance with defaults. It stops short of stating when *not* to use it (e.g. vs. generate_image/generate_audio), so a 4 rather than 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
4 tool updates
v0.1.0- First observed
check_video - First observed
generate_audio - First observed
generate_image - First observed
start_video
TDQS
Scored across 4 tools
Each tool targets a distinct modality and action: generate_image (images), generate_audio (audio), and the start_video/check_video pair form a clearly documented async lifecycle. The start/check pairing is explicitly cross-referenced in both descriptions, so there is no risk of misselection.
All four names follow a strict verb_noun snake_case pattern (generate_image, generate_audio, start_video, check_video). The verbs accurately reflect each tool's role, and the async pair uses a clean start/check convention rather than an inconsistent verb.
Four tools is well-scoped for a media generation server covering image, audio, and video. Each tool earns its place: one per modality plus the necessary polling companion for the async video job.
The core generation lifecycle for images (including edits via input_images), audio (including prompt-based fal models), and video is fully covered. Minor gaps remain, such as no job cancellation, job listing, or file cleanup, but agents can work around these.
Maintenance
Related MCP Connectors
Create images & video from any MCP agent — 17 models, spend limits, one URL.
OCR, transcription, file extraction, and image generation for AI agents via MCP.
Generate images, video, audio and short films with 140+ AI models from any MCP client.
Generate AI images and videos from any compatible MCP client.
Related MCP Servers
- AlicenseAqualityCmaintenanceMulti-provider media generation MCP server that generates images, videos, audio, and transcriptions from text prompts using OpenAI, xAI, Gemini, ElevenLabs, and BFL through a single unified interface.658 npm2MIT
- FlicenseNot gradedqualityBmaintenanceEnables AI clients like Claude and ChatGPT to generate images and videos, animate images, create lip-synced videos, list TTS voices, and manage media via remote MCP tools.-
- AlicenseAqualityCmaintenanceEnables video and image generation from any MCP client, with support for models like Veo 3.1, Grok Imagine, and Nano Banana, including text-to-video, image-to-video, image generation and editing.4MIT
- AlicenseNot gradedqualityBmaintenanceEnables any MCP client to search and submit tasks across 350+ multimodal image, video, audio, and 3D models, run ComfyUI workflows and AI apps, upload/download files, and chat with LLMs. It supports stdio MCP integration and optional scope trimming for image, video, or audio only.2MIT