Skip to main content
Glama
JigeeshaJain

gh-review-queue-mcp

by JigeeshaJain

gh-review-queue-mcp

Un servidor MCP que responde a una sola pregunta: ¿qué debería revisar a continuación?

Expone exactamente una herramienta, get_review_queue, que devuelve una vista clasificada y deduplicada de tu cola de revisión de pull requests de GitHub: revisiones solicitadas a ti, revisiones solicitadas a tus equipos y tus propios pull requests que esperan a alguien más.

Una sola herramienta es una restricción deliberada. Un asistente que tiene que elegir entre list_prs, search_prs y get_pr_status gasta su primer turno decidiendo; un asistente con una herramienta que devuelve una lista ya priorizada puede simplemente responder.


Qué hace realmente

Cuando se llama a la herramienta, ocurren cuatro cosas en orden.

1. Te identifica a ti y a tus equipos

El servidor emite una consulta GraphQL para viewer { login } más los equipos a los que perteneces (organizations.teams(role: MEMBER)). Los slugs de los equipos importan porque la API de búsqueda de GitHub no tiene un calificador "solicitado a cualquiera de mis equipos": tienes que nombrar cada equipo explícitamente. Esta es la única razón por la que el token necesita el alcance read:org.

2. Se expande en una búsqueda por lotes

GitHub no tiene una única consulta para "todo lo que necesita mi atención", así que el servidor ejecuta varias búsquedas y las combina. Todas salen en un solo documento GraphQL usando alias, por lo que es un solo viaje de ida y vuelta HTTP sin importar en cuántos equipos estés:

Alias

Búsqueda

Se convierte en motivo

requested_of_me

is:pr is:open archived:false review-requested:@me

requested_of_me

my_pr_awaiting_review

is:pr is:open archived:false author:@me

my_pr_awaiting_review

team_0, team_1, …

is:pr is:open archived:false team-review-requested:<org>/<team>

requested_of_my_teams

Las cadenas de búsqueda se pasan como variables de GraphQL, nunca se interpolan en el documento de consulta, por lo que un slug de equipo no puede reformar la consulta.

La misma consulta también pide rateLimit { remaining resetAt }, para que cada respuesta pueda informar de tu presupuesto restante sin una segunda llamada.

Dos notas sobre la forma de la respuesta. La búsqueda search(type: ISSUE) de GitHub devuelve tanto issues como pull requests; como el conjunto de selección es un fragmento en línea en PullRequest, los issues vuelven como nodos vacíos y se descartan durante el análisis. Y statusCheckRollup se lee de commits(last: 1) — el estado de CI del commit head, no de todo el historial de la rama.

3. Fusionar, deduplicar, filtrar, clasificar

El mismo pull request suele aparecer de varias búsquedas: un PR donde eres revisor directo y se solicita a tu equipo aparece en dos cubos. Se deduplican por node id de GraphQL, y los motivos se acumulan en una sola entrada, de modo que la respuesta dice "esto está aquí por dos razones" en lugar de listarlo dos veces.

Luego se aplican tus filtros, y lo que sobrevive se puntúa y ordena.

4. Serializar

La lista clasificada vuelve como salida estructurada: la herramienta declara un esquema JSON completo de salida, por lo que un cliente recibe campos tipados, no prosa que tenga que parsear.


Related MCP server: github-ops-mcp

Cómo funciona la clasificación

La clasificación es por niveles, no ajustada por pesos. Cada pull request cae exactamente en un nivel, y el nivel vale mucho más que cualquier cosa que se acumule dentro de él:

Nivel

Condición

Base

3

Tu propio PR con CI fallando

300

2

Tu propio PR con cambios solicitados

200

1

Una revisión solicitada directamente a ti

100

0

Una solicitud de equipo, o tu propio PR que simplemente espera

0

Dentro de un nivel, se aplican dos señales menores:

  • Edad — 2 puntos por día desde que se abrió el PR, con un tope de 20. Las solicitudes de revisión antiguas salen a la superficie, pero un PR de seis meses no puede dominar para siempre.

  • Diff pequeño — una bonificación fija de 8 puntos para diffs de 100 líneas o menos, con la teoría de que una revisión pequeña que puedes terminar ahora supera a una grande que pospondrás.

El tope es el punto clave. Lo máximo que cualquier cosa puede acumular dentro de un nivel es 20 + 8 = 28, muy por debajo del paso de nivel de 100, por lo que la dominancia de nivel se mantiene por construcción: una solicitud directa recién creada siempre supera a una solicitud de equipo antigua, y ningún ajuste futuro de pesos puede invertirlo silenciosamente. Si añades una señal de puntuación, mantén el total dentro del nivel por debajo de 100 o esa garantía se rompe.

Los empates se resuelven por la actividad más reciente (updatedAt), por lo que una discusión activa supera a una estancada con la misma puntuación.

Cada elemento lleva priority_reasons — cadenas legibles como ["my PR, CI failing", "3 days old"] — para que la clasificación pueda explicarse de vuelta a ti en lugar de llegar como un número sin explicación.


Instalación

Requiere Python 3.11+ y uv.

git clone <this repo>
cd ReviewQueueMcp
uv sync

Token

El servidor lee un token de acceso personal de GitHub de GITHUB_TOKEN:

cp .env.example .env      # then edit it
export GITHUB_TOKEN=ghp_...

Alcances necesarios:

  • repo — leer pull requests en repositorios privados

  • read:org — leer tus membresías de equipo, para las búsquedas de team-review-requested

Un PAT clásico es lo más simple. Los tokens de grano fino funcionan si se les concede "Pull requests: read" más lectura de miembro de organización. Crea uno en https://github.com/settings/tokens.

GITHUB_GRAPHQL_URL opcionalmente sobrescribe el endpoint para GitHub Enterprise Server.

El token se lee por llamada a la herramienta, no al inicio — el servidor arranca limpiamente sin uno y devuelve un error accionable cuando se le llama, en lugar de morir durante el handshake de MCP donde el cliente solo vería una tubería rota.


Ejecutarlo

uv run gh-review-queue-mcp

Habla MCP sobre stdio y espera un cliente al otro lado; ejecutado directamente, solo espera.

Con MCP Inspector

npx @modelcontextprotocol/inspector uv --directory /absolute/path/to/ReviewQueueMcp run gh-review-queue-mcp

Abre la URL impresa, conéctate, y la herramienta aparece bajo Tools con su esquema de entrada generado.

Con Claude Desktop

Añade a claude_desktop_config.json — en macOS en ~/Library/Application Support/Claude/claude_desktop_config.json:

{
  "mcpServers": {
    "gh-review-queue": {
      "command": "uv",
      "args": [
        "--directory",
        "/absolute/path/to/ReviewQueueMcp",
        "run",
        "gh-review-queue-mcp"
      ],
      "env": {
        "GITHUB_TOKEN": "ghp_..."
      }
    }
  }
}

Las rutas deben ser absolutas — Claude Desktop no lanza servidores desde tu shell, por lo que no tiene directorio de trabajo ni entorno exportado que heredar. Reinicia Claude Desktop después de editar. Luego pregúntale "¿qué debería revisar hoy?"


Referencia de la herramienta

get_review_queue

Todos los argumentos son opcionales.

Argumento

Tipo

Por defecto

Significado

include

array de requested_of_me | requested_of_my_teams | my_pr_awaiting_review

los tres

Qué motivos incluir. Un elemento sobrevive si se incluye cualquiera de sus motivos.

exclude_drafts

boolean

true

Elimina borradores. Se excluyen, no se degradan: un borrador aún no se puede revisar.

max_age_days

integer

ninguno

Elimina PRs abiertos hace más de este número de días. Incluye el límite.

repos

array de owner/name

ninguno

Restringe a estos repositorios. Coincidencia exacta.

limit

integer 1–100

25

Máximo de elementos devueltos. total_matching sigue informando del recuento completo.

Respuesta:

{
  "viewer": "octocat",
  "generated_at": "2026-08-20T12:00:00Z",
  "returned": 5,
  "total_matching": 5,
  "rate_limit_remaining": 4712,
  "warnings": [],
  "items": [
    {
      "repository": "acme/payments-api",
      "number": 4830,
      "title": "Add idempotency keys",
      "url": "https://github.com/acme/payments-api/pull/4830",
      "author": "octocat",
      "reasons": ["my_pr_awaiting_review"],
      "priority_score": 306.0,
      "priority_reasons": ["my PR, CI failing", "3 days old"],
      "age_days": 3.0,
      "diff_size": 374,
      "changed_files": 12,
      "is_draft": false,
      "review_decision": "REVIEW_REQUIRED",
      "ci_status": "FAILURE"
    }
  ]
}

returned vs total_matching distingue "aquí hay 25" de "hay numerosos" — sin ello, una respuesta limitada es indistinguible de una completa.

warnings lleva fallos parciales de GraphQL. GitHub puede devolver datos utilizables junto con errores (una org ilegible, una búsqueda fallando); en lugar de descartar toda la cola, esos se degradan a advertencias y el resto de los resultados aún vuelven.


Arquitectura

Cuatro módulos bajo src/gh_review_queue/, y los límites son estructurales:

server.py    MCP wiring. Parse arguments -> call client -> domain layer -> serialize.
   |         Deliberately thin; its docstring sets a ~120-line budget.
   v
github.py    The only module that touches the network. Builds GraphQL, handles HTTP
   |         and GraphQL errors, returns domain objects. Never ranks or filters.
   v
queue.py     Pure functions: merge -> apply_filters -> rank/score, via build_queue.
   |         Input is a snapshot and a clock. Nothing else.
   v
models.py    Frozen pydantic value objects. The only place GitHub's nested GraphQL
             shape is flattened. No network types.

La recompensa es queue.py: como toma un QueueSnapshot y un datetime y nada más, cada regla de clasificación se prueba con datos simples y sin mocks, sin red y sin parcheo de reloj. Esa es la razón de la división, y por qué una importación de httpx nunca debe llegar a él.

Degradar en lugar de fallar

Los valores de enum desconocidos de GitHub — un nuevo reviewDecision, un nuevo estado de rollup de CI — se mapean a None en lugar de lanzar una excepción. Un estado añadido del lado de GitHub nunca debería romper toda tu cola. El mismo instinto recorre la capa de análisis: los autores faltantes se convierten en ghost (la propia convención de GitHub para cuentas eliminadas), los resultados de búsqueda que no son PR se descartan, y los timestamps ausentes son el único caso genuinamente irrecuperable que sí lanza una excepción.


Desarrollo

uv run pytest                       # all tests
uv run pytest tests/test_queue.py   # one file
uv run pytest -k "rank or score"    # by name
uv run ruff check .                 # lint
uv run ruff format .                # format
uv run mypy                         # typecheck (strict)

Ejecuta mypy sin argumentos — toma sus objetivos de [tool.mypy] files en pyproject.toml, por lo que pasar una ruta comprueba menos de lo previsto.

Enfoque de pruebas

Las pruebas se ejecutan con tests/fixtures/queue_response.json, una respuesta GraphQL capturada construida para contener los casos incómodos: un PR que aparece en dos cubos, un borrador, un PR muy antiguo, un PR con CI fallando del viewer, y un rollup de estado nulo.

test_rank_orders_the_fixture_the_way_a_reviewer_would_read_it afirma puntuaciones exactas contra un reloj fijo. Es el canario para cambios de puntuación: si falla, decide si el nuevo orden es genuinamente mejor antes de actualizar los números.


Estado

Fase

Alcance

Estado

1

Andamiaje, empaquetado, herramientas

hecho

2

models.py, queue.py, pruebas de dominio

hecho

3

github.py cliente GraphQL, server.py real

hecho

4

Pruebas de cliente y servidor

no iniciado

5

Documentación

este archivo

La fase 3 está verificada de extremo a extremo — un handshake real de MCP stdio, descubrimiento de herramientas y una llamada a la herramienta — pero tests/test_server.py sigue siendo un marcador de posición. Los caminos de error del cliente (401, 403, fallos parciales de GraphQL, host inalcanzable) están escritos pero aún no cubiertos por pruebas automatizadas.

F
license - not found
Not graded
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

View all related MCP servers

Related MCP Connectors

  • A Model Context Protocol (MCP) application for automated GitHub PR analysis and issue management.…

  • An MCP server that gives your AI access to the source code and docs of all public github repos

  • A MCP server built for developers enabling Git based project management with project and personal…

View all MCP Connectors

Latest Blog Posts

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/JigeeshaJain/ReviewQueueMcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server