ai-image-router-mcp
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., "@ai-image-router-mcpgenerate a 1024px wide watercolor painting of a lighthouse at dusk"
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.
ai-image-router-mcp
An MCP server that routes image generation, image-to-video, text-to-video, and local background removal across multiple LLM gateways — built on the official TypeScript SDK, using direct REST calls only (no vendor SDKs).
Supported gateways
Gateway | Image generation | Text→Video | Image→Video |
✅ ( | ✅ ( | ✅ (frame images) | |
✅ (Agents | — | — | |
✅ ( | ✅ ( | ✅ (single + multi-ref) | |
✅ (queue — FLUX 2 Pro, FLUX 1.1, Recraft, Cosmos, Krea 2, Ideogram) | ✅ (queue — Veo/Kling/… ; not Cosmos) | ✅ (queue — Cosmos 3, single image) |
fal image request defaults — fal's image models default to
jpegand may apply a strict safety gate.fal.generateImageseedsoutput_format:"png",safety_tolerance:"5"(most permissive), andenable_safety_checker:falseonly on models whose schema carries them (per-model; a caller's explicitprovider_optionsoverrides). fal models differ per family: FLUX/Recraft/Cosmos take an objectimage_size{width,height}(exact pixels) or an enum tier; Krea 2/Ideogram take anaspect_ratioenum (no exact pixels).
Background removal runs locally (no gateway) via ONNX Runtime + BiRefNet.
Related MCP server: OpenAI GPT-Image MCP Server
Tools
Tool | What it does |
| Generate image(s) from a prompt; saves to the output dir and returns the path (+ inline preview). Size: |
| With |
|
|
| Turn stills into motion. |
| Generate a video from a text prompt. Async by default: poll with just |
| Local background removal (BiRefNet / BRIA / IS-Net / BEN2) → transparent PNG (no gateway). |
| Crop an exact pixel region from an image (sharp |
| One tool to downsize (sharp MKS-2021 / ffmpeg, shrink-only), convert format (png/jpg/webp/avif — Tinify when configured, else sharp), extract a still frame from a video (skips mostly-black frames), and/or change |
| Build a whole icon set in one verifiable operation: every declared size is derived from the intended source by downscaling (never re-generated), emitted as its own exact- |
| Detailed health: gateway, configured models/options, execution provider, logging, and any wizard-time or runtime errors. |
| Soft reload — re-read |
| Gracefully flush logs and stop the process. |
generate_video appears only when the active gateway supports text-to-video (so Mistral
never shows it). image_to_video is always available — its output_format:"gif" mode
runs locally, so it works under any gateway; only its mp4 mode needs an image-to-video
model. remove_background appears unless the background model is set to none.
The generation tools accept a provider_options object to pass gateway/model-specific fields
(e.g. OpenRouter image_config, MiniMax prompt_optimizer/camera commands, Veo generate_audio;
Mistral's image tool takes none — they are ignored there and the reply says so). Notes like
Note: … generated WITHOUT: resolution, fps tell you when a request had to be adapted.
Requirements
Node.js ≥ 20
One or more gateway API tokens, each as a plain text file in the project root (token only, no prefix):
openrouter token.txtmistral ai token.txteden ai token.txt
(optional) A Tinify key as
tinify com token.txt— enables PNG compression + WebP output.(optional) ffmpeg on your PATH — required only for video crop/downsize; image editing and everything else work without it.
Install
npm install
npm run buildConfigure
Run the interactive wizard:
npm run configureIt walks you through:
Gateway selection.
Token source (auto-detects the root
*.txtfile).Image model — pulled live from the gateway API, with Artificial Analysis leaderboard top-10 matches marked
⭐ #Nand floated to the top of the list (best rank first; the rest follow latest-first). Ranked models the gateway doesn't offer can't be selected, so the wizard prints a note listing them (e.g. OpenRouter doesn't carry#2GPT Image 1.5, so it's absent) (see docs/UPDATING-LEADERBOARDS.md to refresh those lists).Default aspect ratio (from the API, or a curated preset list with explanations — default
4:3).Default resolution (from the API, defaulting to the highest; custom input otherwise).
Sync vs async — right after selecting each model, you choose whether generation runs as an async background job (default: returns a
job_idto poll, so a slow generation never trips a client timeout) or synchronous (the call blocks until the result is ready). Set separately for image, image-to-video and text-to-video; override per call withwait:true/wait:false.Image-to-video & text-to-video (if the gateway supports them): model, sync/async, FPS, resolution, duration. (Whether an i2v model accepts multiple reference images is derived from the gateway, not asked.)
Background removal — the wizard asks for the ONNX execution provider first (
auto/cpu/dml/webgpu/cuda/coreml), shows your free/total RAM and VRAM, then lists the models annotated with their empirical RAM/VRAM use for that provider (and whether each one actually runs on it). Models:none,birefnet-general(default, best quality),birefnet-massive(broader training),bria-rmbg(BRIA RMBG-2.0),isnet-general-use(lighter IS-Net). Heads-up: BiRefNet and bria-rmbg break DirectML regardless of VRAM. On CPU they need ≈7.5 GB free RAM (≈25 s). On WebGPU the server transparently converts them to a GPU-compatible (cascaded) variant on first use (≈7–8 s) —isnet-general-use(IS-Net) also runs on WebGPU directly and is fastest (≈2.5 s, ≈1.3 GB VRAM). If free RAM is too low the tool fails with a clear "needs ~N GB free, you have Y GB" message (override the check withBG_RAM_CHECK=off).Logging policy —
none,today(default), orpersistent-daily.
The result is written to config.json, along with a diagnostics block recording any
errors or missing data hit while pulling model lists (surfaced by health_status).
Re-running the wizard when a config.json already exists pre-selects your current
settings as the default for each prompt, so you can press Enter through the ones you
want to keep and only change what you need. (Switching to a different gateway resets the
gateway-specific choices — model, token, aspect ratio, resolution, video — to their
standard defaults, since the old selections no longer apply.)
config.jsonand the token*.txtfiles are git-ignored — they hold secrets.
Run
For stdio (the usual case) you don't run the server yourself — register it
(below) and your MCP client spawns it on demand. npm start is only for a manual
stdio smoke test. HTTP mode is the one you start yourself:
npm start # stdio — normally launched by the client, not by you
npm start -- --http # Streamable HTTP transport (host/port from config.json)The HTTP endpoint is http://<host>:<port>/mcp (default 127.0.0.1:8765). It is unauthenticated unless
http.authToken is set — the wizard offers to generate one (saved as mcp http token.txt). With a token
configured, every request must carry Authorization: Bearer <token> (or X-API-Key: <token>) and anything
else gets a plain 401. Set one before exposing the port beyond localhost: the tools read and write local paths.
Without a token the server still refuses requests whose Host or Origin header names a foreign domain
(403). This guards against DNS rebinding, where a malicious web page reaches 127.0.0.1 through its own
domain and drives the tools from your browser. Loopback names (localhost) and IP literals are always
accepted. To reach a token-less server through another hostname (e.g. a LAN name), list it in
http.allowedHosts. With a token set the check is skipped, so a tunnel's public hostname just works.
Sessions idle for http.sessionIdleMinutes (default 30) are closed; a client using an expired session id
gets a 404 and re-initializes, as the MCP spec prescribes.
Register with Claude Code
claude mcp add ai-image-router -- node /absolute/path/to/ai-image-router-mcp/dist/index.jsRegister with Claude Desktop (claude_desktop_config.json)
{
"mcpServers": {
"ai-image-router": {
"command": "node",
"args": ["V:/MCP/ai-image-router-mcp/dist/index.js"]
}
}
}Register with Pi
Add the server to Pi's MCP config. Global (all projects) lives at
~/.pi/agent/mcp.json; project-scoped servers go in .pi/mcp.json instead:
{
"mcpServers": {
"ai-image-router": {
"type": "stdio",
"command": "node",
"args": ["V:/MCP/ai-image-router-mcp/dist/index.js"],
"env": {}
}
}
}Pi discovers MCP servers at startup. If Pi is already running, you don't need to
quit and restart it — run /reload in the Pi chat to re-read the config and pick
up the newly registered server without leaving the session.
After /reload the server may appear in Pi's MCP list but show as
not connected (mcp({}) / /mcp). Reconnect it in the chat with:
/mcp reconnect ai-image-router(equivalently mcp({ connect: "ai-image-router" })). Once connected, the tools
show up under ai-image-router_*.
Using with Le Chat / Mistral Vibe
Le Chat (custom MCP connector, over HTTP)
Le Chat connects from Mistral's cloud, so the server must be reachable at a public HTTPS URL with a valid
TLS certificate — localhost cannot work.
Run
npm run configureand enable HTTP with an auth token (writesmcp http token.txt), or sethttp.enabled: trueandhttp.authTokeninconfig.json. Thennpm start -- --http.Expose it, e.g. with a tunnel:
cloudflared tunnel --url http://127.0.0.1:8765(use the printedhttps://….trycloudflare.comURL +/mcp).In Le Chat: Connectors → Add connector → Add a custom connector. Give it a name (letters/digits only — e.g.
aiimagerouter; an underscore keeps the form disabled), the URL (https://<tunnel-host>/mcp) and a description. Auto-detect selects API Token Authentication → Bearer; paste the token and click Add connector — the page should then show Valid and the tool list. Verify the public path first withnpx tsx scripts/connector-test.ts https://<tunnel-host>/mcp. Adding a connector is an admin action (the account owner on Free/Pro).Tools only — Le Chat does not use MCP resources/prompts. Each tool has an "Always allow" toggle.
Notes: the server deliberately answers an unauthenticated request with a plain 401 (no
WWW-Authenticate challenge) so Le Chat offers token entry instead of attempting OAuth. Returned file
paths are on the server's disk — a later tool call can read them (chaining by path works), but you
cannot open them from Le Chat; use output_mode:"base64" for media you want to see there.
Mistral Vibe CLI
Vibe reads ~/.vibe/config.toml (or a trusted project ./.vibe/config.toml); each server is a
[[mcp_servers]] entry and its tools appear as {name}_{tool} (e.g. air_generate_image).
stdio (Vibe spawns the server; BG_NO_PREWARM skips the ~1 GB background-model load at startup):
[[mcp_servers]]
name = "air"
transport = "stdio"
command = "node"
args = ["V:/MCP/ai-image-router-mcp/dist/index.js"]
env = { BG_NO_PREWARM = "1" }
startup_timeout_sec = 60
tool_timeout_sec = 300HTTP (server started separately with npm start -- --http; Vibe has no OAuth, so use a static header):
[[mcp_servers]]
name = "air"
transport = "streamable-http" # "http" also accepted
url = "http://127.0.0.1:8765/mcp"
headers = { Authorization = "Bearer <token from mcp http token.txt>" }
startup_timeout_sec = 60
tool_timeout_sec = 300In Vibe, /mcp lists the servers and /mcp air lists that server's tools.
Generated media & previews
Files are written to the configured output directory (default output/) with
descriptive, timestamped names. Tools return the absolute file path as a resource_link,
plus an inline image preview for small images (downscaled automatically if needed). This
keeps large videos out of the conversation while still giving you the file.
When a call fails, the result is isError: true with a text block describing what
went wrong. Where the underlying cause is an account/config issue the gateway reports
opaquely, the result may also include actionable possible-cause hints (e.g. an
OpenRouter provider on your Ignored Providers list, or a key with Include BYOK
enabled while OpenRouter credit remains). Each hint is a text block prefixed
Possible cause: and tagged with _meta."ai-image-router/category" = "possibleCause",
so it both displays in any client and is detectable programmatically. These are
best-effort guesses, not guarantees.
Image compression & WebP (Tinify)
Provide a Tinify key (default file tinify com token.txt,
or set it in the wizard) to optimise generate_image output via direct REST calls (no
Tinify SDK):
generate_imagegains anoutput_formatofpng,webp,jpg, oravif.png(default): the model is steered to PNG, the raw PNG is kept as<name>-original.png, and a Tinify-compressed PNG is saved as<name>.pngand returned.webp/jpg/avif: the source PNG is kept as<name>.pngand a Tinify-converted<name>.webp/<name>.jpg/<name>.avifis saved and returned. This always goes through Tinify (even for models that can emit those formats natively) because Tinify produces noticeably smaller files (avifis usually the smallest).If Tinify fails, the original PNG is saved and a warning is included — a generation is never lost.
Typical results on a 1 MB generated PNG: compressed PNG ≈ −46–64%, WebP ≈ −95%.
Media editing (crop_media & transform_media)
crop_media and transform_media work on images and videos and take a file path, http(s)
URL, data: URL, or base64:
Images use sharp — crop is a pixel-exact
.extract({left, top, width, height}); downsize uses the Magic Kernel Sharp 2021 kernel and only ever shrinks (preserves aspect).transform_mediais a Swiss-army tool: passwidth/heightto downsize,output_format(png/jpg/webp/avif) to convert (Tinify when configured, else sharp), nothing butoutput_modeto return the file unchanged, or an imageoutput_formaton a video to extract a representative still (it samples from 10% in and skips mostly-black frames).output_format:"mp4"on a video converts it to an H.264/AAC mp4 (webm/mov/mkv/avi → mp4; an mp4 passes through unchanged). Asking for a video format on an image errors and points you atimage_to_video.save:falsewrites nothing (inline previews instead, when enabled) — including when building an.ico.ICO inputs are read with the project's own decoder: PNG-compressed entries (the 256 px entry in most modern favicons), 1/4/8-bpp paletted, 16/24/32-bpp bitmaps, and the AND transparency mask.
output_mode(on every media tool):filePath(default — saves and returns the path) orbase64(also saves, but returns the full bytes inline; large for video). A PNG returned asbase64while Tinify is enabled is compressed first (the uncompressed copy is kept as-original).Videos use ffmpeg from your PATH (frame extraction needs
ffprobetoo, which ships with ffmpeg). Ifffmpegis not installed, video operations return a clear message (image editing is unaffected).
Configuration reference (config.json)
Key | Notes |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| wizard timestamp + recorded issues/sources (read-only telemetry) |
Set AIR_MCP_CONFIG=/path/to/config.json to use a config file outside the project root.
Development
npm run dev # run the server from source via tsx
npm run typecheck # tsc --noEmit
npm test # unit + integration:nonpayment (no network, no cost)
npm run unit # pure unit tests only
npm run integration:nonpayment # real subsystems, no paid API
npm run integration:paid # LIVE billed API tests (tests/paid/**) — needs tokens/cost, run explicitly
npx tsx scripts/smoke.ts list openrouter # list a gateway's image models
npx tsx scripts/smoke.ts genimg openrouter "<prompt>" <model> # one-off generation
npx tsx scripts/mcp-test.ts # spawn the server and exercise it as a clientWorking on the code? Start with CLAUDE.md — architecture, conventions, the documentation map, and the hard-won gotchas. docs/API-NOTES.md holds the exact gateway/endpoint contracts the clients are built against, and docs/UPDATING-LEADERBOARDS.md covers refreshing the wizard's leaderboard highlights.
License
MIT — see LICENSE.
This server cannot be deployed
Maintenance
Related MCP Connectors
LLM chat, text tools, image generation, editing, batch image jobs, and asynchronous video generation
Create images and videos from prompts, with options for image mixing, reference images, and start/…
- MochifyOAuthapp.mochify
Image and PDF toolkit: convert to AVIF/WebP/JXL, resize, crop, remove backgrounds, optimize PDFs.
Image and video AI tools and your own pipelines, run from any AI assistant.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables comprehensive image processing, stock image search from Pexels and Pixabay, and AI image generation using OpenAI DALL-E with support for resizing, format conversion, color extraction, and watermarking.15 npmMIT
- AlicenseAqualityCmaintenanceEnables image generation and editing using OpenAI's GPT Image API (gpt-image-1, 1.5, 2) with support for multi-image generation, history management, and batch processing.12125 npm1MIT
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to generate and edit images using multiple models through OpenRouter, with features like style presets, batch operations, and variations.22 npm1MIT
- AlicenseAqualityCmaintenanceGives AI assistants image generation and editing capabilities through OpenRouter, supporting multiple models, style presets, variations, and batch operations.553 npm2MIT