Skip to main content
Glama
JigeeshaJain

gh-review-queue-mcp

by JigeeshaJain

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 실패, 연결할 수 없는 호스트)는 작성되었지만 아직 자동화된 테스트로 다루어지지 않았습니다.

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