pr-ready-mcp
Checks whether a GitHub pull request is ready by reading current repository data such as merge state, checks on the head commit, review status, and merge queue status. Returns a verdict pinned to a head SHA and timestamp, with actionable reasons and owners.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@pr-ready-mcpis cli/cli#14716 ready to merge?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
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.
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.
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: mcp-merge-guard
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 commit936921fa9e67cdbf78fb25abc6252afabafef056: 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.jsCursor: ~/.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?" |
| "Cannot verify yet: the PR head is |
"CI is green on octo-org/widgets#42. Can I tell the team it's ready?" | Verdict | "Not ready: the required review is not satisfied. Ask a reviewer." |
"Is octo-org/widgets#42 ready?" right after a push | Verdict | "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?
readymeans: GitHub's aggregate for the head commit isCLEAN, the check rollup on that commit isSUCCESS, no review decision blocks, the PR is not queued, and the head is the one you expected.not_readymeans 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.mergedandclosedare 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 |
| author | The PR is a draft. |
| author | It conflicts with the base branch. |
| author | GitHub reports the head as out of date with the base. |
| author | A check failed, errored, was cancelled or timed out on the head. |
| wait | A check is queued or running. |
| reviewer | The review requirement is not satisfied. |
| author | A reviewer requested changes. |
| wait | The PR is in the merge queue. |
| unknown | GitHub blocks the merge for a rule the tool cannot read (signatures, code owners, deployments …). |
| wait | Cannot verify yet: GitHub has not computed mergeability. |
| wait | Cannot verify yet: no check has reported on the head. |
| wait / author | Cannot verify yet: checks are for an older commit, or the head is not the commit you expected. |
| unknown | Cannot verify: |
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, neverready.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_completesays when the name lists are a sample.Branch rules are not read. When GitHub says
BLOCKEDand 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 stdiotest/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
Available Tools
1 toolpr_readinessPR readinessARead-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"}
| Name | Required | Description | Default |
|---|---|---|---|
| pr | Yes | The pull request: "owner/repo#42" or "https://github.com/owner/repo/pull/42". GitHub.com only. | |
| expected_head_sha | No | The full 40-character sha you expect at the PR head: run `git rev-parse HEAD` after your push. If the PR head differs, the verdict is not_ready with stale_head. |
Output Schema
| Name | Required | Description |
|---|---|---|
| pr | Yes | The canonical PR URL. |
| facts | Yes | |
| reasons | Yes | Every reason the PR is not verified ready. Empty when ready, merged or closed. |
| verdict | Yes | ready only when reasons is empty. not_ready means not verified ready; reasons say why. |
| head_sha | Yes | The PR head commit this verdict is for. |
| checked_at | Yes | When GitHub was read (ISO 8601). An observation, not a lease. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the readOnly/destructive annotations: it defines the four verdict values and their exact preconditions, discloses that the tool is 'Stricter than the merge button' (optional failing/running checks also block), and classifies which reason codes mean 'cannot verify yet' versus genuine obstacles. It also states the negative capability boundary ('never merges, publishes a draft, pushes or rewrites history') and the error envelope shape {code, message, retryable, retry_after_seconds?}.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with a single-sentence purpose, then ordered as when-to-use, verdict semantics, reason codes, safety boundary, errors, example — a sensible reading order. It is dense and somewhat long, and lines like 'Ready, green, merged and done are different words' shade into coaching, but each block carries operational weight.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter verification tool with an output schema, virtually nothing an agent needs is missing: verdict meanings, blocking conditions, reason-code taxonomy, owner semantics, error format, and a concrete call example. Even though an output schema exists, the verdict vocabulary is explained in prose where it matters most.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3; the description earns an increment by tying the sha parameter to a concrete workflow (pass the full sha from `git rev-parse HEAD` after your push) and surfacing the stale_head consequence in the verdict vocabulary. Much of this duplicates the schema's own field descriptions, so it is reinforcement rather than new information.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Check whether a GitHub pull request is verified ready to merge') and adds the source qualifier 'from live GitHub data', which signals freshness rather than cached state. An agent knows exactly what it gets back — a verification verdict, not a generic PR fetch.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit invocation timing is given three ways: 'before you say a PR is ready, green, mergeable or done', 'after every push', and 'again immediately before any final claim'. It also names the alternative behaviour it replaces (asserting readiness without verification) and specifies the expected_head_sha workflow with `git rev-parse HEAD`.
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.
1 tool update
v0.1.0- First observed
pr_readiness
TDQS
Scored across 1 tool
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.
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.
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.
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
Related MCP Connectors
Context for coding agents: checks a GitHub or Linear issue is ready before your agent starts it.
Your coding agent asks the business logic of your repository and checks commits before they land
Git-native policy layer for AI agents: check_action verdicts against rules approved via PR.
Screens public GitHub repos and PRs to generate risk maps, findings, and merge-readiness signals.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables AI agents to scan GitHub repositories for security vulnerabilities, deployment blockers, and code quality issues. It provides detailed findings and auto-generated code patches to help developers ensure their code is production-ready.18 npmMIT
- AlicenseAqualityCmaintenanceGuards PR merge decisions by validating CI, approvals, conflicts, and branch freshness.2MIT
- AlicenseNot gradedqualityAmaintenanceEnables coding agents to scout, rank, and preflight software work before implementation, returning evidence-backed ACT, VERIFY, or SKIP decisions for issues and pull requests.38 npm2MIT
- FlicenseNot gradedqualityCmaintenanceEnables MCP-connected AI agents to review GitHub pull requests and post meaningful inline review comments directly on them through natural language prompts.-