gh_mcp
This MCP server integrates the GitHub CLI to provide read and write access to GitHub repositories, issues, pull requests, releases, workflows, and more.
Read Operations:
Search repositories, issues/PRs, and code with various qualifiers.
List and get detailed information for repositories, issues, PRs, releases, workflows, runs, labels, milestones.
Get file contents and view PR diffs, changed files, and commits.
Watch workflow runs until completion.
Provide server and GH CLI info (version, auth status).
Write Operations (disabled by default, require opt-in):
Create and edit repositories, issues, pull requests, releases, labels, milestones.
Upsert (create or overwrite) labels.
Submit formal PR reviews (approve, request changes, comment) and merge PRs with exact head SHA validation.
Post comments on issues/PRs; create branches linked to issues.
Atomically commit files to a branch with expected head SHA.
Trigger workflow dispatch events.
Safety:
Writes are disabled by default; enabled via
MCP_GH_ALLOW_WRITE_COMMANDS.High-risk operations require separate opt-in flags.
Writes can be scoped to specific repos/owners via allowlists.
All commands are non-interactive, async, with configurable timeouts.
Results are bounded and paginated with hard limits.
Allows managing GitHub repositories, issues, pull requests, releases, labels, milestones, and more through the gh command-line interface.
Provides tools for listing, viewing, and triggering GitHub Actions workflows and monitoring workflow runs.
Click on "Install 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., "@gh_mcpshow me open pull requests in the repo vercel/next.js"
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.
MCP 2.0 GitHub CLI Server
A Python MCP server for the gh CLI. It uses the official MCP Python SDK 2.x,
runs gh asynchronously without a terminal, and returns structured results from
direct JSON output or a post-write readback.
Tools
Read-only (27)
gh_server_info: report the deployed MCP server and tool-schema version without contacting GitHub or starting a subprocess.gh_info: gh CLI version, authentication status, and active account.gh_search_repos: search GitHub repositories with qualifiers.gh_search_issues: search issues and pull requests with qualifiers.gh_search_code: search source code with qualifiers.gh_list_issues: list issues in a repository with filters.gh_get_issue: get details of a specific issue or pull request.gh_list_prs: list pull requests in a repository.gh_get_pr: get a bounded, fully typed pull-request snapshot and exact base/head commit SHAs through one explicit noninteractive GET.gh_get_pr_diff: read a bounded diff or patch pinned to the PR's exact base and head SHAs, with truncation metadata and a SHA-256 fingerprint.gh_list_pr_files: list one bounded page of changed files and patch fragments.gh_list_pr_commits: list one bounded page of commits in a pull request.gh_get_repo: get details of a specific repository.gh_list_repos: list repositories for a user or organization.gh_list_releases: list releases in a repository.gh_get_release: get details of a specific release.gh_list_workflows: list GitHub Actions workflows in a repository.gh_get_workflow: get details of a specific workflow.gh_list_runs: list recent GitHub Actions workflow runs.gh_get_run: get details of a specific workflow run.gh_watch_run: poll a workflow run until completion or a caller-supplied timeout.gh_get_pr_checks: return bounded CI check summaries pinned to an exact PR revision.gh_list_run_jobs: list one bounded page of jobs and steps for an exact run attempt.gh_get_failed_run_logs: return bounded failed-step logs for an exact run attempt.gh_list_labels: list labels in a repository.gh_list_milestones: list milestones in a repository.gh_get_file_contents: read a complete file at an exact branch, tag, or commit ref.
Write (17)
gh_create_issue: create a new issue (write, disabled by default).gh_create_pr: create a new pull request (write, disabled by default).gh_create_repo: create a new repository (write, disabled by default).gh_create_release: create a new release (write, disabled by default).gh_run_workflow: trigger a workflow dispatch event (write, disabled by default).gh_edit_issue: edit an existing issue (write, disabled by default).gh_create_label: create a new label (write, disabled by default).gh_upsert_label: create or overwrite a label (destructive write, disabled by default).gh_edit_label: edit an existing label (write, disabled by default).gh_create_milestone: create a new milestone (write, disabled by default).gh_create_comment: create a comment on an issue or PR (write, disabled by default).gh_create_branch: create an issue development branch from a branch-name base (additive write, disabled by default).gh_create_branch_from_sha: create a branch at one exact 40-character commit SHA without moving an existing ref (additive write, disabled by default).gh_edit_pr: edit an existing pull request (write, disabled by default).gh_submit_pr_review: submit a formal review pinned to an exact PR head SHA (additive write, disabled by default).gh_merge_pr: merge an exact reviewed PR head with an explicit strategy (destructive write, separately disabled by default).gh_commit_files: atomically create or replace files in one branch commit (destructive write, separately disabled by default).
Related MCP server: GitHub CLI MCP Server
Install
cp .env.example .env
$EDITOR .env
uv sync --devGITHUB_TOKEN is required and can be supplied either in the process
environment or the located .env file. To use an env file outside the
launch directory, set:
export MCP_GH_ENV_FILE=/absolute/path/to/.envStart the MCP Inspector:
uv run mcp dev src/mcp_gh_server/server.pyRun as a local stdio MCP server:
uv run mcp-ghThe default transport is stdio. For local Streamable HTTP:
MCP_GH_TRANSPORT=streamable-http uv run mcp-gh
# endpoint: http://127.0.0.1:8766/mcpAlternative ASGI launch:
uv run uvicorn mcp_gh_server.asgi:app --host 127.0.0.1 --port 8766Client configuration
VS Code / compatible local stdio host
Use an absolute project path. The host should launch the locked project
environment. Run uv sync --dev first so the project has a generated
uv.lock before using --frozen:
{
"servers": {
"gh-local": {
"type": "stdio",
"command": "/absolute/path/to/uv",
"args": [
"run",
"--directory",
"/absolute/path/to/gh_mcp",
"--frozen",
"mcp-gh"
],
"env": {
"MCP_GH_ENV_FILE": "/absolute/path/to/gh_mcp/.env"
}
}
}
}For Qwen Code or another host using the common mcpServers shape, keep
the same command/args and place the entry under mcpServers.
ChatGPT plan and gateway limitations
The action surface is version 0.6.1, but availability in
ChatGPT depends on the account plan and integration surface:
OpenAI currently limits full custom MCP apps, including write/modify actions, to Business and Enterprise/Edu workspaces.
A ChatGPT Plus user may be able to install or discover a custom plugin, but the plugin's MCP gateway is a separate, more limited integration. This project does not assume that gateway supports arbitrary custom MCP tools or write actions.
Seeing
gh_get_file_contentsorgh_commit_filesin a discovery response proves only that the server advertised the tools. It does not prove that the Plus plugin gateway will route either invocation to the server.
The Business/Enterprise Action control, action-refresh, and workspace-publish
instructions do not apply to a Plus account. If the Plus gateway reports that the
plugin or gh_CLI namespace has been disabled, there may be no user-accessible
action setting that can re-enable the tool in that conversation.
Tentative Plus schema-refresh procedure
Limited testing indicates that the Plus custom-plugin gateway may retain a cached tool schema after the backend changes. Deleting and reinstalling the custom plugin appears to force rediscovery of the revised tools and may be necessary when tool names, parameters, annotations, or result schemas change:
Increment the project, package, and MCP server version whenever a deployed revision changes tool names, schemas, annotations, or routing behavior.
Deploy the revised backend and restart the MCP server.
Delete the existing custom plugin from ChatGPT Plus.
Reinstall the plugin so the gateway scans the backend's current tool definitions.
In a new conversation, call
gh_server_infoand confirm bothserver_versionandtool_schema_versionmatch the expected deployment.Only then test the revised GitHub tools.
This procedure is based on observed behavior rather than a documented compatibility guarantee. A backend restart alone may leave the Plus gateway using stale tool definitions, while deletion and reinstallation may still fail if the gateway does not support a particular tool or capability.
gh_server_info is intentionally the smallest and safest possible verification
call. It takes no model-controlled arguments, performs no external I/O, starts no
subprocess, triggers no elicitation or approval flow, and returns only bounded local
metadata. gh_info is not a substitute: it reports the installed GitHub CLI version,
not the deployed MCP server version.
See OpenAI's current MCP app availability and plugin availability.
At INFO, both repository-content tools log a content-free reachability marker:
MCP tool invocation reached server: tool=gh_get_file_contentsThe four focused PR snapshot/review reads emit the same marker using their own tool name.
The version probe emits the equivalent marker with tool=gh_server_info.
gh_get_pr Plus gateway contract
Version 0.5.1 replaces the former gh_get_pr contract that could be discovered
but was not safe for a strict execution gateway. The old definition had no explicit
tool title, did not declare idempotence, accepted unconstrained repository identifiers,
and advertised ambiguous structured-output fragments: label items had an empty JSON
schema and comments had no JSON type. A host can catalog such a tool while rejecting
it later when it constructs or validates the executable route.
The revised operation preserves the mixed read/write server and changes only the offending read contract and common read annotation accuracy:
the title and description explicitly identify a read-only, noninteractive snapshot;
readOnlyHint=true,destructiveHint=false, andidempotentHint=trueare explicit;owner, repository, and positive PR-number constraints are present in the input schema;
every output field is typed, including
labels: string[], nonnegative integercomments, and required 40-character base/head SHAs;the implementation performs exactly one
gh api ... -X GETrequest and exposes no approval, elicitation, comment, review, merge, or generic-command path;the reachability marker is logged before repository validation or client execution:
MCP tool invocation reached server: tool=gh_get_prAfter deploying the current release, delete and reinstall the Plus custom plugin and
verify gh_server_info reports both versions as 0.6.1. An immediate namespace-disabled
response with no gh_get_pr marker still proves rejection occurred in the host before
the revised server operation. It does not indicate GitHub authentication, repository,
PR, or readback failure and must not be retried as though a GitHub write partially ran.
If ChatGPT reports that the app or namespace is disabled and this marker is absent,
the call was rejected by ChatGPT's plugin gateway before reaching the MCP server.
Restarting gh, changing the GitHub token, or changing this server's command
implementation cannot repair that host-side state. On Plus, full validation should
therefore use a standard MCP client such as the local stdio or Streamable HTTP
configurations above; passing those checks does not establish compatibility with
ChatGPT's limited custom-plugin gateway.
Read-only pull-request review without checkout
The server deliberately does not expose a generic command executor or a standalone checkout operation. A checkout performed by this backend would exist on the MCP server's filesystem, not in ChatGPT's local environment, and a path alone would not provide a safe review workspace. The focused review tools instead operate through noninteractive GitHub reads and return bounded structured results:
Call
gh_get_prand record its exactbase_shaandhead_sha.Call
gh_get_pr_difffor a unifieddiffor email-stylepatch. The server resolves the PR's object IDs and reads the comparison by those immutable SHAs.Check
truncated,bytes_returned,total_bytes, andsha256. A truncated result is not a complete diff and must not be described as one.Page through
gh_list_pr_filesandgh_list_pr_commitsas needed. The server rechecks the SHA pair after each numbered-PR page and rejects the result if the snapshot changed during the read. GitHub may omit or truncate an individual file'spatch, and the server also bounds patch fragments and commit messages; inspect their truncation fields and use the unified diff plusgh_get_file_contentsat the returned SHAs for complete file inspection.If the PR changes during review, restart from the new exact SHA pair rather than combining observations from different snapshots.
gh_get_pr_diff returns at most MCP_GH_MAX_PR_DIFF_BYTES UTF-8 bytes. A caller may
request a smaller limit, but cannot raise the deployment cap above 1,000,000 bytes:
MCP_GH_MAX_PR_DIFF_BYTES=500000
MCP_GH_MAX_PR_FILE_PATCH_BYTES=8000
MCP_GH_MAX_PR_COMMIT_MESSAGE_BYTES=4000This workflow is valid for source-level, read-only review. It does not check out a worktree, inspect generated or untracked files, install dependencies, build code, or run tests. A validation record should state that boundary explicitly, for example:
Reviewed the pull request using GitHub metadata, diff data, and repository file contents pinned to the recorded base and head SHAs. No local checkout, build, or test execution was performed.
If acceptance requires execution, use a separate isolated repository runner with a managed workspace, bounded commands, cancellation, cleanup, and exact-head-SHA validation. The read-only MCP tools are not a substitute for that environment.
Formal pull-request review and merge
gh_create_comment creates an issue-style conversation comment; it does not submit
a GitHub pull-request review and cannot produce the formal APPROVED,
CHANGES_REQUESTED, or COMMENTED review states. Use gh_submit_pr_review when a
formal disposition is required.
The safe completion sequence is:
Read and review the PR using
gh_get_pr,gh_get_pr_diff, file pages, commit pages, and exact-ref file reads. Record the returnedhead_sha.Call
gh_submit_pr_reviewwith that SHA and one ofapprove,request_changes, orcomment. A body is mandatory for the latter two actions.Confirm the structured result's
state,commit_sha, andreview_id. The tool submits the review with GitHub'scommit_idfield and rejects a stale head before writing.If merge is separately authorized, call
gh_merge_prwith the same exact head SHA and an explicitmerge,squash, orrebasestrategy.Treat the PR as merged only when the result reports
merged: true. A successful command may instead report a merge queue or unmet requirements; formal review submission by itself never merges or closes the PR.
Both operations are focused tools with bounded text fields. They start no nested MCP elicitation, inherit no stdin, and return structured readback. Review request bodies are transferred through a temporary JSON input file; merge bodies are supplied on controlled stdin. If a write succeeds but readback fails, the response is marked as partial success and instructs the caller not to retry automatically.
Before an approve write, the server reads the authenticated GitHub login and PR
author. GitHub documents that PR authors cannot approve their own pull requests, so
an exact login match is rejected before the POST with an explicit no review was attempted error. comment remains available to the author. GitHub's public review
documentation does not explicitly state the equivalent author rule for
request_changes, so the server does not invent one: GitHub remains authoritative.
When GitHub rejects any review write, including HTTP 422 validation failures, the
client now preserves a bounded, sanitized JSON error summary containing GitHub's
message, errors, documentation_url, and status. Request values and arbitrary
response fields are excluded. A failed POST remains a direct tool error—there is no
readback and no partial-success result because GitHub did not create a review. Do not
retry it automatically; correct the reported validation or use comment when the
authenticated account is the PR author.
gh_merge_pr deliberately exposes no administrator bypass, branch deletion, or
automatic-merge switch. It passes GitHub CLI's --match-head-commit guard so a
force-push or new commit cannot silently change the authorized merge target. GitHub
permissions and branch protection still apply, and an author generally cannot
approve their own pull request.
Read-only CI diagnosis
Use the focused CI tools instead of inferring a failure from run metadata:
Call
gh_get_prand record the exact PRhead_sha.Call
gh_get_pr_checks. Its result includes the same base/head SHA pair and categorizedpass,fail,pending,skipping, orcancelchecks. Failed and pending checks are returned as data even thoughgh pr checksuses nonzero status codes for those states.Use the check link or
gh_list_runsto identify the positive integer run ID.Call
gh_list_run_jobs, optionally with an exact attempt number, to retrieve one page of jobs and their step status/conclusion metadata.Call
gh_get_failed_run_logsfor the same run attempt. Inspecttruncated,bytes_returned,total_bytes, andsha256before claiming the returned text is complete.
All three tools are explicitly read-only, idempotent, and open-world. They expose no
watch, rerun, cancel, delete, dispatch, browser, generic-command, approval, or
elicitation option. Repository identifiers, PR/run IDs, attempts, pages, and output
sizes are schema constrained. Every gh subprocess remains asynchronous and
noninteractive with detached stdin.
gh_get_pr_checks reads and verifies the PR SHA pair around the checks request so a
force-push cannot silently mix revisions. Jobs and logs first resolve a concrete run
attempt and head SHA, operate on that exact attempt, and verify it again before
returning. Job pages contain at most 100 jobs. Failed logs are bounded by both the
request and deployment setting:
MCP_GH_MAX_FAILED_RUN_LOG_BYTES=500000The deployment setting is capped at 1,000,000 UTF-8 bytes. Empty failed-log output is valid when GitHub reports no failed steps. Authentication, retention expiry, missing logs, or malformed output are returned as ordinary tool errors; the namespace remains available for subsequent reads.
Write-command policy
Write execution is off by default:
MCP_GH_ALLOW_WRITE_COMMANDS=falseTo enable writes:
MCP_GH_ALLOW_WRITE_COMMANDS=trueWrite tools do not initiate nested MCP elicitation. A compatible MCP host is
responsible for presenting any user-facing action approval. The ChatGPT Plus
custom-plugin gateway may reject write tools instead of offering approval. The
server independently enforces the write-enable flag, optional repository policy,
and high-risk operation switches before starting gh.
Limit enabled writes to explicit repositories or owners:
MCP_GH_ALLOWED_REPOSITORIES=fvanevski/project-a,fvanevski/project-b
MCP_GH_ALLOWED_OWNERS=fvanevskiWhen either allowlist is non-empty, a target is accepted if its exact
owner/repo or its owner is listed. Fine-grained GitHub token permissions
remain the primary GitHub-side authorization boundary.
Repository creation, release creation, workflow dispatch, repository-content commits, and PR merging require separate opt-in because they can have broader effects:
MCP_GH_ALLOW_REPO_CREATION=true
MCP_GH_ALLOW_RELEASE_CREATION=true
MCP_GH_ALLOW_WORKFLOW_DISPATCH=true
MCP_GH_ALLOW_CONTENT_COMMITS=true
MCP_GH_ALLOW_PR_MERGE=trueEnable only the operations the deployment actually needs; all five default to
false.
Exact-SHA branch creation
The two branch tools intentionally have different contracts:
gh_create_branchdelegates togh issue develop. Its optionalbaseis an existing branch name, because GitHub CLI resolves that field as a branch. The tool rejects a 40-character commit SHA before startingghand directs the caller to the exact-SHA primitive.gh_create_branch_from_shaaccepts no issue number or moving base name. It requires an exact 40-characterbase_sha, verifies that exact commit in the target repository, and creates onlyrefs/heads/<name>through GitHub's Git refs API.
Use gh_create_branch_from_sha whenever the base is an immutable reviewed commit.
The operation is additive: it never force-updates, moves, overwrites, or deletes an
existing ref. If GitHub rejects or interrupts the create response, the tool reads the
requested branch. A branch already at the requested SHA is returned as a safe
no-write result; a branch at any other SHA is an error and remains unchanged. An
unexpected successful response produces an explicit partial-success warning telling
the caller to read the branch and not retry automatically.
Both tools use the ordinary server write gate, repository/owner allowlists, and the
branch_create operation policy. Their schemas contain canonical repository bounds,
positive issue-number constraints where applicable, bounded branch names, and an
exact SHA pattern. They are classified as additive external writes and contain no
generic command input, nested MCP elicitation, interactive stdin, force option, ref
update, or issue-content mutation. Host approval remains the only interactive approval
layer.
gh_commit_files accepts complete UTF-8 file contents, validates repository-relative
paths, and creates all supplied files in one Git tree and one commit. It conditionally
advances the named branch only if it still points to expected_head_sha; the update
uses GitHub's atomic updateRefs mutation with beforeOid and never forces a ref.
The operation does not support file deletion. Bound its request size with:
MCP_GH_MAX_COMMIT_FILES=100
MCP_GH_MAX_FILE_BYTES=1000000
MCP_GH_MAX_COMMIT_BYTES=5000000If the final ref-update response is interrupted, the tool reads the branch before reporting the outcome. An indeterminate result explicitly requires a fresh read and must not be retried automatically.
Operational limits
Search tools use GitHub's
gh searchsubcommands with--jsonoutput.Results are bounded by
MCP_GH_DEFAULT_MAX_RESULTS(default: 30) and capped atMCP_GH_HARD_MAX_RESULTS(default: 100).All output is JSON-safe:
Decimal→ string,bytes→base64:prefix, datetimes → ISO 8601, infinities → string.Logs are sent to stderr so stdio protocol output is not corrupted.
Every
ghprocess is noninteractive, receives either closed or explicitly supplied stdin, and runs with prompting, pagers, Git credential prompts, spinners, color, and update notices disabled.User-authored bodies and notes are supplied through stdin rather than command arguments. Debug command logs redact titles and other free-form values.
Commands run asynchronously, are terminated with their process group on timeout or cancellation, and default to
MCP_GH_COMMAND_TIMEOUT_SECONDS=30.Write results distinguish write completion from structured readback. A partial-success warning explicitly instructs callers to verify before retrying.
Streamable HTTP binds to
127.0.0.1by default and uses MCP's localhost DNS-rebinding protection.MCP_GH_LOG_LEVEL(default:INFO) controls logging verbosity; set toDEBUGfor detailed command logs.
Validation
uv run ruff check .
uv run ruff format --check .
uv run mypy
uv run pytestKnown boundaries
The server runs
ghas a subprocess, including allowlisted REST and GraphQL calls inside focused tools; it does not expose a generic command or API executor. Rate limits, authentication, and permission scoping are governed by theghCLI and the token inGITHUB_TOKEN.Commands like
gh release createthat require file uploads or complex multi-step flows are intentionally out of scope — they would need a dedicated maintenance tool.The
ghCLI must be installed and available on PATH.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- Alicense-qualityDmaintenanceAn MCP server that wraps around the GitHub CLI tool, allowing AI assistants to interact with GitHub repositories through commands for pull requests, issues, and repository operations.Last updated43MIT
- Alicense-qualityDmaintenanceAn MCP server that wraps the GitHub CLI to provide comprehensive access to repository management, pull requests, issues, and workflows. It enables users to perform complex GitHub operations and interact with the GitHub API through a standardized interface.Last updated171ISC
- Flicense-qualityCmaintenanceMCP server for the GitHub REST API that enables interaction with repositories, pull requests, issues, branches, commits, reviews, and code search, with configurable write and destructive operations.Last updated
- Flicense-qualityCmaintenanceA read-only MCP server that exposes GitHub user profiles, repository info, and search via tools for AI assistants like Claude.Last updated
Related MCP Connectors
An MCP server that gives your AI access to the source code and docs of all public github repos
A MCP server built for developers enabling Git based project management with project and personal…
An MCP server that let you interact with Cycloid.io Internal Development Portal and Platform
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/fvanevski/gh_mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server