Content
# gh-issue-to-pr-mcp
[](https://github.com/huzaifaali14/gh-issue-to-pr-mcp/actions/workflows/ci.yml)
[](LICENSE)
A local MCP server for **Claude Code** that handles the mechanical, error-prone parts of
"take this issue and open a PR": branching, running your build/typecheck/lint commands,
checking for merge conflicts before you push, committing, pushing, and opening the PR.
**Writing the actual code fix is not this server's job** — that stays as normal Claude Code
agentic work (Claude reads the issue via `get_issue`, edits files with its usual tools, then
uses the rest of these tools to ship it). If you have your own PR title/description
conventions (a Claude Code skill, a `CONTRIBUTING.md`, a PR template), point Claude at those —
`create_pull_request` just submits whatever `title`/`body` it's given, it doesn't compose them.
## What it does NOT do
- It does not write code. `get_issue` gives Claude the issue text; Claude edits files itself.
- It does not force-push, rewrite history, or auto-resolve conflicts — `check_conflicts` only
*detects* conflicts (read-only, via `git merge-tree`) so Claude/you can resolve them deliberately.
- It never runs on a dirty working tree without telling you — `create_branch_for_issue` refuses
to switch branches if there are uncommitted changes.
## Requirements
- Node.js >= 18
- [`gh`](https://cli.github.com) CLI installed and authenticated (`gh auth login`) — used for
reading issues and opening PRs
- Git repo with an `origin` remote
## Install
```bash
git clone https://github.com/huzaifaali14/gh-issue-to-pr-mcp.git
cd gh-issue-to-pr-mcp
npm install
npm run build
```
## Register with Claude Code
```bash
claude mcp add gh-issue-to-pr -- node /absolute/path/to/gh-issue-to-pr-mcp/dist/index.js
```
Or add it directly to your Claude Code MCP config (e.g. `.mcp.json` in the repo, or your global
config):
```json
{
"mcpServers": {
"gh-issue-to-pr": {
"command": "node",
"args": ["/absolute/path/to/gh-issue-to-pr-mcp/dist/index.js"]
}
}
}
```
By default the server operates on whatever directory it's launched from (Claude Code's cwd,
i.e. your repo). To pin it to a specific checkout regardless of cwd, set:
```json
{
"mcpServers": {
"gh-issue-to-pr": {
"command": "node",
"args": ["/absolute/path/to/gh-issue-to-pr-mcp/dist/index.js"],
"env": { "GH_ISSUE_TO_PR_MCP_REPO_ROOT": "/absolute/path/to/your/repo" }
}
}
}
```
## Configure your build/typecheck/lint commands
Out of the box, the server auto-detects your build/typecheck/lint/test commands — no config
required. If auto-detection doesn't fit your setup, drop a `.issue-to-pr.json` in your repo root
and specify the commands explicitly:
```json
{
"baseBranch": "main",
"commands": {
"build": "npm run build",
"typecheck": "npm run typecheck",
"lint": "npm run lint",
"test": "npm test"
}
}
```
You only need to include the checks you want to override — anything you omit still falls back to
auto-detection. See `.issue-to-pr.example.json` in this folder for a starting point.
**Resolution order for every check**, from highest to lowest priority:
1. An explicit `commands` override passed in the `run_checks` tool call itself
2. `.issue-to-pr.json` at the repo root (the file above)
3. Auto-detection — inspects `package.json` scripts across the repo, including monorepo/workspace
setups, and picks a command that runs the check across all packages rather than looping them
by hand.
Run `detect_checks` any time to see what was found/configured without actually running anything.
## Tools
| Tool | Purpose |
|---|---|
| `get_issue` | Fetch issue title/body/labels by number, `#N`, or URL |
| `create_branch_for_issue` | Fetch base, verify clean tree, create/checkout `issue-N-slug` branch |
| `detect_checks` | Report what build/typecheck/lint/test commands would be used, and why |
| `run_checks` | Run one or more checks, return exit code + output for each (doesn't stop on first failure by default) |
| `check_conflicts` | Read-only check for merge conflicts against base via `git merge-tree` |
| `commit_and_push` | `git add -A && git commit && git push -u origin <branch>` |
| `create_pull_request` | `gh pr create`, optionally appending `Closes #N` |
## Typical flow (what Claude Code will naturally do with these tools)
1. `get_issue` — read the issue
2. `create_branch_for_issue` — branch off it
3. Claude edits files to implement the fix (normal agentic coding, not a tool call here)
4. `run_checks` with `["build","typecheck","lint","test"]` — iterate until green
5. `check_conflicts` against base — rebase and resolve if needed, re-check
6. `commit_and_push`
7. `create_pull_request` with a title/body, `closesIssue` set
## Notes on `check_conflicts`
Uses `git merge-tree <merge-base> HEAD origin/<base>`, which computes the merge result without
touching your working tree, index, or starting a real merge — safe to call as often as you like.
Requires Git 2.38+ for the structured conflict report; older Git still works but conflict-file
extraction from the output may be less precise.
## Security notes
- Build/typecheck/lint/test commands (from `.issue-to-pr.json`, tool-call overrides, or
auto-detection) run through a real shell, since they're expected to be full shell command
strings you configured yourself. Don't point this server at a repo whose `.issue-to-pr.json`
you don't trust.
- Everything else that touches free-text or externally-sourced content — commit messages, issue
titles/bodies, PR titles/bodies, branch names — is passed as argv to `git`/`gh` directly with
no shell interpolation, so it can't be used to inject shell commands.
## Contributing
Issues and PRs welcome — see [CONTRIBUTING.md](CONTRIBUTING.md).
## License
[MIT](LICENSE)