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
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ágina | Contenido |
|---|---|
| Primeros pasos | Instalación, primera ejecución, conexión a un cliente. |
| Configuración | Todos los campos y variables de entorno. |
| Concesiones y tokens OAuth2 | Concesiones, inicio de sesión interactivo, ciclo de vida de tokens y caché. |
| Descubrimiento | Descubrimiento de endpoints RFC 9728 / RFC 8414. |
| Seguridad | Modelo 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 problemas | Problemas comunes y preguntas frecuentes. |
| Arquitectura · Puente · Internos de OAuth2 | Cómo funciona internamente. |
| Contribuciones y versiones | Configuración de desarrollo, pruebas, proceso de publicación. |
Contenido
- Características
- Cómo funciona
- Requisitos
- Instalación
- Inicio rápido
- Conéctalo a un cliente MCP
- Configuración
- Seguridad
- Desarrollo
- Fuera del alcance
- Licencia
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_credentialspara 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-streamy el canal opcional de notificaciones del servidor de larga duración. RespetaMcp-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
- Descubrimiento. Opcionalmente, obtén metadatos RFC 9728/8414 para
completar
tokenUrl,authorizationUrl,scopeyresource. - Gestor de tokens. Envuelve el
Grantconfigurado con caché, desviación de actualización, deduplicación en vuelo e invalidación 401. - 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. - Puente. Para cada línea JSON-RPC de stdin, haz POST a
upstream.urlcon un tokenBearer; las respuestas JSON de una sola respuesta se convierten en una línea de stdout, las respuestas SSE en una línea por evento. Un401activainvalidate()y un único reintento. - Flujo del servidor. Después de
initialize, opcionalmente mantén abierto un canalGET text/event-streampara 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/callbackcomo URI de redirección (o lo que sea que configures enOAUTH2_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 entorno | Se asigna a |
|---|---|
UPSTREAM_URL | upstream.url |
OAUTH2_GRANT | oauth2.grant |
OAUTH2_CLIENT_ID | oauth2.clientId |
OAUTH2_CLIENT_SECRET | oauth2.clientSecret |
OAUTH2_TOKEN_URL | oauth2.tokenUrl |
OAUTH2_SCOPE | oauth2.scope |
OAUTH2_RESOURCE | oauth2.resource |
LOG_LEVEL | log.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
Authorizationdel 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 conALLOW_INSECURE_HTTP=true);https://yhttp://de loopback siempre están permitidos. El listener de callback interactivo valida la cabeceraHostpara evitar el reenlace de DNS. - Todos los registros van a stderr con tokens, secretos y cabeceras
Authorizationredactados; 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)