github-mcp-server
Provides tools for interacting with GitHub's REST API for repository issues: listing issues (filterable by state/labels), retrieving full issue details, searching issues with GitHub search syntax, and performing write actions (creating issues, commenting on issues, closing issues) gated behind an explicit two-step confirmation token flow.
Click on "Deploy 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., "@github-mcp-serverlist the open issues in your-username/your-repo"
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.
github-mcp-server
A custom MCP (Model Context Protocol) server that connects an LLM to a GitHub repository's issues — with strict safety guardrails: read operations run freely, write operations require an explicit two-step confirmation before anything is sent to GitHub.
Built as a demonstration of MCP server design: authenticated API access, a small typed tool surface, and a confirmation pattern that can't be bypassed by prompt phrasing.
Why this exists
MCP is the emerging standard for giving LLMs permissioned access to private/authenticated tools and data — beyond what web search can reach. This project shows the full loop: a real external API (GitHub), a real auth token, and a safety layer that a model can't talk its way around.
Related MCP server: GitHub Issue Manager
Architecture
github-mcp-server/
├── server.py # MCP server: tool definitions & routing
├── github_client.py # Thin async GitHub REST API wrapper
├── confirmation.py # Two-step confirmation token store for writes
├── requirements.txt
├── .env.example
└── README.mdTools exposed:
Tool | Type | Description |
| read | List issues in a repo, filterable by state/labels |
| read | Full detail on one issue |
| read | GitHub search syntax across issues |
| write (confirm) | Open a new issue |
| write (confirm) | Post a comment |
| write (confirm) | Close an issue |
Confirmation pattern: every write tool, when called without a
confirm_token, returns a preview of the exact action it would
take and a short-lived token — it does not touch GitHub yet. The
caller (model or human) reviews the preview and calls the tool again
with that token to actually execute. Tokens are single-use, expire
after 5 minutes, and are bound to the exact arguments — changing the
arguments invalidates the token. This means a write can never happen
on the first call, regardless of how the request is phrased.
Setup (VS Code)
Clone / open this folder in VS Code.
Create a virtual environment and install dependencies:
python3 -m venv .venv source .venv/bin/activate # Windows: .venv\Scripts\activate pip install -r requirements.txtCreate a GitHub token: GitHub → Settings → Developer settings → Personal access tokens → Fine-grained tokens. Scope it to the specific repo(s) you want, with Issues: Read and write permission only (don't grant more than the server needs).
Configure environment:
cp .env.example .env # then edit .env and fill in GITHUB_TOKEN and GITHUB_DEFAULT_REPORun it standalone to sanity-check it boots:
python server.pyIt will sit waiting on stdio — that's correct, it's meant to be driven by an MCP client, not run interactively.
Connecting it to Claude Desktop / Claude Code
Add this to your MCP client config (for Claude Desktop:
~/Library/Application Support/Claude/claude_desktop_config.json on
macOS, %APPDATA%\Claude\claude_desktop_config.json on Windows):
{
"mcpServers": {
"github-issues": {
"command": "/absolute/path/to/.venv/bin/python",
"args": ["/absolute/path/to/github-mcp-server/server.py"],
"env": {
"GITHUB_TOKEN": "ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"GITHUB_DEFAULT_REPO": "your-username/your-repo"
}
}
}
}Restart the client, then in a conversation try: "List the open issues in my repo" (read, runs immediately) or "Open an issue titled 'Fix login bug'" (write — you'll see the preview + be asked to confirm before it actually posts to GitHub).
For Claude Code, run claude mcp add and point it at the same
command/args, or add an equivalent entry to your project's
.mcp.json.
Design notes worth highlighting (e.g. in an interview / CV writeup)
Least-privilege by default: reads need no confirmation; writes always do.
REQUIRE_CONFIRMATIONcan be flipped off for local testing but defaults totrue.Confirmation can't be forged: the token is a server-generated fingerprint of
tool_name + args, so a model can't just invent a token or reuse one from a different action.Small, typed tool surface: each tool has a docstring the LLM reads to decide when/how to call it — treat these docstrings as part of the API contract, not just documentation.
Payload trimming:
_format_issue()strips GitHub's verbose response down to what an LLM actually needs, keeping context usage low and avoiding leaking noisy internal fields.
Extending it
The structure is deliberately generic — add a notion_client.py
alongside github_client.py, register new @mcp.tool() functions in
server.py, and reuse the same confirmation.py gate for any new
write actions (e.g. create_notion_page).
Cost
Free — this only uses the free GitHub REST API within standard rate limits (5,000 requests/hour for authenticated requests).
Verification — proof it works end to end
This isn't just code that compiles — it's been run against a live Claude Desktop client and a real (test) GitHub repo.
1. Server boots and registers all 6 tools cleanly:
$ python server.py
[hangs on stdio, no errors — waiting for a client]Confirmed via Claude Desktop → Settings → Developer, where the
server shows a Running status with its command/args resolved
correctly.
2. Read path — list_issues called live through Claude Desktop:
Prompt: "List the open issues in my mcp-server-test repo"
Response: "Your mcp-server-test repo (Rhytham4306/mcp-server-test) has no open issues right now — it's all clear."
Confirms the full chain: Claude → MCP client → this server (stdio) → GitHub REST API → back through the same path → correct answer.
3. Write path with confirmation — create_issue called live:
Prompt: "Create an issue in mcp-server-test titled 'Test issue from MCP' with body 'Testing write confirmation flow'"
What actually happened under the hood (visible by expanding the tool
call in Claude Desktop): two separate calls to create_issue —
First call, no
confirm_token→ server returned a preview (status: confirmation_required) plus a single-use token. No write happened yet.Second call, same arguments plus the returned
confirm_token→ server validated the token against the argument fingerprint, consumed it, and only then called the GitHub API.
Result: issue #1 was created at
github.com/Rhytham4306/mcp-server-test/issues/1.
4. Confirmation gate rejects forged/mismatched tokens — verified
directly by calling create_issue with a random, invalid
confirm_token string: the server returned
{"status": "error", "error": "Confirmation token is invalid or has expired..."} and made no GitHub API call. See confirmation.py —
tokens are single-use, expire after 5 minutes, and are bound to a
SHA-256 fingerprint of the exact tool name + arguments, so a token
from one action can't be replayed against another.
Screenshots
:

This server cannot be deployed
Maintenance
Related MCP Connectors
Connect AI assistants to GitHub - manage repos, issues, PRs, and workflows through natural language.
Task management for people and AI agents, with scoped OAuth access to issues, projects, and docs.
Access the GitHub API, enabling file operations, repository management, search functionality, and…
OAuth 2.1 short-link tools for AI agents with scoped tokens, approvals, audit logs, and revocation.
Related MCP Servers
- FlicenseAqualityCmaintenanceEnables LLMs to list, create, and comment on GitHub issues using your own GitHub identity via stdio transport.3-
- AlicenseBqualityCmaintenanceIntegrates with GitHub REST API to allow LLM agents to list and create repository issues.2256 npmISC
- AlicenseNot gradedqualityCmaintenanceEnables LLM agents to search, read, and create GitHub issues and pull requests via natural language, using the GitHub API.1MIT
- FlicenseNot gradedqualityCmaintenanceExposes GitHub issue operations as tools for LLM agents, enabling listing, creating, commenting on, closing, and searching issues via natural language.-