Skip to main content
Glama
JigeeshaJain

gh-review-queue-mcp

gh-review-queue-mcp

하나의 질문에 답하는 MCP 서버: 다음에 무엇을 리뷰해야 할까?

정확히 하나의 도구인 get_review_queue를 노출하며, 이 도구는 GitHub 풀 리퀘스트 리뷰 대기열의 순위가 매겨지고 중복이 제거된 뷰를 반환합니다 — 여러분에게 요청된 리뷰, 여러분의 팀에 요청된 리뷰, 그리고 다른 사람을 기다리는 여러분 자신의 풀 리퀘스트를 포함합니다.

하나의 도구는 의도적인 제약입니다. list_prs, search_prs, get_pr_status 사이에서 선택해야 하는 어시스턴트는 첫 턴을 선택하는 데 소비하지만, 이미 우선순위가 매겨진 목록을 반환하는 하나의 도구를 가진 어시스턴트는 바로 답할 수 있습니다.


실제로 하는 일

도구가 호출되면 네 가지 일이 순서대로 발생합니다.

1. 사용자와 팀 식별

서버는 viewer { login }에 대한 GraphQL 쿼리와 사용자가 속한 팀(organizations.teams(role: MEMBER))을 함께 발행합니다. 팀 슬러그가 중요한 이유는 GitHub의 검색 API에 "내 팀 중 하나에 요청됨" 한정자가 없기 때문입니다 — 각 팀을 명시적으로 지정해야 합니다. 이것이 토큰에 read:org 범위가 필요한 유일한 이유입니다.

2. 하나의 배치 검색으로 분산

GitHub에는 "내 주의가 필요한 모든 것"에 대한 단일 쿼리가 없으므로 서버는 여러 검색을 실행하고 이를 결합합니다. 모든 검색은 별칭을 사용하여 하나의 GraphQL 문서로 전송되므로, 팀이 몇 개든 HTTP 왕복은 한 번입니다:

Alias

Search

결과 이유

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

검색 문자열은 GraphQL 변수로 전달되며 쿼리 문서에 보간되지 않으므로 팀 슬러그가 쿼리를 변경할 수 없습니다.

동일한 쿼리는 rateLimit { remaining resetAt }도 요청하므로 두 번째 호출 없이 모든 응답에서 남은 예산을 보고할 수 있습니다.

응답 형태에 대한 두 가지 참고 사항. GitHub의 search(type: ISSUE)는 풀 리퀘스트뿐만 아니라 이슈도 반환합니다. 선택 집합이 PullRequest의 인라인 프래그먼트이므로 이슈는 빈 노드로 반환되고 파싱 중에 제거됩니다. 그리고 statusCheckRollupcommits(last: 1)에서 읽습니다 — 전체 브랜치 기록이 아닌 헤드 커밋의 CI 상태입니다.

3. 병합, 중복 제거, 필터링, 순위 지정

동일한 풀 리퀘스트가 여러 검색에서 반복적으로 반환됩니다 — 직접 리뷰어이고 동시에 팀이 요청된 PR은 두 버킷에 나타납니다. GraphQL 노드 ID로 중복이 제거되고 이유가 하나의 항목에 누적되므로 응답은 두 번 나열하는 대신 "두 가지 이유로 여기에 있습니다"라고 말합니다.

그런 다음 필터가 적용되고, 남은 항목에 점수가 매겨지고 정렬됩니다.

4. 직렬화

순위가 매겨진 목록은 구조화된 출력으로 반환됩니다 — 도구는 전체 JSON 출력 스키마를 선언하므로 클라이언트는 파싱해야 하는 텍스트가 아닌 타입이 지정된 필드를 받습니다.


Related MCP server: github-ops-mcp

순위 지정 방식

순위는 가중치 조정이 아닌 계층화 방식입니다. 각 풀 리퀘스트는 정확히 하나의 계층에 속하며, 계층의 가치는 계층 내부에서 누적되는 어떤 것보다 훨씬 큽니다:

계층

조건

기본 점수

3

CI가 실패한 내 PR

300

2

변경이 요청된 내 PR

200

1

나에게 직접 요청된 리뷰

100

0

팀 요청, 또는 단순히 대기 중인 내 PR

0

계층 내에서는 두 가지 더 작은 신호가 적용됩니다:

  • 나이 — PR이 열린 이후 하루당 2점, 최대 20점. 오래된 리뷰 요청이 표면화되지만, 6개월 된 PR이 영원히 우위를 점할 수는 없습니다.

  • 작은 diff — 100줄 이하의 diff에 대해 고정 8점 보너스. 지금 끝낼 수 있는 작은 리뷰가 미루게 될 큰 리뷰보다 낫다는 이론에 기반합니다.

상한이 바로 핵심입니다. 계층 내에서 누적될 수 있는 최대치는 20 + 8 = 28로, 계층 간격인 100보다 훨씬 낮으므로 계층 우위는 구조적으로 유지됩니다: 새로운 직접 요청은 항상 오래된 팀 요청보다 위에 있으며, 향후 가중치 조정으로 이를 조용히 뒤집을 수 없습니다. 점수 신호를 추가한다면 계층 내 합계를 100 미만으로 유지하세요. 그렇지 않으면 그 보장이 깨집니다.

동점은 가장 최근 활동(updatedAt)으로 결정되므로, 같은 점수에서는 활발한 토론이 중단된 토론보다 위에 있습니다.

모든 항목은 priority_reasons를 포함합니다 — ["my PR, CI failing", "3 days old"] 같은 사람이 읽을 수 있는 문자열 — 따라서 순위는 설명 없는 숫자로 도착하는 대신 다시 설명될 수 있습니다.


설치

Python 3.11+ 및 uv가 필요합니다.

git clone <this repo>
cd ReviewQueueMcp
uv sync

토큰

서버는 GITHUB_TOKEN에서 GitHub 개인 액세스 토큰을 읽습니다:

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

필요한 범위:

  • repo — 비공개 저장소의 풀 리퀘스트 읽기

  • read:org — 팀 리뷰 요청 검색을 위해 팀 멤버십 읽기

클래식 PAT가 가장 간단합니다. 세분화된 토큰은 "Pull requests: read"와 조직 멤버 읽기가 부여된 경우 작동합니다. https://github.com/settings/tokens에서 생성하세요.

GITHUB_GRAPHQL_URL은 선택적으로 GitHub Enterprise Server의 엔드포인트를 재정의합니다.

토큰은 시작 시가 아니라 도구 호출마다 읽습니다 — 서버는 토큰 없이도 깨끗하게 시작되며, 호출 시 실행 가능한 오류를 반환합니다. 클라이언트가 끊어진 파이프만 보게 되는 MCP 핸드셰이크 중에 죽는 대신입니다.


실행

uv run gh-review-queue-mcp

stdio를 통해 MCP로 통신하며 반대편에 클라이언트가 있기를 기대합니다. 직접 실행하면 그냥 대기합니다.

MCP Inspector 사용

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

출력된 URL을 열고 연결하면 도구가 생성된 입력 스키마와 함께 Tools 아래에 나타납니다.

Claude Desktop 사용

claude_desktop_config.json에 추가하세요 — macOS에서는 ~/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_..."
      }
    }
  }
}

경로는 절대 경로여야 합니다 — Claude Desktop은 셸에서 서버를 실행하지 않으므로 상속할 작업 디렉터리나 내보낸 환경이 없습니다. 편집 후 Claude Desktop을 다시 시작하세요. 그런 다음 "오늘 무엇을 리뷰해야 할까?"라고 물어보세요.


도구 참조

get_review_queue

모든 인자는 선택 사항입니다.

인자

타입

기본값

의미

include

array of requested_of_me | requested_of_my_teams | my_pr_awaiting_review

all three

포함할 이유. 항목은 이유 중 하나라도 포함되면 유지됩니다.

exclude_drafts

boolean

true

초안을 제외합니다. 순위가 낮아지는 것이 아니라 제외됩니다 — 초안은 아직 리뷰할 수 없습니다.

max_age_days

integer

none

이 일수보다 더 오래 전에 열린 PR을 제외합니다. 경계값은 포함합니다.

repos

array of owner/name

none

이 저장소로 제한합니다. 정확히 일치해야 합니다.

limit

integer 1–100

25

반환되는 최대 항목 수. total_matching은 여전히 전체 개수를 보고합니다.

응답:

{
  "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"
    }
  ]
}

returnedtotal_matching은 "여기 25개가 있습니다"와 "많이 있습니다"를 구분합니다 — 이것이 없으면 제한된 응답과 완전한 응답을 구분할 수 없습니다.

warnings는 GraphQL 부분 실패를 전달합니다. GitHub는 오류와 함께 사용 가능한 데이터를 반환할 수 있습니다(조직 하나를 읽을 수 없거나 검색 하나가 실패하는 경우). 전체 대기열을 버리는 대신 이러한 오류는 경고로 격하되고 나머지 결과는 계속 반환됩니다.


아키텍처

src/gh_review_queue/ 아래에 네 개의 모듈이 있으며, 모듈 간 경계가 핵심적인 역할을 합니다:

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.

핵심은 queue.py입니다: QueueSnapshotdatetime만 받고 그 외에는 아무것도 받지 않기 때문에 모든 순위 규칙이 일반 데이터로 테스트되며 mock도, 네트워크도, 시계 패치도 없이 테스트됩니다. 이것이 분리의 이유이며, httpx 임포트가 여기에 도달해서는 안 되는 이유이기도 합니다.

실패 대신 저하

GitHub의 알 수 없는 열거형 값 — 새로운 reviewDecision, 새로운 CI 롤업 상태 — 은 예외를 발생시키는 대신 None으로 매핑됩니다. GitHub 쪽에서 추가된 상태가 전체 대기열을 깨뜨려서는 안 됩니다. 같은 원칙이 파싱 계층에도 적용됩니다: 누락된 작성자는 ghost가 되고(GitHub가 삭제된 계정에 사용하는 자체 규칙), PR이 아닌 검색 결과는 제거되며, 타임스탬프가 없는 경우는 예외를 발생시키는, 진정으로 복구 불가능한 유일한 사례입니다.


개발

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)

mypy를 인자 없이 실행하세요 — pyproject.toml[tool.mypy] files에서 대상을 가져오므로 경로를 전달하면 의도보다 적게 검사합니다.

테스트 접근 방식

테스트는 tests/fixtures/queue_response.json을 기반으로 실행됩니다. 이 파일은 까다로운 사례를 포함하도록 구성된 캡처된 GraphQL 응답입니다: 두 버킷에 나타나는 PR, 초안, 매우 오래된 PR, 뷰어의 CI 실패 PR, null 상태 롤업.

test_rank_orders_the_fixture_the_way_a_reviewer_would_read_it은 고정된 시계에 대해 정확한 점수를 검증합니다. 이는 점수 변경을 감지하는 카나리아입니다 — 실패하면 숫자를 업데이트하기 전에 새 순서가 진정으로 더 나은지 결정하세요.


상태

단계

범위

상태

1

스캐폴드, 패키징, 도구

완료

2

models.py, queue.py, 도메인 테스트

완료

3

github.py GraphQL 클라이언트, 실제 server.py

완료

4

클라이언트 및 서버 테스트

시작 전

5

문서화

이 파일

3단계는 종단 간 검증되었습니다 — 실제 MCP stdio 핸드셰이크, 도구 검색, 도구 호출 — 하지만 tests/test_server.py는 여전히 자리 표시자입니다. 클라이언트의 오류 경로(401, 403, 부분 GraphQL 실패, 연결할 수 없는 호스트)는 작성되었지만 아직 자동화된 테스트로 다루어지지 않았습니다.

Available Tools

1 tool
get_review_queueA

Return the viewer's GitHub pull request review queue, ranked by what needs attention first: their own pull requests with failing CI, then their own with changes requested, then reviews requested of them directly, then reviews requested of their teams. Within a tier, older and smaller pull requests rank higher. Every item carries priority_reasons explaining its position, and total_matching reports how many matched before the limit.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoMaximum items to return.
reposNoRestrict to these repositories, as 'owner/name'.
includeNoWhich reasons to include. Defaults to all three.
max_age_daysNoDrop pull requests opened more than this many days ago.
exclude_draftsNoDrop draft pull requests. Defaults to true.

Output Schema

ParametersJSON Schema
NameRequiredDescription
itemsYes
viewerYes
returnedYes
warningsNo
generated_atYes
total_matchingYes
rate_limit_remainingNo

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the burden of disclosure. It reveals the ranking tiers, tie-breaking rules, and the fact that results include priority_reasons and total_matching. It does not discuss auth, errors, or side effects, but the operation is clearly read-oriented and described in useful detail.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core purpose and ranking intent, then economically conveys the tier order and output signals in two structurally clear runs. Every clause earns its place and no filler exists.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description is complete enough for reliable invocation. It covers behavior, output information, ordering, and scoping semantics, the output schema and full parameter documentation handle the remaining return-value details, and there are no required parameters or sibling tools to complicate selection.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3. The description does not elaborate on the individual parameters such as limit, repos, include, max_age_days, or exclude_drafts, but it does not need to because those parameters are already well-documented in the input schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: "Return the viewer's GitHub pull request review queue," and goes further by specifying the exact ranking logic. It is immediately clear what this tool does and how it differs from a generic list-pull-requests tool.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There are no siblings to contrast against, so the explicit when/when-not language is less necessary. The description makes the intended use clear: retrieve a prioritized review queue with tiered attention ordering, which is sufficient context for an agent to select it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.

  1. 1 tool updatev0.1.0
    • First observedget_review_queue

TDQS

A4.4/5.0
Disambiguation5/5

The set contains only one tool, so there is no possibility of overlap or selecting the wrong tool. Its purpose is clearly and specifically described.

Naming Consistency5/5

The single tool name follows the conventional verb_noun pattern with a clear action and resource. There are no other tool names to create inconsistency.

Tool Count4/5

One tool is small, but the server is narrow by design: it exists specifically to fetch a GitHub review queue. The tool is substantial rather than trivial, so the count is slightly lean but still appropriate for the server's scope.

Completeness5/5

The tool covers the full review queue surface described: own PRs, requested changes, direct review requests, and team review requests, along with ranking reasons and match counts. There are no obvious read-model gaps within this narrow domain.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

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