9Router MCP Server
Servidor MCP para 9Router: expone búsqueda web, recuperación web, TTS y otras capacidades como herramientas nativas, eliminando la sobrecarga por llamada de los enfoques basados en archivos de habilidades (relectura de instrucciones, formato manual, reintento ante errores) en favor de llamadas estructuradas a herramientas a través de stdio.
Documentación
9Router MCP Server
Servidor MCP que expone las capacidades de 9Router como herramientas nativas para cualquier cliente MCP: descubrimiento de modelos, respaldo automático y entradas validadas con Zod.
Estado: 9Router ya oculta la complejidad específica de cada proveedor detrás de una única API. Este servidor expone esa API a través de MCP, para que agentes y aplicaciones puedan llamar a búsqueda web, recuperación web, generación de imágenes, TTS, STT y embeddings como herramientas MCP estándar — sin cargar archivos de habilidades, sin código de integración por proveedor.
Por qué usarlo
- Las herramientas siempre están registradas; no hay carga manual de habilidades (ahorra tokens y contexto).
- Respaldo automático de modelo cuando el modelo principal falla.
- Entradas validadas con Zod con mensajes de error claros antes de cualquier llamada de red.
- Un solo archivo de configuración para endpoint, autenticación y modelos predeterminados con cadenas de respaldo.
- Transporte único (
stdio); funciona con cualquier cliente compatible con MCP.
El chat / la generación de código están intencionalmente excluidos — para eso está el modelo anfitrión.
Contenido
Instalación
El paquete es ninerouter-mcp en npm. El cuerpo JSON es idéntico en todos los clientes MCP — solo la clave de nivel superior y la ruta del archivo difieren. Pega el bloque en la clave correcta de la configuración de tu cliente:
{
"ninerouter": {
"type": "stdio",
"command": "npx",
"args": ["-y", "ninerouter-mcp"],
"env": {
"NINEROUTER_URL": "http://localhost:20128"
}
}
}
Claves de nivel superior por cliente: VS Code (servers), OpenCode (mcp, renombra env → environment, establece type: "local" y enabled: true), Claude Code / Cursor / Windsurf / Claude Desktop / Zed (mcpServers o context_servers, elimina la línea type). JetBrains usa un diálogo de interfaz en Settings → Tools → AI Assistant → MCP con el mismo comando, argumentos y entorno.
Claude Code
claude mcp add --scope user ninerouter -e NINEROUTER_URL=http://localhost:20128 -- npx -y ninerouter-mcp
Codex CLI
codex mcp add ninerouter --env NINEROUTER_URL=http://localhost:20128 -- npx -y ninerouter-mcp
Hermes Agent
Añade a ~/.hermes/config.yaml:
mcp_servers:
ninerouter:
command: npx
args:
- -y
- ninerouter-mcp
env:
NINEROUTER_URL: http://localhost:20128
Configuración
El servidor necesita una URL base de 9Router. Opcionalmente acepta una clave de API y respaldos de modelo predeterminado para cada herramienta.
Fuentes, en orden de prioridad (la más alta primero):
- Indicador de línea de comandos
--config <path>(o entorno--config-file,-c,NINEROUTER_CONFIG) ~/.config/ninerouter-mcp/config.toml- Variables de entorno:
NINEROUTER_URL,NINEROUTER_KEY
Si el archivo de configuración existe, tiene prioridad sobre las variables de entorno.
Configuración rápida
Genera un archivo de configuración inicial y edítalo:
npx ninerouter-mcp create-config
Esto escribe ~/.config/ninerouter-mcp/config.toml y se niega a sobrescribir un archivo existente.
Configuración manual (variables de entorno)
Windows (PowerShell):
$env:NINEROUTER_URL = "http://localhost:20128"
$env:NINEROUTER_KEY = "sk-..." # optional
macOS / Linux:
export NINEROUTER_URL=http://localhost:20128
export NINEROUTER_KEY=sk-... # optional
NINEROUTER_KEY es opcional y solo se requiere cuando tu instancia de 9Router tiene la autenticación habilitada.
Configuración manual (archivo de configuración)
# 9Router base URL (required)
base_url = "http://localhost:20128"
# Optional API key
# api_key = "sk-..."
# Default models with fallback support.
# Single string = one model.
# Array = tried in order, first success wins, errors are aggregated.
[default_models]
web_search = ["tavily/search", "brave-search/search"]
web_fetch = ["firecrawl/fetch", "jina-reader/fetch"]
generate_image = "openai/dall-e-3"
text_to_speech = "openai/tts-1"
speech_to_text = ["openai/whisper-1", "groq/whisper-large-v3-turbo"]
embeddings = "openai/text-embedding-3-small"
# Defaults for the list_models tool (all optional; these are the built-in values)
[list_models]
limit = 20 # default page size
offset = 0 # default start index
cache_ttl_seconds = 60 # 0 disables caching
La tabla ninerouter también se acepta como alias para base_url y api_key de nivel superior:
[ninerouter]
base_url = "http://localhost:20128"
api_key = "sk-..."
Apunta a un archivo de configuración no predeterminado:
npx -y ninerouter-mcp --config /path/to/config.toml
# or
NINEROUTER_CONFIG=/path/to/config.toml npx -y ninerouter-mcp
Ejecución
Después de npm install desde este repositorio:
npm run build
npm start
O en modo de observación durante el desarrollo:
npm run dev
Los usuarios del paquete publicado pueden ejecutarlo directamente:
npx -y ninerouter-mcp
Herramientas
Cada herramienta se registra con el servidor MCP al inicio. Salvo que se indique lo contrario, todas las herramientas devuelven un único bloque de contenido de texto con JSON impreso de forma legible.
list_models
Consulta los identificadores de modelo expuestos por 9Router. Esta herramienta es opcional: todas las demás funcionan sin ella, porque cada una tiene un modelo predeterminado configurado o una cadena de respaldo. Llámala solo para apuntar a un modelo específico o para descubrir identificadores que difieren de los predeterminados. Filtra por search, luego pagina entre las coincidencias con offset/limit, de modo que un catálogo grande no pueda inundar la ventana de contexto. Cada respuesta informa total, count, offset y nextOffset (omitido en la última página). La lista ascendente se almacena en caché durante aproximadamente un minuto, porque 9Router reconstruye todo el catálogo en cada solicitud (varios segundos), por lo que solo la primera llamada es lenta.
| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
kind | string | no | Uno de chat, image, tts, embedding, web, stt, image-to-text. Omítelo para los modelos de chat predeterminados. |
search | string | no | Coincidencia de subcadena sin distinción de mayúsculas/minúsculas contra identificadores/nombres de modelo. |
limit | number | no | Tamaño de página (predeterminado 20, máximo 500). Usa 0 para la lista completa. |
offset | number | no | Índice del primer modelo a devolver (predeterminado 0). Usa nextOffset para paginar. |
refresh | boolean | no | Omite la caché y vuelve a obtener de 9Router. |
Los valores predeterminados se pueden sobrescribir en config.toml:
[list_models]
limit = 20 # default page size
offset = 0 # default start index
cache_ttl_seconds = 60 # 0 disables caching
Valores predeterminados integrados (usados cuando se omite una clave): limit = 20, offset = 0, cache_ttl_seconds = 60.
web_search
Busca en la web a través de 9Router.
| Parámetro | Tipo | Predeterminado | Notas |
|---|---|---|---|
query | string | — | Obligatorio. |
model | string | — | Identificador de modelo de 9Router (p. ej. tavily/search). Se respalda en provider, luego en default_models.web_search. |
provider | string | — | Alias para model. |
maxResults | number | 5 | 1–20. |
searchType | string | web | web o news. |
country | string | — | |
language | string | — | |
timeRange | string | — | |
domainFilter | string | — |
web_fetch
Recupera una URL y la devuelve como markdown, texto o HTML.
| Parámetro | Tipo | Predeterminado | Notas |
|---|---|---|---|
url | string | — | Obligatorio. Debe ser una URL válida. |
model | string | — | p. ej. jina-reader/fetch, firecrawl/fetch. |
provider | string | — | Alias para model. |
format | string | markdown | markdown, text o html. |
maxCharacters | number | 8000 | Límite de truncamiento. |
generate_image
Generación de texto a imagen. Siempre escribe un archivo y devuelve la imagen como bloque de contenido base64 más { outputPath, bytes, contentType }. Omite outputPath para escribir en el directorio temporal del sistema operativo.
| Parámetro | Tipo | Predeterminado | Notas |
|---|---|---|---|
prompt | string | — | Obligatorio. |
model | string | — | p. ej. openai/dall-e-3, gemini/gemini-3-pro-image-preview. |
provider | string | — | Alias para model. |
n | number | 1 | 1–10. |
size | string | 1024x1024 | |
quality | string | — | standard o hd. |
outputPath | string | tmpdir del SO | Dónde escribir el archivo. Predeterminado os.tmpdir()/ninerouter-<slug>-<ts>.<ext>. Extensión desde el tipo de contenido. |
text_to_speech
Sintetiza audio. Siempre escribe un archivo y devuelve el audio como bloque de contenido base64 más { outputPath, bytes, contentType }. Omite outputPath para escribir en el directorio temporal del sistema operativo.
| Parámetro | Tipo | Predeterminado | Notas |
|---|---|---|---|
input | string | — | Obligatorio. |
model | string | — | p. ej. openai/tts-1, edge-tts/vi-VN-HoaiMyNeural. |
provider | string | — | Alias para model. |
outputPath | string | tmpdir del SO | Dónde escribir el archivo. Predeterminado os.tmpdir()/ninerouter-<slug>-<ts>.<ext>. Extensión desde el tipo de contenido. |
speech_to_text
Transcribe audio. Proporciona exactamente uno de audioPath o audioBase64.
| Parámetro | Tipo | Predeterminado | Notas |
|---|---|---|---|
audioPath | string | — | Ruta de archivo local. |
audioBase64 | string | — | Carga útil base64. |
fileName | string | derivado | Se usa para el nombre de archivo de la carga multiparte. |
model | string | — | p. ej. openai/whisper-1, groq/whisper-large-v3-turbo. |
provider | string | — | Alias para model. |
language | string | — | Código ISO-639-1, p. ej. en, vi. |
prompt | string | — | |
responseFormat | string | json | json, text, verbose_json, srt, vtt. |
temperature | number | — | 0–1. |
embeddings
Genera embeddings para una cadena o un lote de cadenas.
| Parámetro | Tipo | Predeterminado | Notas |
|---|---|---|---|
input | string | array | — | Obligatorio. O un solo string o un array de strings no vacíos. |
model | string | — | p. ej. openai/text-embedding-3-small. |
provider | string | — | Alias de model. |
encodingFormat | string | float | float o base64. |
dimensions | number | — | Anulación opcional. |
Notas de comportamiento
- Cadena de respaldo. Para cada herramienta que usa modelos: si
model/providerestá definido, solo se prueba ese modelo. De lo contrario, se prueba la cadena endefault_models.<tool>en orden. Si todas las entradas fallan, la herramienta lanza un errorAll models failed. Errors: ...que incluye cada mensaje por modelo. provideres un alias demodelen cada herramienta que acepta un modelo. Usa el que se lea mejor para tu caso de uso.- Las imágenes y el audio siempre se escriben en un archivo y se devuelven como un bloque de contenido.
generate_imageytext_to_speechsolicitanb64_json/mp3al proveedor, escriben los bytes enoutputPath(o en el directorio temporal del sistema si lo omites) y devuelven el recurso como un bloque de contenido MCPimage/audioademás de{ outputPath, bytes, contentType }. El host puede mostrarlo en línea o simplemente usar la ruta. La extensión se deriva delcontent-typedel proveedor. - El archivo de configuración tiene prioridad sobre las variables de entorno. Si necesitas ajustes diferentes para una sola ejecución, prefiere
--configsobre exportar variables de entorno. - Carga multiparte de STT. La herramienta envía el audio como
multipart/form-data;fileNamesolo importa cuando el proveedor inspecciona el nombre del archivo. list_modelsse recorta y se almacena en caché. La herramienta limita su salida (predeterminado20) y mantiene la lista completa del proveedor en memoria durante aproximadamente un minuto. Esto no es paginación del lado del servidor:/v1/modelsignora los parámetros de consulta y siempre devuelve el catálogo completo. El límite protege la ventana de contexto y la caché protege la latencia, ya que 9Router reconstruye el catálogo en cada solicitud (observado ~7s, incluso para/v1/models/<kind>, que devuelve un cuerpo pequeño). Pasarefresh: truepara forzar una nueva obtención.- La configuración se lee una vez al inicio. Edita
config.tomlo cambiaNINEROUTER_URL/NINEROUTER_KEY, luego reinicia el servidor MCP en tu cliente. La recarga en caliente no está implementada.
Solución de problemas
NINEROUTER_URL is required— define la variable de entorno o crea~/.config/ninerouter-mcp/config.tomlconbase_url.No model specified and no default_models.<tool> configured— o pasamodelen la llamada o añade una entradadefault_modelsa tu configuración.All models failed. Errors: ...— cada modelo de respaldo devolvió un error; el mensaje agregado incluye cada uno para el diagnóstico.- Errores de autenticación (401/403) — tu instancia de 9Router requiere una clave; define
NINEROUTER_KEYoapi_keyen el archivo de configuración. - STT falla con "Provide audioPath or audioBase64" — exactamente uno de esos dos debe estar definido.
Desarrollo
npm install
npm run dev # tsx watch mode
npm run build # tsc -> dist/
npm start # node dist/index.js
npm run check # typecheck + lint + prettier --check
Estructura del proyecto:
src/
index.ts # bin entry; dispatches create-config or server
server.ts # McpServer setup
ninerouter-client.ts # config + HTTP helpers
create-config.ts # `ninerouter-mcp create-config` subcommand
tools/
models.ts # list_models
web.ts # web_search, web_fetch
media.ts # generate_image, text_to_speech, speech_to_text
embeddings.ts # embeddings
common.ts # shared fallback + json helpers
config.example.toml # sample config (mirrors create-config output)
Licencia
Apache-2.0. Consulta LICENSE.