mcp-oauth2-proxy

Un servidor MCP local stdio que actúa como proxy hacia un servidor MCP HTTP remoto protegido por OAuth2.

Documentación

mcp-oauth2-proxy

npm version node license: MIT

Un servidor MCP stdio local que actúa como proxy hacia un servidor MCP HTTP remoto protegido con OAuth2. Conéctalo a Claude Desktop, Cursor, VS Code Copilot o cualquier otro cliente MCP: inicia sesión una vez en tu navegador y listo.

MCP client ─stdio (JSON-RPC)─▶ mcp-oauth2-proxy ─HTTP+SSE + Bearer─▶ upstream MCP server
                                      │
                                      └─ OAuth2 token endpoint (IdP)

Documentación

Este README es una guía rápida. La documentación completa está en la wiki.

PáginaContenido
Primeros pasosInstalación, primera ejecución, conexión a un cliente.
ConfiguraciónTodos los campos y variables de entorno.
Concesiones y tokens OAuth2Concesiones, inicio de sesión interactivo, ciclo de vida de tokens y caché.
DescubrimientoDescubrimiento de endpoints RFC 9728 / RFC 8414.
SeguridadModelo de amenazas y defensas integradas.
Hosts remotos (reenvío de puertos SSH)Iniciar sesión cuando el proxy se ejecuta de forma remota.
Solución de problemasProblemas comunes y preguntas frecuentes.
Arquitectura · Puente · Internos de OAuth2Cómo funciona internamente.
Contribuciones y versionesConfiguración de desarrollo, pruebas, proceso de publicación.

Contenido

Características

  • Flujo interactivo authorization_code + PKCE con un listener de callback local integrado en el navegador: sin copiar/pegar código manualmente.
  • Caché de tokens de actualización en disco (AES‑256‑GCM, 0600), para que el navegador solo se abra una vez por máquina.
  • Concesión client_credentials para uso sin interfaz / servicio a servicio.
  • Descubrimiento RFC 9728 + RFC 8414 de endpoints de token y autorización desde el upstream: normalmente no se requiere configuración OAuth.
  • Actualización proactiva de tokens con desviación, deduplicación en vuelo y un bucle 401 → invalidar → reintentar.
  • Soporte upstream Streamable-HTTP: JSON de una sola respuesta, respuestas SSE text/event-stream y el canal opcional de notificaciones del servidor de larga duración. Respeta Mcp-Session-Id.
  • Registro solo en stderr (pino) con redacción de tokens, secretos y cabeceras Authorization: stdout permanece como un canal JSON-RPC limpio.

Cómo funciona

  1. Descubrimiento. Opcionalmente, obtén metadatos RFC 9728/8414 para completar tokenUrl, authorizationUrl, scope y resource.
  2. Gestor de tokens. Envuelve el Grant configurado con caché, desviación de actualización, deduplicación en vuelo e invalidación 401.
  3. Precarga. Llama a getToken() una vez al inicio para que el flujo interactivo del navegador (si es necesario) ocurra antes de que llegue el primer mensaje MCP.
  4. Puente. Para cada línea JSON-RPC de stdin, haz POST a upstream.url con un token Bearer; las respuestas JSON de una sola respuesta se convierten en una línea de stdout, las respuestas SSE en una línea por evento. Un 401 activa invalidate() y un único reintento.
  5. Flujo del servidor. Después de initialize, opcionalmente mantén abierto un canal GET text/event-stream para notificaciones iniciadas por el servidor.

Para conocer todos los detalles internos, consulta las páginas de la wiki Arquitectura, Internos del puente e Internos de OAuth2.

Requisitos

  • Node.js 20+
  • Un servidor MCP protegido con OAuth2 que hable el transporte MCP HTTP Streamable.
  • Un cliente OAuth2 registrado con tu IdP. Para el flujo interactivo, registra http://127.0.0.1:53682/callback como URI de redirección (o lo que sea que configures en OAUTH2_CALLBACK_PORT).

Instalación

No necesitas instalar nada: los clientes MCP pueden lanzar el proxy directamente mediante npx:

npx -y mcp-oauth2-proxy

Para desarrollo con una copia local:

git clone https://github.com/ChengleiYuan/mcp-oauth2-proxy.git
cd mcp-oauth2-proxy
npm install
npm run build

Inicio rápido

Inicio de sesión interactivo (recomendado para usuarios finales)

UPSTREAM_URL=https://mcp.example.com/mcp \
OAUTH2_GRANT=authorization_code \
OAUTH2_CLIENT_ID=<your-client-id> \
  npx -y mcp-oauth2-proxy

En el primer lanzamiento, el proxy descubre los endpoints OAuth, abre tu navegador para un inicio de sesión PKCE, captura el código en http://127.0.0.1:53682/callback, guarda en caché el token de actualización (cifrado) en el directorio de configuración de tu SO e inicia el puente. Los lanzamientos posteriores reutilizan el token en caché silenciosamente. Detalles: Concesiones y tokens OAuth2.

Sin interfaz / cuenta de servicio

UPSTREAM_URL=https://mcp.example.com/mcp \
OAUTH2_GRANT=client_credentials \
OAUTH2_TOKEN_URL=https://idp.example.com/oauth2/token \
OAUTH2_CLIENT_ID=my-service \
OAUTH2_CLIENT_SECRET='…' \
OAUTH2_SCOPE='mcp:read mcp:write' \
  npx -y mcp-oauth2-proxy

Conéctalo a un cliente MCP

{
  "mcpServers": {
    "remote-oauth2-mcp": {
      "command": "npx",
      "args": ["-y", "mcp-oauth2-proxy"],
      "env": {
        "UPSTREAM_URL": "https://mcp.example.com/mcp",
        "OAUTH2_GRANT": "authorization_code",
        "OAUTH2_CLIENT_ID": "<your-client-id>"
      }
    }
  }
}

En hosts Windows que no resuelven .cmd shims (por lo que command: "npx" no puede iniciarse), usa la forma explícita:

{
  "command": "cmd",
  "args": ["/c", "npx", "-y", "mcp-oauth2-proxy"]
}

Las rutas en el bloque env deben ser absolutas y usar barras diagonales en todas las plataformas.

Configuración

El proxy se puede configurar mediante un archivo JSON (MCP_PROXY_CONFIG), variables de entorno o una combinación: las variables de entorno anulan los valores del archivo y luego se valida el resultado combinado. Archivo de ejemplo mínimo:

{
  "upstream": { "url": "https://mcp.example.com/mcp" },
  "oauth2": {
    "grant": "authorization_code",
    "clientId": "my-client",
    "scope": "mcp:read mcp:write",
    "resource": "https://mcp.example.com/mcp"
  }
}

Consulta config.example.json para ver un ejemplo más completo.

Variables de entorno más utilizadas:

Variable de entornoSe asigna a
UPSTREAM_URLupstream.url
OAUTH2_GRANToauth2.grant
OAUTH2_CLIENT_IDoauth2.clientId
OAUTH2_CLIENT_SECREToauth2.clientSecret
OAUTH2_TOKEN_URLoauth2.tokenUrl
OAUTH2_SCOPEoauth2.scope
OAUTH2_RESOURCEoauth2.resource
LOG_LEVELlog.level

Referencia completa: todos los campos, valores predeterminados y variables de entorno están documentados en la página de la wiki Configuración. El descubrimiento automático de endpoints se cubre en Descubrimiento. ¿Ejecutas el proxy en una máquina remota? Consulta Hosts remotos (reenvío de puertos SSH). ¿Tienes un problema? Consulta Solución de problemas.

Seguridad

  • Los tokens los obtiene el propio proxy; la cabecera Authorization del upstream siempre la establece el proxy, nunca se pasa desde el cliente.
  • Los tokens de acceso solo viven en memoria. Los tokens de actualización se guardan en caché cifrados (AES‑256‑GCM, modo de archivo de clave 0600): ofuscación honesta contra lecturas casuales del disco, no protección contra un proceso que se ejecute como el mismo usuario del SO.
  • El http:// en texto claro hacia hosts que no sean loopback se rechaza al inicio (anula con ALLOW_INSECURE_HTTP=true); https:// y http:// de loopback siempre están permitidos. El listener de callback interactivo valida la cabecera Host para evitar el reenlace de DNS.
  • Todos los registros van a stderr con tokens, secretos y cabeceras Authorization redactados; stdout está reservado para JSON-RPC.

Modelo de amenazas y defensas completo: Seguridad.

Desarrollo

npm install
npm run build       # compile TS to dist/
npm run dev         # tsx watch
npm test            # vitest (unit + integration)

La prueba de integración levanta un endpoint de token OAuth2 simulado y un upstream MCP simulado en el mismo proceso y maneja el puente real a través de flujos PassThrough: no se requiere red. La estructura del proyecto, la estrategia completa de pruebas y el proceso automatizado de publicación están documentados en Contribuciones y versiones.

Fuera del alcance

  • Múltiples servidores MCP upstream por proceso
  • Almacenamiento de tokens de actualización respaldado por el llavero del SO (DPAPI / Keychain / libsecret)
  • Concesiones mTLS / JWT-bearer / device-code / ROPC
  • Transporte entrante HTTP / SSE (este es un servidor MCP stdio)

Licencia

MIT