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

npm version node license: MIT

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áginaO que contém
Getting StartedInstalação, primeira execução, integração com um cliente.
ConfigurationTodos os campos e variáveis de ambiente.
OAuth2 Grants and TokensGrants, login interativo, ciclo de vida de tokens e cache.
DiscoveryDescoberta de endpoints RFC 9728 / RFC 8414.
SecurityModelo de ameaças e defesas integradas.
Remote Hosts (SSH Port Forwarding)Login quando o proxy é executado remotamente.
TroubleshootingProblemas comuns e FAQ.
Architecture · Bridge · OAuth2 internalsComo funciona internamente.
Contributing and ReleasesConfiguração de desenvolvimento, testes, processo de release.

Conteúdo

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_credentials para 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-stream e o canal opcional de notificações de longa duração do servidor. Respeita Mcp-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

  1. Descoberta. Opcionalmente, busca metadados RFC 9728/8414 para preencher tokenUrl, authorizationUrl, scope e resource.
  2. Gerenciador de tokens. Envolve o Grant configurado com cache, skew de atualização, deduplicação de requisições em andamento e invalidação por 401.
  3. 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.
  4. Bridge. Para cada linha JSON-RPC do stdin, faz POST para upstream.url com um token Bearer; respostas JSON de disparo único viram uma linha no stdout, respostas SSE uma linha por evento. Um 401 dispara invalidate() e uma única nova tentativa.
  5. Stream do servidor. Após initialize, opcionalmente mantém aberto um canal GET text/event-stream para 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/callback como URI de redirecionamento (ou o que você definir em OAUTH2_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 varMapeia para
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

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 Authorization do 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 com ALLOW_INSECURE_HTTP=true); https:// e loopback http:// são sempre permitidos. O listener de callback interativo valida o cabeçalho Host para impedir DNS-rebinding.
  • Todos os logs vão para stderr com tokens, segredos e cabeçalhos Authorization redigidos; 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)

Licença

MIT