Skip to main content
Glama
kenzoob
by kenzoob

github-triage-mcp

Let an AI assistant read and triage your GitHub issues — without giving it the keys to the kingdom.

CI License: MIT Node.js 22+ TypeScript MCP

Read-only access · a repository allowlist · strict input validation · untrusted-content marking — four independent layers standing between a manipulated model and your repos.


Contents

Related MCP server: GitHub MCP Server

Why this exists

Issue trackers are open to the internet. Anything in an issue body or comment — including text engineered to hijack an AI reading it — can end up in your model's context. github-triage-mcp is built around that threat model from line one: every tool is read-only, every repository must be explicitly allowlisted, every input is validated before it touches the network, and every piece of third-party text is fenced off and labeled as untrusted before it reaches the model.

What is MCP?

The Model Context Protocol is an open protocol that connects AI applications to tools and data. An MCP server exposes tools (functions the model can call), resources (data it can read) and prompts (reusable instructions). An MCP client, such as Claude Desktop or Claude Code, discovers them and calls them when needed.

Features

Tools

Tool

Inputs

Returns

list_issues

owner, repo, state (open, closed, all), labels (optional), limit (max 50)

Number, title, labels, author, date and comment count. Pull requests are excluded.

get_issue

owner, repo, number

The issue body and its 20 most recent comments

search_issues

owner, repo, query

Issues matching the search query

repo_activity

owner, repo, days (default 7, max 90)

Issues opened and closed, and pull requests merged over the period

Prompt

  • triage_issues: lists the open issues of a repository, groups them by theme, suggests a label and a priority for each one, and flags likely duplicates.

Resource

  • github://{owner}/{repo}/labels: the labels defined in a repository.

Security model

Issue content is written by anyone on the internet, and an AI model reads it. This server is designed with that in mind.

Risk

Mitigation

Overly broad access

A fine-grained GitHub token with read-only Issues and Metadata permissions

The model is manipulated into reading other repositories

ALLOWED_REPOS allowlist; any other repository is rejected with a clear message

Malformed or abusive inputs

Every input is validated with Zod (repository name format, bounded limit and days) before any network call

Prompt injection hidden in issues

Issue and comment text is wrapped in clear delimiters and preceded by a warning that it is untrusted content; long texts are truncated

Rate limits

When GitHub's rate limit is reached, the tool returns a clear message with the reset time instead of failing

Secret leakage

The token never appears in logs or tool output, and a test checks this

No single measure stops prompt injection completely. The goal is defense in depth: even if the model is manipulated, it can only read issues from approved repositories.

Tech stack

  • TypeScript (strict), Node.js 22+

  • Official MCP TypeScript SDK (@modelcontextprotocol/sdk, stdio transport)

  • Zod for input schemas

  • Native fetch for the GitHub REST API

  • Vitest, MCP Inspector, GitHub Actions

Getting started

1. Create a GitHub token

In GitHub, go to Settings → Developer settings → Fine-grained tokens, and create a token with:

  • Repository access: only the repositories you want to triage

  • Permissions: Issues: Read-only and Metadata: Read-only

2. Install and build

git clone https://github.com/kenzoob/github-triage-mcp.git
cd github-triage-mcp
npm install
npm run build

3. Configure

Copy .env.example to .env (or export these directly in your MCP client config):

Variable

Description

Example

GITHUB_TOKEN

Read-only fine-grained token

github_pat_...

ALLOWED_REPOS

Comma-separated allowlist

kenzoob/My-Engine,facebook/react

MAX_BODY_CHARS

Truncation limit for issue text (optional, default 4000)

4000

The server validates these at startup and exits immediately with a clear error if anything is missing or malformed — no silent misconfiguration.

4. Connect it to an MCP client

Claude Desktop: open Settings → Developer → Edit Config and add:

{
  "mcpServers": {
    "github-triage": {
      "command": "node",
      "args": ["/absolute/path/to/github-triage-mcp/dist/index.js"],
      "env": {
        "GITHUB_TOKEN": "github_pat_...",
        "ALLOWED_REPOS": "kenzoob/My-Engine,facebook/react"
      }
    }
  }
}

Restart Claude Desktop, then ask: "Triage the open issues of facebook/react."

Claude Code:

claude mcp add --transport stdio \
  --env GITHUB_TOKEN=github_pat_... \
  --env ALLOWED_REPOS=kenzoob/My-Engine \
  github-triage -- node /absolute/path/to/github-triage-mcp/dist/index.js

5. Inspect it manually

npx @modelcontextprotocol/inspector node dist/index.js

How it works

 MCP client (Claude Desktop, Claude Code, ...)
          │  stdio, JSON-RPC
          ▼
 ┌──────────────────────────────────────────┐
 │ github-triage-mcp                         │
 │  index.ts    server, tools, prompt        │
 │     ├─ config.ts  env validation at boot  │
 │     ├─ guard.ts   allowlist + Zod         │
 │     ├─ github.ts  REST client, PR filter, │
 │     │             rate-limit handling     │
 │     └─ format.ts  output text, truncation,│
 │                    untrusted-content tags │
 └──────────────────────────────────────────┘
          │  HTTPS, read-only token
          ▼
      GitHub REST API

GitHub endpoints used:

Purpose

Endpoint

List issues

GET /repos/{owner}/{repo}/issues

Get one issue

GET /repos/{owner}/{repo}/issues/{number}

Issue comments

GET /repos/{owner}/{repo}/issues/{number}/comments

Search

GET /search/issues?q=repo:{owner}/{repo}+is:issue+...

The /issues endpoint also returns pull requests. They are identified by their pull_request field and filtered out.

Project structure

github-triage-mcp/
├── src/
│   ├── index.ts     # server setup, tools, prompt, resource, stdio transport
│   ├── config.ts     # environment validation at startup
│   ├── guard.ts       # allowlist and Zod input schemas
│   ├── github.ts      # GitHub REST client, error handling
│   └── format.ts      # output formatting and untrusted-content wrapping
├── test/
│   ├── github.test.ts # PR filtering, 404s, rate limits, token non-leakage
│   ├── guard.test.ts  # allowlist enforcement, input bounds
│   └── format.test.ts # untrusted-content wrapping and truncation
├── .github/workflows/ci.yml
└── .env.example

Testing

npm test

All tests use a mocked fetch; none call the real GitHub API. They check that:

  • list_issues excludes pull requests

  • Repositories outside the allowlist are rejected

  • limit above 50 is rejected

  • Issue text is marked as untrusted and truncated

  • Rate-limit errors return the reset time

  • A 404 returns "issue or repository not found"

  • The token never appears in any output

Design decisions

  • stdio transport: for a local tool, it is the simplest and safest option, with no open port. A shared remote deployment would use the Streamable HTTP transport with authentication.

  • Allowlist on top of a read-only token: defense in depth. The token might still see private repositories; the allowlist limits what the model can reach.

  • Validation at the boundary: every tool input is checked before any network call.

  • Fail fast at startup: missing or malformed configuration stops the server immediately with a clear message, instead of failing confusingly on the first tool call.

Roadmap

  • Four read-only tools, triage prompt and labels resource

  • Security guards and tests

  • 60-second in-memory cache

  • Optional write tools (add labels, comment) behind an explicit opt-in flag

  • Streamable HTTP transport with OAuth for remote use

License

MIT

Available Tools

4 tools
get_issueGet issueB

Returns an issue's body and its 20 most recent comments.

ParametersJSON Schema
NameRequiredDescriptionDefault
repoYes
ownerYes
numberYes

TDQS

B3.1/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden. It usefully discloses that only the 20 most recent comments are returned, which is a real behavioral constraint, but it omits auth requirements, error behavior for missing issues, and any rate-limit context.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single front-loaded sentence with no filler. Every word earns its place, and the key return-content fact is stated immediately.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple three-parameter read tool with no annotations and no output schema, the description covers the return shape but leaves auth, error handling, and parameter semantics undocumented. It is minimally adequate but has clear gaps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so owner, repo, and number have no documented meaning anywhere. The description adds no parameter detail at all, failing to compensate for the coverage gap, though the parameter names themselves are somewhat self-explanatory.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: 'Returns an issue's body and its 20 most recent comments.' This clearly identifies the operation and scope. However, it does not differentiate itself from siblings like list_issues, search_issues, or repo_activity, so it falls short of a 5.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance is given about when to use this tool versus alternatives such as list_issues or search_issues. The description only says what is returned, leaving route selection entirely to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_issuesList issuesC

Lists issues (not pull requests) for an allowlisted repository, with labels, author, date and comment count.

ParametersJSON Schema
NameRequiredDescriptionDefault
repoYes
limitNo
ownerYes
stateNoopen
labelsNo

TDQS

C2.7/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden. It adds one useful constraint (allowlisted repository, implying a scoping/permission restriction) but omits pagination behavior, how the limit parameter is applied, ordering, and rate limits for what is clearly a paged read tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single compact sentence with the resource scope front-loaded and no filler. Efficient, though it spends words on return fields while leaving the actual parameters unexplained.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 5-parameter tool with 0% schema description coverage, no annotations, and no output schema, the description is too thin. It partially covers return fields but leaves state/limit/owner/repo semantics and pagination entirely undocumented.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% across 5 parameters. The description names only 'labels' (a real parameter) while owner, repo, limit, and state are undocumented anywhere; 'author, date and comment count' are output fields, not parameters, so they do not compensate for the input gap.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (Lists) and resource (issues), and explicitly excludes pull requests, which is the most common ambiguity for this resource type. However it does not distinguish itself from sibling tools like search_issues or get_issue, so an agent cannot route between them from this text alone.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No when-to-use guidance is given. The description never states when to prefer this over search_issues (filtered/query-based listing) or get_issue (single-item retrieval), and gives no prerequisites besides the allowlist mention.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

repo_activityRepository activityC

Summarizes issues opened and closed, and pull requests merged, over a recent period.

ParametersJSON Schema
NameRequiredDescriptionDefault
daysNo
repoYes
ownerYes

TDQS

C2.8/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations and no output schema, the description carries the full behavioral burden, yet it only names the categories aggregated. It does not disclose whether results are counts or breakdowns, whether the window is inclusive, or what happens for repos with no activity. "Recent period" is also vague against a days parameter with a 7-day default.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single compact sentence front-loads the verb and resource, and every clause carries information about what is summarized. It is efficient, though it is short at the expense of the details an agent actually needs.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple read-only aggregation the description covers the essential 'what,' but with no annotations and no output schema the agent has no sense of the return shape or the time-window semantics. The missing pieces are moderate rather than severe given the tool's low complexity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% across all three parameters, so the description must compensate and largely fails to. "Over a recent period" loosely gestures at the days parameter but never names it, cites its default (7), or explains the 1–90 bound; owner and repo receive no clarification beyond their self-evident names.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ("summarizes") over a concrete resource set (issues opened/closed, PRs merged) with a time scope, which is clearly distinguishable from the item-level siblings list_issues/get_issue. It stops short of naming those siblings or contrasting itself with them, so the differentiation is implicit rather than explicit.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no when-to-use guidance at all – nothing says to prefer this over list_issues or search_issues when the agent wants aggregate counts rather than individual items. The only contextual hint is the vague phrase "over a recent period," which leaves the selection decision to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_issuesSearch issuesC

Searches issues in an allowlisted repository matching a query.

ParametersJSON Schema
NameRequiredDescriptionDefault
repoYes
ownerYes
queryYes

TDQS

C2.7/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full behavioral burden, and it gives almost nothing. It hints at a scoping constraint ('allowlisted repository') but omits pagination, result caps, sorting, auth requirements, and whether the query uses GitHub search syntax or free text.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single front-loaded sentence with no filler. It is efficient, though the tightness comes at the cost of specificity rather than being paired with adequate detail.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a three-parameter, all-required search tool with no annotations, no output schema, and no parameter documentation, this is too thin. The undefined query syntax and the owner/repo relationship leave real gaps an agent would hit at call time.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate, and it does not. It gestures at 'repository' and 'query' but never explains the owner/repo split, the query syntax or operators, or the length and character constraints enforced by the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ('Searches') and resource ('issues') with a scoping constraint ('in an allowlisted repository matching a query'). It is clear what the tool does, but it does not differentiate itself from the sibling search-like tools list_issues or get_issue, so an agent must infer the distinction.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no when-to-use guidance and no mention of alternatives such as list_issues or get_issue. 'Matching a query' only weakly implies the search use case; nothing tells the agent when this is preferred over listing all issues.

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. 4 tool updatesv0.1.0
    • First observedget_issue
    • First observedlist_issues
    • First observedrepo_activity
    • First observedsearch_issues

TDQS

B3.1/5.0

Scored across 4 tools

Disambiguation4/5

list_issues, get_issue, and search_issues all target issues and could be confused at the margins, but the descriptions draw clear lines (enumerate vs. fetch one vs. query-match), and repo_activity is unmistakably distinct as a period summary.

Naming Consistency4/5

Three tools follow a clean verb_noun pattern (list_issues, get_issue, search_issues), but repo_activity breaks it with a noun-only form, a minor deviation from an otherwise predictable convention.

Tool Count4/5

Four tools is a tight, well-scoped set for a triage-focused server; each earns its place, though the surface arguably sits at the thin end given the absence of any action tools.

Completeness3/5

The toolset is entirely read-only: it can list, fetch, search, and summarize issues but offers no way to label, comment on, assign, or close them, which are core actions for an actual triage workflow.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    B
    quality
    D
    maintenance
    Enables AI assistants to inspect local Git repositories and interact with the GitHub API for reading commits, diffs, files, issues, comments, pull requests, and project boards.
    10
    155 npm
    -
  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables AI assistants to interact with GitHub through the GitHub REST API, supporting repository, file, issue, pull request, branch, commit, search, and label operations with explicit confirmation for write operations.
    -
  • A
    license
    A
    quality
    B
    maintenance
    Connects AI assistants to GitHub repositories, pull requests, issues, commits, and code search while enabling repository visibility controls, CI/CD monitoring, sandboxed local filesystem access, and code quality/security analysis.
    13
    1
    MIT