Skip to main content
Glama
README.md
# triage-mcp

A read-only [Model Context Protocol](https://modelcontextprotocol.io) server that lets a coding agent
check a GitHub issue properly before it writes a fix.

I have had around a hundred pull requests merged into open-source projects, and the most common way to
waste an afternoon is to fix something that already has an open PR, or to miss a contribution rule.
Before I start on an issue I check the same four things by hand. This server gives an agent those
checks as tools, so it does them too.

## Tools

| Tool | Question it answers |
|---|---|
| `search_issues` | Is there an issue for this, open or closed? |
| `get_issue` | What does it say, and what did people add in the latest comments? |
| `find_related_code` | Which files is it about? (needs a token, see below) |
| `check_existing_fix` | Is it assigned, is someone already fixing it, or is it already fixed? |
| `repo_contribution_rules` | What does CONTRIBUTING say, and does it mention AI use or disclosure? |

Every tool is read-only. There is no tool that comments, assigns, labels or opens a pull request.

### check_existing_fix

This is the one that saves the most time. It collects pull requests that reference the issue from two
places, the issue timeline and a search, merges duplicates, and returns one verdict:

| Verdict | Meaning |
|---|---|
| `already_fixed` | a pull request that references the issue was merged |
| `open_pr_exists` | someone has an open pull request for it (drafts included) |
| `assigned` | no pull request yet, but the issue has an assignee |
| `unclaimed` | none of the above |

A pull request that was closed without merging does not count as a fix.

Real output for [markedjs/marked#4099](https://github.com/markedjs/marked/issues/4099), trimmed:

```json
{
  "verdict": "open_pr_exists",
  "reason": "Open PR #4196 by VadimToptunov references issue #4099.",
  "pullRequests": [{ "number": 4196, "state": "open", "foundVia": ["timeline", "search"] }]
}
```

## Run it

Needs Node 20 or newer. It is not published to npm, so build it from a clone:

```sh
git clone https://github.com/shaurya703/triage-mcp && cd triage-mcp
npm install
npm run build
```

Then point an MCP client at it. For Claude Code or Claude Desktop:

```json
{
  "mcpServers": {
    "triage": {
      "command": "node",
      "args": ["/absolute/path/to/triage-mcp/dist/index.js"],
      "env": { "GITHUB_TOKEN": "<a token with public read access>" }
    }
  }
}
```

`GITHUB_TOKEN` is optional. Without it you get GitHub's lower unauthenticated rate limit, and
`find_related_code` returns an error, because GitHub's code search refuses requests with no token.

## Rate limits

GitHub rate limits are easy to handle badly: either the tool hangs for an hour or it hammers the API.
This server does neither.

- If GitHub says to retry within 10 seconds, it waits and retries, twice at most.
- If the wait is longer, it does not wait. The agent gets an error that says when the limit resets.
- A 403 that is not a rate limit is reported as a permission error and is not retried.

The longest wait is configurable with `TRIAGE_MAX_WAIT_MS`.

## Tests

```sh
npm test            # 43 tests, no network: fetch is mocked
npm run typecheck
```

The tests cover every verdict, duplicate pull requests found by both routes, closed-but-unmerged pull
requests, each rate-limit path (with an injected clock, so nothing really sleeps), bad input, 404s,
body truncation, and one end-to-end test that starts the real server over the SDK's in-memory
transport and calls a tool through a real MCP client.

## Limits worth knowing

- A pull request that only mentions an issue ("see #42") is treated the same as one that fixes it. When
  a pull request was merged but the issue is still open, the reason says so, so the agent can look.
- "I'll take this" in a comment is not detected as a claim.
- The AI-policy check is a keyword match. It returns the matching lines so the agent reads them instead
  of trusting a yes or no.
- The issue timeline is read for up to 500 events, and the search looks at the 30 most recently
  updated pull requests.

Design notes are in [docs/DESIGN.md](docs/DESIGN.md).

## License

MIT

TDQS

A3.6/5.0

Scored across 5 tools

Disambiguation4/5

Each tool targets a distinct step of issue triage: fetching an issue, searching issues, searching code, checking for existing fixes, and fetching contribution rules. Minor overlap exists between get_issue (returns assignees) and check_existing_fix (checks assignment status) and between the two search tools, but descriptions make the boundaries clear.

Naming Consistency4/5

Four of five names follow a verb_noun snake_case pattern (get_issue, find_related_code, check_existing_fix, search_issues). repo_contribution_rules breaks the pattern by dropping the verb, but it is still readable and unambiguous.

Tool Count5/5

Five tools is well-scoped for a narrow triage workflow, and each one maps to a distinct decision an agent needs to make before claiming an issue. Nothing appears redundant or padding the surface.

Completeness4/5

The read-only triage lifecycle is well covered: discover an issue, search related issues/code, verify no existing fix, and check contribution rules before acting. Gaps are minor (no full untruncated issue body, no direct PR inspection or comment listing beyond what get_issue returns), but an agent can work around them.

Maintenance

ActivityMaintained
ResponsivenessNo recent community issues