github-mcp — a read+write MCP over a real external API
Python 74 passing tests read + write write-gated by default typed rate-limit handlingThe problem
Most MCP requests are the same shape: "expose our tool's API to Claude so the team can read and change records from a chat." The read half is easy. The parts that decide whether it's safe to put in front of a real API — where the credential lives, what happens when the upstream rate-limits you mid-call, and whether a write action can fire by accident — are the parts a hiring team can't see from a pitch. They have to trust that you handle them.
What I built
github-mcp is a read+write MCP server over the GitHub REST API — the exact pattern of the most common client request, built in the open so the discipline is verifiable instead of asserted. 14 tools across two groups:
- Read (9 tools, always on) — repos, issues, pull requests, file contents, commits, search, users. Works unauthenticated at GitHub's 60 req/hr tier, so it demos with zero secrets.
github_mcp/groups/read.py - Write (5 tools, OFF by default) — create/comment/label/close issues, PR review comments — refused with a structured error unless
GITHUB_MCP_ENABLE_WRITE=1is set per deployment.github_mcp/groups/write.py - Auth from the environment — a fine-grained PAT read from
GITHUB_TOKEN, never hardcoded, never logged.github_mcp/config.py - Typed upstream errors — GitHub's rate limit (primary and secondary/abuse) and 4xx/5xx surface as clean typed errors carrying the reset time, never a raw crash.
github_mcp/client.py
Evidence you can check yourself
Public on purpose — every claim maps to a file you can open before you reply:
- Repo: github.com/jaimenbell/github-mcp
- Tests:
python -m pytest→74 passed, 1 skipped, 0 failed(the skip is a live-API smoke, gated behind an env flag) - Safety: try any write tool without
GITHUB_MCP_ENABLE_WRITE=1and it returns a structured policy refusal — write access is opt-in per deployment, not a default.
Stated plainly in the README: this is a reference portfolio implementation, not the official GitHub MCP server. It exists to show how I build a read+write API server — the auth boundary, the write gate, the typed error handling — on a public API you already know, so the pattern transfers directly to your internal tool.
What it shows about how I work
This is the artifact behind the pitch. When a post says "build a custom MCP server that exposes read/write actions over our tool's API, keep secrets in env, handle errors cleanly," this is that, already built and green — with write actions defaulting off, because the safe default on a real API is the one you have to deliberately turn on.