GitHub MCP Gateway
A read-only GitHub MCP server that can read repositories, branches, files, code search, commits, pull requests, reviews, issues, comments, Actions runs and artifacts, and organization members, scoped to the repositories where the GitHub App is installed.
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 Gatewayshow me open pull requests"
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 Gateway
A read-only GitHub MCP server that you deploy to your own Cloudflare account. It can read only the repositories where you install your GitHub App, and only the GitHub accounts you list can connect to it.
One MCP tool,
github, with 32 read operations covering repositories, branches, files, code search, commits, pull requests, reviews, issues, comments, Actions runs and artifacts, and organization members.No write operations. The GitHub App gets read permissions only.
Every response has a fixed size limit. Long files and lists come back in pages, each with the exact request for the next page.
Works with MCP clients that support remote servers with OAuth sign-in, such as Claude, Claude Code, Cursor, and VS Code.
Runs on the Cloudflare Workers Free plan.
Setup
You need a Cloudflare account and a GitHub account. Steps 1 to 3 collect the values that the deploy form in step 4 asks for. To deploy from your own machine with Wrangler instead of the deploy button, follow docs/setup.md.
1. Work out the Worker's address
The Worker is named github-mcp by default, so its address is:
https://github-mcp.<your-subdomain>.workers.devYour workers.dev subdomain is shown on the Workers & Pages page of the Cloudflare dashboard. If you give the Worker a different name in step 4, use that name here.
2. Create a GitHub App
The links below create a private app. A private app can be installed only on the account that owns it, so create it under the account whose repositories the server should read. If other people will sign in, create it under an organization they belong to: only members of the owning organization can sign in to an organization's private app.
Open the GitHub App form with this project's settings filled in:
For an organization: replace
YOUR-ORGin the address bar with the organization's name.
On the form:
Enter a GitHub App name. It must not already be in use on GitHub.
In Callback URL, replace
YOUR-SUBDOMAINwith your subdomain from step 1. If you chose a different Worker name, replacegithub-mcpas well.Leave Expire user authorization tokens checked and Request user authorization (OAuth) during installation unchecked.
Check that webhooks are off and that every permission is read-only: Actions, Commit statuses, Contents, Issues, Metadata, and Pull requests under Repository permissions, and Members under Organization permissions.
Click Create GitHub App.
On the new app's settings page:
Copy the App ID and the Client ID.
Under Client secrets, click Generate a new client secret and copy it.
Under Private keys, click Generate a private key. Your browser downloads a
.pemfile.Click Install App and choose the repositories this server may read. The installation is the server's only repository access list.
3. Generate two random keys
Run this twice and keep both results:
openssl rand -hex 32If you don't have a terminal, paste this into your browser's developer console instead, once for each key:
crypto.getRandomValues(new Uint8Array(32)).reduce((hex, byte) => hex + byte.toString(16).padStart(2, "0"), "")4. Deploy
Click Deploy to Cloudflare at the top of this page. Cloudflare copies this repository into your GitHub account, creates the KV namespace that stores OAuth grants, and asks for these secrets:
Secret | Value |
| Your GitHub username. Separate several usernames with commas. |
| The App ID from step 2 |
| The Client ID from step 2 |
| The client secret from step 2 |
| The whole |
| The first key from step 3 |
| The second key from step 3 |
Paste the private key exactly as GitHub provides it. If the form removes the line breaks, the Worker restores them, and it converts GitHub's PKCS#1 key format to the PKCS#8 format that its signing library requires on Workers. Delete the downloaded .pem file after the deploy; you can generate a new key in the app's settings if you need one later.
Deployment stops if any of the seven secrets is missing, and the build log lists which ones. If that happens, add them under Settings → Variables and Secrets on the Worker's page in the Cloudflare dashboard, then retry the build.
5. Connect a client
The MCP endpoint is:
https://github-mcp.<your-subdomain>.workers.dev/mcpThe first connection opens an approval page on the Worker. It shows the client's name and the address that will receive the access token. After you approve, you sign in with GitHub, and the Worker checks your username against AUTHORIZED_GITHUB_LOGINS. The browser remembers the approval for 30 days for that client and address.
Claude (web, desktop, and mobile): go to Customize → Connectors, click + Add → Add custom connector, and enter a name and the endpoint. On Team and Enterprise plans, an owner adds the connector under Organization settings → Connectors first.
Claude Code: run
claude mcp add --transport http github https://github-mcp.<your-subdomain>.workers.dev/mcp, then run/mcpinside Claude Code to sign in.Other clients: add the endpoint as a remote (HTTP) MCP server. A client that can only start local commands can use
mcp-remote:npx mcp-remote https://github-mcp.<your-subdomain>.workers.dev/mcp.
To check that the Worker is running, open /health on the Worker's address. It returns {"status":"ok"}. If connecting fails, see Troubleshooting.
Related MCP server: github-mcp
How access works
Three separate checks decide what a client can read:
Which client gets a token. MCP clients register themselves, so the Worker asks you to approve each client and redirect address before it starts a sign-in. Without this step, a page that a signed-in user visits could start a sign-in for a client that the attacker controls. GitHub skips its own prompt after the first approval, so it does not give this protection.
Who can connect. Sign-in uses GitHub's user authorization for your GitHub App. The Worker uses the resulting user token once, to look up the GitHub username, and then discards it. Only usernames in
AUTHORIZED_GITHUB_LOGINSreceive an MCP access token, and the Worker checks the list again on every request.What can be read. Every GitHub read uses a short-lived installation token for your GitHub App, so the server can read exactly the repositories in the app's installation. The Worker keeps no second repository list.
Continuation tokens are bound to the GitHub user ID of the person who signed in. The server has no write operations.
To change access later:
Add or remove repositories in the GitHub App's installation settings.
Change who can connect by updating the
AUTHORIZED_GITHUB_LOGINSsecret. A removed username is refused on its next request, even if its client still holds a token.Remove all repository access by uninstalling the GitHub App.
Rotate the app's private key and client secret in its settings, then update the matching Worker secrets.
Using the github tool
The tool takes one of three actions. Agents should call execute directly when they know the operation and its arguments:
{"action":"execute","operation":"list_pull_request_comments","arguments":{"repository_full_name":"owner/repo","pr_number":42}}search finds operations by keyword. It returns 8 concise signatures by default and at most 20:
{"action":"search","query":"pull request comments"}describe returns the full input and result schemas for one operation. Use it only when a signature is not enough:
{"action":"describe","operation":"list_pull_request_comments"}The server never requires search or describe before execute. Operation names, arguments, and results use snake_case. A successful call returns:
{"ok":true,"operation":"fetch_file","data":{}}A failed call sets MCP isError and returns a JSON error object with a code such as not_found, forbidden, invalid_arguments, rate_limited, or range_too_large, a message, a request_id, and a retryable flag. When a GitHub request fails, the message is a fixed description of the failure, not GitHub's response text.
Limits and paging
A complete result is at most 20,000 UTF-8 bytes, and inline text is at most 16,000 bytes. The server never substitutes a truncated preview.
A file read without an end line returns
state: "partial"and an exactnext_requestwhen more text remains. A line range that is too large returnsrange_too_large, and a single line over 16,000 bytes returnsline_too_large.Long text (issue and pull request bodies, comments, review bodies, commit messages, and patches) is read with the
read_textoperation and areference_token. Comment and review lists return metadata and tokens instead of every body.Standard lists return at most 20 items per page, comment and review lists at most 10, and directory listings at most 50 entries.
The server stops a tool call after 20 GitHub requests. The GitHub client library can repeat a request after a server error or a rate-limit response, and those repeats are not counted. File reads scan at most 64 KiB at a time.
Files of 1 MiB or less are read through the GitHub Contents API. Larger files, and small files whose inline content GitHub omits, are read in byte ranges from GitHub's signed download URL. Files over 100 MiB return metadata only, with
content_available: false. Those range requests use a direct TLS connection toraw.githubusercontent.com, because a Worker'sfetchasks GitHub for a compressed response even when told not to, and compression breaks byte ranges. The installation token is never sent to the download URL.Workflow job logs are not supported.
Reading by URL
The fetch operation maps a GitHub URL to one of the read operations above. It accepts these HTTPS URL forms:
github.com: a repository, its issue list, an issue, a pull request, a commit, a branch (/tree/<branch>, for branch names without a slash), a file (/blob/<ref>/<path>), or a workflow runapi.github.com/repos/<owner>/<repo>: the repository,contents(the root directory) orcontents/<path>(a file),issuesorissues/<number>,pulls/<number>,commits/<sha>,branches/<branch>, oractions/runs/<id>raw.githubusercontent.com/<owner>/<repo>/<ref>/<path>: a file
For other directories, call list_directory. fetch rejects user information, custom ports, URL fragments, path traversal, encoded separators, and unsupported query parameters. Query values, such as per_page on an issue list, must meet the same limits as a direct call.
fetch is the only operation that can fall back to an unauthenticated read of a public resource outside the installation. Only the first page of such a read is available, because each next_request uses the GitHub App's installation. GitHub allows 60 unauthenticated requests per hour per source IP, and that limit is shared by every request from the same IP.
Workflow artifacts
download_workflow_artifact returns metadata and an MCP resource_link to the complete ZIP file. Not every MCP client fetches resource links automatically.
The link expires after five minutes. Until then, anyone who has the link can download the artifact without signing in, so keep it out of logs, tickets, chat messages, and analytics. The artifact route accepts only GET and HEAD, and it responds with Cache-Control: no-store, Referrer-Policy: no-referrer, and X-Content-Type-Options: nosniff. Cloudflare invocation logs are turned off in wrangler.jsonc because artifact request URLs contain the link token. The Worker's own logs record only the operation, status, request ID, and error category.
Continuation tokens and artifact links are encrypted with AES-256-GCM under REFERENCE_TOKEN_KEY. Each token's purpose and operation are bound as additional authenticated data, so a token issued for one operation cannot be used with another. Changing the key invalidates all outstanding tokens and links.
GitHub App permissions
The app needs these read-only permissions and no webhooks:
Repository: Actions, Commit statuses, Contents, Issues, Metadata, Pull requests
Organization: Members
Every REST request specifies GitHub API version 2026-03-10.
Development
Requirements: Node 22 or newer and Yarn 1.22.
yarn install
yarn type-check
yarn lint
yarn test
yarn buildTests use fake identities and mocked GitHub services. To run the Worker on your machine, see Local development. docs/future-patch-reconstruction.md describes a possible design for rebuilding the patches that GitHub omits from commit and pull request responses.
Security
Report vulnerabilities privately as described in SECURITY.md.
License
This server cannot be deployed
Maintenance
Related MCP Connectors
Cloudflare Workers MCP server: graphql-rest-bridge
Cloudflare Workers MCP server: api-composition-gateway
MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.
Remote streamable-HTTP MCP server running on a single Cloudflare Worker. Your assistant gets live Airbnb, Amazon, Booking.com, Google Flights, Maps and Reddit data, social search on X, Instagram and TikTok, the Meta Ad Library, and image/video generation without any keys. Connect your own accounts to let it send WhatsApp or Telegram messages, work an IMAP inbox, manage Meta Ads campaigns and publish to X and LinkedIn. OAuth 2.1 with PKCE; stored credentials are AES-256-GCM encrypted.
Related MCP Servers
- FlicenseBqualityDmaintenanceA server that allows you to explore the GitHub GraphQL schema and execute GraphQL queries through MCP client tools, enabling efficient data retrieval from GitHub with reduced token consumption.44-
- AlicenseNot gradedqualityDmaintenanceA production-ready MCP server providing all 26 official GitHub tools, deployed on Cloudflare Workers with GitHub OAuth 2.0 authentication.538 npmISC
- FlicenseNot gradedqualityCmaintenanceEnables GitHub repository operations (list/read files, create branches, commit files, open/list PRs) via an authless remote MCP server that keeps your GitHub token encrypted on Cloudflare, with access limited to allowed repositories.-
- AlicenseNot gradedqualityAmaintenanceA remote MCP server that gives MCP clients authenticated access to GitHub: repos, issues, pull requests, file contents, and search, over a proper OAuth 2.1 handshake. Runs on Cloudflare Workers.1Apache 2.0