mcp-oauth2-proxy
Um servidor MCP stdio local que faz proxy para um servidor MCP HTTP remoto protegido por OAuth2.
Documentação
mcp-oauth2-proxy
Um servidor MCP stdio local que atua como proxy para um servidor MCP HTTP remoto protegido por OAuth2. Integre-o ao Claude Desktop, Cursor, VS Code Copilot ou qualquer outro cliente MCP — faça login uma vez no seu navegador — pronto.
MCP client ─stdio (JSON-RPC)─▶ mcp-oauth2-proxy ─HTTP+SSE + Bearer─▶ upstream MCP server
│
└─ OAuth2 token endpoint (IdP)
Documentação
Este README é um guia rápido. A documentação completa está na wiki.
| Página | O que contém |
|---|---|
| Getting Started | Instalação, primeira execução, integração com um cliente. |
| Configuration | Todos os campos e variáveis de ambiente. |
| OAuth2 Grants and Tokens | Grants, login interativo, ciclo de vida de tokens e cache. |
| Discovery | Descoberta de endpoints RFC 9728 / RFC 8414. |
| Security | Modelo de ameaças e defesas integradas. |
| Remote Hosts (SSH Port Forwarding) | Login quando o proxy é executado remotamente. |
| Troubleshooting | Problemas comuns e FAQ. |
| Architecture · Bridge · OAuth2 internals | Como funciona internamente. |
| Contributing and Releases | Configuração de desenvolvimento, testes, processo de release. |
Conteúdo
- Features
- How it works
- Requirements
- Install
- Quick start
- Wire it into an MCP client
- Configuration
- Security
- Development
- Out of scope
- License
Features
- Fluxo interativo
authorization_code+ PKCE com um listener de callback local integrado no navegador — sem copiar/colar códigos manualmente. - Cache de refresh-token em disco (AES‑256‑GCM,
0600), para que o navegador abra apenas uma vez por máquina. - Grant
client_credentialspara uso headless / service-to-service. - Descoberta RFC 9728 + RFC 8414 de endpoints de token e autorização a partir do upstream — geralmente nenhuma configuração OAuth é necessária.
- Atualização proativa de tokens com skew, de-duplicação de requisições em andamento e loop 401 → invalidar → tentar novamente.
- Suporte a upstream Streamable-HTTP: respostas JSON de disparo único, SSE
text/event-streame o canal opcional de notificações de longa duração do servidor. RespeitaMcp-Session-Id. - Logs apenas em stderr (pino) com redação de tokens, segredos e cabeçalhos
Authorization— o stdout permanece um canal JSON-RPC limpo.
Como funciona
- Descoberta. Opcionalmente, busca metadados RFC 9728/8414 para preencher
tokenUrl,authorizationUrl,scopeeresource. - Gerenciador de tokens. Envolve o
Grantconfigurado com cache, skew de atualização, deduplicação de requisições em andamento e invalidação por 401. - Pré-busca. Chama
getToken()uma vez na inicialização para que o fluxo interativo do navegador (se necessário) ocorra antes da primeira mensagem MCP chegar. - Bridge. Para cada linha JSON-RPC do stdin, faz POST para
upstream.urlcom um tokenBearer; respostas JSON de disparo único viram uma linha no stdout, respostas SSE uma linha por evento. Um401disparainvalidate()e uma única nova tentativa. - Stream do servidor. Após
initialize, opcionalmente mantém aberto um canalGET text/event-streampara notificações iniciadas pelo servidor.
Para detalhes internos completos, consulte as páginas da wiki Architecture, Bridge Internals e OAuth2 Internals.
Requisitos
- Node.js 20+
- Um servidor MCP protegido por OAuth2 que fale o transporte MCP Streamable HTTP.
- Um cliente OAuth2 registrado no seu IdP. Para o fluxo interativo, registre
http://127.0.0.1:53682/callbackcomo URI de redirecionamento (ou o que você definir emOAUTH2_CALLBACK_PORT).
Instalação
Você não precisa instalar nada — clientes MCP podem iniciar o proxy diretamente via npx:
npx -y mcp-oauth2-proxy
Para desenvolvimento com um checkout local:
git clone https://github.com/ChengleiYuan/mcp-oauth2-proxy.git
cd mcp-oauth2-proxy
npm install
npm run build
Início rápido
Login interativo (recomendado para usuários finais)
UPSTREAM_URL=https://mcp.example.com/mcp \
OAUTH2_GRANT=authorization_code \
OAUTH2_CLIENT_ID=<your-client-id> \
npx -y mcp-oauth2-proxy
Na primeira execução, o proxy descobre os endpoints OAuth, abre seu navegador para um login PKCE, captura o código em http://127.0.0.1:53682/callback, armazena em cache o refresh token (criptografado) no diretório de configuração do seu SO e inicia o bridge. Execuções subsequentes reutilizam o token em cache silenciosamente. Detalhes: OAuth2 Grants and Tokens.
Headless / conta de serviço
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
Integre a um 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>"
}
}
}
}
Em hosts Windows que não resolvem shims .cmd (para que command: "npx" consiga iniciar), use o formato explícito:
{
"command": "cmd",
"args": ["/c", "npx", "-y", "mcp-oauth2-proxy"]
}
Os caminhos no bloco env devem ser absolutos e usar barras normais em todas as plataformas.
Configuração
O proxy pode ser configurado por um arquivo JSON (MCP_PROXY_CONFIG), por variáveis de ambiente ou por uma combinação — variáveis de ambiente sobrescrevem valores do arquivo, e o resultado mesclado é validado. Exemplo mínimo de arquivo:
{
"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"
}
}
Consulte config.example.json para um exemplo mais completo.
Variáveis de ambiente mais usadas:
| Env var | Mapeia para |
|---|---|
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 |
Referência completa: todos os campos, padrões e variáveis de ambiente estão documentados na página da wiki Configuration. A descoberta automática de endpoints é abordada em Discovery. Executando o proxy em uma máquina remota? Consulte Remote Hosts (SSH Port Forwarding). Enfrentando um problema? Consulte Troubleshooting.
Segurança
- Os tokens são obtidos pelo próprio proxy; o cabeçalho
Authorizationdo upstream é sempre definido pelo proxy, nunca repassado pelo cliente. - Tokens de acesso ficam apenas em memória. Refresh tokens são armazenados em cache criptografados (AES‑256‑GCM, arquivo de chave com modo
0600) — ofuscação honesta contra leituras casuais de disco, não proteção contra um processo executado pelo mesmo usuário do SO. http://em texto claro para hosts não-loopback é rejeitado na inicialização (substituível comALLOW_INSECURE_HTTP=true);https://e loopbackhttp://são sempre permitidos. O listener de callback interativo valida o cabeçalhoHostpara impedir DNS-rebinding.- Todos os logs vão para stderr com tokens, segredos e cabeçalhos
Authorizationredigidos; o stdout é reservado para JSON-RPC.
Modelo de ameaças completo e defesas: Security.
Desenvolvimento
npm install
npm run build # compile TS to dist/
npm run dev # tsx watch
npm test # vitest (unit + integration)
O teste de integração inicia um endpoint de token OAuth2 simulado e um upstream MCP simulado em processo e aciona o bridge real por streams PassThrough — sem necessidade de rede. A estrutura do projeto, a estratégia completa de testes e o processo automatizado de release estão documentados em Contributing and Releases.
Fora do escopo
- Múltiplos servidores MCP upstream por processo
- Armazenamento de refresh tokens com suporte a keychain do SO (DPAPI / Keychain / libsecret)
- Grants mTLS / JWT-bearer / device-code / ROPC
- Transporte de entrada HTTP / SSE (este é um servidor MCP stdio)