MCP server providing access to 300+ AI models via OpenRouter
Project description
Overview
The Punchline
mcp-openrouter is a Python MCP server that gives Codex, Claude Code, opencode, and other MCP hosts access to OpenRouter's model catalog through five practical tools: chat, image generation, embeddings, model listing, and model search.
The Pain
OpenRouter exposes hundreds of models, but every agent host needs a clean way to call them with the right API key, model defaults, request shape, and host-specific MCP configuration.
The Solution
Install mcp-openrouter with uvx, persist your OPENROUTER_API_KEY, and let the server translate MCP tool calls into OpenRouter API requests with retry handling, .env support, and optional default models.
The Result
You get one local stdio MCP server for text, images, embeddings, and model discovery across supported MCP clients, without wiring each workflow to OpenRouter manually.
| Fact | Detail |
|---|---|
| MCP tools | chat, generate_image, embed, list_models, find_models |
| Supported installers | Codex, Claude Code, opencode |
| Runtime | Python 3.10+ with uvx mcp-openrouter |
| Registry package | io.github.tsilva/mcp-openrouter via PyPI package mcp-openrouter |
Features
- Unified chat requests: send prompts or multi-turn message arrays to any OpenRouter chat model, with sampling, JSON response, reasoning, provider routing, and assistant prefill options.
- Image generation: create images through OpenRouter image-capable models, control aspect ratio and size, and optionally save generated files to an absolute local path.
- Embeddings: generate vector embeddings for a string or a list of strings, including optional encoding format and dimension controls.
- Model discovery: list OpenRouter models and filter by
vision,image_gen,embedding,tools, orlong_context. - Model search: find matching model slugs by name or identifier and return a compact result set for fast selection.
- Host-aware installer: detect eligible MCP clients, prompt for targets, replace stale configs only when requested, and support non-interactive installs.
- Default model configuration: make
modeloptional per tool by setting default model environment variables. - Retry and error handling: retry transient OpenRouter failures and return clearer messages for authentication, credits, rate limits, and moderation errors.
Quick Start
Use It Now
Install into every detected MCP client:
uvx mcp-openrouter install --yes
Install into specific clients:
uvx mcp-openrouter install --yes --clients codex,claude
Pass the OpenRouter key directly for non-interactive setup:
uvx mcp-openrouter install --yes --api-key sk-or-v1-...
Replace an existing openrouter MCP config when it differs:
uvx mcp-openrouter install --yes --force
The interactive installer reuses OPENROUTER_API_KEY from your shell when it is set. Otherwise, it prompts securely.
Run Locally
git clone https://github.com/tsilva/mcp-openrouter.git
cd mcp-openrouter
uv sync --dev
OPENROUTER_API_KEY=your-key uv run mcp-openrouter
mcp-openrouter with no arguments starts the stdio MCP server. The explicit equivalent is:
OPENROUTER_API_KEY=your-key uv run mcp-openrouter serve
Check the Project
uv run pytest tests/test_cli.py tests/test_client.py tests/test_config.py tests/test_installer.py tests/test_release_metadata.py tests/test_server.py
OPENROUTER_API_KEY=your-key uv run pytest tests/test_tools.py
OPENROUTER_API_KEY=your-key uv run pytest tests/
uv run ruff check src/
uv run ruff format src/
Integration tests in tests/test_tools.py require a live OpenRouter API key. The unit tests mock network calls.
Installation Details
The installer targets the production runtime command:
uvx mcp-openrouter
Installed host configs are equivalent to:
| Host | Configuration |
|---|---|
| Codex | codex mcp add openrouter --env OPENROUTER_API_KEY=... -- uvx mcp-openrouter |
| Claude Code | claude mcp add -s user openrouter -e OPENROUTER_API_KEY=... -- uvx mcp-openrouter |
| opencode | Adds openrouter under the mcp object in ~/.opencode/settings.json |
Uninstall from all detected clients:
uvx mcp-openrouter uninstall --yes
Uninstall from selected clients:
uvx mcp-openrouter uninstall --yes --clients claude,opencode
Manual uninstall commands:
codex mcp remove openrouter
claude mcp remove -s user openrouter
For opencode, the uninstaller removes the openrouter entry from ~/.opencode/settings.json.
Configuration
Required:
| Variable | Description |
|---|---|
OPENROUTER_API_KEY |
OpenRouter API key used for all tool requests |
Optional defaults:
| Variable | Used by |
|---|---|
DEFAULT_TEXT_MODEL |
chat when no model is passed |
DEFAULT_IMAGE_MODEL |
generate_image when no model is passed |
DEFAULT_EMBEDDING_MODEL |
embed when no model is passed |
DEFAULT_CODE_MODEL |
Reserved for code-oriented client defaults |
DEFAULT_VISION_MODEL |
Reserved for vision-oriented client defaults |
The server loads environment variables from .env in the current working directory and from the repository root when running from a checkout.
Example .env:
OPENROUTER_API_KEY=sk-or-v1-your-key-here
DEFAULT_TEXT_MODEL=google/gemini-3-pro-image-preview
DEFAULT_IMAGE_MODEL=google/gemini-3-pro-image-preview
DEFAULT_CODE_MODEL=anthropic/claude-sonnet-4.5
DEFAULT_VISION_MODEL=google/gemini-3-pro-image-preview
DEFAULT_EMBEDDING_MODEL=mistralai/mistral-embed-2312
Tool Usage
Chat
Use openrouter chat with anthropic/claude-sonnet-4 to summarize this file
chat accepts either prompt or messages, not both.
| Parameter | Type | Required | Description |
|---|---|---|---|
prompt |
string | Yes* | User message to send |
messages |
array | Yes* | Multi-turn list of {role, content} messages |
model |
string | No** | OpenRouter model slug |
system |
string | No | System prompt prepended to the conversation |
max_tokens |
int | No | Maximum response tokens |
temperature |
float | No | Sampling temperature |
top_p |
float | No | Nucleus sampling threshold |
top_k |
int | No | Top-k sampling limit |
frequency_penalty |
float | No | Repetition penalty |
presence_penalty |
float | No | Presence penalty |
seed |
int | No | Deterministic seed when supported |
stop |
array | No | Stop sequences |
json_mode |
bool | No | Request JSON object output |
response_format |
object | No | Explicit OpenRouter response format |
reasoning_effort |
string | No | minimal, medium, or high |
provider |
object | No | Provider routing preferences |
assistant_prefill |
string | No | Assistant message prefix |
*Provide one of prompt or messages.
**Required unless DEFAULT_TEXT_MODEL is set.
Generate Image
Use openrouter generate_image with google/gemini-3-pro-image-preview to create a square app icon
| Parameter | Type | Required | Description |
|---|---|---|---|
prompt |
string | Yes | Image description |
model |
string | No* | OpenRouter image model slug |
aspect_ratio |
string | No | 1:1, 16:9, 9:16, 4:3, 3:4, or 21:9 |
size |
string | No | 1K, 2K, or 4K |
background |
string | No | Background setting such as transparent |
quality |
string | No | Quality setting such as high, medium, or low |
output_format |
string | No | png, webp, jpeg, or model-supported format |
output_path |
string | No | Absolute file path for saving the generated image |
*Required unless DEFAULT_IMAGE_MODEL is set.
Embed
Use openrouter embed with mistralai/mistral-embed-2312 to embed "Hello world"
| Parameter | Type | Required | Description |
|---|---|---|---|
input |
string or array | Yes | Text string or list of strings |
model |
string | No* | OpenRouter embedding model slug |
encoding_format |
string | No | float or base64 |
dimensions |
int | No | Model-dependent output dimensions |
*Required unless DEFAULT_EMBEDDING_MODEL is set.
List Models
Use openrouter list_models with capability "image_gen"
| Parameter | Type | Required | Description |
|---|---|---|---|
capability |
string | No | vision, image_gen, embedding, tools, or long_context |
Find Models
Use openrouter find_models to search for "claude"
| Parameter | Type | Required | Description |
|---|---|---|---|
search_term |
string | Yes | Text to search for in model names or slugs |
Architecture
MCP host
-> FastMCP tools in src/mcp_openrouter/server.py
-> get_client()
-> OpenRouterClient in src/mcp_openrouter/client.py
-> https://openrouter.ai/api/v1
| Path | Purpose |
|---|---|
src/mcp_openrouter/server.py |
FastMCP server, tool registration, env loading, tool argument validation |
src/mcp_openrouter/client.py |
OpenRouter HTTP client, retry handling, model normalization |
src/mcp_openrouter/config.py |
Default model environment variable lookup |
src/mcp_openrouter/cli.py |
serve, install, and uninstall command dispatch |
src/mcp_openrouter/installer.py |
MCP client detection and host-specific config writers |
server.json |
MCP Registry metadata for the PyPI package |
tests/ |
Unit tests plus live OpenRouter integration tests |
Local MCP Development
If you want an MCP host to run directly from a local checkout instead of the published PyPI package, register the repo path manually.
Claude Code:
claude mcp add openrouter --scope user -- uv run --directory /path/to/mcp-openrouter mcp-openrouter
Codex:
codex mcp add openrouter --env OPENROUTER_API_KEY=your-key -- uv run --directory /path/to/mcp-openrouter mcp-openrouter
opencode:
{
"mcp": {
"openrouter": {
"type": "local",
"command": ["uv", "run", "--directory", "/path/to/mcp-openrouter", "mcp-openrouter"],
"environment": {
"OPENROUTER_API_KEY": "your-key"
},
"enabled": true
}
}
}
After changing server code, restart the MCP host session so it launches a fresh server process.
Tech Stack
- FastMCP for MCP server and tool registration.
- OpenRouter for chat, image, embedding, and model catalog APIs.
- uv for local dependency management and
uvxruntime installs. - requests for HTTP calls with explicit retry behavior.
- python-dotenv for
.envloading during local development. - pytest and Ruff for test and lint coverage.
Troubleshooting
| Problem | Fix |
|---|---|
OPENROUTER_API_KEY is not set |
Set it in your shell or .env, then restart the MCP host. |
| Installer finds no clients | Make sure codex, claude, or opencode is installed and available on PATH. |
| Existing config is skipped | Re-run with --force if you want the installer to replace it. |
| Image save fails | output_path must be absolute, for example /Users/you/output.png. |
| Auth, credit, or rate-limit errors | Check your key and account status at openrouter.ai/keys. |
| Local source changes do not appear | Restart the MCP host so the long-lived server process reloads. |
Publishing Notes
- Publish the Python package to PyPI as
mcp-openrouter. - Keep
server.jsonin sync with the released package version. - Preserve the
<!-- mcp-name: io.github.tsilva/mcp-openrouter -->marker for MCP Registry ownership verification. - Update
CHANGELOG.mdbefore release so GitHub release notes stay readable. - Use the Makefile helper for version bumps:
make release-1.1.8
Support
Open an issue for bugs, model compatibility problems, or host installation edge cases. Contributions are welcome when they keep the server small, explicit, and easy to verify.
License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mcp_openrouter-1.1.8.tar.gz.
File metadata
- Download URL: mcp_openrouter-1.1.8.tar.gz
- Upload date:
- Size: 195.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ed85cf7d680a8626dcaff547ae50658f663a7dec9ecea3dae0954892c3977bda
|
|
| MD5 |
81d4fb82b0cf46298e22132ceaa91446
|
|
| BLAKE2b-256 |
b4a7a1772e79baf657caf341457b0ceab7686cdd3fd4c3a236059ae40610f94c
|
Provenance
The following attestation bundles were made for mcp_openrouter-1.1.8.tar.gz:
Publisher:
release.yml on tsilva/mcp-openrouter
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mcp_openrouter-1.1.8.tar.gz -
Subject digest:
ed85cf7d680a8626dcaff547ae50658f663a7dec9ecea3dae0954892c3977bda - Sigstore transparency entry: 1403014433
- Sigstore integration time:
-
Permalink:
tsilva/mcp-openrouter@d506c728b57eda71b7abca2fdecb274744f2e2ed -
Branch / Tag:
refs/heads/main - Owner: https://github.com/tsilva
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@d506c728b57eda71b7abca2fdecb274744f2e2ed -
Trigger Event:
push
-
Statement type:
File details
Details for the file mcp_openrouter-1.1.8-py3-none-any.whl.
File metadata
- Download URL: mcp_openrouter-1.1.8-py3-none-any.whl
- Upload date:
- Size: 20.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7508ccde6bbf6cf56e9968923bf8009f527582bc218f3cc8883404b414fb30cd
|
|
| MD5 |
493f65f057b7caaf07b5eaad961afd14
|
|
| BLAKE2b-256 |
12c0595dd4550be9e20065fd486e2dfa4638c063980a25e666c75205e7ef0225
|
Provenance
The following attestation bundles were made for mcp_openrouter-1.1.8-py3-none-any.whl:
Publisher:
release.yml on tsilva/mcp-openrouter
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
mcp_openrouter-1.1.8-py3-none-any.whl -
Subject digest:
7508ccde6bbf6cf56e9968923bf8009f527582bc218f3cc8883404b414fb30cd - Sigstore transparency entry: 1403014518
- Sigstore integration time:
-
Permalink:
tsilva/mcp-openrouter@d506c728b57eda71b7abca2fdecb274744f2e2ed -
Branch / Tag:
refs/heads/main - Owner: https://github.com/tsilva
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@d506c728b57eda71b7abca2fdecb274744f2e2ed -
Trigger Event:
push
-
Statement type: