Skip to main content
Glama
github-review-queue-mcp

github-review-queue-mcp

by alijahak

github-review-queue-mcp

ci

An MCP server for your GitHub review queue. From Claude, ChatGPT or any MCP client, you can find the pull requests waiting on you, read them, check CI, comment, and submit reviews.

It runs two ways:

  • Locally over stdio, with your token.

  • As a remote server with its own OAuth 2.1 authorization server: PKCE, dynamic client registration, a consent screen per client, audience-bound tokens and refresh-token rotation. GitHub is used only to sign the user in.

> What's waiting on my review?
  list_review_requests -> 3 pull requests
> Summarize alice-org/app#7 and tell me why CI is red.
  get_pull_request, list_pull_request_files, get_pull_request_checks
  -> "test" failed: 2 failed (test_a, test_b)

Tools

Tool

What it does

readOnly

destructive

idempotent

openWorld

list_review_requests

Open PRs where your review is requested (optionally one repo)

yes

no

yes

yes

get_pull_request

Title, author, branches, size, mergeability, latest review per reviewer, description

yes

no

yes

yes

list_pull_request_files

Changed files with +/- counts, optional diffs (capped per file)

yes

no

yes

yes

get_pull_request_checks

CI on the head commit: overall state, counts, each failing check with link and summary

yes

no

yes

yes

comment_on_pull_request

Posts a comment as you

no

no

no

yes

submit_pull_request_review

APPROVE / REQUEST_CHANGES / COMMENT as you

no

yes

no

yes

  • Reads and writes are separate tools.

  • Every tool has a title, all four hints, validated input and structured output.

  • An approval is marked destructive on purpose: it can satisfy branch protection and start an auto-merge, so clients always ask before submitting one.

  • Errors say what to do next: "GitHub's rate limit for this account is used up. It resets at ...", "Not found: owner/repo#7. Either it doesn't exist or this GitHub account can't see it."

Related MCP server: github-pr-control-mcp

Local use (stdio)

Create a fine-grained token with Pull requests: read and write, Commit statuses: read and Checks: read, or use gh auth token.

Claude Code:

claude mcp add review-queue -e GITHUB_TOKEN=github_pat_... -- npx -y github:alijahak/github-review-queue-mcp

Claude Desktop, Cursor and others (mcpServers config):

{
  "mcpServers": {
    "review-queue": {
      "command": "npx",
      "args": ["-y", "github:alijahak/github-review-queue-mcp"],
      "env": { "GITHUB_TOKEN": "github_pat_..." }
    }
  }
}

Remote server (OAuth)

MCP client ──OAuth 2.1 + PKCE──▶ this server ──"Sign in with GitHub"──▶ github.com
     │                              │ (its own authorization server)
     └── Bearer <this server's token> ──▶ /mcp ──▶ api.github.com (with the user's GitHub token, server-side only)
  1. Create a GitHub OAuth App. Set its callback URL to https://<your-host>/github/callback.

  2. Run the server:

docker build -t review-queue-mcp .
docker run -p 3000:3000 \
  -e PUBLIC_URL=https://<your-host> \
  -e GITHUB_CLIENT_ID=... -e GITHUB_CLIENT_SECRET=... \
  -e TOKEN_ENCRYPTION_KEY="$(openssl rand -base64 32)" \
  -e TRUST_PROXY=1 \
  review-queue-mcp
  1. Add https://<your-host>/mcp as a custom connector in Claude or ChatGPT.

Variable

PUBLIC_URL

Public origin. The MCP endpoint is $PUBLIC_URL/mcp.

GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET

From the OAuth App

TOKEN_ENCRYPTION_KEY

32 random bytes, base64; encrypts stored GitHub tokens

GITHUB_SCOPE

Default repo (private repos too); public_repo limits it to public ones

GITHUB_OAUTH_URL, GITHUB_API_URL

For GitHub Enterprise Server

TRUST_PROXY

Number of proxies in front, for per-IP rate limiting

PORT

Default 3000

State is in memory: restarting signs everyone out, which fails safe. For several replicas, put the store (src/http/store.ts) in Redis or Postgres.

Security model

  • No token passthrough.

    • Clients get this server's own tokens: random, stored only as SHA-256 hashes, valid for 1 hour, and bound to $PUBLIC_URL/mcp (RFC 8707 resource; any other audience is refused).

    • The user's GitHub token never leaves the server, and it is stored encrypted (AES-256-GCM).

  • Consent per client. Any client can register itself (that's how MCP clients connect), and every one of them gets this server's consent screen before the user is sent to GitHub. Without it, a malicious client could ride on an earlier GitHub approval of this server's single OAuth App: the confused-deputy problem in the MCP security best practices.

  • The OAuth details:

    • PKCE S256 between client and server, and again between server and GitHub.

    • Exact redirect-URI matching.

    • Authorization codes that work once.

    • A one-time state toward GitHub.

    • A CSRF token on the consent form.

    • Registration accepts only https or loopback redirect URIs.

  • Refresh rotation with reuse detection. Each refresh issues a new pair. Presenting a used refresh token revokes everything issued from that sign-in.

  • Tenant isolation by construction. A tool can only get a GitHub client from the user ID inside the verified access token. Tests sign in two users and check that every GitHub call carries the right user's token.

  • Bounded calls.

    • Explicit timeouts.

    • One retry for reads on 502/503/504, and none for writes, since a timed-out POST may have succeeded.

    • Capped output sizes.

    • Rate limits on the OAuth endpoints.

Directory readiness

It passes mcp-readiness with no findings, both for its tool definitions and for its OAuth discovery (401 with resource_metadata, RFC 9728 and RFC 8414 metadata, S256, DCR, refresh):

$ npm run readiness
Verdict
  Claude Connectors Directory  ready (0 errors, 0 warnings)
  ChatGPT app directory        ready (0 errors, 0 warnings)
  MCP spec and hygiene         ready (0 errors, 0 warnings)

The test suite runs the same checks. A directory listing still needs things outside the code: a hosted instance, a privacy policy, a support contact, and a reviewer test account.

Tests

npm test runs 27 tests against a fake GitHub (OAuth with PKCE verification, plus REST) and two users:

  • the whole sign-in: discovery, registration, consent, GitHub, callback, token, tools;

  • tenant isolation;

  • no passthrough, and encryption at rest;

  • wrong PKCE verifier, code reuse, a token for another resource;

  • refresh rotation and reuse revocation;

  • revocation and expiry;

  • consent denial, a forged CSRF value, HTML escaping of a hostile client name, insecure redirect URIs;

  • GitHub error mapping, and the retry policy.

scripts/smoke.mjs is a read-only check against the real GitHub API:

$ GITHUB_TOKEN=$(gh auth token) node scripts/smoke.mjs modelcontextprotocol/typescript-sdk 2943
list_review_requests: N open review request(s)
get_pull_request: [v1.x] fix(stdio): release consumed ReadBuffer storage | +50/-1 in 2 files | reviews: 0
list_pull_request_files: src/shared/stdio.ts, test/shared/stdio.test.ts
get_pull_request_checks: success {"success":9,"failure":0,"pending":0,"skipped":1,"neutral":0}
error path: Not found: octocat/this-repo-does-not-exist#1. Either it doesn't exist or this GitHub account can't see it.

License

MIT

Available Tools

6 tools
comment_on_pull_requestComment on a pull requestA

Posts a comment on a pull request's conversation, as you. Everyone with access to the repository can see it.

Inputs: body (required), repo (required), number (required). Returns: id, url, created_at

get_pull_requestGet a pull requestB
Read-onlyIdempotent

Returns a pull request's summary: title, author, branches, size, mergeability, requested reviewers, each reviewer's latest review, and the description (first 4,000 characters).

Inputs: repo (required), number (required). Returns: url, base, body, head, +18 more

get_pull_request_checksGet CI statusA
Read-onlyIdempotent

Returns the CI result for a pull request's latest commit: an overall state, counts per outcome, and every failing check with its link and summary.

Inputs: repo (required), number (required). Returns: counts, failing, overall, head_sha

list_pull_request_filesList changed filesA
Read-onlyIdempotent

Lists the files a pull request changes, with additions and deletions per file. Set include_patch to also get each file's diff (first 3,000 characters per file).

Inputs: repo (required), number (required), limit, include_patch. Returns: count, files

list_review_requestsList my review requestsA
Read-onlyIdempotent

Lists open pull requests where your review is requested, most recently updated first. Optionally limited to one repository.

Inputs: repo, limit. Returns: count, pull_requests

submit_pull_request_reviewSubmit a reviewA
Destructive

Submits a review on a pull request, as you: APPROVE, REQUEST_CHANGES, or COMMENT. REQUEST_CHANGES and COMMENT need a body.

Inputs: repo (required), event (required), number (required), body. Returns: id, url, state, submitted_at

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.8/5.0

    Scored across 6 tools

    Disambiguation5/5

    Each tool targets a distinct resource and action: listing the review queue, fetching one PR, its files, its CI checks, posting a comment, and submitting a review. There is no overlap or confusingly similar pair.

    Naming Consistency5/5

    All six tools follow a consistent snake_case verb_noun pattern (list_*, get_*, comment_on_*, submit_*). The repeated pull_request stem reinforces the domain without creating ambiguity.

    Tool Count5/5

    Six tools is well-scoped for a focused PR review-queue workflow. Every tool earns its place with no redundancy or filler.

    Completeness4/5

    Covers the full review loop: find requests, inspect PR metadata/files/checks, comment, and submit a verdict. Minor gaps remain, such as reading existing conversation/thread replies or dismissing/updating a prior review, but no core workflow dead-ends.

    Maintenance

    ActivitySlowing
    ResponsivenessOutdated data

    Related MCP Connectors

    Related MCP Servers