Skip to main content
Glama
vmhq

OpenRouter MCP Server

by vmhq

OpenRouter MCP Server

Servidor MCP remoto (HTTP streamable, JSON sin estado) que permite a los agentes de IA delegar tareas en modelos más baratos a través de la API de OpenRouter, consultando el catálogo y los precios en vivo, con una política de costos configurable mediante un archivo .env.

Qué hace

  • Catálogo en vivo: consulta GET /api/v1/models de OpenRouter (con caché de 5 minutos) y expone precios en USD por millón de tokens, ventana de contexto y soporte de llamada a herramientas.

  • Delegación explícita: el agente elige el modelo mirando los precios y delega la tarea.

  • Delegación automática basada en precio: el servidor elige el modelo según un nivel (economy / balanced / quality) usando bandas de precio configurables.

  • Política mediante .env: topes de precio máximo, listas de modelos permitidos/bloqueados, modelo predeterminado, proveedores preferidos.

  • Costo real: cada delegación devuelve los tokens usados y el costo estimado en USD.

Related MCP server: frugal

Instalación

npm install
cp .env.example .env   # edit and set your OPENROUTER_API_KEY
npm run build
npm start              # listens on http://localhost:3000/mcp

Para desarrollo con recarga automática: npm run dev.

Docker

Una imagen multi-arquitectura (linux/amd64, linux/arm64) se compila automáticamente mediante GitHub Actions y se publica en GHCR:

ghcr.io/vmhq/openrouter-mcp-server

Etiquetas disponibles: latest (rama principal), vX.Y.Z / X.Y (lanzamientos), main y sha-<commit>.

Docker Compose

services:
  openrouter-mcp:
    image: ghcr.io/vmhq/openrouter-mcp-server:latest
    container_name: openrouter-mcp
    restart: unless-stopped
    ports:
      - "3000:3000"
    env_file:
      - .env
    volumes:
      # Persists OAuth state (registered clients, token hashes)
      - ./data:/app/data
    healthcheck:
      test: ["CMD", "wget", "-qO-", "http://localhost:3000/health"]
      interval: 30s
      timeout: 5s
      retries: 3
docker compose up -d

Nota: el contenedor se ejecuta como el usuario no privilegiado node. Asegúrate de que el directorio montado ./data sea escribible por el UID 1000 (chown -R 1000:1000 ./data); de lo contrario, el estado de OAuth no se puede persistir.

Ejemplo de .env

# --- Required ---
# Your OpenRouter API key (https://openrouter.ai/keys)
OPENROUTER_API_KEY=sk-or-v1-...

# --- HTTP server ---
# Port where the MCP endpoint is exposed (http://host:PORT/mcp)
PORT=3000
# Optional static bearer token. If set, MCP clients must send
# "Authorization: Bearer <token>". Strongly recommended if the server
# is reachable outside localhost.
MCP_AUTH_TOKEN=

# --- Interactive OAuth with PocketID (for AI agents like Claude) ---
# Public URL of this server (e.g. https://mcp.example.com). Required so the
# OAuth metadata and callback point to the right URL behind a reverse proxy.
MCP_PUBLIC_URL=
# When all three POCKETID_* variables are set, the /oauth/authorize flow
# delegates the human login to your PocketID instance (passkey).
# In PocketID: create an OIDC client and register this callback:
#   <MCP_PUBLIC_URL>/oauth/callback
POCKETID_ISSUER=
POCKETID_CLIENT_ID=
POCKETID_CLIENT_SECRET=
# Optional OIDC scopes (space-separated). Default: "openid profile email".
# POCKETID_SCOPES=openid profile email
# Path of the file where OAuth state is persisted (registered clients,
# one-time codes, and token hashes). Default: ./data/oauth-state.json
# MCP_OAUTH_STATE_PATH=./data/oauth-state.json
# OAuth access token lifetime, in seconds. Default: 2592000 (30 days).
# MCP_OAUTH_TOKEN_TTL_S=2592000

# --- Optional OpenRouter attribution (rankings) ---
APP_URL=
APP_TITLE=OpenRouter MCP Server

# --- Delegation policy ---
# Default model when the agent doesn't specify one in openrouter_delegate_task
DEFAULT_MODEL=

# Price caps (USD per million tokens). Models above them are rejected
# with an explanatory error. Empty = no limit.
MAX_PROMPT_PRICE_PER_M=
MAX_COMPLETION_PRICE_PER_M=

# Comma-separated control lists. Accept exact ids ("openai/gpt-4.1-mini")
# or provider prefixes ("openai/"). Empty ALLOWED_MODELS = all allowed
# (except blocked ones).
ALLOWED_MODELS=
BLOCKED_MODELS=

# Allow free models (price 0)? They usually have strict rate limits.
ALLOW_FREE_MODELS=true

# Preferred providers for automatic selection (openrouter_auto_delegate)
PREFERRED_PROVIDERS=openai,anthropic,google,meta-llama,mistralai,deepseek,qwen,x-ai,amazon

# "Combined" price caps (70% prompt + 30% completion, USD/M tokens)
# for each tier of the automatic selection.
TIER_ECONOMY_MAX_PRICE=0.5
TIER_BALANCED_MAX_PRICE=3
TIER_QUALITY_MAX_PRICE=15

# Model catalog cache, in seconds
MODELS_CACHE_TTL_SECONDS=300

Variables de entorno

Consulta .env.example — las principales:

Variable

Descripción

OPENROUTER_API_KEY

Obligatoria. Tu clave de https://openrouter.ai/keys

PORT

Puerto HTTP (por defecto 3000)

MCP_AUTH_TOKEN

Si se define, los clientes deben enviar Authorization: Bearer <token>. Prácticamente obligatoria si expones el servidor fuera de localhost.

MCP_PUBLIC_URL

URL pública del servidor (p. ej. https://mcp.example.com); necesaria para el flujo OAuth detrás de un proxy inverso

POCKETID_ISSUER / POCKETID_CLIENT_ID / POCKETID_CLIENT_SECRET

Habilita el inicio de sesión OAuth interactivo delegando la autenticación a tu instancia de PocketID (ver más abajo)

DEFAULT_MODEL

Modelo usado por openrouter_delegate_task cuando el agente no especifica uno

MAX_PROMPT_PRICE_PER_M / MAX_COMPLETION_PRICE_PER_M

Tope de precio (USD/M tokens); los modelos más caros se rechazan

ALLOWED_MODELS / BLOCKED_MODELS

Listas separadas por comas: ids exactos o prefijos (openai/)

ALLOW_FREE_MODELS

Permitir modelos gratuitos (por defecto true)

TIER_*_MAX_PRICE

Topes de precio combinados (0.7·entrada + 0.3·salida) para cada nivel de la selección automática

Herramientas expuestas

Herramienta

Descripción

openrouter_list_models

Lista modelos con precios en vivo; filtra por texto, precio, contexto, llamada a herramientas; ordena por precio/contexto/recencia; paginado

openrouter_get_model

Detalle completo de un modelo + si la política del .env lo permite

openrouter_delegate_task

Delega una tarea a un modelo específico; devuelve respuesta, tokens y costo estimado

openrouter_auto_delegate

El servidor elige el modelo según el nivel de precio (economy/balanced/quality) y delega

openrouter_check_credits

Uso y límites de la clave API configurada

Flujo típico del agente: openrouter_list_models (o directamente openrouter_auto_delegate con el nivel economy) → delegar la tarea → usar la respuesta, sabiendo cuánto costó.

Importante: el modelo delegado no ve la conversación del agente; la tarea (task) debe ser autocontenida, con todo el contexto necesario.

Conectar un agente

Claude Code:

claude mcp add --transport http openrouter http://localhost:3000/mcp

Con un token de autenticación:

claude mcp add --transport http openrouter http://YOUR_HOST:3000/mcp --header "Authorization: Bearer YOUR_TOKEN"

Cualquier cliente MCP: apúntalo al endpoint POST /mcp con el transporte "streamable HTTP". Hay un endpoint GET /health para monitoreo.

claude.ai (conector remoto): requiere una URL HTTPS pública — despliega el servidor en un VPS detrás de un proxy inverso (Caddy/nginx) o usa un túnel (p. ej. cloudflared tunnel). Con OAuth habilitado (ver más abajo), añade el conector apuntando a https://YOUR_HOST/mcp y deja vacíos los campos avanzados de OAuth Client ID/Secret: el servidor publica metadatos OAuth y soporta Dynamic Client Registration, por lo que Claude se registra solo y obtiene su token automáticamente al hacer clic en Authorize.

OAuth con PocketID

El servidor implementa OAuth 2.1 completo para agentes de IA (Claude, Cursor, …): actúa como servidor de autorización hacia los clientes MCP (Dynamic Client Registration RFC 7591 + PKCE S256 + emisión de sus propios tokens, con metadatos RFC 8414/9728) y delega el inicio de sesión humano a tu instancia de PocketID mediante OIDC (passkey).

Flujo: el cliente MCP recibe un 401 con WWW-Authenticate → descubre los metadatos en /.well-known/oauth-protected-resource → se registra en /oauth/register → abre /oauth/authorize en el navegador → el usuario inicia sesión en PocketID con su passkey → PocketID devuelve a /oauth/callback → el servidor emite su propio código y el cliente lo intercambia en /oauth/token por un token de acceso (30 días por defecto).

Configuración:

  1. En PocketID, crea un nuevo cliente OIDC.

  2. Registra la devolución de llamada: <MCP_PUBLIC_URL>/oauth/callback.

  3. Restringe quién puede iniciar sesión usando los grupos permitidos del cliente OIDC en PocketID.

  4. Copia el Client ID y Client Secret en POCKETID_CLIENT_ID / POCKETID_CLIENT_SECRET, y establece la URL base de PocketID en POCKETID_ISSUER.

  5. Establece MCP_PUBLIC_URL a la URL HTTPS pública del servidor.

Si las variables POCKETID_* no están definidas, el flujo interactivo /oauth/authorize muestra un error; el bearer estático MCP_AUTH_TOKEN sigue funcionando en paralelo para acceso máquina a máquina (curl, Codex, etc.).

El estado de OAuth (clientes registrados, códigos de un solo uso y hashes SHA-256 de los tokens — nunca los tokens en texto plano) se persiste en ./data/oauth-state.json (configurable mediante MCP_OAUTH_STATE_PATH). Si el conector falla después de un reinicio con el estado borrado, elimínalo en Claude y vuelve a añadirlo para que se vuelva a registrar.

Cómo openrouter_auto_delegate elige un modelo

  1. Filtra el catálogo según la política del .env y los requisitos de la llamada (require_tools, min_context, salida de texto).

  2. Calcula el precio combinado por modelo: 0.7·input_price + 0.3·output_price (USD/M tokens).

  3. Según el nivel, busca dentro de su banda de precio (con respaldo a la banda vecina si está vacía):

    • economy (≤ $0.5/M por defecto): el más barato.

    • balanced ($0.5–$3/M): el más barato en la banda media.

    • quality ($3–$15/M): el de mayor precio dentro del tope (el precio como proxy de capacidad, sin llegar a los modelos insignia).

  4. Prefiere proveedores de PREFERRED_PROVIDERS, e informa en la respuesta el modelo elegido, el razonamiento y las alternativas descartadas.

Seguridad

  • La clave API de OpenRouter vive solo en el .env del servidor; nunca se expone a los agentes.

  • El archivo .env está en .gitignore.

  • Si el puerto es accesible desde fuera, establece MCP_AUTH_TOKEN y sirve detrás de HTTPS.

Maintenance

ActivitySlowing
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers