Single source of truth for registered tool ids, parameters, JSON output shapes, error codes, and idempotency. Install and MCP clients: install.md. Operator guide: HUMANS.md. Implementation map: AGENTS.md.
MCP clients expose tools as {serverName}_{toolName}. With the server registered as rethunk-github, examples use the prefix rethunk-github_.
| Short id | Client id (server rethunk-github) |
Mode | Purpose |
|---|---|---|---|
repo_status |
rethunk-github_repo_status |
read | Multi-repo dashboard: default branch HEAD, CI, open PRs/issues, latest commit. Up to 64 repos per call; omit repos to use the active MCP workspace root. |
my_work |
rethunk-github_my_work |
read | Cross-repo personal queue: authored PRs, review requests, assigned issues. blockedOnMe lens for action items. |
pr_preflight |
rethunk-github_pr_preflight |
read | Pre-merge safety check: mergeability, reviews, CI, behind-base count, commit granularity, and computed safe verdict. |
pr_comment_batch |
rethunk-github_pr_comment_batch |
write | Submit a single PR review with inline comments in one API call. |
pr_create |
rethunk-github_pr_create |
write | Create a pull request from an existing head branch. |
issue_from_template |
rethunk-github_issue_from_template |
write | Create an issue by rendering a repository issue template. |
release_readiness |
rethunk-github_release_readiness |
read | What would ship if we release now? Unreleased commits, PR metadata, CI on head, diff stats, and release-asset checksum coverage when applicable. |
release_create |
rethunk-github_release_create |
write | Create a GitHub release with optional GitHub-generated notes. |
ci_diagnosis |
rethunk-github_ci_diagnosis |
read | Why is CI red? Resolves the failed run, extracts failed job logs, shows trigger commit. |
org_pulse |
rethunk-github_org_pulse |
read | Org-wide dashboard: failing CI, stale PRs, unreviewed PRs across recently active repos. |
pin_drift |
rethunk-github_pin_drift |
read | Audit upstream dependency pins in a local repo. Defaults to the active MCP workspace root; accepts glob patterns for pinFiles. |
ecosystem_activity |
rethunk-github_ecosystem_activity |
read | Chronological commit feed across multiple repos since a given timestamp or relative duration. |
module_pin_hint |
rethunk-github_module_pin_hint |
read | Return the Go pseudo-version string (v0.0.0-YYYYMMDDHHMMSS-sha12) for any repo ref. |
changelog_draft |
rethunk-github_changelog_draft |
read | Draft a CHANGELOG.md section for unreleased commits, grouped by PR metadata. |
workflow_dispatch |
rethunk-github_workflow_dispatch |
write | Trigger a GitHub Actions workflow_dispatch event. |
gh_auth_status |
rethunk-github_gh_auth_status |
read | Check whether the server currently has usable GitHub credentials. |
actions_runs_filter |
rethunk-github_actions_runs_filter |
read | List and filter GitHub Actions workflow runs. |
labels_sync |
rethunk-github_labels_sync |
write | Converge a repository's labels to a declared set. |
check_run_create |
rethunk-github_check_run_create |
write | Publish a synthetic GitHub check run against a commit SHA. |
security_alerts |
rethunk-github_security_alerts |
read | Roll up Dependabot and Code Scanning alerts by severity. Requires security_events scope (or repo). |
pr_review_thread_ops |
rethunk-github_pr_review_thread_ops |
write | List, resolve, or unresolve PR review threads. Requires PR write (repo / pull_requests:write). |
branch_protection_status |
rethunk-github_branch_protection_status |
read | Check branch protection rules for a repository branch. Requires branch-protection read (admin or repo). |
deployment_status |
rethunk-github_deployment_status |
read | Check deployment status and latest state per environment. Requires deployments read (repo). |
issue_dedup |
rethunk-github_issue_dedup |
read | Find likely-duplicate issues by title similarity before opening a new one. Requires issues read (repo). |
- Read-only rollup tools with
formatsupport default to JSON and acceptformat: "markdown"for human-readable output. gh_auth_statusis read-only and always returns compact JSON.- Write-capable tools always return compact JSON.
labels_sync,release_create,workflow_dispatch,pr_create,pr_comment_batch,check_run_create,issue_from_template, andpr_review_thread_opsacceptdryRunto compute and return the planned action without mutating GitHub state.pr_create,pr_comment_batch,check_run_create, andissue_from_templatereturn{ dryRun: true, plan: { ... } }whereplancontains the resolved parameters.pr_review_thread_opsreturns{ dryRun: true, action, targetThreadIds }. repo_statusandorg_pulseacceptcompact: truefor a condensed summary (counts and top highlights) instead of full per-item detail.actions_runs_filter,ecosystem_activity, andchangelog_draftemittruncatedCountwhen results are capped by thelimitparameter (matchesrelease_readinessbehaviour).
The server advertises MCP roots support and reads file:// roots from the client at runtime. Local-repository read tools normalize the selected root to its git toplevel, so a single globally installed server follows the project opened in VS Code, Claude Code, Cursor, or any roots-capable MCP client.
This default applies to repo_status, pr_preflight, pin_drift, and ecosystem_activity. Explicit arguments still win: pass localPath or repos when you want a target other than the active workspace.
Payloads are minified (JSON.stringify, no pretty-print). MCP_JSON_FORMAT_VERSION is "2". Optional fields are omitted when empty/null.
Tool-level failures return a top-level error object:
Per-item failures (inside arrays like repos[] or pins[]) follow the same envelope shape in the item's error field. The batch does not fail as a whole when a per-item failure occurs.
Agents can decide programmatically whether to retry (e.g. exponential backoff on retryable: true) vs. surface the problem to the user (retryable: false).
| Code | Meaning | Retryable |
|---|---|---|
AUTH_MISSING |
No GITHUB_TOKEN/GH_TOKEN and gh auth token failed. |
no |
AUTH_FAILED |
GitHub rejected the token (HTTP 401). | no |
NOT_FOUND |
Repository, PR, org, ref, or workflow run does not exist (HTTP 404). | no |
PERMISSION_DENIED |
Token lacks scopes or repo access (HTTP 403, not rate limit). | no |
RATE_LIMITED |
GitHub rate limit exhausted (HTTP 403 + x-ratelimit-remaining: 0). suggestedFix includes the reset time. |
yes |
VALIDATION |
Request failed GitHub's input validation (HTTP 422). | no |
UPSTREAM_FAILURE |
GitHub 5xx or GraphQL-level error. | yes |
NO_CI_RUNS |
No workflow runs found for the given ref/PR (ci_diagnosis). |
no |
COMPARE_FAILED |
Reserved: base...head comparison failure distinct from a 404. |
no |
LOCAL_REPO_NO_REMOTE |
Local path has no resolvable GitHub origin remote. |
no |
UNSUPPORTED_LANGUAGE |
module_pin_hint was called with a language other than "go". |
no |
AMBIGUOUS_REPO |
Reserved: pin source does not encode which GitHub repo a value belongs to. | no |
INTERNAL |
Unrecognized/unexpected failure. | no |
- Read-only tools are idempotent.
labels_syncis convergent: repeating the same desired label set should produce the same repository label state.workflow_dispatch,check_run_create,issue_from_template,pr_create,pr_comment_batch, andrelease_createare not idempotent. Retrying may create additional GitHub state or fail validation because state already exists.
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
repos |
(RepoRef | LocalPath)[] |
no | active workspace root | 1–64 repos. Each is { owner, repo } or { localPath }. |
format |
"markdown" | "json" |
no | "json" |
Output format. |
compact |
boolean |
no | false |
Return a condensed summary (counts + top highlights) instead of full per-repo detail. |
JSON output:
{
"repos": [{
"owner": "org",
"repo": "name",
"defaultBranch": "main",
"latestCommit": { "sha7": "abc1234", "message": "Fix bug", "author": "alice", "date": "2h ago" },
"ci": { "status": "success", "failedChecks": [/* only if failing */] },
"openPRs": 3,
"draftPRs": 1,
"openIssues": 12,
"local": { "branch": "feature", "dirty": 2, "ahead": 1, "behind": 0 }
// "error": { "code": "NOT_FOUND", "message": "...", "retryable": false }
// — on per-repo failure (does not fail the batch)
}]
}When localPath is given, the tool resolves the GitHub remote from git remote get-url origin and includes the local object with branch/dirty/ahead/behind.
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
username |
string |
no | authenticated user | GitHub username to query. Must match ^[A-Za-z0-9-]+$; other values return a VALIDATION error. |
maxResults |
int |
no | 30 |
1–100 results per section. |
blockedOnMe |
boolean |
no | false |
When true, filters to items needing your immediate action: authored PRs with CI failure or changes requested, plus all pending review requests. |
format |
"markdown" | "json" |
no | "json" |
Output format. |
JSON output:
{
"username": "alice",
"authoredPrs": [{ "repo": "org/name", "number": 42, "title": "...", "draft": false, "ci": "SUCCESS", "reviewDecision": "APPROVED", "updatedAt": "..." }],
"reviewRequests": [{ "repo": "org/name", "number": 45, "title": "...", "author": "bob", "updatedAt": "..." }],
"assignedIssues": [{ "repo": "org/name", "number": 99, "title": "...", "labels": ["bug"], "updatedAt": "..." }]
}Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
owner |
string |
no | active workspace root | GitHub owner/org. Not required when localPath or workspace roots are available. |
repo |
string |
no | active workspace root | Repository name. Not required when localPath or workspace roots are available. |
localPath |
string |
no | active workspace root | Local clone path; auto-detects owner/repo from git remote get-url origin. |
number |
int |
no | — | Single PR number. |
numbers |
int[] |
no | — | Batch of PR numbers to check in one call (alternative to number). |
ref |
string |
no | — | PR number, GitHub PR URL, or owner/repo#N slug (alternative to number). |
includeLogs |
boolean |
no | false |
When true, also fetches truncated CI logs for failing jobs — combining preflight + diagnosis in one call. |
maxLogLines |
int |
no | 50 |
10–500 log lines per failing job when includeLogs is true. |
format |
"markdown" | "json" |
no | "json" |
Output format. |
Exactly one of number, numbers, or ref must be given; numbers accepts 1–20 entries and is processed with concurrency 4.
JSON output:
{
"number": 42,
"title": "Fix auth bug",
"safe": false,
"reasons": ["CI failing: test-unit", "3 commits behind main"],
"mergeable": "MERGEABLE",
"reviewDecision": "APPROVED",
"reviews": [{ "author": "alice", "state": "APPROVED" }],
"pendingReviewers": ["charlie"],
"ci": {
"status": "FAILURE",
"checks": [{ "name": "test-unit", "conclusion": "FAILURE", "status": "COMPLETED" }]
},
"behindBase": 3,
"labels": ["bug"],
"conflicts": false,
"commitGranularity": {
"verdict": "warn",
"details": "1 of 4 commits are over-bundled (>15 files).",
"oversizedCommits": [{ "sha": "abc1234", "message": "feat: refactor everything", "filesChanged": 29 }]
},
"failingLogs": [{ "job": "test-unit", "log": "..." }]
}The safe boolean is computed from: PR must be open, not a draft, no conflicts, approved or no required reviews, CI passing, no pending checks.
reasons lists all blockers and warnings. Warnings (e.g. behind base) do not set safe: false by themselves.
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
owner |
string |
yes | — | GitHub owner/org. |
repo |
string |
yes | — | Repository name. |
base |
string |
no | latest semver tag | Base ref to compare from (e.g. v1.2.0). Omit to auto-pick the latest semver tag. |
head |
string |
no | default branch | Head ref to compare to. |
maxCommits |
int |
no | 50 |
1–200 commits. |
format |
"markdown" | "json" |
no | "json" |
Output format. |
JSON output:
{
"base": "v1.2.0",
"head": "main",
"aheadBy": 15,
"truncatedCount": 0, // commits not shown when the list is capped (omitted when 0)
"headCi": { "status": "success", "failedChecks": [] },
"commits": [{
"sha7": "abc1234",
"message": "Fix auth bug",
"author": "alice",
"date": "2025-04-10T12:00:00Z",
"pr": { "number": 42, "title": "Fix auth bug", "labels": ["bug"] }
}],
"stats": { "additions": 1234, "deletions": 567, "changedFiles": 23 },
"artifactIntegrity": {
"verdict": "ok",
"details": "All assets covered by checksum file",
"missingFromChecksum": [],
"checksumAsset": "SHA256SUMS"
}
}PR associations are extracted from commit message (#123) patterns, then resolved via GraphQL in batches of 20. When base resolves to a GitHub release tag, the tool also checks whether that release's checksum asset covers the other uploaded artifacts. truncatedCount is set (and commits is shorter than aheadBy) when the compared range exceeds the GitHub compare-endpoint cap or maxCommits.
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
owner |
string |
yes | — | GitHub owner/org. |
repo |
string |
yes | — | Repository name. |
ref |
string |
no | — | Branch or SHA. Finds latest run for this ref. |
prNumber |
int |
no | — | PR number. Alternative to ref. |
runId |
int |
no | — | Specific run ID. Highest priority. |
maxLogLines |
int |
no | 50 |
10–500 lines of log output per job. |
grepLog |
string |
no | — | Regex applied to each log; only matching lines are returned. |
format |
"markdown" | "json" |
no | "json" |
Output format. |
Run resolution priority: runId > prNumber > ref > latest failed run on default branch.
JSON output:
{
"runId": 12345,
"workflow": "CI",
"conclusion": "failure",
"branch": "main",
"url": "https://github.com/org/repo/actions/runs/12345",
"triggerCommit": { "sha7": "abc1234", "message": "Bump deps", "author": "alice" },
"failedJobs": [{
"name": "build",
"conclusion": "failure",
"failedSteps": [{ "name": "logs", "log": "... [last 150 lines] ..." }]
}]
}Logs are tail-truncated (last N lines kept) since failure output is at the bottom.
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
org |
string |
yes | — | GitHub organization login. |
maxRepos |
int |
no | 30 |
1–100 repos (ordered by most recently pushed). |
staleDays |
int |
no | 7 |
Days without activity before a PR is stale. |
includeArchived |
boolean |
no | false |
Include archived repositories. |
format |
"markdown" | "json" |
no | "json" |
Output format. |
compact |
boolean |
no | false |
Return a condensed summary (counts + top highlights) instead of full per-repo detail. |
JSON output:
{
"org": "my-org",
"scannedRepos": 30,
"summary": {
"failingCI": 2,
"stalePRs": 5,
"unreviewedPRs": 3,
"totalOpenPRs": 18,
"totalOpenIssues": 42
},
"attention": [{
"repo": "my-org/api",
"ci": "failure",
"openPRs": 4,
"openIssues": 8,
"stalePRs": [{ "number": 12, "title": "...", "author": "bob", "daysSinceUpdate": 14 }],
"unreviewedPRs": [{ "number": 15, "title": "...", "author": "alice" }],
"lastPush": "2025-04-09T08:00:00Z"
}]
}The attention array is sorted by urgency: failing CI repos first, then by stale PR count. Healthy repos (no failing CI, no stale/unreviewed PRs) are listed only in markdown mode.
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
localPath |
string |
no | active workspace root | Local repo whose dependency pins to audit. |
pinFiles |
string[] |
no | auto-detect | Files to parse. Accepts glob patterns (e.g. **/go.mod). Auto-detection tries: go.mod, .gitmodules, scripts/versions.env, package.json. |
ownerAllowlist |
string[] |
no | — | Only audit pins whose GitHub owner matches one of these values (case-insensitive). Useful to skip third-party upstreams. |
grep |
string |
no | — | Regex filter: only commits whose message matches are counted in grepMatches. All commits still count toward behindBy. |
format |
"markdown" | "json" |
no | "json" |
Output format. |
JSON output:
{
"localPath": "/home/me/myapp",
"pins": [{
"source": "go.mod",
"owner": "Rethunk-Tech",
"repo": "bastion-satcom",
"pinnedRef": "877f8d94448e",
"pinnedDate": "2026-04-11T12:22:16Z",
"defaultBranch": "main",
"headSha": "6589cad7c93e5fd59ece17284b4636c525bf8cf0",
"behindBy": 17,
"grepMatches": 3, // only when grep supplied
"commits": [{ "sha7": "abc1234", "message": "Fix bug", "author": "alice", "date": "2026-04-12T..." }],
"stale": true
}],
"skipped": [{
"source": "scripts/versions.env",
"key": "BASTION_SATCOM_REF",
"value": "877f8d94448e8cc843e83409dd0a59bb73562e45",
"reason": "ambiguous_repo"
}],
"summary": { "totalPins": 4, "stale": 2, "upToDate": 2 }
}Pin source notes:
go.mod: handlesreplacedirectives andrequirelines with pseudo-versions (v0.0.0-YYYYMMDDHHMMSS-sha12). The 12-char SHA prefix is resolved to a full SHA via the GitHub API..gitmodules: reads submodule paths + URLs, usesgit ls-tree HEAD <path>to obtain the pinned commit SHA.scripts/versions.env: shellKEY=VALUElines whose key ends in_REF,_SHA, or_VERSIONand whose value is a 40-char hex SHA. These are always reported underskippedwithreason: "ambiguous_repo"because the file does not encode which GitHub repo each key belongs to.package.json:dependencies/devDependencieswhose version is a GitHub shorthand (owner/repo#ref) or HTTPS GitHub URL.
behindBy: -1 signals an error resolving that pin. When this happens the pin entry also carries an error: { code, message, retryable, suggestedFix? } field explaining why (e.g. NOT_FOUND, RATE_LIMITED, UPSTREAM_FAILURE).
skipped[].reason remains a free-text parser-level code (ambiguous_repo, ambiguous_ref, not_github, ls_tree_no_sha, ls_tree_failed) — it describes a pin that couldn't be parsed at all, not a GitHub-side error.
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
repos |
(RepoRef | LocalPath)[] |
no | active workspace root | 1–64 repos. Each is { owner, repo } or { localPath }. |
since |
string |
yes | — | ISO8601 timestamp or relative duration: "48h", "7d". |
paths |
string[] |
no | — | Filter to commits touching these paths (applied per repo via GraphQL history(path:...)). Multiple paths are OR'd together. |
grep |
string |
no | — | Regex filter applied client-side to commit message subjects. |
maxCommitsPerRepo |
int |
no | 50 |
1–200 commits fetched per repo before merge. |
format |
"markdown" | "json" |
no | "json" |
Output format. |
JSON output:
{
"since": "2026-04-10T17:19:40Z",
"repos": [
{ "owner": "Rethunk-Tech", "repo": "bastion-satcom", "commitCount": 12 },
{
"owner": "Rethunk-AI",
"repo": "some-lib",
"commitCount": 0,
"error": { "code": "NOT_FOUND", "message": "...", "retryable": false }
}
],
"commits": [{
"owner": "Rethunk-Tech",
"repo": "bastion-satcom",
"sha7": "abc1234",
"message": "Fix SATCOM reconnect",
"author": "alice",
"date": "2026-04-12T08:00:00Z",
"pr": { "number": 42, "title": "Fix SATCOM reconnect" } // null when no (#N) in message
}], // merged + sorted date desc
"summary": {
"totalCommits": 47,
"repoBreakdown": { "bastion-satcom": 12, "some-lib": 35 }
},
"truncatedCount": 5 // omitted when 0; commits beyond maxCommitsPerRepo that were not returned
}Commits are merged across repos and sorted newest-first. Per-repo errors do not fail the batch.
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
owner |
string |
yes | — | GitHub owner or organization. |
repo |
string |
yes | — | GitHub repository name. |
ref |
string |
no | default branch HEAD | Branch, tag, or SHA to resolve. |
language |
string |
no | "go" |
Module system. Only "go" is supported in MVP. |
format |
"markdown" | "json" |
no | "json" |
Output format. |
JSON output:
{
"owner": "Rethunk-Tech",
"repo": "bastion-satcom",
"ref": "main",
"resolvedSha": "6589cad7c93e5fd59ece17284b4636c525bf8cf0",
"committerDate": "2026-04-13T00:17:01Z",
"goPseudoVersion": "v0.0.0-20260413001701-6589cad7c93e"
}The pseudo-version is formatted as v0.0.0-YYYYMMDDHHMMSS-<first12SHAchars> using the committer date in UTC. Use this when pinning a module in go.mod via a SHA rather than a release tag.
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
owner |
string |
yes | — | GitHub owner/org. |
repo |
string |
yes | — | Repository name. |
base |
string |
no | latest semver tag | Base ref (tag/branch). Omit to auto-pick the latest semver tag. |
head |
string |
no | default branch | Head ref to compare to. |
version |
string |
no | "Unreleased" |
Version string for the section header (e.g. "v1.3.0"). |
maxCommits |
int |
no | 50 |
1–200 commits. |
format |
"markdown" | "json" |
no | "json" |
Output format. |
JSON output:
{
"version": "v1.3.0",
"date": "2026-04-21",
"base": "v1.2.0",
"head": "main",
"entries": [{
"sha7": "abc1234",
"message": "feat: add blockedOnMe lens to my_work",
"author": "alice",
"date": "2026-04-20T10:00:00Z",
"pr": { "number": 42, "title": "feat: add blockedOnMe lens", "labels": ["enhancement"] }
}],
"truncatedCount": 3 // omitted when 0; commits beyond maxCommits that were not returned
}Commits are compared as base...head. PR metadata (title, labels) is resolved via GraphQL for up to 20 PRs. Markdown output is Keep-a-Changelog style, ready to paste into CHANGELOG.md.
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
owner |
string |
yes | — | GitHub owner/org. |
repo |
string |
yes | — | Repository name. |
pullNumber |
int |
yes | — | Pull request number. |
body |
string |
no | — | Overall review body text. |
event |
"COMMENT" | "APPROVE" | "REQUEST_CHANGES" |
no | "COMMENT" |
Review event type. |
comments |
{ path, line, body }[] |
no | — | Inline comments relative to repository root. |
dryRun |
boolean |
no | false |
Return the planned review without mutating. |
commentsRequested reports the number of inline comments submitted in the request; GitHub's review-creation response does not echo the created comments, so this is the requested count, not a server-confirmed one.
JSON output:
{ "reviewId": 123456, "url": "https://github.com/org/repo/pull/42#pullrequestreview-123456", "state": "COMMENTED", "commentsRequested": 2 }When dryRun: true:
{ "dryRun": true, "plan": { "owner": "org", "repo": "name", "prNumber": 42, "event": "COMMENT", "commentCount": 2, "comments": [{ "path": "src/foo.ts", "line": 10, "bodySnippet": "..." }] } }Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
owner |
string |
yes | — | GitHub owner/org. |
repo |
string |
yes | — | Repository name. |
title |
string |
yes | — | Pull request title. |
body |
string |
no | — | Pull request body. |
head |
string |
yes | — | Source branch name. The branch must already exist on GitHub. |
base |
string |
yes | — | Target branch name. |
draft |
boolean |
no | false |
Create the PR as a draft. |
maintainerCanModify |
boolean |
no | true |
Allow maintainers to modify the PR branch. |
dryRun |
boolean |
no | false |
Return the planned creation without mutating. |
JSON output:
{ "number": 42, "url": "https://github.com/org/repo/pull/42", "state": "open", "draft": false }When dryRun: true:
{ "dryRun": true, "plan": { "owner": "org", "repo": "name", "head": "feature/x", "base": "main", "title": "My PR", "draft": false, "bodyPreview": "..." } }Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
owner |
string |
yes | — | GitHub owner/org. |
repo |
string |
yes | — | Repository name. |
template |
string |
yes | — | Template filename or partial match under .github/ISSUE_TEMPLATE. |
variables |
Record<string, unknown> |
yes | — | Values used to replace {{ key }} (mustache) patterns. The legacy $key form is no longer substituted. |
title |
string |
yes | — | Issue title. |
assignees |
string[] |
no | — | Assignee usernames. |
labels |
string[] |
no | — | Labels to apply. |
dryRun |
boolean |
no | false |
Fetch and render the template (with variable substitution), then return the planned issue without mutating. |
JSON output:
{ "number": 101, "url": "https://github.com/org/repo/issues/101", "title": "Investigate release drift" }When dryRun: true:
{ "dryRun": true, "plan": { "owner": "org", "repo": "name", "title": "...", "bodyPreview": "...", "labels": ["bug"] } }Template matching tries exact filename first, then case-insensitive partial matching.
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
owner |
string |
yes | — | GitHub owner/org. |
repo |
string |
yes | — | Repository name. |
tag |
string |
yes | — | Release tag (for example v1.2.3). |
name |
string |
no | tag | Release title. |
body |
string |
no | "" |
Release notes body. |
draft |
boolean |
no | false |
Create as draft. |
prerelease |
boolean |
no | false |
Mark as prerelease. |
generateNotes |
boolean |
no | false |
Ask GitHub to generate release notes. |
dryRun |
boolean |
no | false |
When true, return the resolved release parameters without creating the release. |
JSON output:
{ "url": "https://github.com/org/repo/releases/tag/v1.2.3", "id": 999, "tag": "v1.2.3", "draft": false, "prerelease": false }When both body and generateNotes are supplied, GitHub-generated notes win and the response carries a warnings array noting that the supplied body was overridden. If a release already exists for tag, the tool returns a VALIDATION error rather than mutating. A dryRun response carries dryRun: true and the parameters that would have been used.
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
owner |
string |
yes | — | GitHub owner/org. |
repo |
string |
yes | — | Repository name. |
workflow |
string |
yes | — | Workflow filename (for example ci.yml) or numeric workflow id. |
ref |
string |
yes | — | Branch or tag to run against. |
inputs |
Record<string, string> |
no | {} |
Optional workflow input values. |
dryRun |
boolean |
no | false |
When true, return the resolved dispatch parameters without triggering the workflow. |
JSON output:
{ "message": "Workflow 'ci.yml' dispatched successfully on org/repo:main. GitHub returns 204 (no run ID); poll workflow runs to find the dispatched run." }Parameters: none.
JSON output:
{ "authenticated": true, "login": "alice", "scopes": ["repo", "read:org"] }On missing or invalid auth, the tool returns { "authenticated": false } instead of a top-level error envelope.
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
owner |
string |
yes | — | GitHub owner/org. |
repo |
string |
yes | — | Repository name. |
workflow |
string |
no | — | Workflow name substring or id filter. |
status |
"queued" | "in_progress" | "completed" |
no | — | Filter by run status. |
conclusion |
"success" | "failure" | "cancelled" |
no | — | Filter by run conclusion. |
branch |
string |
no | — | Filter by branch name. |
limit |
int |
no | 20 |
Maximum number of runs to return (1–500, default 20). |
format |
"markdown" | "json" |
no | "json" |
Output format. |
JSON output:
{
"runs": [{
"id": 12345,
"name": "CI",
"status": "completed",
"conclusion": "failure",
"branch": "main",
"createdAt": "2026-05-01T10:00:00Z",
"url": "https://github.com/org/repo/actions/runs/12345"
}],
"truncatedCount": 12 // omitted when 0; total available minus returned
}Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
owner |
string |
yes | — | GitHub owner/org. |
repo |
string |
yes | — | Repository name. |
labels |
{ name, color, description? }[] |
yes | — | Desired label set. color may be passed with or without #. |
deleteExtra |
boolean |
no | false |
Delete labels not present in the declared set. |
dryRun |
boolean |
no | false |
When true, compute and return the planned create/update/delete set without mutating any label. |
JSON output:
{
"created": ["bug"],
"updated": ["enhancement"],
"deleted": ["needs-triage"],
"skipped": ["docs"],
"failures": [{ "name": "wontfix", "action": "update", "error": "..." }], // per-label failures; empty when all succeeded
"dryRun": true // present and true only when dryRun was requested
}The existing label set is fully paginated, so the deleteExtra "extra" computation is correct for repositories with more than 100 labels. Each label operation is applied independently: a partial failure populates failures while completed work still appears in created/updated/deleted — the call never discards successful mutations.
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
owner |
string |
yes | — | GitHub owner/org. |
repo |
string |
yes | — | Repository name. |
name |
string |
yes | — | Check run name. |
headSha |
string |
yes | — | Commit SHA to attach the check run to. |
status |
"queued" | "in_progress" | "completed" |
no | "queued" |
Check run status. |
conclusion |
"success" | "failure" | "neutral" | "cancelled" | "skipped" | "timed_out" |
no | — | Required when status is "completed". |
title |
string |
no | — | Output title. |
summary |
string |
no | — | Output summary. |
dryRun |
boolean |
no | false |
Return the planned check run without mutating. |
JSON output:
{ "id": 5555, "url": "https://github.com/org/repo/runs/5555" }When dryRun: true:
{ "dryRun": true, "plan": { "owner": "org", "repo": "name", "name": "my-check", "headSha": "abc1234", "status": "completed", "conclusion": "success" } }If status is "completed" without a conclusion, the tool returns a VALIDATION error envelope. The dryRun path applies the same validation before returning.
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
owner |
string |
yes | — | GitHub owner or organization. |
repo |
string |
yes | — | GitHub repository name. |
state |
"open" | "dismissed" | "fixed" | "auto_dismissed" |
no | "open" |
Alert state to filter by. |
severity |
"critical" | "high" | "medium" | "low" |
no | — | Filter to a specific severity. Omit to return all severities. |
includeDependabot |
boolean |
no | true |
Include Dependabot alerts. |
includeCodeScanning |
boolean |
no | true |
Include Code Scanning alerts. |
limit |
int |
no | 30 |
Maximum alerts per source (1–100). |
format |
"markdown" | "json" |
no | "json" |
Output format. |
Requires: security_events scope (or repo).
JSON output:
{
"rollup": { "critical": 1, "high": 3, "medium": 5, "low": 2 },
"dependabot": {
"enabled": true,
"total": 4,
"truncatedCount": 0,
"alerts": [{
"number": 12,
"ghsaId": "GHSA-xxxx-xxxx-xxxx",
"severity": "high",
"state": "open",
"package": "lodash",
"summary": "Prototype pollution in lodash",
"htmlUrl": "https://github.com/org/repo/security/dependabot/12"
}]
},
"codeScanning": {
"enabled": true,
"total": 7,
"truncatedCount": 0,
"alerts": [{
"number": 3,
"ruleId": "js/code-injection",
"severity": "critical",
"state": "open",
"htmlUrl": "https://github.com/org/repo/security/code-scanning/3"
}]
}
}When a source is disabled or not accessible (HTTP 403/404), it reports { "enabled": false, "reason": "..." } instead of an error, and the other source is still returned. truncatedCount on each source shows how many alerts matched but were not returned due to limit.
Idempotency: read-only.
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
owner |
string |
yes | — | GitHub repository owner or organization. |
repo |
string |
yes | — | GitHub repository name. |
prNumber |
int |
yes | — | Pull request number. |
action |
"list" | "resolve" | "unresolve" |
yes | — | Operation to perform. |
threadIds |
string[] |
no | — | Review thread node IDs to resolve/unresolve. Required for resolve/unresolve unless resolveOutdated is true. |
resolveOutdated |
boolean |
no | false |
When action=resolve: resolve all currently unresolved and outdated threads instead of specifying threadIds. |
dryRun |
boolean |
no | false |
Compute the target thread set and return it without mutating. |
Requires: PR write (repo or pull_requests:write). action=list is read-only in effect but still uses a write-capable token for the GraphQL endpoint.
JSON output — action=list:
{
"threads": [{
"id": "PRRT_...",
"path": "src/foo.ts",
"line": 42,
"isResolved": false,
"isOutdated": true,
"author": "alice",
"bodySnippet": "Please use const here…"
}],
"truncatedCount": 5 // present when PR has more than 100 threads
}JSON output — action=resolve or action=unresolve:
{ "action": "resolve", "resolved": ["PRRT_aaa", "PRRT_bbb"], "failures": [] }JSON output — dryRun=true:
{ "dryRun": true, "action": "resolve", "targetThreadIds": ["PRRT_aaa", "PRRT_bbb"] }Idempotency: convergent — resolving an already-resolved thread is a no-op. action=list is read-only.
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
owner |
string |
yes | — | GitHub owner or organization. |
repo |
string |
yes | — | GitHub repository name. |
branch |
string |
no | default branch | Branch name. Omit to query the repository default branch. |
format |
"markdown" | "json" |
no | "json" |
Output format. |
Requires: branch-protection read (repository admin or repo scope).
JSON output:
{
"branch": "main",
"protected": true,
"requiredStatusChecks": { "strict": true, "contexts": ["ci/test"] },
"requiredReviews": { "count": 1, "dismissStaleReviews": true, "requireCodeOwnerReviews": false },
"enforceAdmins": false,
"requiredLinearHistory": true,
"allowForcePushes": false,
"requiredSignatures": false,
"restrictions": null
}When the branch has no protection rules, returns { "branch": "main", "protected": false }. The restrictions field is null (no restrictions) or { "users": [...], "teams": [...] }.
Idempotency: read-only.
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
owner |
string |
yes | — | GitHub owner or organization. |
repo |
string |
yes | — | GitHub repository name. |
environment |
string |
no | — | Filter by environment name (e.g. "production"). |
limit |
int |
no | 10 |
Maximum deployments to fetch (1–50). |
format |
"markdown" | "json" |
no | "json" |
Output format. |
Requires: deployments read (repo scope).
JSON output:
{
"environmentFilter": "production",
"deployments": [{
"id": 123456,
"environment": "production",
"ref": "main",
"sha": "abc1234",
"state": "success",
"creator": "alice",
"createdAt": "2026-05-20T10:00:00Z",
"updatedAt": "2026-05-20T10:05:00Z",
"url": "https://myapp.example.com"
}],
"byEnvironment": { "production": "success", "staging": "failure" },
"truncatedCount": 0
}byEnvironment maps each environment name to its latest deployment state (first-seen wins since the API returns newest-first). truncatedCount is always 0 in this version (reserved for future use).
Idempotency: read-only.
Parameters:
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
owner |
string |
yes | — | GitHub owner or organization. |
repo |
string |
yes | — | GitHub repository name. |
title |
string |
yes | — | The candidate issue title to check for duplicates. |
labels |
string[] |
no | — | Filter candidate issues by these labels (OR semantics). |
state |
"open" | "closed" | "all" |
no | "open" |
Which issue states to scan. |
limit |
int |
no | 50 |
Maximum existing issues to scan (1–100). |
threshold |
number |
no | 0.5 |
Minimum similarity score (0–1) to include in results. |
format |
"markdown" | "json" |
no | "json" |
Output format. |
Requires: issues read (repo scope).
JSON output:
{
"candidateTitle": "Button click handler broken in Safari",
"scanned": 50,
"matches": [{
"number": 88,
"title": "Safari click handler regression",
"state": "open",
"url": "https://github.com/org/repo/issues/88",
"score": 0.67,
"exactMatch": false
}],
"truncatedCount": 3 // omitted when absent; matches above threshold capped at 20
}Similarity uses token-set Jaccard on normalized titles (lowercase, punctuation stripped). exactMatch: true is set when normalized titles match exactly. Results are sorted by score descending and capped at 20 matches (excess reported in truncatedCount).
Idempotency: read-only.
All tools except gh_auth_status require a GitHub token. Resolution order:
GITHUB_TOKENenvironment variableGH_TOKENenvironment variable (matchesghCLI convention)gh auth tokensubprocess fallback (ifghCLI is installed and authenticated)
Set the token in the MCP client's env block. For GitHub Enterprise, set GITHUB_API_URL (and optionally GITHUB_GRAPHQL_URL).
{ "error": { "code": "NOT_FOUND", "message": "PR Rethunk-AI/github-mcp#42 not found.", "retryable": false, "suggestedFix": "Verify the PR number." // optional } }