A production-ready MCP (Model Context Protocol) bridge server that connects Claude Chat (claude.ai) to any GitHub repository. Claude can read files, write code, search code, batch-commit changes, and manage Issues directly from a conversation — all through a custom MCP connector using Streamable HTTP transport with OAuth 2.0 authentication.
V2: Multi-repo mode — no hardcoded repo. Claude passes owner and repo on every tool call. Lock Claude to a specific repo using a Claude Project system prompt (see Project Scoping below).
Claude Chat (claude.ai)
↕ MCP connector (Streamable HTTP + OAuth 2.0)
MCP Bridge Server (your host) — multi-repo mode
↕ GitHub REST API (Octokit)
Any GitHub Repo (files + Issues)
The server exposes a single /mcp endpoint that speaks the MCP protocol over Streamable HTTP. Claude.ai connects to this endpoint using OAuth 2.0 Client Credentials, discovers the available tools, and calls them as needed during your conversation. In V2, the server is repo-agnostic — Claude specifies the target owner/repo on every tool call.
- A GitHub account with a repository you want Claude to manage
- A Claude Pro, Max, or Team plan (custom MCP connectors require a paid plan)
- A hosting platform that can run a Node.js server (Replit, Railway, Render, VPS, etc.)
git clone https://github.com/ioTus/gitbridge-mcp.git
cd gitbridge-mcp
npm install- Go to GitHub → Settings → Developer Settings → Personal Access Tokens → Tokens (classic)
- Click Generate new token (classic)
- Give it a descriptive name (e.g.
claude-mcp-bridge) - Select the
reposcope (file read/write, Issues, and repository metadata) and theprojectscope (Projects V2 board access) - Click Generate token and copy the value — you won't see it again
These credentials protect your MCP endpoint using industry-standard OAuth 2.0:
# Generate a random Client ID and Client Secret
OAUTH_CLIENT_ID=$(openssl rand -hex 16)
OAUTH_CLIENT_SECRET=$(openssl rand -hex 32)
echo "OAUTH_CLIENT_ID=$OAUTH_CLIENT_ID"
echo "OAUTH_CLIENT_SECRET=$OAUTH_CLIENT_SECRET"Save both values — you'll need them in the next step and when configuring Claude.
Create a .env file or set these in your hosting platform's secrets/environment panel:
| Variable | Required | Description |
|---|---|---|
GITHUB_PERSONAL_ACCESS_TOKEN |
Yes | GitHub PAT with repo and project scopes |
OAUTH_CLIENT_ID |
Yes | OAuth Client ID for authenticating MCP connections |
OAUTH_CLIENT_SECRET |
Yes | OAuth Client Secret (used to sign/verify JWT access tokens) |
ALLOWED_REPOS |
No | Comma-separated owner/repo pairs to restrict which repositories tools can access (e.g. ioTus/my-repo,ioTus/other-repo). If unset, all repos the PAT can reach are allowed. |
PORT |
No | Server port (default: 5000) |
The server will refuse to start if any required variable is missing. All three are mandatory — there is no unauthenticated mode.
V2 note:
GITHUB_OWNERandGITHUB_REPOenvironment variables are no longer used. The target repository is specified per tool call viaownerandrepoparameters.
On Replit: Click Run. The server starts automatically.
Locally or on other platforms:
npm run devThe server will start on port 5000 (or whatever you set PORT to). You should see:
[MCP] OAuth 2.0 Client Credentials authentication is ENABLED
[MCP] Token endpoint: /oauth/token
[MCP] MCP endpoint: /mcp
- Go to claude.ai → Settings → Integrations → Add More → Custom MCP connector
- Enter your server URL:
https://your-server-url.example.com/mcp - Open Advanced settings
- Set Client ID to your
OAUTH_CLIENT_IDvalue - Set Client Secret to your
OAUTH_CLIENT_SECRETvalue - Set Authorization URL to
https://your-server-url.example.com/oauth/token - Claude will authenticate using the Client Credentials flow and discover all tools automatically
In any Claude conversation, you can now say things like:
- "Read the file src/index.ts from the repo"
- "Create a new file called utils/helpers.ts with a debounce function"
- "List all open issues labeled 'bug'"
- "Create an issue titled 'Add dark mode support' with a description"
Claude will use the MCP tools to interact with your GitHub repo directly.
The server implements the OAuth 2.0 Client Credentials flow (RFC 6749). When Claude.ai connects:
- Claude POSTs to
/oauth/tokenwithclient_id,client_secret, andgrant_type=client_credentials - The server validates the credentials against
OAUTH_CLIENT_IDandOAUTH_CLIENT_SECRET - If valid, the server returns a signed JWT access token (HMAC-SHA256, expires in 1 hour)
- Claude includes the JWT as a
Bearertoken in theAuthorizationheader for all MCP requests - The server verifies the JWT signature and expiration on every request
- When the token expires, Claude automatically re-authenticates
No secrets are embedded in URLs. All authentication happens via standard HTTP headers.
- Your OAuth credentials control who can connect to the MCP server
- Your
GITHUB_PERSONAL_ACCESS_TOKENcontrols what the server can do on GitHub — the PAT's scope determines which repos Claude can access - Anyone with your OAuth credentials can use your GitHub PAT's permissions through the server
- In multi-repo mode, Claude can access any repo the PAT has permissions for — use Claude Project system prompts to constrain which repo Claude targets (see Project Scoping)
- Treat all tokens and secrets as confidential — never commit them to version control
Your GitHub PAT determines the blast radius — every repo the PAT can access is reachable through the MCP bridge. To minimize risk:
- Use fine-grained PATs (GitHub → Settings → Developer Settings → Fine-grained tokens) scoped to specific repositories whenever possible. This limits Claude to only the repos you explicitly grant access to, even if someone obtains your OAuth credentials.
- Use classic PATs with
repo+projectscopes if fine-grained tokens don't support your use case. Avoid grantingadmin,delete_repo, or other elevated scopes. - Create separate PATs per use case — e.g., one for your personal projects, another for work repos. Run separate bridge instances if needed.
- Rotate PATs regularly and revoke any that are no longer in use.
- The server requires
OAUTH_CLIENT_IDandOAUTH_CLIENT_SECRET— it will not start without them - Set
ALLOWED_REPOSto restrict which repositories can be accessed through the bridge (e.g.ALLOWED_REPOS=ioTus/my-repo,ioTus/other-repo) - Use a GitHub PAT with the minimum required scopes (
repo+project) - Rotate credentials periodically
- Audit your PAT's repository access periodically at GitHub → Settings → Developer Settings → Personal Access Tokens
All tools accept owner and repo as required parameters. Write tools prefix their responses with ✅ Writing to: {owner}/{repo}.
| Tool | Description |
|---|---|
read_file |
Read the contents of a file from a GitHub repository |
write_file |
Create or update a single file in a GitHub repository |
push_multiple_files |
Create or update multiple files in a single commit using the Git Data API |
list_files |
List files and folders at a path in a GitHub repository |
| Tool | Description |
|---|---|
create_issue |
Create a new GitHub Issue in a repository |
update_issue |
Update an existing GitHub Issue (change status, labels, title, or body) |
list_issues |
List GitHub Issues in a repository with optional filters |
add_issue_comment |
Add a comment to an existing GitHub Issue |
read_issue |
Read the full body and comments of a GitHub Issue |
| Tool | Description |
|---|---|
search_files |
Search file contents across a GitHub repository using GitHub Code Search |
get_recent_commits |
Return recent commit history for a branch in a GitHub repository |
get_file_diff |
Show file changes between a commit SHA and a branch head (default: main). Returns changed files with status and patch content. |
| Tool | Description |
|---|---|
create_branch |
Create a new branch from an existing one |
list_branches |
List all branches in a GitHub repository |
| Tool | Description |
|---|---|
move_file |
Move or rename a file. Reads from old path, writes to new path, then returns a GitHub link for the user to manually delete the original. |
delete_file |
Delete a file from a GitHub repository. This is a destructive operation — the file will be permanently removed from the specified branch. |
queue_write |
Queue a file write for batch commit. Writes are held in server memory and flushed together when flush_queue is called. Queue resets if the server restarts. |
flush_queue |
Commit all queued writes for a repository in a single GitHub commit. Call queue_write first to add files to the queue. |
| Tool | Description |
|---|---|
create_repo |
Create a new GitHub repository on a personal account or within an organization |
| Tool | Description |
|---|---|
get_project_board |
Read a GitHub Projects V2 board — returns columns (status values) and the issues/PRs in each column |
move_issue_to_column |
Move an issue to a target column (status) on a GitHub Projects V2 board |
| Method | Path | Description |
|---|---|---|
POST |
/oauth/token |
OAuth 2.0 token endpoint (Client Credentials flow) |
POST |
/mcp |
MCP over Streamable HTTP (recommended) |
GET |
/mcp |
SSE stream for an existing Streamable HTTP session |
DELETE |
/mcp |
Close a Streamable HTTP session |
GET |
/sse |
Legacy SSE transport (MCP over SSE) |
POST |
/messages |
Message endpoint for legacy SSE transport |
GET |
/api/status |
Server status, tool registry, and auth status |
Since V2 uses multi-repo mode (no hardcoded GITHUB_OWNER/GITHUB_REPO), you should use Claude Project system prompts to control which repositories Claude targets. There are two approaches depending on your workflow:
The simplest and safest approach. Create a separate Claude Project for each repository, with a system prompt that locks Claude to that specific repo.
You are working exclusively in the GitHub repository:
owner=YOUR_USERNAME repo=YOUR_REPO
Pass these values on every tool call to the GitHub MCP bridge.
Never write to any other repository regardless of what the user asks.
If asked to work in a different repo, tell the user to switch to
the appropriate Claude Project for that repository.
## Session Startup (do this every conversation)
1. Read `IME.md` at the repo root — this is the spoke bootstrap
with repo identity and tool reference. Follow its hub pointer
to `ioTus/ime` for universal rules.
2. Read `IME-AGENTS.md` and `IME-AGENTS-replit.md` — these define the
multi-agent collaboration workflow.
3. Call `list_files` to confirm connectivity.
4. Check `IME-docs/plans/` for active plans (status: executing).
5. Check open Issues with `list_issues`.
6. Ask the user what they want to work on.
## Critical Rules (always active, even before reading IME.md)
- NEVER commit a file without showing the user the content first
and getting explicit approval.
- NEVER overwrite an existing file without reading the current
version first.
- NEVER delete a file without the user confirming the specific
file path.
- For all other rules, defer to IME.md and IME-AGENTS.md in the repo.
## Your Role
You are the PM and strategist for this project. You write plans,
specs, documentation, and issues. You do not own implementation
code — that belongs to Replit Agent. Propose technical ideas inside
plan docs and issue bodies, not as committed code files in Replit
Agent's protected directories (server/, client/, script/).
See IME.md for the spoke context and IME-AGENTS-replit.md
for workspace boundaries.
## Connection Failure Protocol
This lives here — not on the server — because when the bridge
is down, server-side instructions are unreachable.
### Degraded Mode (activate immediately on failure)
When any MCP tool call fails:
1. Announce: "Bridge is down. Switching to degraded mode —
all work will be staged here and pushed when it's back."
2. Draft all files/issues exactly as they'd appear in the repo.
Tag each with file path + commit message, or issue title + labels.
3. Maintain a queue manifest:
| # | Type | Path / Title | Status |
|---|------|-------------|--------|
4. Silent-retry bridge ONCE per new user message.
5. Continue working. Zero productivity loss.
Never skip approval. Never spam retries. Never lose the queue.
### Diagnose (on request, or if user wants to troubleshoot)
If the user asks why the bridge is down or wants to fix it:
1. Classify: auth error (handshake/PAT), timeout (server asleep),
connection refused (server down/URL wrong), 403 (PAT scopes),
404 (bad path/repo), rate limit (wait/retry)
2. Try `list_files` to confirm systemic vs. isolated failure
3. Report: what failed, what it means, ONE recommended fix
tailored to user's environment. Never a generic list.
4. Ask desktop or mobile BEFORE prescribing recovery steps.
- Desktop: remove/re-add connector in Settings → Connectors.
Check deployment is awake. Verify PAT not expired.
- Mobile: try claude.ai in mobile browser with "request
desktop site" to access Connectors. If inaccessible →
stay in degraded mode until desktop available.
- Either: visit server URL in browser to confirm it responds.
### Reconnection (exiting degraded mode)
When any MCP call succeeds after a period of degraded mode:
1. Announce: "Bridge is back online."
2. Display the full queue manifest.
3. Get single user approval to push everything.
4. Execute: files via push_multiple_files, issues via create_issue.
5. Confirm each item pushed successfully.
6. Clear the queue. Resume normal operations.
This approach is recommended for most users. Each project has clear boundaries, and there's no risk of cross-repo mistakes.
For power users who work across multiple repos in a single conversation. The system prompt defines Claude's role but doesn't lock to a specific repo. Instead, each repo self-documents through an IME.md file at its root.
You are a developer assistant with access to GitHub repositories via
the MCP bridge. You can work across multiple repos in a single session.
Before performing any operation on a repo, read its IME.md file
(if it exists) to pick up project-specific rules and context:
call read_file with owner=OWNER repo=REPO path=IME.md
Always confirm the target owner/repo before any write operation.
When switching between repos, announce the switch clearly.
## Session Startup (do this every conversation)
1. Ask the user which repo(s) they want to work with.
2. Read `IME.md` from each target repo — this is the spoke bootstrap
with repo identity and hub pointer. Follow the hub pointer for
universal rules.
3. Read `IME-AGENTS.md` and `IME-AGENTS-replit.md` from each target repo
(if they exist) for multi-agent collaboration context.
4. Call `list_files` on each repo to confirm connectivity.
5. Check `IME-docs/plans/` for active plans (status: executing).
6. Check open Issues with `list_issues`.
7. Ask the user what they want to work on.
## Critical Rules (always active, even before reading IME.md)
- NEVER commit a file without showing the user the content first
and getting explicit approval.
- NEVER overwrite an existing file without reading the current
version first.
- NEVER delete a file without the user confirming the specific
file path.
- For all other rules, defer to IME.md and IME-AGENTS.md in each repo.
## Your Role
You are the PM and strategist for these projects. You write plans,
specs, documentation, and issues. You do not own implementation
code — that belongs to Replit Agent. Propose technical ideas inside
plan docs and issue bodies, not as committed code files in Replit
Agent's protected directories (server/, client/, script/).
See IME.md in each repo for the spoke context and
IME-AGENTS-replit.md for workspace boundaries.
## Connection Failure Protocol
This lives here — not on the server — because when the bridge
is down, server-side instructions are unreachable.
### Degraded Mode (activate immediately on failure)
When any MCP tool call fails:
1. Announce: "Bridge is down. Switching to degraded mode —
all work will be staged here and pushed when it's back."
2. Draft all files/issues exactly as they'd appear in the repo.
Tag each with file path + commit message, or issue title + labels.
3. Maintain a queue manifest:
| # | Type | Path / Title | Status |
|---|------|-------------|--------|
4. Silent-retry bridge ONCE per new user message.
5. Continue working. Zero productivity loss.
Never skip approval. Never spam retries. Never lose the queue.
### Diagnose (on request, or if user wants to troubleshoot)
If the user asks why the bridge is down or wants to fix it:
1. Classify: auth error (handshake/PAT), timeout (server asleep),
connection refused (server down/URL wrong), 403 (PAT scopes),
404 (bad path/repo), rate limit (wait/retry)
2. Try `list_files` to confirm systemic vs. isolated failure
3. Report: what failed, what it means, ONE recommended fix
tailored to user's environment. Never a generic list.
4. Ask desktop or mobile BEFORE prescribing recovery steps.
- Desktop: remove/re-add connector in Settings → Connectors.
Check deployment is awake. Verify PAT not expired.
- Mobile: try claude.ai in mobile browser with "request
desktop site" to access Connectors. If inaccessible →
stay in degraded mode until desktop available.
- Either: visit server URL in browser to confirm it responds.
### Reconnection (exiting degraded mode)
When any MCP call succeeds after a period of degraded mode:
1. Announce: "Bridge is back online."
2. Display the full queue manifest.
3. Get single user approval to push everything.
4. Execute: files via push_multiple_files, issues via create_issue.
5. Confirm each item pushed successfully.
6. Clear the queue. Resume normal operations.
This approach requires more discipline but enables cross-repo workflows (e.g., coordinating changes across a frontend and backend repo). Every write tool response includes ✅ Writing to: {owner}/{repo} so you can always verify the target.
The server includes a web dashboard at the root URL. Unauthenticated visitors see only the server name, version, and status. Sign in with your OAuth credentials (OAUTH_CLIENT_ID / OAUTH_CLIENT_SECRET) to view:
- Connection details for setting up Claude's custom MCP connector
- Active MCP sessions
- Full tool registry with phase indicators
- Architecture diagram and setup instructions
- Runtime: Node.js with TypeScript
- MCP SDK:
@modelcontextprotocol/sdk(Streamable HTTP + SSE transports) - GitHub API: Octokit REST client
- Auth: OAuth 2.0 Client Credentials with HMAC-SHA256 signed JWTs
- Server: Express
- Frontend: React + Vite + Tailwind CSS + shadcn/ui
MIT