This MCP server provides multimodal capabilities for AI agents by enabling chat with 300+ LLMs via OpenRouter. It supports analysis and generation across text, vision, audio, and video within the Model Context Protocol (MCP).
π οΈ Key Features
OpenRouter-backed chat with 300+ models
Multimodal processing: text, vision, audio, and video
MCP server for multimodal AI agents
Distributed as an npm package (as indicated by the npm badge in the excerpt)
π Use Cases
Analyzing and generating content from different modalities (vision, audio, video)
Building multimodal AI agents that communicate through MCP
Using OpenRouter models in MCP-based workflows
β‘ Developer Benefits
One install setup (as stated: βOne installβ)
Broad model availability (300+ OpenRouter models)
Tool-oriented approach in MCP (excerpt states β19 toolsβ)
β οΈ Limitations
The provided source excerpt does not specify tool details, authentication, or runtime constraints beyond β19 tools.β
Model discovery, validation, reranking, ops health
Production hardening: input/output path sandboxes (including analyze_* local files as of v4.5.2), SSRF guards, structured errors with _meta.code, MCP 2025-06-18 structured outputs, tool icons (2025-11-25), async video progress notifications, and 1000+ automated tests (unit, mock, regression, and live integration).
No credits required to start. Free models such as google/gemma-4-26b-a4b-it:free work for chat and vision. Video/audio generation typically needs credits.
Install
MCP servers are distributed through several packaging models. This server is implemented in Node.js/TypeScript; the table below maps each ecosystem method to how you run it here.
uvx vs npx: In the MCP ecosystem, npx runs npm (Node) packages and uvx runs PyPI (Python) packages. Because this server is Node-based, uvx uses a thin Python launcher that execs npx -y @stabgan/openrouter-mcp-multimodal β you still need Node installed.
Errors use a closed _meta.code taxonomy: INVALID_INPUT Β· UNSAFE_PATH Β· UPSTREAM_* Β· MODEL_NOT_FOUND Β· JOB_STILL_RUNNING Β· and more.
Binary tool results (v4.7.0+)
Generate tools (generate_image, generate_image_dedicated, generate_audio, text_to_speech, generate_video, generate_video_from_image, get_video_status) return image, audio, or video bytes. As of 4.7.0 the behavior is explicit:
save_path
Tool result
Set
Text pointer only β e.g. Image saved to: out.png (β¦ bytes, image/png) plus _meta.save_path. No inline base64 (avoids duplicating large payloads in the MCP channel).
Unset, under byte ceiling
Inline media block and summary text (images/audio use MCP image / audio types; video uses MCP resource blocks).
Unset, over ceiling
Text only with a hint to pass save_path.
Default inline ceilings (override per kind or globally):
If you previously relied on both a saved file and inline media in the same tool result, read the file from _meta.save_path (or omit save_path to get inline media when under the ceiling).
Examples
Chat (free model)
json
{"tool":"chat_completion","arguments":{"model":"google/gemma-4-26b-a4b-it:free","messages":[{"role":"user","content":"Summarize MCP in one sentence."}]}}
Analyze an image
json
{"tool":"analyze_image","arguments":{"image_path":"diagram.png","question":"List every label in this diagram."}}
Use image_path and question β not image / prompt.
{"tool":"generate_video","arguments":{"model":"google/veo-3.1","prompt":"Ocean waves at sunrise, cinematic drone shot","duration":4,"save_path":"river.mp4"}}
If the job is still running when max_wait_ms elapses, the response succeeds with _meta.code: JOB_STILL_RUNNING and a video_id β call get_video_status to resume. This is not an error.
With save_path set (as above), the result is a text pointer to the saved file once complete β not inline video. See Binary tool results.
Input path sandbox β local paths on analyze_* and reference images must stay inside OPENROUTER_INPUT_DIR (falls back to OPENROUTER_OUTPUT_DIR, then cwd)
Output path sandbox β save_path must stay inside OPENROUTER_OUTPUT_DIR
Async job reads β get_chat_completion_status resolves disk paths only under OPENROUTER_OUTPUT_DIR/openrouter-jobs/ (4.7.0+)
SSRF protection β private/reserved IPs blocked on URL fetches
Override sandboxes only with OPENROUTER_ALLOW_UNSAFE_PATHS=1 (discouraged).
Report vulnerabilities: SECURITY.md (private disclosure β do not file public issues for exploits).
Configuration
Environment variables
Variable
Required
Default
Description
OPENROUTER_API_KEY
Yes
β
OpenRouter API key
OPENROUTER_DEFAULT_MODEL
No
google/gemma-4-26b-a4b-it:free
Default when tools omit model
OPENROUTER_OUTPUT_DIR
No
cwd
Sandbox root for save_path
OPENROUTER_INPUT_DIR
No
OUTPUT_DIR or cwd
Sandbox root for local input files
OPENROUTER_INLINE_MAX_BYTES
No
1048576 (image/audio)
Global inline media ceiling
OPENROUTER_IMAGE_INLINE_MAX_BYTES
No
falls back to global
Per-kind inline ceiling
OPENROUTER_AUDIO_INLINE_MAX_BYTES
No
falls back to global
Per-kind inline ceiling
OPENROUTER_VIDEO_INLINE_MAX_BYTES
No
10485760
Video inline ceiling
OPENROUTER_LOG_LEVEL
No
info
error / warn / info / debug
See .env.example for the full list (provider routing, fetch limits, caching, video polling, async jobs, integration-test overrides).
Development
bash
git clone https://github.com/stabgan/openrouter-mcp-multimodal.git
cd openrouter-mcp-multimodal
npm install
cp .env.example .env# add OPENROUTER_API_KEY
npm run build
Testing
Command
What it runs
npm test
1018 unit + mock tests (no API key, <20s)
npm run test:regression
Security + schema regression guards
npm run test:integration
16 live OpenRouter scenarios (requires.env key)
npm run test:e2e
Full MCP stdio smoke (scripts/live-e2e.mjs)
npm run ci
lint + format + build + all of the above except e2e
Free models for CI / zero-credit accounts: integration tests default to google/gemma-4-26b-a4b-it:free (override with OPENROUTER_INTEGRATION_MODEL). GitHub Actions requires the OPENROUTER_API_KEY repository secret.
Mock tests live under src/__tests__/mock/ and cover handlers, path sandboxes, SSRF blocks, model-cache pagination, tool descriptions, and structured outputs β 330+ additional cases beyond the core suite.
bash
npm run lint
npm run format:check
npm run version:check # package.json vs src/version.ts, server.json, pyproject.toml
Releasing
Published artifacts (npm, PyPI/uvx, Docker, GHCR) all ship from the same semver on a git tag (vX.Y.Z). Pushing to main runs tests but does not publish to npm or PyPI.
Normal flow: merge conventional commits to main β Release Please opens a Release PR β merge it β tag is created β CI publishes everywhere.
Manual flow: bump all version files β npm run version:check β npm run ci + smoke tests β commit β git tag vX.Y.Z β git push origin vX.Y.Z.
Full checklist, file list, CI secrets, and agent instructions:
Expected β result is text + _meta.save_path only; omit save_path or read the saved file
MCP client shows stale tool list
Client cache
Restart MCP / reload window after upgrading the package pin
Structured errors include _meta.suggestions with agent-oriented next steps when available.
FAQ
Do I need paid OpenRouter credits?
No, to get started. Free models work for chat and vision. Audio/video generation usually requires credits; analysis may return 402 on some models β the server surfaces that as a structured error.
Which MCP clients are supported?
Any MCP-compatible client over stdio: Cursor, Claude Desktop, VS Code Copilot, Windsurf, Cline, Kiro, and custom agents.
How is this different from calling OpenRouter directly?
This server adds MCP tool schemas, security sandboxes, error taxonomy, model caching, async video polling with progress notifications, and agent-oriented tool descriptions β so LLMs invoke the right capability without custom HTTP glue.
Where is the security advisory for path traversal?
OpenRouter API key. Get one free at https://openrouter.ai/keys
OPENROUTER_DEFAULT_MODEL
Default model for chat + analyze tools. Defaults to nvidia/nemotron-nano-12b-v2-vl:free.
OPENROUTER_OUTPUT_DIR
Sandbox root for save_path on generate_* tools. Defaults to the current working directory.
OPENROUTER_MAX_TOKENS
Default max_tokens for chat_completion when unset in the request.
OPENROUTER_PROVIDER_SORT
price / throughput / latency
OPENROUTER_PROVIDER_IGNORE
CSV of provider slugs to exclude.
OPENROUTER_PROVIDER_ORDER
JSON array or CSV of preferred provider IDs.
OPENROUTER_PROVIDER_QUANTIZATIONS
CSV of quantization levels (fp16,int8).
OPENROUTER_PROVIDER_REQUIRE_PARAMETERS
true/false. Require providers to support all request params.
OPENROUTER_PROVIDER_DATA_COLLECTION
allow/deny
OPENROUTER_PROVIDER_ALLOW_FALLBACKS
true/false
OPENROUTER_CACHE_RESPONSES
Enable response caching server-wide. Sends X-OpenRouter-Cache: true on every chat/analyze call unless overridden per-request. Zero tokens billed on cache hits.
OPENROUTER_INCLUDE_REASONING
Enable reasoning tokens passthrough server-wide. Adds _meta.reasoning to chat_completion responses for DeepSeek R1 / Gemini Thinking / Opus 4.7.