github-mcp-proxy
by kazaminn
README.md
# github-mcp-proxy
A self-hosted **GitHub MCP server** running on Cloudflare Workers, designed for personal / small-team use with **per-repository guardrails** for AI agents.
Any [MCP](https://modelcontextprotocol.io/)-capable agent (Claude, Codex, ChatGPT, Cursor, Cline, …) can be plugged in — with tight control over *which* repos it can touch and *how*.
> [!WARNING]
> If you need security or stability, use the [official GitHub MCP server](https://github.com/github/github-mcp-server).
> Fork freely; security issues are your responsibility once forked.
## Why
Generic GitHub tokens give an agent full account access. This server narrows that down:
- **Per-repo permission levels** — `read` / `issues` / `full`
- **Branch protection** — new branches must match a prefix (default `claude/`); `main`/`master` never writable
- **Commit-message policy** — Conventional Commits, validated server-side
- **Label whitelist** — `allowedLabels` per repo; the server never auto-creates labels on GitHub
- **Forbidden paths** — `.github/workflows/**` always blocked
- **Audit trail** — every write auto-appends `Signed-off-by` / `Assisted-by` trailers or a footer identifying the agent and model
## Architecture
```
MCP agent ──(Streamable HTTP + OAuth)──▶ Cloudflare Worker
│
├── workers-oauth-provider (OAuth 2.1 server to MCP clients)
├── GitHub OAuth (OAuth client to github.com)
├── KV (session tokens)
├── Durable Object (MCP agent state)
└── Octokit (GitHub REST)
```
Config (`ghmcp.config.ts`) is bundled with the Worker at deploy time — no runtime KV reads, typechecked via `satisfies`.
## Quick start
```bash
git clone <your-fork>
cd kz-github-mcp
npm install
cp ghmcp.config.sample.ts ghmcp.config.ts # edit: repos you want to expose
cp wrangler.sample.jsonc wrangler.jsonc # edit: KV id + worker name
cp .env.example .env # edit: for local dev only
```
Create a [GitHub OAuth App](https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/creating-an-oauth-app) (Homepage = `https://<worker>.<subdomain>.workers.dev`, Callback = `/callback`), then:
```bash
wrangler kv namespace create "OAUTH_KV" # add the id to wrangler.jsonc
wrangler secret put GITHUB_CLIENT_ID
wrangler secret put GITHUB_CLIENT_SECRET
wrangler secret put COOKIE_ENCRYPTION_KEY # openssl rand -hex 32
npm run deploy
```
Local development: same flow with a second OAuth App pointing at `http://localhost:8788`, credentials in `.env`, then `npm run dev`.
### Continuous deployment (optional)
`.github/workflows/deploy.yml` deploys to Cloudflare on every push to `main`. Set two repo secrets in GitHub Settings → Secrets and variables → Actions:
| Secret | Where to get it |
|---|---|
| `CLOUDFLARE_API_TOKEN` | [Cloudflare dashboard → My Profile → API Tokens](https://dash.cloudflare.com/profile/api-tokens) → create a token with the "Edit Cloudflare Workers" template |
| `CLOUDFLARE_ACCOUNT_ID` | Cloudflare dashboard → right sidebar of any Workers page |
The GitHub OAuth credentials (`GITHUB_CLIENT_ID`, `GITHUB_CLIENT_SECRET`, `COOKIE_ENCRYPTION_KEY`) live as **Wrangler** secrets on the Worker itself, not in GitHub Actions — you only need to set them once with `wrangler secret put`.
See [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) for how it works, [`docs/CONFIG.md`](docs/CONFIG.md) for every config field.
## Connect an AI agent
**Claude (claude.ai)** — Settings → Connectors → Add custom connector → paste `https://<worker>.<subdomain>.workers.dev/sse`.
**Claude Code / Codex / Cursor / Cline** — add to the client's MCP config:
```json
{
"mcpServers": {
"github": {
"command": "npx",
"args": ["mcp-remote", "https://<worker>.<subdomain>.workers.dev/sse"]
}
}
}
```
**Any MCP host** — point it at the same `/sse` endpoint. OAuth flow runs on first connect.
## Tools
Prefixed with `ghmcp_`. Each declares a minimum permission level; the server denies calls below that.
| Category | Tools | Min level |
|---|---|---|
| User | `get_me` | read |
| Repo | `list_repos`, `get_file_content`, `search_code` | read |
| Issues | `list_issues`, `get_issue`, `search_issues`, `list_issue_comments` | read |
| Issues | `create_issue`, `update_issue`, `add_issue_comment` | issues |
| PRs | `list_pull_requests`, `get_pull_request` | read |
| PRs | `create_pull_request` | issues |
| Files | `create_or_update_file`, `create_branch` | full |
| Actions | `list_workflow_runs`, `get_workflow_run_logs` | read |
Any tool can be disabled via `disabledTools` in the config.
## Validation
```bash
npm run validate-config
```
Uses the `gh` CLI to confirm that every repo in `ghmcp.config.ts` exists and that every label in `allowedLabels` is present on GitHub. Runs automatically as a `prebuild` hook, so a typo fails `npm run build`.
## License
Originally forked from [`cloudflare/ai/demos/remote-mcp-github-oauth`](https://github.com/cloudflare/ai/tree/main/demos/remote-mcp-github-oauth). MIT-licensed.
This tool is MIT-licensed. — see [LICENSE](LICENSE).
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues