GitMCP
permite a los asistentes de IA explorar repositorios de GitHub, código fuente, issues, pull requests y commits a través de 14 herramientas validadas de solo lectura, además de 4 herramientas de escritura opcionales que están desactivadas por defecto.
Documentación
GitMCP
Un servidor de GitHub para asistentes de IA: permite que Claude y otros clientes MCP lean repositorios, issues, pull requests y commits a través de herramientas validadas, con escrituras deshabilitadas a menos que optes por habilitarlas.
- 14 herramientas de solo lectura más 4 herramientas de escritura opcionales, cada una con un esquema de entrada Pydantic estricto
- Los fallos transitorios (429, 5xx, timeouts) se reintentan dentro de un presupuesto estricto; los errores de autenticación, permisos y 404 nunca se reintentan
- Seguro por defecto: escrituras desactivadas, token nunca registrado ni devuelto, tamaños de respuesta limitados, sin acceso arbitrario a URL/shell
- Funciona con Claude Code y Claude Desktop a través de stdio; los repositorios públicos no necesitan token
Expectativas honestas: solo stdio, por lo que cada usuario ejecuta su propia copia local. La búsqueda de código y los repositorios privados necesitan un token de GitHub. La lectura de archivos es solo texto UTF-8.
Lo que construí
GitMCP es un servidor MCP en Python que adapta la API REST de GitHub en 18 herramientas que un asistente de IA puede descubrir y
llamar. La lógica de GitHub (github/*.py) es independiente de MCP, por lo que se prueba sin un servidor en ejecución; un
server.py delgado registra las herramientas y convierte cada fallo en un mensaje corto, seguro y accionable. Se
construyó contra el SDK oficial actual de MCP para Python (2.x) y se verificó con un cliente MCP stdio real.
Resultados de un vistazo
Medido en una laptop con Windows 11, Python 3.14, anónimo (sin token) contra la API de GitHub en vivo.
| Métrica | Resultado |
|---|---|
| Pruebas automatizadas | 112 aprobadas, 1 omitida (prueba de integración en vivo, necesita token), ~13 s |
| Lint / tipos | ruff limpio, mypy --strict limpio (18 archivos fuente) |
| Inicio en frío: proceso de arranque, handshake MCP, listar 14 herramientas | 1.3 s |
Latencia de github_get_repository | 0.6 s primera llamada (configuración TLS), ~0.02 s mediana en conexión reutilizada |
| Tamaño del código | ~2,100 líneas en src/, ~1,400 líneas de pruebas |
La latencia está dominada por GitHub y la red, no por el servidor. Las compensaciones de diseño están en DECISIONS.md.
Arquitectura
flowchart LR
Client["MCP client<br/>(Claude Code / Desktop)"] -- "stdio JSON-RPC" --> Server["server.py<br/>tool registration + error guard"]
Server --> Repos["github/repositories.py"]
Server --> Issues["github/issues.py"]
Server --> PRs["github/pull_requests.py"]
Server --> Commits["github/commits.py"]
Repos & Issues & PRs & Commits --> GH["github/client.py<br/>auth, errors, size limit"]
GH --> Retry["retry.py<br/>backoff + jitter + Retry-After"]
GH -- HTTPS --> API[("GitHub REST API")]
Server -. validates with .-> Schemas["schemas/<br/>Pydantic in/out models"]
Config["config.py<br/>env settings"] --> Server
| Módulo | Responsabilidad |
|---|---|
server.py | Crea el MCPServer, registra herramientas, convierte errores en errores de herramienta seguros, cierra el cliente HTTP al apagar |
github/*.py | Lógica de negocio. Sin imports de MCP, por lo que es comprobable sin un servidor |
github/client.py | Cliente httpx autenticado, mapeo de estado HTTP → error tipado, límite de tamaño de respuesta |
retry.py | Política de reintentos (429 / 5xx / red), manejo de Retry-After y encabezados de reinicio |
schemas/ | Modelos de entrada Pydantic estrictos (extra="forbid") y modelos de salida |
errors.py | Excepciones tipadas con mensajes seguros y sugerencias |
logging_utils.py | Registro en stderr con redacción de secretos |
Por qué está construido así: ver DECISIONS.md.
Inicio rápido
Requiere Python 3.11+. Repositorio: https://github.com/wablevaibhav/gitmcp
python -m pip install git+https://github.com/wablevaibhav/gitmcp
python -m gitmcp # starts the server (waits silently for an MCP client)
Luego conéctalo a tu cliente de IA: ver Claude Code o Claude Desktop. No necesitas clonar el repositorio para usar GitMCP.
Última versión: v0.1.0. Para instalar exactamente esa versión:
python -m pip install git+https://github.com/wablevaibhav/gitmcp@v0.1.0
Para actualizar más tarde:
python -m pip install --upgrade --force-reinstall git+https://github.com/wablevaibhav/gitmcp
Alternativas (no requeridas): pipx install git+https://github.com/wablevaibhav/gitmcp, o con
uv: uvx --from git+https://github.com/wablevaibhav/gitmcp gitmcp.
Instalación para desarrollo (contribuidores)
git clone https://github.com/wablevaibhav/gitmcp.git
cd gitmcp
python -m venv .venv
# Windows (PowerShell): .venv\Scripts\Activate.ps1
# macOS / Linux: source .venv/bin/activate
pip install -e ".[dev]"
requirements-lock.txt fija las versiones exactas con las que se probó el proyecto
(pip install -r requirements-lock.txt, luego pip install -e . --no-deps).
Configuración del token de GitHub
El token es opcional para repositorios públicos (límite anónimo: 60 solicitudes/hora) pero requerido para repositorios privados, búsqueda de código y herramientas de escritura.
Crea un token de acceso personal de grano fino en GitHub → Configuración → Configuración de desarrollador → Tokens de acceso personales → Tokens de grano fino, restringido solo a los repositorios que quieras que el asistente vea.
| Capacidad | Permiso de repositorio |
|---|---|
| Repos, contenidos, lectura de archivos, commits | Contenidos: Lectura (Metadatos: Lectura es implícito) |
| Issues y comentarios | Issues: Lectura |
| Pull requests, archivos, revisiones | Pull requests: Lectura |
github_create_issue, github_add_issue_comment | Issues: Lectura y escritura |
github_create_branch | Contenidos: Lectura y escritura |
github_create_pull_request | Pull requests: Lectura y escritura |
Comienza con permisos de solo lectura. Agrega permisos de escritura solo si habilitas herramientas de escritura.
Público vs. autenticado: sin token solo se ven datos públicos y GitHub devuelve 404 para recursos
privados. Con un token ves exactamente lo que el token puede ver, nada más; GitMCP nunca elude la autorización de GitHub.
Configuración
Variables de entorno (o un archivo .env en el directorio de trabajo; copia .env.example):
| Variable | Predeterminado | Significado |
|---|---|---|
GITHUB_TOKEN | (ninguno) | Token de acceso personal |
GITHUB_API_URL | https://api.github.com | Base de API (GitHub Enterprise: https://HOST/api/v3) |
GITHUB_API_VERSION | 2022-11-28 | Encabezado X-GitHub-Api-Version |
GITHUB_REQUEST_TIMEOUT | 30 | Tiempo de espera por solicitud, segundos |
GITHUB_MAX_RETRIES | 3 | Reintentos después del primer intento (0–10) |
GITHUB_MAX_RATE_LIMIT_WAIT | 60 | Espera máxima de límite de tasa que GitMCP dormirá, segundos |
GITHUB_ENABLE_WRITE_TOOLS | false | Registrar herramientas de escritura |
GITMCP_LOG_LEVEL | INFO | DEBUG/INFO/WARNING/ERROR (stderr) |
GITMCP_MAX_FILE_BYTES | 200000 | Archivo más grande que github_get_file_contents devuelve |
GITMCP_MAX_PATCH_CHARS | 8000 | Truncamiento de diff por archivo |
GITMCP_MAX_COMMENT_CHARS | 4000 | Truncamiento de cuerpo de comentario/revisión |
GITMCP_MAX_RESPONSE_BYTES | 5000000 | Límite máximo en cualquier cuerpo de respuesta de GitHub |
Ejecutar el servidor
python -m gitmcp # or simply: gitmcp
El servidor habla MCP a través de stdio, por lo que por sí solo imprime una línea de "listo" en stderr y espera. Está diseñado para ser lanzado por un cliente MCP. Para confirmar que es descubrible y llamable usando un cliente MCP stdio real (desde un clon de este repositorio):
python scripts/verify_tools.py # lists the tools
python scripts/verify_tools.py octocat/Hello-World # also calls github_get_repository
Mantén tu token en secreto. Nunca lo pegues en chats, issues, capturas de pantalla ni lo confirmes. Si un token alguna vez se expone, revócalo inmediatamente en https://github.com/settings/personal-access-tokens y crea uno nuevo.
Claude Code
macOS / Linux / Git Bash:
claude mcp add gitmcp --scope user -e GITHUB_TOKEN="$GITHUB_TOKEN" -- python -m gitmcp
Windows PowerShell (Windows PowerShell 5.1 se traga el separador --, así que ejecuta a través de cmd):
$env:GITHUB_TOKEN = "your-token" # type it in your own terminal only
cmd /c "claude mcp add gitmcp --scope user -e GITHUB_TOKEN=%GITHUB_TOKEN% -- python -m gitmcp"
Verifica con claude mcp list (o /mcp dentro de Claude Code). Si python no es el intérprete donde instalaste
GitMCP, usa su ruta completa (where python / which python), p. ej.
C:\Users\you\AppData\Local\Programs\Python\Python312\python.exe.
También puedes compartir un .mcp.json a nivel de proyecto, haciendo referencia a la variable de entorno de cada persona (nunca
escribas el token en el archivo):
{
"mcpServers": {
"gitmcp": {
"command": "python",
"args": ["-m", "gitmcp"],
"env": { "GITHUB_TOKEN": "${GITHUB_TOKEN}" }
}
}
}
Claude Desktop
Edita claude_desktop_config.json (Windows: %APPDATA%\Claude\, macOS:
~/Library/Application Support/Claude/), luego reinicia Claude Desktop:
{
"mcpServers": {
"gitmcp": {
"command": "python",
"args": ["-m", "gitmcp"],
"env": {
"GITHUB_TOKEN": "your-token",
"GITHUB_ENABLE_WRITE_TOOLS": "false"
}
}
}
}
Si Claude Desktop no puede encontrar python, establece command a la ruta completa del intérprete, con barras invertidas dobles
en Windows ("C:\\Users\\you\\AppData\\Local\\Programs\\Python\\Python312\\python.exe").
Usarlo con otros
Cada persona ejecuta su propia copia local; no se comparte ningún servidor y los tokens nunca se comparten. Todos hacen:
python -m pip install git+https://github.com/wablevaibhav/gitmcp- Crea su propio token de GitHub de grano fino (ver más abajo).
- Agrega el servidor a su cliente usando una de las configuraciones anteriores.
Los repositorios públicos funcionan sin token (60 solicitudes/hora); los repositorios privados, la búsqueda de código y las herramientas de escritura requieren uno.
Instalar el paquete no hace que el servidor aparezca en un cliente por sí solo; el cliente debe configurarse como se indicó anteriormente. El servidor y el comando se verificaron con
scripts/verify_tools.py(un cliente MCP stdio real). Los fragmentos de Claude Code / Desktop siguen los formatos documentados de esos productos.
Uso
Salida real de python scripts/verify_tools.py octocat/Hello-World (un cliente MCP hablando con el servidor
a través de stdio, sin token):
Connected. 14 tools:
- github_search_repositories
- github_get_repository
- github_list_repository_contents
- github_get_file_contents
...
is_error: False
{'full_name': 'octocat/Hello-World', 'owner': 'octocat', 'name': 'Hello-World',
'visibility': 'public', 'stars': 3842, 'default_branch': 'master', ...}
Los errores son cortos, tipados y accionables (salida real, anónima):
github_get_repository -> NotFoundError: Resource not found. Hint: Check owner, repo, path and ref.
Private resources also return 404 when the token lacks access.
No GITHUB_TOKEN is configured, so only public data is visible.
github_search_code -> AuthenticationError: GitHub code search requires authentication.
Hint: Set GITHUB_TOKEN, and scope the query with repo:, org: or user:.
Herramientas
Cada herramienta toma un argumento de objeto llamado params. Todas las entradas rechazan campos desconocidos. Las herramientas de lista aceptan
page (1–1000) y per_page (1–100, predeterminado 30) y devuelven has_next_page. owner/repo/ref/path son
validados (sin traversal, sin caracteres de referencia inválidos).
| Herramienta | Argumentos clave | Devuelve |
|---|---|---|
github_search_repositories | query, language, topic, min_stars, sort, order, paginación | recuento total; elementos con nombre completo, propietario, descripción, URL, visibilidad, idioma, estrellas, rama predeterminada |
github_get_repository | owner, repo | resumen + licencia, forks, issues abiertos, temas, URL de clon/API, marcas de tiempo |
github_list_repository_contents | owner, repo, path, ref | entradas: nombre, ruta, tipo, tamaño, sha, URL web/API/descarga |
github_get_file_contents | owner, repo, path, ref | content UTF-8, sha, tamaño. Errores para directorios, binarios, > límite de tamaño |
github_search_code | query (necesita repo:/org:/user:), paginación | elementos: ruta, repositorio, URL, fragmentos. Requiere token |
github_list_issues | owner, repo, state, labels, assignee, include_pull_requests, paginación | resúmenes con indicador is_pull_request |
github_get_issue | owner, repo, issue_number | detalles: cuerpo, etiquetas, asignados, hito, marcas de tiempo, URL |
github_list_issue_comments | owner, repo, issue_number, paginación | comentarios (cuerpos truncados, marcados) |
github_list_pull_requests | owner, repo, state, base, head (owner:branch), paginación | resúmenes de PR |
github_get_pull_request | owner, repo, pull_number | ramas, SHAs, autor, borrador/fusionado/fusionable, tamaño, revisores |
github_list_pull_request_files | owner, repo, pull_number, paginación | archivos: estado, +/−, parche (truncado, marcado) |
github_list_pull_request_reviews | owner, repo, pull_number, paginación | revisiones: autor, APPROVED/CHANGES_REQUESTED/…, cuerpo |
github_list_commits | owner, repo, ref, path, author, paginación | resúmenes de commits |
github_get_commit | owner, repo, ref | mensaje, autor, padres, estadísticas, archivos (máx. 100, parches truncados) |
github_create_issue ⚠ | owner, repo, title, body, labels, assignees | número, URL |
github_add_issue_comment ⚠ | owner, repo, issue_number, body | id de comentario, URL |
github_create_branch ⚠ | owner, repo, branch, from_ref | nueva ref, SHA |
github_create_pull_request ⚠ | owner, repo, title, head, base, body, draft | número, URL |
⚠ Herramienta de escritura: registrada solo cuando GITHUB_ENABLE_WRITE_TOOLS=true.
Ejemplos de indicaciones
- Exploración de repositorio: "Mira
octocat/Hello-World. ¿Cuál es la rama predeterminada, qué hay en la raíz y qué dice el README?" - Búsqueda de código: "Encuentra dónde se define
parse_configenacme/api." (necesita un token) - Investigación de issues: "Lista los issues abiertos etiquetados como
bugenacme/api, luego resume la discusión en el más comentado." - Revisión de PR: "Revisa el PR 482 en
acme/api: muestra los metadatos, los archivos cambiados y los parches, las revisiones existentes, y señala cambios riesgosos." - Historial: "¿Quién tocó por última vez
src/auth.pyenacme/apiy qué cambiaron esos commits?"
Límites de tasa y manejo de errores
| Situación | Comportamiento |
|---|---|
429, o 403 con señales de límite de tasa | Reintentado, respetando Retry-After / x-ratelimit-reset. Si la espera excede GITHUB_MAX_RATE_LIMIT_WAIT, falla inmediatamente con RateLimitError indicando la espera. Nunca duerme más allá de ese límite |
500/502/503/504, tiempos de espera, errores de conexión | Reintentado hasta GITHUB_MAX_RETRIES con retroceso exponencial y jitter completo (base 0.5 s, tope 8 s) |
401 | AuthenticationError — sin reintento |
403 (permiso) | AuthorizationError — sin reintento; la pista menciona el permiso a otorgar |
404 | NotFoundError — sin reintento; la pista señala que los recursos privados también devuelven 404 |
400/409/422 | InputValidationError — sin reintento |
| Cuerpo malformado / demasiado grande / no JSON | GitHubAPIError |
Las solicitudes de escritura (POST) nunca se reproducen después de un tiempo de espera o un 5xx, ya que la escritura pudo haber tenido éxito; solo se reintentan cuando GitHub las rechazó con un límite de tasa.
Los clientes reciben ErrorType: message Hint: .... Los tracebacks, cuerpos de respuesta y tokens nunca llegan al cliente.
Seguridad
- El token proviene únicamente del entorno, se mantiene como
SecretStry se redacta de registros y errores (coincidencia exacta más patronesghp_…/github_pat_…/Authorization:). - Las herramientas de escritura no se registran a menos que
GITHUB_ENABLE_WRITE_TOOLS=true, y cada método de servicio de escritura se niega de forma independiente si la bandera está desactivada. GitHub aún aplica los permisos propios del token. - Sin ejecución de shell, sin obtención arbitraria de URL, sin GraphQL, sin proxy API genérico: cada herramienta se asigna a un endpoint REST fijo y los argumentos de la herramienta se codifican en porcentaje en la ruta.
- Los tamaños de archivo, parche, comentario y respuesta total están limitados; los registros nunca contienen código fuente ni respuestas completas.
- Use un token de grano fino con alcance a repositorios específicos y establezca una fecha de expiración.
- El transporte HTTP Streamable se implementa intencionalmente no; un servidor expuesto a la red necesitaría su propia autenticación, lo cual está fuera del alcance de esta versión.
Desarrollo
Desde una instalación de desarrollo:
pytest # unit + MCP tests (no token, no network)
ruff check . && ruff format --check .
mypy # strict, on src/
Pruebas en vivo opcionales (solo lectura, omitidas a menos que se configuren):
GITMCP_TEST_TOKEN=github_pat_xxx GITMCP_TEST_REPO=owner/repo pytest -m integration
Solución de problemas
| Síntoma | Causa probable / solución |
|---|---|
| El cliente no muestra herramientas | Python incorrecto en la configuración del cliente. Ejecute python -m gitmcp con ese intérprete exacto; use su ruta completa en la configuración |
error: unknown option '-m' (PowerShell) | PowerShell 5.1 elimina --. Use la forma cmd /c "claude mcp add ..." anterior |
No module named gitmcp | Instalado en un Python/venv diferente al que el cliente lanza |
NotFoundError en un repositorio que puede abrir en un navegador | Repositorio privado y token faltante o con alcance insuficiente |
AuthorizationError | El token carece del permiso en la tabla anterior o el repositorio no está seleccionado para el token |
RateLimitError inmediatamente | El restablecimiento está más lejos que GITHUB_MAX_RATE_LIMIT_WAIT; establezca un token o espere |
github_search_code falla | Necesita GITHUB_TOKEN y un calificador repo:/org:/user: |
| Faltan herramientas de escritura | Intencional: establezca GITHUB_ENABLE_WRITE_TOOLS=true y reinicie el cliente |
invalid configuration al inicio | Una configuración falló la validación; los nombres de campo se imprimen en stderr |
| Salida de protocolo distorsionada | Algo escribió en stdout; use stderr para cualquier depuración |
Limitaciones y hoja de ruta
- Las herramientas de lectura devuelven la primera porción de un resultado (la paginación es explícita); no hay seguimiento automático de todas las páginas.
- El contenido de los archivos es solo texto UTF-8; los archivos binarios y los archivos de más de
GITMCP_MAX_FILE_BYTESse rechazan. - La búsqueda de código depende del índice de búsqueda de GitHub y sus límites (máximo 1000 resultados, consulta ≤ 256 caracteres).
github_get_commitlimita los archivos a 100 y no pagina la paginación de archivos de confirmación de GitHub.- GitHub Actions, lanzamientos, comentarios de revisión (en línea) y Projects no están cubiertos.
- Solo stdio; planificado: HTTP Streamable autenticado, caché de solicitudes condicionales (ETag), herramienta de árbol de repositorio.
- Python 3.14 y
mcp2.3 se usaron para el desarrollo; el código apunta a Python ≥ 3.11.