Self-hosted GitHub MCP server for ChatGPT, Notion, and coding agents.
Repository inspection, safe file changes, commits, and pull requests through a guarded HTTP tool layer.
- MCP over HTTP at
POST /mcp. - ChatGPT OAuth 2.1 authorization-code flow with mandatory PKCE S256.
- GitHub App browser login for per-user GitHub credentials.
- Legacy Bearer and owner-token compatibility routes.
- 40 GitHub tools with the existing safety policies preserved, including pull request lifecycle, checks, review threads, reviewer requests, and branch updates.
- Durable encrypted OAuth and GitHub credential storage.
- Refresh-token rotation, single-flight GitHub refresh, and signed revocation webhooks.
- Protected-branch, repository allowlist, payload, path, and secret-scanning guards.
The GitHub tool registry and handlers remain in src/server.js. OAuth, user identity, and credential selection are implemented by the public wrapper without rewriting those tools.
ChatGPT
-> Purr OAuth + PKCE
-> GitHub App browser authorization
-> encrypted GitHub user credential reference
-> public credential router
-> loopback-only existing MCP server
-> GitHub API as that user
Compatibility access remains available:
valid SERVER_TOKEN
-> existing owner GITHUB_TOKEN
-> existing tools
The internal MCP child runs only on loopback. The public wrapper removes the owner credentials from the child environment and injects the correct GitHub credential per request.
The GitHub login design follows the official github/github-mcp-server OAuth patterns.
Runtime integration uses maintained Octokit packages:
@octokit/oauth-app
@octokit/webhooks
Octokit handles GitHub authorization URLs, code exchange, refresh, revocation, and webhook signature verification.
git clone https://github.com/0xheycat/Purr-github-MCP.git
cd Purr-github-MCP
npm install
npm run check
npm startThe public server starts on PORT, default 3000.
curl http://localhost:3000/healthConfigure the public OAuth server and a GitHub App. ChatGPT connects to:
https://<public-host>/mcp
Requested Purr scopes are hierarchical:
github.read -> github.plan -> github.write -> github.admin
A client requesting github.admin receives the complete current tool catalog. GitHub's own user and GitHub App permissions are enforced again when a tool executes.
SERVER_TOKEN=<private-mcp-token>
GITHUB_TOKEN=<owner-github-token>A direct valid SERVER_TOKEN continues to use the owner GitHub credential and receives the existing full catalog.
The bare server still supports direct GitHub Bearer credentials for trusted internal or local integrations. The hosted OAuth wrapper itself controls access to its loopback child.
GET /oauth/github/callback
POST /oauth/github/webhooks
Required GitHub App events:
github_app_authorization
installation
installation_repositories
The full permission matrix for the current tools is in docs/github-app-permissions.md.
PORT=3000
HOST=0.0.0.0
SERVER_TOKEN=<existing-private-mcp-token>
GITHUB_TOKEN=<existing-owner-github-token>
PUBLIC_BASE_URL=https://<public-host>
OAUTH_RESOURCE_URL=https://<public-host>/mcp
OAUTH_ISSUER=https://<authorization-host>
OAUTH_AUTHORIZATION_SERVERS=https://<authorization-host>
OAUTH_CLIENT_ID=chatgpt-purr-git
OAUTH_ALLOWED_REDIRECT_URIS=<exact-chatgpt-callback>
OAUTH_STORE_PATH=/var/lib/purr-github-mcp/oauth-store.json
GITHUB_APP_CLIENT_ID=<github-app-client-id>
GITHUB_APP_CLIENT_SECRET=<github-app-client-secret>
GITHUB_APP_CALLBACK_URL=https://<public-host>/oauth/github/callback
GITHUB_APP_WEBHOOK_SECRET=<github-app-webhook-secret>Use a persistent volume for OAUTH_STORE_PATH. Independent encryption and cookie keys are recommended:
OAUTH_ENCRYPTION_KEY=<base64-encoded-32-byte-key>
OAUTH_COOKIE_KEY=<base64-encoded-32-byte-key>
OAUTH_SECRET_SOURCE=<independent-secret-source>Partial GitHub App configuration fails at startup rather than silently downgrading.
Existing controls apply regardless of whether a request uses the owner credential or a GitHub user credential.
Direct commits are blocked by default on:
main, master, production, staging, release
New branches must use an approved prefix such as:
feat/, fix/, docs/, chore/, refactor/, test/, perf/
Write tools enforce repository policy, file-count and byte limits, dangerous-path blocking, secret-like content detection, and operation-specific controls. Large and binary writes remain available only through the bounded tools intended for them.
npm run checkThe suite covers:
- ChatGPT PKCE and refresh rotation
- GitHub callback binding and replay rejection
- encrypted user credentials and user isolation
- user-token versus owner-token routing
- concurrent GitHub refresh serialization
- signed authorization revocation
- installation lifecycle tracking
- scope-filtered tool dispatch
- legacy compatibility
- 40-tool smoke parity
- large commits, annotations, and secret blocking
Docker:
docker build -t purr-github-mcp .
docker run --rm -p 3000:3000 --env-file .env purr-github-mcpManufact and process-runner deployments use:
npm install --omit=dev
npm startSee docs/manufact.md for deployment and docs/chatgpt-oauth.md for GitHub App setup, acceptance checks, and rollback.
Purr-github-MCP/
├── src/server.js # existing GitHub MCP tools and guards
├── src/oauth-wrapper.js # public OAuth and routing entrypoint
├── src/oauth/ # durable ChatGPT OAuth primitives
├── src/github-auth/ # GitHub App identity and lifecycle adapter
├── scripts/ # OAuth, routing, lifecycle, and smoke tests
├── docs/ # architecture, permissions, and deployment
├── Dockerfile
├── Procfile
└── package.json
MIT
Contributions are welcome and appreciated! 🐾
- 📖 Read the Contributing guide and Code of Conduct.
- 🌱 New here? Look for
good first issue. - 💬 Ideas & questions → Discussions.
purr-github-mcp · mcp · model-context-protocol · mcp-server · github · github-api · github-app · octokit · oauth · pkce · ai-agents · coding-agents · chatgpt-connector · codex · nodejs · automation · pull-requests · devtools · self-hosted