github-mcp-gateway
github-mcp-gateway
Un servidor MCP remoto que ofrece a cualquier cliente MCP acceso autenticado a GitHub — repos, issues, pull requests, contenido de archivos y búsqueda — mediante un handshake OAuth 2.1 real, en Cloudflare Workers.
Funciona con Claude Code, Claude.ai / Cowork y cualquier cliente MCP compatible con la especificación. La autenticación es un flujo user-to-server de una App de GitHub, por lo que los repos a los que puede acceder son los que marcas en la propia pantalla de instalación de GitHub — no todo lo que tu cuenta puede ver.
Esto es código que ejecutas, no un servicio al que te suscribes. No hay ninguna instancia compartida. Despliegas tu propio Worker contra tu propia App de GitHub, y tus credenciales nunca salen de tu cuenta — ver Límites de diseño. La configuración es un script y unos diez minutos:
git clone https://github.com/mazze93/github-mcp-gateway cd github-mcp-gateway && ./scripts/setup.sh <your-github-login>
Qué obtienes
21 herramientas | repos (6), issues (5), pull requests (5), contenido de archivos (3), búsqueda de código e issues (2) — todas las herramientas de listado paginadas |
OAuth 2.1 real | PKCE, Registro Dinámico de Clientes y documentos de metadatos de Client ID, a través del |
Tokens que se renuevan solos | tokens de acceso a GitHub de 8 horas renovados de forma transparente mediante un token de refresco de 6 meses; el cliente MCP nunca ve ninguno de los dos |
Un release endurecido | imagen de toolchain multiarquitectura, no root y distroless, firmada sin claves con cosign, publicada con SBOM y procedencia SLSA |
Probado contra el runtime real | 66 pruebas en |
Related MCP server: Cloudflare GitHub OAuth MCP Server
Por qué existe esto y su forma
Un cliente MCP no puede hablar directamente con la API de GitHub con tus credenciales: necesita algo intermedio que (a) demuestre quién pregunta, (b) tenga un token real de GitHub y (c) traduzca las llamadas a herramientas en peticiones a la API de GitHub. Este Worker es esa capa intermedia y desempeña dos roles de OAuth a la vez:
Cliente OAuth de GitHub (upstream) — te envía a la pantalla de consentimiento propia de GitHub e intercambia el código resultante por un token.
Servidor OAuth para el cliente MCP (downstream) — el cliente nunca ve tu token de GitHub. Obtiene su propio token de este Worker, con alcance solo para este Worker.
@cloudflare/workers-oauth-provider(la propia librería de Cloudflare) implementa esa mitad downstream: OAuth 2.1, PKCE y el Registro Dinámico de Clientes (DCR) — DCR, precisamente, es lo que permite que un cliente se registre en la primera conexión sin que crees credenciales manualmente para él.
MCP client ──OAuth (DCR, PKCE)──▶ this Worker ──OAuth (GitHub App)──▶ GitHub
│
▼
Workers KV (OAUTH_KV)
state · refresh tokens · approved clientsPor qué una GitHub App en lugar de una OAuth App clásica
La propia plantilla de Cloudflare usa una OAuth App clásica, que es más simple pero te da un alcance de repos de todo o nada y un token que nunca caduca a menos que construyas la caducidad tú mismo. Esta versión usa una GitHub App con el flujo de token user-to-server en su lugar:
Alcance por repositorio en el momento de la instalación — eliges exactamente qué repos puede tocar este servidor (el selector de instalación propio de GitHub), no "todo lo que esta cuenta puede ver."
Tokens que de verdad caducan y se renuevan solos — con la opción "Expire user authorization tokens" activada, GitHub devuelve un token de acceso de 8 horas y un token de refresco de 6 meses, y usar el token de refresco genera un nuevo par de ambos. Mientras uses este servidor al menos una vez cada 6 meses, nunca se queda obsoleto y nunca tienes que generar un token nuevo manualmente.
Ese ciclo de refresco lo gestiona src/github-client.ts, con independencia de la propia sesión de Cowork con este Worker — ver Ciclo de vida del token, más abajo.
1. Crea la GitHub App
Ve a github.com/settings/apps/new (cuenta personal) o github.com/organizations/<org>/settings/apps/new (de una organización — usa esta si quieres tenerla bajo una organización en lugar de tu cuenta personal).
Campo | Valor |
Nombre de la GitHub App |
|
URL de la página de inicio |
|
URL de callback |
|
Webhook | Desmarca "Active" — este servidor no usa webhooks |
Permisos del repositorio → Contenidos | Lectura y escritura |
Permisos del repositorio → Issues | Lectura y escritura |
Permisos del repositorio → Pull requests | Lectura y escritura |
Permisos del repositorio → Metadatos | Lectura (obligatorio, seleccionado automáticamente) |
¿Dónde se puede instalar esta GitHub App? | Solo en esta cuenta |
Después de crearla:
Anota el Client ID en la parte superior de la página de configuración de la app.
Haz clic en Generate a new client secret — cópialo ahora, solo se muestra una vez.
En Optional features, busca User-to-server token expiration y haz clic en Opt-in. Esto es lo que hace que existan los tokens de refresco — si te lo saltas, el servidor fallará en el paso del callback con un error claro que te dirá que vuelvas y hagas esto.
Ve a Install App (barra lateral izquierda) e instálala en tu cuenta, eligiendo Only select repositories — elige los repos a los que quieres que llegue este servidor (puedes añadir más luego desde la misma pantalla).
Te convendrá una segunda GitHub App, configurada de forma idéntica pero con la URL de callback http://localhost:8788/callback, si planeas iterar con wrangler dev localmente antes de desplegar.
2. Crea el namespace KV
La vía más rápida — ./scripts/setup.sh <your-github-login> instala las dependencias, crea el namespace y reescribe wrangler.jsonc con tu id de namespace y tu lista de permitidos. Entonces salta al paso 3.
A mano:
cd github-mcp-gateway
npm ci
npx wrangler kv namespace create OAUTH_KVCopia el id devuelto en wrangler.jsonc bajo kv_namespaces[0].id, reemplazando el valor incluido en el repositorio. Ese valor es el namespace en vivo del mantenedor, no un marcador de posición: este repositorio es a la vez un despliegue en funcionamiento y una plantilla, así que la configuración registrada es real. Es un identificador, no una credencial: no le concede nada a un fork, pero dejarlo en su sitio significa que tu Worker arranca contra un namespace al que tu cuenta no puede acceder.
3. Establece los secretos y la variable de la lista de permitidos
npx wrangler secret put GITHUB_APP_CLIENT_ID
npx wrangler secret put GITHUB_APP_CLIENT_SECRET
openssl rand -hex 32 | npx wrangler secret put COOKIE_ENCRYPTION_KEYALLOWED_GITHUB_LOGINS es una variable normal, no un secreto — añádela a wrangler.jsonc en un bloque "vars" de nivel superior:
"vars": {
"ALLOWED_GITHUB_LOGINS": "your-github-login"
}Esta es una lista de permitidos de defensa en profundidad que se comprueba en el callback de OAuth: aunque solo tú puedes completar la pantalla de consentimiento de GitHub para tu propia cuenta, esto hace que la puerta sea explícita en el código en lugar de implícita en "quien pueda autenticarse". Un valor sin establecer o vacío deniega a todos — se cierra por defecto, así que un paso omitido te deja fuera en lugar de abrir el servidor.
4. Despliega
npx wrangler deploy5. Conecta un cliente
Apunta cualquier cliente MCP a:
https://github-mcp-gateway.<your-subdomain>.workers.dev/mcpClaude Code:
claude mcp add --transport http github-mcp-gateway <url>Claude.ai / Cowork: añade un conector MCP personalizado con esa URL.
El cliente se registra mediante DCR, te redirige a través de la pantalla de consentimiento de este servidor, luego a la de GitHub, y vuelve con las herramientas disponibles.
Desarrollo local
cp .dev.vars.example .dev.vars # fill in the *local* GitHub App's credentials
npx wrangler devwrangler dev sirve en http://localhost:8788 — apunta un cliente MCP (p. ej., el MCP Inspector) a http://localhost:8788/mcp.
Ciclo de vida del token
Existen dos relaciones de token independientes, con relojes distintos:
Cowork ↔ este Worker. Tokens de acceso/refresco OAuth 2.1 estándar emitidos por
workers-oauth-provider. Cowork los renueva solo, automáticamente, según la especificación de MCP — no hay nada que gestionar aquí.Este Worker ↔ GitHub. Un token de acceso de 8 horas + un token de refresco de 6 meses.
src/github-client.tscomprueba la caducidad antes de cada llamada a la API de GitHub y renueva de forma transparente cuando faltan menos de 5 minutos para la caducidad, persistiendo el par rotado enOAUTH_KVbajogithub:tokens:{your-login}. Esto, deliberadamente, no está conectado a través del hooktokenExchangeCallbackdeworkers-oauth-provider— ese mecanismo tiene un bug upstream abierto (los props que se quedaban obsoletos tras un refresco provocaban bucles de reautenticación; ver Referencias) —, así que se gestiona directamente en la capa de herramientas, donde es más simple razonar y probar.
Si el token de refresco de GitHub caduca (sin uso durante más de 6 meses) o revocas el acceso de la app, la siguiente llamada a una herramienta fallará con un mensaje ReauthorizationRequiredError claro que te indica que te desconectes y reconectes en Cowork. Aquí no hay modo de fallo silencioso — o funciona silenciosamente en segundo plano, o te dice exactamente qué hacer.
Herramientas
Módulo | Herramientas |
|
|
|
|
|
|
|
|
|
|
Todas las herramientas de listado aceptan per_page y page para la paginación.
github_merge_pull_request y github_delete_file son las dos operaciones destructivas — irreversibles a través de la propia herramienta una vez invocadas. El cliente debe confirmar contigo antes de invocar cualquiera de ellas.
Sure, I can translate this README into Spanish while preserving all the code spans and Markdown structure. Here is the translation:
github_update_repo (description, homepage, topics) requires the GitHub app to have the Administration repository permission. The app as
configured (Contents/Issues/PRs/Metadata) does not include it —
add the permission in the app settings and re-approve the installation to
enable this tool, or make those edits with the gh CLI instead.
Deliberate design limits
Read this before adopting — these are decisions, not gaps.
One operator per deployment
This server is single-tenant by design. ALLOWED_GITHUB_LOGINS gates
the OAuth callback, and while it accepts a comma-separated list and token
storage is already per-login (github:tokens), the intended shape is one deployment per operator.
That is a threat-model decision. A shared deployment would mean one operator’s KV namespace holding other people’s GitHub refresh tokens — six-month credentials with repository write access. That makes the operator a credential custodian with a breach-notification obligation, on infrastructure with no such guarantees. Self-hosting keeps every credential in the account it belongs in, which is the whole point of the design.
So: fork it and run your own. ./scripts/setup.sh exists for exactly
that. Setup is roughly ten minutes, and the Cloudflare free tier covers
personal use.
Repository scope is set at install time, not by this server
Because this is a GitHub App rather than a classic OAuth App, the repos reachable through it are the ones you select on GitHub’s own installation screen. This server cannot exceed that restriction, and no tool call can ever reach beyond it. To change the scope, change the installation.
github_update_repo needs a permission the app does not ship with
It requires the Administration repository permission. Add it in the app
settings and re-approve the installation, or use the gh CLI for
description and topic edits.
Not a hosted service
There is no public instance to point a client at. Any workers.dev URL
you find referenced in this repository (in deploy.yml, SECURITY.md, or the
Dockerfile header) is the maintainer’s own deployment, and its allowlist
will reject you. This is source you run, not a service you sign up for.
Security notes / known upstream issues this build accounts for
CSRF, state, session fixation — handled in
src/oauth/workers-oauth-utils.tsvia a CSRF token + cookie pair on the consent form, one-time-use KV-backed state (10 min TTL), and a session-binding cookie (SHA-256 hash of the state token) proving the browser completing the GitHub callback is the same one that started the flow.workers-oauth-providerIssue #133 — a path-handling bug in audience validation has, in some versions, broken Claude.ai/Cowork connections specifically. This build avoids adding any path to any resource indicator (the/mcpand/sseroutes are registered at the root orapiHandlers, not nested under a longer path) as a documented workaround. If Cowork’s first connection attempt fails at the token exchange step, this is the first thing to check upstream.Issue #108 (RFC 8707 audience validation with paths) — same root cause as above, same mitigation.
Issue #29 (redirect URI mismatch in production) — DCR-registered redirect URIs have been reported to behave differently in production vs.
wrangler devfor some clients. If Cowork’s redirect fails only after deploying (and works locally), this is the known suspect.__Host-cookie prefix used everywhere — guarantees (browser- forzably) that a cookie could only have been set by this exact origin over HTTPS, with noDomainattribute that could widen its scope.
References
Cloudflare Agents — Build a Remote MCP Server
cloudflare/workers-oauth-provider— the downstream OAuth 2.1 implementation this depends onGitHub Docs — Refreshing user access tokens
workers-oauth-providerIssue #133 (Claude.ai connection failures) and Issue #108 (the RFC 8707 path audience bug)github_update_repo(descripción, página de inicio, temas) requiere que la aplicación de GitHub tenga el permiso del repositorio Administración. La aplicación tal como está configurada (Contenido/Incidencias/PRs/Metadatos) no lo incluye: añade el permiso en los ajustes de la aplicación y vuelve a aprobar la instalación para habilitar esta herramienta, o haz esos cambios con la CLIghen su lugar.
Límites de diseño (adrede)
Lee esto antes de adoptarlo: son decisiones, no carencias.
Un operador por despliegue
Este servidor es de un solo inquilino por diseño. ALLOWED_GITHUB_LOGINS limita la devolución de OAuth, y aunque acepta una lista separada por comas y el almacenamiento de tokens ya está clasificado por login (github:tokens), la forma prevista es un despliegue por operador.
Eso es una decisión de modelo de amenazas. Un despliegue compartido significaría que el espacio de claves KV de un operador contiene tokens de refresco de GitHub de otras personas, unas credenciales de seis meses passo打法—llamadas de seis meses con acceso de escritura al repositorio. Eso convierte al operador en un custodio de credenciales con obligación de notificar brechas, en una infraestructura sin tales garantías. Autoalojar mantiene cada credencial en la cuenta a la que pertenece, que es el sentido de todo el diseño.
Así que: hazle un fork y ejecuta el tuyo. ./scripts/setup.sh existe exactamente para eso. La configuración toma unos diez minutos, y la capa gratuita de Cloudflare cubre el uso personal.
El ámbito del repositorio se fija en tiempo de instalación, no por este servidor
Como esto es una aplicación de GitHub en lugar de una aplicación OAuth clásica, los repositorios accesibles a través de ella son los que seleccionas en la pantalla de instalación de GitHub. Este servidor no puede ampliar eso, y ninguna herramienta de invocación puede llegar más allá. Para cambiar el ámbito, cambia la instalación.
P.D.: github_update_repo necesita un permiso con el que la aplicación no incluye
Requiere el permiso del repositorio Administración. Añádelo en los ajustes de la aplicación y vuelve a aprobar la instalación, o haz esas ediciones con la CLI gh.
No es un servicio alojado
No hay ninguna instancia pública a la que apuntar los clientes. Cualquier URL workers.dev que encuentres referenciada en este repo (en la cabecera de deploy.yml, SECURITY.md o el Dockerfile) es el propio del operador, y su lista de permitidos te rechazará. Esto no es un servicio que te suscribes, sino fuente que ejecutas.
Notas de seguridad / problemas ascendentes conocidos que esta versión tiene en cuenta
CSRF, estado y fijación de sesión — gestionado en
src/oauth/workers-oauth-utils.tsmediante un token CSRF + una pareja de cookies en el formulario de consentimiento, estado respaldado por KV para un solo uso (10 min de TTL), y una cookie de vínculo de sesión (hash SHA-256 del estado) que demuestra que el navegador que llama al callback de GitHub es el mismo que inició el flujo.workers-oauth-providerEdición #125 — un error de manipulación de rutas en la validación de audiencia ha, en algunas versiones, roto las conexiones Claude.ai/Cowork específicamente. Esta versión evita añadir rutas a cualquier indicador de recurso (las rutas/mcpy/ssese encuentran registradas en la raíz deapiHandlers, no en una ruta más larga) como el solucionario documentado. Si el primer intento de conexión de Cowork falla en el paso del intercambio de tokens, esto es lo primero a mirar río arriba.Issue #108 (validación de audiencia RFC 8707 con rutas) — misma causa raíz que la anterior, misma mitigación para el problema de seguridad.
Issue #29 (el redirect URI no coincide en producción) — los redirect URIs registrados por DCR se han informado demuestran una diferencia de comportamiento entre producción y dev local para algunos clientes. Si el redirect de Cowork falla solo luego de un despliegue (y funciona localmente), este es el sospechoso conocido.
prefijo de cookie
__Host-usado por todas partes — garantiza (forzoso- mente desde el navegador) que una cookie solo pudo haber sido puesta por este origen exacto mediante HTTPS, sin atributoDominioque pueda ampliar su alcance.
Referencias
Agentes de Cloudflare — Crea un servidor MCP remoto
cloudflare/workers-oauth-provider— la implementacion de OAuth 2.1 aguas abajo que esto requiereDocumentos de GitHub — Actualizar los tokens de acceso de los usuarios
workers-oauth-providerProblema #133 (fallos de conexion a Claude.ai) y el problema #108 (el fallo de la ruta de RFC 907 audiencia)
This server cannot be installed
Maintenance
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceA Cloudflare Workers-deployed MCP server that provides secure remote access to MCP tools through GitHub OAuth authentication. Includes example tools for basic math operations, user info retrieval, and image generation with configurable user access controls.241Apache 2.0
- FlicenseNot gradedqualityDmaintenanceA reference MCP server for Cloudflare Workers that provides remote connection support with integrated GitHub OAuth authentication. It enables developers to build and deploy authenticated remote tools with user-specific access controls and persistent state management.
- FlicenseNot gradedqualityCmaintenanceA remote MCP server for Cloudflare Workers featuring built-in GitHub OAuth for secure user authentication and identity-based access control to tools. It provides a reference implementation for managing remote MCP connections with persistent state and OAuth provider integration.1
- AlicenseNot gradedqualityBmaintenanceEnables remote MCP connections with GitHub OAuth authentication, providing tools like add, userInfoOctokit, and image generation (restricted) deployed on Cloudflare Workers.11MIT
Related MCP Connectors
An MCP server that gives your AI access to the source code and docs of all public github repos
Hosted remote MCP server for YNAB on Cloudflare Workers with OAuth
Search your AI chat history (ChatGPT, Claude, Codex) from any MCP client. Remote, private, read-only
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/mazze93/github-mcp-gateway'
If you have feedback or need assistance with the MCP directory API, please join our Discord server