Skip to main content
Glama

pr-ready-mcp

An MCP server for people who let coding agents open and look after pull requests. It has one read-only tool, pr_readiness, that checks an agent's "the PR is ready" against current GitHub data before the agent says it. It answers with a verdict pinned to a head commit and a time, every reason the PR is not verified ready, and whose move each reason is.

It is not GitHub's merge button, permission to merge, or a code review. Its rule is stricter than GitHub's merge eligibility, on purpose (see the rule).

One call, end to end: the agent asks about a PR, the tool reads GitHub once, applies the rule, and answers with a verdict pinned to a commit and a time.

Sequence diagram: a coding agent calls pr_readiness with a PR and, after a push, the commit it expects; the tool sends one read-only GraphQL query to GitHub, applies the rule to the snapshot, and returns a verdict with reasons, each naming an owner, plus head_sha and checked_at.

How the verdict is decided: a wrong head is not_ready even on a merged or closed PR, merged and closed PRs are otherwise reported rather than judged, and an open PR is ready only when no reason applies.

Flowchart: the head commit is compared with the expected sha; a mismatch is stale_head and the verdict is not_ready; a merged or closed PR with the right head is reported as merged or closed; an open PR collects every applicable reason about merge state, checks on the head commit, review and merge queue, each with an owner; ready only when no reason is listed.

Why

Agents say "green" too early. They read a check list before the last check finished. They read checks that belong to the previous push. They see 100 passing checks and miss the five failures listed after them. They report "CI passed" on a PR that still needs a review, or call an unknown merge state "fine". Each mistake is small. The person who trusted the claim finds out at merge time.

You can compose the right answer yourself from gh pr view --json … and gh pr checks. It takes about ten rules: pending is not passed; checks belong to one commit; GitHub's aggregate covers more checks than one page lists; BEHIND and BLOCKED mean something; some reviews block; UNKNOWN means ask again; no checks at all means no evidence. This tool applies those rules in one call and returns the result as data an agent can branch on.

A verdict that names the head sha and the time it was observed can be checked later. "The agent said it was green" cannot. Every reason carries a code and an owner (author, reviewer, wait, unknown), so an agent loop can tell "fix it", "ask someone", "wait" and "go and look" apart without parsing prose.

Whether this beats a well-instructed gh workflow is a claim, so it was measured. In a small paired run on six live public PRs, the agent using this tool gave the expected claim and hand-off in 6 of 6; the same agent using gh gave it in 3 of 6, with no false "ready" in either arm. That is a small sample, not a benchmark: the method, the raw counts and their limits are in DECISIONS.md.

Related MCP server: gitworthy

What it looks like

The same question, same model, same policy text, on cli/cli#14716 at 2026-10-22 15:38 UTC (transcripts):

With gh: "I can't confirm yet that cli/cli#14716 is ready to merge. … the two allowed commands don't show whether the PR is in a merge queue."

With pr_readiness: "Yes, cli/cli#14716 looks ready to merge. GitHub reported this at 2026-10-22 15:38 UTC for head commit 936921fa9e67cdbf78fb25abc6252afabafef056: merge state CLEAN … The rollup is SUCCESS. Of 16 checks, 9 passed and 7 were skipped. … The PR is not in a merge queue."

The gh baseline was given a fixed field list without isInMergeQueue, which is why it could not finish; the tool reads that field.

Install

Requires Node.js 20 or newer and a GitHub token (see Auth). The package is not on npm yet, so run it from a checkout:

git clone https://github.com/fabriciopirini/pr-ready-mcp.git
cd pr-ready-mcp
npm ci            # installs and builds dist/

Then point your client at node /absolute/path/to/pr-ready-mcp/dist/index.js. After the package is published, npx -y pr-ready-mcp replaces that command.

Claude Code

claude mcp add pr-ready -- node /absolute/path/to/pr-ready-mcp/dist/index.js

Cursor: ~/.cursor/mcp.json, or .cursor/mcp.json in a project:

{ "mcpServers": { "pr-ready": { "command": "node", "args": ["/absolute/path/to/pr-ready-mcp/dist/index.js"] } } }

Claude Desktop: ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows). Desktop apps do not inherit your shell, so pass the token:

{
  "mcpServers": {
    "pr-ready": {
      "command": "node",
      "args": ["/absolute/path/to/pr-ready-mcp/dist/index.js"],
      "env": { "GITHUB_TOKEN": "<token>" }
    }
  }
}

Codex: ~/.codex/config.toml:

[mcp_servers.pr-ready]
command = "node"
args = ["/absolute/path/to/pr-ready-mcp/dist/index.js"]

Any other stdio client: command node, argument /absolute/path/to/pr-ready-mcp/dist/index.js, optional env GITHUB_TOKEN.

Which of these were exercised, and how, is listed in DECISIONS.md.

Using it

Input: {"pr": "owner/repo#42"} or {"pr": "https://github.com/owner/repo/pull/42"}, plus "expected_head_sha" (the full 40-character git rev-parse HEAD) after a push. Call it before claiming ready, after every push, and again right before any final claim.

Prompt

What happens

Expected answer

"I just pushed. Is octo-org/widgets#42 ready?"

pr_readiness with expected_head_sha. The PR head is still the previous commit.

"Cannot verify yet: the PR head is 4f1c…, not the commit you pushed. Check whether the push landed."

"CI is green on octo-org/widgets#42. Can I tell the team it's ready?"

Verdict not_ready, reason review_required (owner reviewer).

"Not ready: the required review is not satisfied. Ask a reviewer."

"Is octo-org/widgets#42 ready?" right after a push

Verdict not_ready, reason checks_missing (owner wait).

"Cannot verify yet: no check has reported on this head. Ask again in a minute."

Full schemas: docs/tools.md. Machine-readable summary: llms.txt.

When is a PR ready?

ready means: GitHub's aggregate for the head commit is CLEAN, the check rollup on that commit is SUCCESS, no review decision blocks, the PR is not queued, and the head is the one you expected. not_ready means not verified ready: its reason codes distinguish a known blocker from evidence that is not in yet, scope the tool does not cover, or the wrong head. merged and closed are reported, not judged.

A failing or still-running optional check does not stop GitHub's merge button, but this rule waits for it: until it finishes, the PR's colour is not final. facts.merge_state always carries GitHub's own aggregate, and each listed check carries required.

Code

Owner

Meaning

draft

author

The PR is a draft.

conflicts

author

It conflicts with the base branch.

behind_base

author

GitHub reports the head as out of date with the base.

checks_failing

author

A check failed, errored, was cancelled or timed out on the head.

checks_pending

wait

A check is queued or running.

review_required

reviewer

The review requirement is not satisfied.

changes_requested

author

A reviewer requested changes.

merge_queue

wait

The PR is in the merge queue.

blocked_by_branch_rule

unknown

GitHub blocks the merge for a rule the tool cannot read (signatures, code owners, deployments …).

mergeable_unknown

wait

Cannot verify yet: GitHub has not computed mergeability.

checks_missing

wait

Cannot verify yet: no check has reported on the head.

stale_head

wait / author

Cannot verify yet: checks are for an older commit, or the head is not the commit you expected.

unsupported_merge_state

unknown

Cannot verify: HAS_HOOKS, an unexplained UNSTABLE, or a state the tool does not know.

owner is a hand-off hint: whose move it is. It is not permission to act, not a statement of who caused the problem, and not a claim that anything else is clear. A fix never contains a write command.

A merged or closed PR queried with a different expected_head_sha is not_ready with stale_head: it reached that state, but not with the commit you asked about.

Errors

Failures return isError: true and JSON text, never a verdict:

{
  "code": "rate_limited",
  "message": "GitHub rate limit reached; retry in 60s.",
  "retryable": true,
  "retry_after_seconds": 60
}

Codes: invalid_input, auth_required, forbidden, not_found_or_inaccessible, rate_limited, upstream_error, invalid_response. retry_after_seconds appears only when GitHub sent a reset time. Any GraphQL error, even beside partial data, is invalid_response: a missing field is never judged as a pass. Arguments that fail the input schema are rejected by the MCP SDK with its own plain-text error.

Auth

The token is read on the first call: GITHUB_TOKEN, then GH_TOKEN, then gh auth token. Classic tokens and the gh token usually carry far more access than this tool needs. For public repositories, a fine-grained token with "Public repositories (read-only)" access should be enough; private repositories additionally need read access to pull requests, commit statuses and checks. Neither fine-grained setup has been exercised yet; see DECISIONS.md.

Limitations

  • GitHub.com only, one PR per call, PRs with CI. A repository without CI gets checks_missing, never ready.

  • Check names are read for the first 100 checks. GitHub's rollup and per-state counts cover all of them, so the verdict does not depend on the cap; facts.checks.details_complete says when the name lists are a sample.

  • Branch rules are not read. When GitHub says BLOCKED and nothing visible explains it, the tool says so (blocked_by_branch_rule) and points at the PR page.

  • Every call is a fresh read. A verdict is an observation at checked_at, not a lock: a review, a rerun or a base change can alter it on the same head.

  • The server only reads. It never merges, marks a draft ready, pushes, re-runs checks or writes any file.

Development

npm ci
npm test              # contract tests, offline, no token
npm run typecheck
npm run lint
npm run docs          # regenerate docs/tools.md after changing the schema or description
node scripts/smoke.mjs   # start the built server and run a replayed decision over stdio

test/fixtures/ holds recorded public PR responses (node scripts/record-fixture.ts <pr> <name>) and scenarios.json, one explicit override per failure mode with the reason it exists. evals/agent/ holds the agent runs: run.mjs (Claude Code, adversarial or paired comparison), score.mjs, and the transcripts.

License

MIT

Available Tools

1 tool
pr_readinessPR readinessA
Read-onlyIdempotent

Check whether a GitHub pull request is verified ready to merge, from live GitHub data.

Call it before you say a PR is ready, green, mergeable or done; after every push; and again immediately before any final claim. Pass expected_head_sha = the full sha from git rev-parse HEAD after your push.

verdict: ready | not_ready | merged | closed. ready means GitHub's merge state is CLEAN, every check on the head passed, no review decision blocks, the PR is not queued, and the head is the one you expected. Stricter than the merge button: an optional failing or running check also blocks. not_ready means not verified ready; reasons say why.

Each reason has a code, an owner, a detail and a fix. The codes mergeable_unknown, checks_missing, stale_head and unsupported_merge_state mean "cannot verify yet": report them as that, not as a defect. Every other code is a known obstacle, checks_pending and blocked_by_branch_rule included. owner (author | reviewer | wait | unknown) says whose move it is; it is not permission to act and not a claim that anything else is clear.

This tool reads; it never merges, publishes a draft, pushes or rewrites history, and its verdict does not authorise you to. Ready, green, merged and done are different words: use the one the verdict supports, with head_sha and checked_at.

Errors come back as isError with JSON text {code, message, retryable, retry_after_seconds?}.

Example: {"pr": "octo-org/widgets#42", "expected_head_sha": "4f1c2e7a9b0d3c6e8f1a2b4c5d6e7f8091a2b3c4"}

Inputs: pr (required), expected_head_sha. Returns: pr, facts, reasons, verdict, +2 more

Tool Schema Changelog

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

Loading tool schema changelog…

    TDQS

    A4.8/5.0

    Scored across 1 tool

    Disambiguation5/5

    Only one tool exists, so there is no overlap or ambiguity. Its purpose—verifying PR merge readiness from live GitHub data—is clearly and narrowly defined.

    Naming Consistency5/5

    The sole tool uses a clear snake_case name, pr_readiness, matching the server's purpose. With a single tool there is no inconsistency, and the name is descriptive and predictable.

    Tool Count4/5

    The server has a narrow, single-purpose scope, and the one comprehensive tool earns its place by covering verdicts, reasons, errors, and head-sha verification. A one-tool surface is inherently thin, but it is not trivial or mismatched to the purpose.

    Completeness5/5

    For the domain of PR readiness checking, the tool covers the full lifecycle: verdict states, reason codes with ownership and fixes, expected head SHA, timestamp, and structured errors. No obvious gaps exist for the stated read-only purpose.

    Maintenance

    ActivityMaintained
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      B
      maintenance
      Enables coding agents to scout, rank, and preflight software work before implementation, returning evidence-backed ACT, VERIFY, or SKIP decisions for issues and pull requests.
      222 npm
      2
      MIT
    • A
      license
      A
      quality
      A
      maintenance
      Enables coding agents to check whether a GitHub issue is already taken before volunteering, by analyzing linked PRs, assignees, claimant comments, AI contribution policies, and repo health to return GO, TAKEN, or CAUTION verdicts.
      3
      76 PyPI
      2
      MIT