Command Palette

Search for a command to run...

UnylyUnyly
Browse all

Openrouter

FreeNot checked

MCP stdio server and CLI for OpenRouter: model discovery, image generation/editing, and image description

GitHubEmbed

About

MCP stdio server and CLI for OpenRouter: model discovery, image generation/editing, and image description

README

License: MIT OR Apache-2.0 Release MCPB MSRV

rust-openrouter-mcp - one Rust binary routing an AI assistant to OpenRouter's models

MCP (stdio) server and CLI for OpenRouter, in a single Rust binary. Discover models, generate and edit images (with parallel variants and a sidecar manifest), describe images with a vision model, and track per-process usage - all behind one openrouter-mcp executable.

Features

  • Model discovery - list_models with server-side filters (modality, supported params, sort, min context), local search, and pricing; describe_model returns full detail for one model id (architecture, context, benchmarks, and per-provider endpoints with pricing - including real pricing_skus for video).
  • Image generation - generate_image: text-to-image, image editing / image-to-image (multiple local inputs), and parallel variants (seed-stepped).
    • Input images may be PNG, JPEG, WebP, GIF, or SVG. SVG inputs are rasterized to PNG (longest side scaled to the dimension cap; transparency preserved). Text in SVGs is not rendered (no fonts are loaded) and is flagged as a warning.
    • The output format is chosen by the provider: PNG/JPEG/WebP/GIF are sniffed from the response bytes; SVG is taken from the provider's declared media type instead (sniffing can't detect it). Either way the file extension is set to match what actually came back. An output_format request hint is passed through, but support varies by model.
    • Requested aspect_ratio / image_size are verified against the actual decoded pixels; mismatches are surfaced as warnings.
    • Every job writes a *.manifest.json sidecar (full settings, per-input and per-variant metadata, cost, provider, timing).
    • Asynchronous: if a job runs longer than wait_seconds (default 10) the tool returns a task_id; poll get_result for completion.
  • Video generation - generate_video: text-to-video and image-to-video (first/last frame and reference images) with an OpenRouter video model. Asynchronous: if the job runs longer than wait_seconds (default 20, video usually needs it) the tool returns a task_id; poll get_result for completion. Once done, the clip is downloaded and saved to disk (a local path, plus a file:// resource link when inline previews are enabled for sandboxed clients), not just the hosted URL. with_audio (renamed from generate_audio in 0.6.0) controls the clip's audio track; if a provider ignores it, the result carries a warning and has_audio reports the file's real state.
  • Speech generation - generate_audio: text-to-speech with an OpenRouter TTS model (voice/format/speed); saves the audio to disk with a manifest.
  • Transcription - transcribe_audio: speech-to-text with an OpenRouter STT model; audio by local path or inline base64, optional language hint.
  • Image description - describe_image: image -> detailed text via any vision-capable model (image input, text output).
  • Chat completion - chat_completion: send a prompt to any OpenRouter chat/text model and get its text reply - route a sub-task to a different model (optional system, temperature, max_tokens). Optionally attach images (path/url/base64) for a vision-capable model; the call is rejected only when the model is known not to accept image input (otherwise it is sent as-is).
  • Reasoning effort - chat_completion and describe_image take an optional reasoning_effort: max, xhigh, high, medium, low, minimal or none. It is omitted from the request unless you set it, so each model keeps its catalog default_effort (see reasoning.supported_efforts in list_models). Reasoning tokens bill as output tokens, so none is the cheapest and fastest setting on models that allow it. Some models make reasoning mandatory and reject none with a 400.
  • Account info - get_account: basic info about the API key in use (label, owning user id, credit usage with daily/weekly/monthly breakdown, spending limit / remaining balance, and tier / key-type flags).
  • Usage stats - get_usage_stats (read-only) and reset_usage_stats (destructive, requires confirm: true): per-process request/cost counters with a by-model breakdown.

Add to Claude Desktop (one-click)

This server ships as a Claude Desktop extension (.mcpb) for macOS, Windows, and Linux - no terminal or Rust toolchain required.

  1. Download the bundle for your platform from the latest release: openrouter-mcp-macos.mcpb, openrouter-mcp-windows.mcpb, or openrouter-mcp-linux.mcpb.
  2. Double-click it (or drag it into Claude Desktop -> Settings -> Extensions).
  3. Click Install, paste your OpenRouter API key, and enable it.

Your API key is stored by Claude Desktop (the OS keychain/credential store) and injected into the server as OPENROUTER_API_KEY. See Privacy Policy.

To build the bundle yourself, run the cross-platform generator on the target platform:

node scripts/build-mcpb.mjs   # -> dist/openrouter-mcp-<os>.mcpb

Per-platform specifics, all handled by the generator: macOS produces a universal arm64+x86_64 binary (via lipo); Linux builds a static x86_64-unknown-linux-musl binary so the bundle runs on any distro regardless of the host's glibc version; Windows statically links the CRT so it starts on a fresh install with no Visual C++ Redistributable. TLS is pure-Rust rustls trusting the OS certificate store, so no system OpenSSL is needed to build any target and custom/corporate root CAs installed on the machine still work.

Connect another client (CLI, IDE, agent)

openrouter-mcp is a universal local stdio MCP server. CONNECT.md has copy-paste setup for Claude Code, Codex CLI, Gemini CLI, Antigravity, Cursor, Windsurf, VS Code (Copilot), Zed, Cline, Roo Code, Continue, Goose, opencode, Crush, Amp, OpenHands, and more.

Install (CLI / other MCP clients)

One-click install into a supported IDE (both wire up openrouter-mcp mcp over stdio - replace the placeholder sk-or-v1-YOUR_KEY with your real key after):

Add to Cursor Install in VS Code

Both require openrouter-mcp to be on your PATH (install it below first).

From a local checkout:

cargo install --path . --locked --force

From crates.io:

cargo install openrouter-mcp

Configuration

Set an OpenRouter API key:

export OPENROUTER_API_KEY="sk-or-v1-..."

On PowerShell:

$env:OPENROUTER_API_KEY = "sk-or-v1-..."

A local .env file is also loaded if present (real env vars take precedence):

OPENROUTER_API_KEY=sk-or-v1-...

Do not commit .env.

All environment variables read by the server/CLI:

Variable Purpose Default
OPENROUTER_API_KEY OpenRouter API key. The only required variable; every API-backed call errors without it. May also be supplied via .env. (none - required)
OPENROUTER_MCP_IMAGE_PREVIEWS Whether generate_image/generate_video/generate_audio (and get_result) embed inline previews - base64 image previews, video file:// resource links, and inline audio blocks: always, never, or auto. auto (inline for all clients except claude-code)
OPENROUTER_MCP_OUTPUT_DIR Base directory for auto-named output artifacts (images/video/audio + manifests). $HOME/Downloads/openrouter-mcp (system temp dir if HOME unset)
OPENROUTER_IMAGE_MAX_DIMENSION Longest-side pixel cap for normalized input images before sending. Clamped to a hard ceiling of 4096; larger values are reduced to 4096. 1536
OPENROUTER_VIDEO_POLL_INTERVAL Polling interval (seconds) for the video generation status loop. 5
OPENROUTER_VIDEO_POLL_TIMEOUT Ceiling (seconds) on the video generation poll loop. 600
OPENROUTER_HTTP_REFERER Overrides the HTTP-Referer app-attribution header (OpenRouter rankings only; no effect on responses). https://github.com/thesimj/rust-openrouter-mcp
OPENROUTER_X_TITLE Overrides the X-Title app-attribution header. rust-openrouter-mcp
HOME OS variable; only used to derive the default output directory when OPENROUTER_MCP_OUTPUT_DIR is unset. Only HOME is checked, not USERPROFILE - a stock Windows install without HOME set falls straight to the system temp dir. (OS-provided)

A few of these warrant extra detail.

OPENROUTER_MCP_IMAGE_PREVIEWS controls whether generate_image, generate_video, generate_audio, and get_result embed the generated media inline in the tool result (base64 images, video file:// resource links, or inline audio blocks), in addition to saving it to disk:

  • auto (default) - inline previews for every client except the local claude-code CLI, which shares the filesystem and can open the saved file directly.
  • always - always embed previews. The Claude Desktop connector sets this, because Desktop runs the server in a sandboxed filesystem it can't read, so the saved path is unreachable and the image must come back inline.
  • never - paths only, never inline bytes.

Inline previews are downscaled to a 1568px longest side; the full-resolution image is always the file saved on disk. At most 4 inline previews are embedded per job (remaining images are reported by path only in the JSON), and inline audio previews are capped at 4 MB (larger clips are saved to disk with the path returned instead).

MCP usage

The server speaks MCP over stdio (the mcp subcommand); it is local-only, with no remote/HTTP transport.

Start the stdio server (mcp subcommand is implied when none is given):

openrouter-mcp        # or: openrouter-mcp mcp

Example MCP client config:

{
  "mcpServers": {
    "openrouter": {
      "command": "openrouter-mcp",
      "env": { "OPENROUTER_API_KEY": "sk-or-v1-..." }
    }
  }
}

If the client already provides OPENROUTER_API_KEY in the environment, the env block is optional.

MCP tools

Tool Kind Description
list_models read-only List models with capabilities and pricing (server-side filters, local search; human-readable $X/M tokens pricing; tiered/time-window overrides are passed through raw and rendered in pricing_human when a model has them).
describe_model read-only Full detail for one model id: description, architecture, context, benchmarks, per-provider endpoints, (for video models) real pricing_skus, and (for image models) per-endpoint image capabilities merged under an image key.
generate_image write Generate or edit images via OpenRouter's dedicated /api/v1/images endpoint (works with any image model: Nano Banana, Grok, Seedream, FLUX, GPT Image, Recraft, ...); supports variants; async with task_id. Inputs by path/url/base64. Optional quality (auto/low/medium/high), output_format (png/jpeg/webp/svg), background (auto/transparent/opaque), and output_compression (0-100, webp/jpeg only) pass through to the provider. No defaults for model, prompt, aspect_ratio, image_size - all four are required by the schema, not just prose; output is optional (auto-named under OPENROUTER_MCP_OUTPUT_DIR).
generate_video write Text-to-video / image-to-video with an OpenRouter video model; async, poll by task_id. Required: model, prompt, duration, with_audio (renamed from generate_audio in 0.6.0).
generate_audio write Text-to-speech with an OpenRouter TTS model; saves audio to disk.
transcribe_audio read-only Speech-to-text via /api/v1/audio/transcriptions: audio by path or base64 (wav/mp3/flac/m4a/ogg/webm/aac, max 25 MB), optional ISO-639-1 language, response_format (json/verbose_json), timestamp_granularities (segment/word - verbose_json + OpenAI-compatible providers only), and temperature; returns the transcript. Find models with list_models + output_modalities="transcription".
chat_completion write Send a prompt to any OpenRouter chat/text model and return its text reply; route a sub-task to a different model. Optionally attach images for a vision model (best-effort gated on the model's declared image-input support).
describe_image read-only Describe image(s) - by path, url, or base64/data-URL - with a vision-capable model; returns text.
get_result read-only Fetch a job by task_id: pending / completed / failed.
get_account read-only Basic info about the API key in use: label, owning user id, credit usage (total + daily/weekly/monthly), limit/remaining, and tier/key-type flags.
get_usage_stats read-only In-memory request/cost counters (and server version) with a by-model breakdown.
reset_usage_stats destructive Reset all counters (confirm: true required).

generate_image returns a lean result - saved paths, decoded width/height, requested vs. actual aspect/size, seeds, and a pointer to the sidecar manifest; the full per-variant detail lives in the manifest on disk.

CLI usage

The same binary is a CLI. Subcommands: models, image, video, audio, transcribe, describe, chat, key, mcp.

Show info about the API key in use:

openrouter-mcp key

Send a prompt to a chat/text model:

openrouter-mcp chat --model openai/gpt-5.4 --prompt "Summarize MCP in one sentence."
openrouter-mcp chat -m anthropic/claude-sonnet-4.6 -s "Be terse." -p "Why Rust?" --temperature 0.3

Browse models:

openrouter-mcp models --query openai --sort newest --table
openrouter-mcp models --output-modalities image --sort newest --table
openrouter-mcp models --query openai --search codex
openrouter-mcp models --query claude --all

Generate an image:

openrouter-mcp image \
  --model google/gemini-3.1-flash-image-preview \
  --prompt "a photorealistic owl with one cybernetic eye, starry sky" \
  --aspect-ratio 1:1 --image-size 1K --seed 1200 \
  --output ./out/owl.png

Edit / image-to-image (repeatable --image, optional label=path):

openrouter-mcp image \
  --model google/gemini-3.1-flash-image-preview \
  --prompt "add a small wizard hat" \
  --image ./out/owl.png \
  --output ./out/owl-hat.png

Four parallel variants (files named *-var-<seed>.<ext> plus a manifest):

openrouter-mcp image -m bytedance-seed/seedream-4.5 \
  --prompt "a cute pixar-style baby dragon" \
  --aspect-ratio 1:1 --image-size 1K --seed 1490 --variants 4 \
  --output ./out/dragon.png

Also accepts --quality, --output-format, --background, and --output-compression (provider support varies; see --help).

Describe an image:

openrouter-mcp describe -m google/gemini-2.5-flash-lite --image ./out/owl.png

The image format the provider returns is not guaranteed; the CLI corrects the saved file's extension to match what actually came back.

Generate a video (blocks through submit + poll; text-to-video or image-to-video via --first-frame / --last-frame):

openrouter-mcp video \
  --model bytedance/seedance-2.0 \
  --prompt "a paper boat drifting down a rain-soaked street, cinematic" \
  --duration 8 --resolution 1080p --output ./out/boat.mp4

Generate speech (text-to-speech):

openrouter-mcp audio \
  --model hexgrad/kokoro-82m --voice af_heart \
  --input "Hello from OpenRouter." --output ./out/hello.mp3

Transcribe audio (speech-to-text):

openrouter-mcp transcribe \
  --model openai/gpt-4o-mini-transcribe --file ./out/hello.mp3 --language en

Also accepts --response-format verbose_json (segment/word timestamps, duration, detected language - OpenAI-compatible providers only), --timestamp-granularities segment,word, and --temperature.

Development

cargo fmt --check
cargo clippy --all-targets --all-features -- -D warnings
cargo test
cargo llvm-cov --summary-only        # coverage (cargo install cargo-llvm-cov)

CI (.github/workflows/ci.yml) runs fmt --check, clippy -D warnings, and the test suite on every push to main and every pull request, plus a separate msrv job that runs cargo check --all-targets at the declared rust-version floor; the release workflow only fires on a version tag, so this is the gate that runs before anything ships.

Live smoke tests (require OPENROUTER_API_KEY):

cargo run -- models --query openai --sort newest --table
cargo run -- describe -m google/gemini-2.5-flash-lite --image ./some.png

Privacy Policy

openrouter-mcp runs entirely on your machine and collects no telemetry. Full details, including the one third-party-URL-fetch exception (image url inputs are fetched directly, not via OpenRouter) and where generated files land (the path you specify, or an auto-named one under OPENROUTER_MCP_OUTPUT_DIR / $HOME/Downloads/openrouter-mcp / the system temp dir): PRIVACY.md.

License

Licensed under either of:

at your option.

from github.com/thesimj/rust-openrouter-mcp

Installing Openrouter

This server has no published package — it is built from source. Open the repository and follow its README.

▸ github.com/thesimj/rust-openrouter-mcp

FAQ

Is Openrouter MCP free?

Yes, Openrouter MCP is free — one-click install via Unyly at no cost.

Does Openrouter need an API key?

No, Openrouter runs without API keys or environment variables.

Is Openrouter hosted or self-hosted?

Self-hosted: the server runs locally on your machine via the install command above.

How do I install Openrouter in Claude Desktop, Claude Code or Cursor?

Open Openrouter on unyly.org, pick your client tab (Claude Desktop, Claude Code, Cursor) and press Install — the config is generated automatically, no JSON editing.

Related MCPs

Compare Openrouter with

Not sure what to pick?

Find your stack in 60 seconds

Author?

Embed badge for your README

Browse similar

All media MCPs