# Rust Openrouter Mcp

> MCP server and CLI for OpenRouter, in a single Rust binary - discover models and generate images, video, and speech from Claude.

- **Type:** MCP server
- **Install:** `agentstack add mcp-thesimj-rust-openrouter-mcp`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [thesimj](https://agentstack.voostack.com/s/thesimj)
- **Installs:** 0
- **Category:** [AI & ML](https://agentstack.voostack.com/c/ai-and-ml)
- **Latest version:** 0.1.0
- **License:** Apache-2.0
- **Upstream author:** [thesimj](https://github.com/thesimj)
- **Source:** https://github.com/thesimj/rust-openrouter-mcp
- **Website:** https://crates.io/crates/openrouter-mcp

## Install

```sh
agentstack add mcp-thesimj-rust-openrouter-mcp
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# rust-openrouter-mcp

[](https://github.com/thesimj/rust-openrouter-mcp#license)
[](https://github.com/thesimj/rust-openrouter-mcp/actions/workflows/release-mcpb.yml)
[](https://github.com/thesimj/rust-openrouter-mcp/blob/main/Cargo.toml)

  

MCP (stdio) server **and** CLI for [OpenRouter](https://openrouter.ai), 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 (PNG/JPEG) is **chosen by the provider** - it is sniffed
    from the response and the file extension is set to match.
  - 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**: returns a `task_id`; poll `get_result` for the hosted clip.
- **Speech generation** - `generate_audio`: text-to-speech with an OpenRouter
  TTS model (voice/format/speed); saves the audio to disk with a manifest.
- **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).
- **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](https://github.com/thesimj/rust-openrouter-mcp/releases/latest):
   `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](https://openrouter.ai/keys), 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](#privacy-policy).

To build the bundle yourself (the macOS build is a universal arm64+x86_64
binary), run the cross-platform generator on the target platform:

```bash
node scripts/build-mcpb.mjs   # -> dist/openrouter-mcp-.mcpb
```

## Connect another client (CLI, IDE, agent)

`openrouter-mcp` is a universal local stdio MCP server. **[CONNECT.md](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):

[](cursor://anysphere.cursor-deeplink/mcp/install?name=openrouter&config=eyJjb21tYW5kIjogIm9wZW5yb3V0ZXItbWNwIiwgImFyZ3MiOiBbIm1jcCJdLCAiZW52IjogeyJPUEVOUk9VVEVSX0FQSV9LRVkiOiAic2stb3ItdjEtWU9VUl9LRVkifX0=)
[](https://insiders.vscode.dev/redirect/mcp/install?name=openrouter&config=%7B%22command%22%3A%20%22openrouter-mcp%22%2C%20%22args%22%3A%20%5B%22mcp%22%5D%2C%20%22env%22%3A%20%7B%22OPENROUTER_API_KEY%22%3A%20%22sk-or-v1-YOUR_KEY%22%7D%7D)

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

From a local checkout:

```bash
cargo install --path . --locked --force
```

From crates.io (once published):

```bash
cargo install openrouter-mcp
```

## Configuration

Set an OpenRouter API key:

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

On PowerShell:

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

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

```text
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` / `get_result` embed inline base64 image previews: `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 `800`; larger values are reduced to `800`. | `800` |
| `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. | (OS-provided) |

A few of these warrant extra detail.

`OPENROUTER_MCP_IMAGE_PREVIEWS` controls whether `generate_image` /
`get_result` embed the generated image **inline** (base64) in the tool result, 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.

## 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):

```bash
openrouter-mcp        # or: openrouter-mcp mcp
```

Example MCP client config:

```json
{
  "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). |
| `describe_model` | read-only | Full detail for one model id: description, architecture, context, benchmarks, per-provider endpoints, and (for video models) real `pricing_skus`. |
| `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`. **No defaults** for `model`, `prompt`, `aspect_ratio`, `image_size`; `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`. |
| `generate_audio` | write | Text-to-speech with an OpenRouter TTS model; saves audio to disk. |
| `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`,
`describe`, `chat`, `key`, `mcp`.

Show info about the API key in use:

```bash
openrouter-mcp key
```

Send a prompt to a chat/text model:

```bash
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:

```bash
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:

```bash
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`):

```bash
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-.` plus a manifest):

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

Describe an image:

```bash
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`):

```bash
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):

```bash
openrouter-mcp audio \
  --model openai/gpt-4o-mini-tts --voice alloy \
  --input "Hello from OpenRouter." --output ./out/hello.mp3
```

## Development

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

Live smoke tests (require `OPENROUTER_API_KEY`):

```bash
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. The
only third party it contacts is [OpenRouter](https://openrouter.ai), and only to
fulfill the requests you make (model discovery, image/video/speech generation,
image description, and chat completion). Your API key is sent solely to
OpenRouter to authenticate those calls. Generated files are written only to
paths you specify (or an auto-named path under `OPENROUTER_MCP_OUTPUT_DIR`);
usage stats live in memory and are lost on exit. Full details:
[PRIVACY.md](PRIVACY.md).

## License

Licensed under either of:

- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE))
- MIT license ([LICENSE-MIT](LICENSE-MIT))

at your option.

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [thesimj](https://github.com/thesimj)
- **Source:** [thesimj/rust-openrouter-mcp](https://github.com/thesimj/rust-openrouter-mcp)
- **License:** Apache-2.0
- **Homepage:** https://crates.io/crates/openrouter-mcp

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** yes
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-thesimj-rust-openrouter-mcp
- Seller: https://agentstack.voostack.com/s/thesimj
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
