GitHub MCP Server
Provides tools for working with GitHub repositories through the GitHub REST/GraphQL API: reading and editing files, committing and pushing changes (multi-file commits via the Git Data API), managing branches, tags, releases, pull requests (create, update, review, merge), issues, comments, labels and milestones, plus repository search, code review, and repository administration (create, delete, archive, transfer, settings, branch protection, collaborators).
Provides tools for managing GitHub Actions: listing workflow runs, reading run logs, and triggering, cancelling or re-running workflows and CI jobs, along with commit/PR CI status.
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
GitHub MCP Server for Claude (Cloudflare Workers)
A remote Model Context Protocol server that lets Claude work with GitHub in plain language — read and edit files, commit and push, manage branches, pull requests, issues, Actions, releases and more — without you running any git commands.
It runs on Cloudflare Workers (free plan is enough), authenticates to GitHub with your Personal Access Token stored as a Worker Secret, and connects to Claude as a custom connector.
npm install
npx wrangler login
npx wrangler secret put GITHUB_TOKEN
npm run deploy # prints your MCP endpoint URL — paste it into ClaudeContents
Related MCP server: GitHub MCP Server
1. How it works
Claude ──HTTPS (MCP, Streamable HTTP)──▶ Cloudflare Worker ──REST/GraphQL──▶ GitHub API
/mcp/<MCP_ACCESS_KEY> (this project) Bearer GITHUB_TOKENThere are two separate credentials:
Credential | Purpose | Where it lives | Who creates it |
| What the server may do on GitHub | Worker Secret | You (step 7) |
| Who may talk to this server | Worker Secret + the endpoint URL |
|
Why the access key? Claude's custom connector screen accepts a server URL (plus optional OAuth). Without protection, anyone who guessed your workers.dev URL could act on GitHub with your token. Instead of building OAuth infrastructure, the deploy script generates a 256-bit random key and puts it in the URL path (/mcp/<key>). That is the simplest mechanism that works with Claude's connector UI. Treat the full URL like a password.
Implementation highlights
Official Cloudflare Agents SDK
createMcpHandler(agents/mcp/server) with an MCP SDK v2 server (@modelcontextprotocol/server) — the stateless, currently recommended pattern. No Durable Objects, KV, databases or OAuth apps.Streamable HTTP transport. Serves both 2025-era clients (
initializehandshake, e.g.2025-06-18,2025-11-25) and the stateless2026-07-28protocol revision.148 tools in 15 toolsets, each with a Zod input schema (sent to Claude as JSON Schema), MCP tool annotations (
readOnlyHint,destructiveHint, …), structured results and actionable errors.GitHub REST API version
2026-03-10, GraphQL where REST has no equivalent (Discussions, blame, draft-PR toggles).Commits and pushes use GitHub's Git Data API (blobs → tree → commit → move branch ref): one commit for any number of files, fast-forward only, with conflict detection.
Retries for transient failures, automatic waiting on short rate-limit back-offs, clear reset times for long ones, and token redaction on every output path.
2. Prerequisites
Node.js 20 or newer (
node -v)A Cloudflare account (free): https://dash.cloudflare.com/sign-up
A GitHub account
A Claude plan with custom connectors (Free, Pro, Max, Team or Enterprise — Free is limited to one custom connector). On Team/Enterprise, an owner may need to add the connector in admin settings.
3. Install dependencies
cd github-mcp-server
npm install4. Create a GitHub Personal Access Token
A fine-grained token is recommended — you choose exactly which repositories and permissions it has.
Open https://github.com/settings/personal-access-tokens/new (GitHub → Settings → Developer settings → Personal access tokens → Fine-grained tokens → Generate new token).
Token name: e.g.
claude-mcp. Expiration: your choice (you can rotate later, see §16).Resource owner: your account, or an organization (the org may need to approve fine-grained tokens).
Repository access: All repositories, or Only select repositories for tighter control.
Set permissions (next section), then Generate token and copy it (it starts with
github_pat_). You will paste it in step 7.
A classic token (ghp_…, scopes such as repo, workflow, delete_repo, notifications, gist, read:org) also works and is required for the notifications tools, but it is broader and cannot be limited to specific repositories.
5. Choose token permissions
Grant only what you need. Read-only permissions are enough for reading code, searching and reviewing; a read-only token cannot create, edit, commit, merge or delete anything — those calls return a 403 with a hint telling Claude which permission is missing (GitHub's X-Accepted-GitHub-Permissions header is passed through as accepted_permissions).
Recommended starting set (fine-grained, repository permissions)
Permission | Level | Needed for |
Metadata | Read (always on) | Everything |
Contents | Read and write | Read/write files, commits, branches, tags, releases, merges, compare |
Pull requests | Read and write | Create/update/review/merge PRs |
Issues | Read and write | Issues, comments, labels, milestones |
Workflows | Read and write | Only if Claude should edit files under |
Actions | Read and write | List runs, read logs (read); trigger, cancel, re-run (write) |
Commit statuses | Read | CI status on commits/PRs |
Optional, add only if you want the feature
Permission | Level | Needed for |
Administration | Read and write | Create (in orgs)/delete/archive/transfer repositories, settings, branch protection, collaborators, branch rename |
Webhooks | Read and write | Webhook tools |
Discussions | Read and write | Discussions tools |
Checks | Read | Check runs in CI status (if your token type offers it; otherwise only commit statuses are shown) |
Account → Gists | Read and write | Gist tools |
Organization → Members | Read | Organization members and teams |
Creating a repository in your personal account works with All repositories access plus Administration: write. Notifications are only available to classic tokens (GitHub limitation).
6. Log in to Cloudflare
npx wrangler loginA browser window opens; approve access. (npx wrangler whoami shows the logged-in account.)
7. Add GITHUB_TOKEN as a Worker Secret
npx wrangler secret put GITHUB_TOKENPaste the token when prompted (input is hidden). If Wrangler says the Worker doesn't exist yet and asks to create it, answer Y. The token is encrypted by Cloudflare, never stored in this project, never logged and never returned by any tool.
8. Deploy
npm run deployThis runs scripts/deploy.mjs, which:
checks you are logged in to Cloudflare,
runs
wrangler deployand reads the real Worker URL from Wrangler's output,checks that
GITHUB_TOKENis set (and tells you if not),creates the
MCP_ACCESS_KEYsecret the first time (random 256-bit key) and saves your endpoint in.mcp-connection.json(git-ignored, readable only by you),calls the live endpoint: health check → MCP
initialize→get_authenticated_user, so you can see that the transport and your GitHub token work,prints your MCP endpoint.
The first deploy on a brand-new Cloudflare account may ask you to choose a workers.dev subdomain.
9. Find your MCP endpoint
It is printed at the end of npm run deploy, and you can show it again at any time:
npm run endpointIt looks like https://github-mcp-server.<your-subdomain>.workers.dev/mcp/<long-random-key> — the host comes from your Cloudflare account; nothing is hard-coded. Opening the Worker's root URL (https://github-mcp-server.<your-subdomain>.workers.dev/) in a browser shows a status page (no secrets) with the tool count and whether the token is configured.
10. Connect it to Claude
Claude (web, desktop, mobile)
Open Settings → Connectors (called Customize → Connectors in some versions of the desktop app). On Team/Enterprise, an owner can add it for the organization under Admin settings → Connectors.
Click Add custom connector.
Name:
GitHub. Remote MCP server URL: paste the full endpoint from step 9. Leave the OAuth fields empty.Click Add. Claude connects and lists the tools.
In a chat, open the + menu → Connectors and make sure the connector is enabled for that conversation.
Claude reaches the server from Anthropic's cloud, so the Worker must be deployed (a localhost URL will not work here). Claude asks for your approval before using tools; write and destructive tools are marked as such.
Claude Code (supports headers, so the key can stay out of the URL):
claude mcp add --transport http github https://github-mcp-server.<sub>.workers.dev/mcp \
--header "Authorization: Bearer <MCP_ACCESS_KEY>"(or simply use the full /mcp/<key> URL without the header).
MCP Inspector (for testing): npx @modelcontextprotocol/inspector@latest, transport Streamable HTTP, URL = your endpoint.
11. Using the tools
Just ask. Examples that work out of the box:
You say | What Claude does |
"Create a private repository called my-project." |
|
"Find the repository with my portfolio website." |
|
"Create a branch called feature/dashboard." |
|
"Read the README from the main branch." |
|
"Create a TypeScript file under src/utils … commit it with 'Add dashboard utilities' and push to the feature branch." |
|
"Update this file with the code I provided." |
|
"Compare my feature branch with main." |
|
"Open a pull request into main." |
|
"Show me the latest commits." |
|
"Find all my repositories that use |
|
"Find and fix the bug in utils/date.ts." |
|
"Delete the obsolete config file." |
|
"Which of my repos haven't been updated in a year?" |
|
"Why did CI fail on PR #12?" |
|
Good to know:
Commit = push.
create_or_update_file,delete_file,commit_files,move_fileandrevert_commitcreate a commit and move the branch immediately. There is no local working copy and no separate push step.Default branch. When you don't name a branch, the repository's default branch is used.
New branch + commit in one step.
commit_fileswithbranch: "feature/x"andcreate_branch_from: "main".Destructive actions need confirmation. Deleting repositories/branches/refs/releases/webhooks/gists, archiving, transferring, force-moving refs and removing protection require a
confirmargument equal to the target's name. If Claude calls without it, the server refuses and explains what is needed — so Claude has to ask you first. (MCP elicitation isn't used because Claude's connectors don't support it yet.)Errors are explained. Every error includes
status, GitHub'smessageand ahint(e.g. "token lacks permission X", "branch moved, re-read and retry", "rate limit resets at …"), so Claude can decide what to do next.Large outputs are bounded. File reads, diffs and logs are truncated with a clear marker; use
start_line/end_line,per_page/pageor paths to narrow down.
12. Tool reference
148 tools. "needs confirm" = the tool refuses unless confirm matches the target (see above).
context (5)
Tool | What it does | Access |
| Return the GitHub account the server's token belongs to (login, name, plan) plus token information. | read |
| Show remaining GitHub API quota (core REST, search, code search, GraphQL) and when each resets. | read |
| Get public profile information for any GitHub user or organization by login. | read |
| Return GitHub instance metadata (API version info, SSH key fingerprints, and optionally the IP ranges GitHub uses for hooks, Actions, etc.). | read |
| Run a GitHub GraphQL query for data the other tools don't cover; mutations only with allow_mutation. | write ⚠️ destructive |
repos (15)
Tool | What it does | Access |
| List your repositories (or a user's/org's), sortable by last push — good for finding stale repos. | read |
| Get a repository's details and settings: default branch, visibility, merge settings, topics, license, your permissions, timestamps and URLs. | read |
| Return the languages used in a repository with byte counts and percentages. | read |
| Create a new repository for the authenticated user, or inside an organization when 'org' is set. | write |
| Fork a repository into your account or an organization. | write |
| Change repository settings: description, homepage, visibility, default branch, features (issues/wiki/projects/discussions) and merge options. | write |
| Replace all topics of a repository with the given list (pass an empty list to clear). | write |
| Archive (make read-only) or unarchive a repository. | write ⚠️ destructive (needs confirm) |
| Permanently delete a repository with all its code, issues, pull requests and releases. | write ⚠️ destructive (needs confirm) |
| Transfer a repository to another user or organization. | write ⚠️ destructive (needs confirm) |
| List users with access to a repository and their permission level. | read |
| List contributors to a repository sorted by number of commits. | read |
| Get the permission level (admin, maintain, write, triage, read, none) a user has on a repository. | read |
| Invite a user to a repository (or change their permission). | write |
| Remove a user's access to a repository. | write ⚠️ destructive (needs confirm) |
files (11)
Tool | What it does | Access |
| Read a file's text content from a repository at any branch, tag or commit (default: the default branch). | read |
| List files and folders directly inside a directory (non-recursive). | read |
| Return the repository's file tree (recursive) at a branch, tag or commit, optionally limited to a sub-directory. | read |
| Find files in ONE repository whose path matches a pattern. | read |
| Get a file's metadata without its content: blob sha, size, type, URLs and the last commit that changed it. | read |
| List the commits that changed a specific file or directory, newest first. | read |
| Show which commit last changed each line range of a file (git blame), via GitHub GraphQL. | read |
| Create a new file or replace an existing file's full content on a branch. | write |
| Delete a single file from a branch with a commit (pushed immediately). | write ⚠️ destructive |
| Create ONE commit that adds, updates and/or deletes any number of files, and push it to a branch (the branch on GitHub moves to the new commit immediately — this is the 'push'). | write |
| Rename/move a file — or a whole directory — within a repository in a single commit, preserving content exactly (equivalent to 'git mv' + commit + push). | write |
git (15)
Tool | What it does | Access |
| List commits on a branch (default: default branch), newest first. | read |
| Get a commit's message, author, parents, stats and changed files with diffs. | read |
| Compare two refs (branches, tags or SHAs): shows whether head is ahead/behind base, the commits in head not in base, and the changed files/diff. | read |
| Create a new commit that undoes a previous (non-merge) commit, like 'git revert', and push it to a branch (or to a new branch for a pull request). | write |
| Get the combined CI result for a commit/branch: commit statuses and GitHub check runs (Actions etc.) with an overall passing/failing/pending verdict. | read |
| List git references matching a prefix, e.g. | read |
| Get what a single reference points to, e.g. | read |
| Create a branch or tag reference pointing at a commit SHA. | write |
| Point a branch/tag reference at another commit. | write ⚠️ destructive (needs confirm) |
| Delete a branch or tag reference. | write ⚠️ destructive (needs confirm) |
| Read a git blob (file content) by its SHA. | read |
| Low-level: store file content as a git blob and get its SHA, for use with create_tree. | write |
| Read a git tree object by tree SHA, commit SHA or branch name. | read |
| Low-level: create a tree object. | write |
| Low-level: create a commit object from a tree SHA and parent SHAs. | write |
branches (10)
Tool | What it does | Access |
| List a repository's branches with their head commit SHA and whether they are protected. | read |
| Get a branch's head commit (SHA, message, author, date) and protection state. | read |
| Create a new branch from another branch, tag or commit (default: the repository's default branch). | write |
| Rename a branch. | write |
| Delete a branch. | write ⚠️ destructive (needs confirm) |
| Merge a branch/commit directly into a base branch without a pull request (creates a merge commit on base, or fast-forwards nothing if already merged). | write |
| Update a branch of a forked repository with the latest changes from the upstream (parent) repository, like the 'Sync fork' button. | write |
| Show branch protection settings (required reviews, status checks, admin enforcement, force-push/deletion rules). | read |
| Create or replace classic branch protection for a branch. | write ⚠️ destructive |
| Remove classic branch protection from a branch. | write ⚠️ destructive (needs confirm) |
pulls (16)
Tool | What it does | Access |
| List pull requests in a repository, filtered by state, base branch or head branch. | read |
| Get a pull request's description, state, head/base branches and SHAs, mergeability, review requests and change stats. | read |
| Open a pull request to merge 'head' into 'base' (e.g. | write |
| Edit a pull request's title, body or base branch, or close (state 'closed') / reopen (state 'open') it. | write |
| Merge a pull request using 'merge', 'squash' or 'rebase'. | write |
| Get the complete unified diff of a pull request as text (truncated for very large PRs; use list_pull_request_files for per-file patches). | read |
| List the files a pull request changes with additions/deletions and optional per-file patches. | read |
| List the commits included in a pull request (oldest first). | read |
| Get the CI status (check runs and commit statuses) for a pull request's latest head commit, with an overall passing/failing/pending verdict. | read |
| Submit a review: APPROVE, REQUEST_CHANGES (body required) or COMMENT, optionally with inline comments on specific lines. | write |
| List the review history of a pull request: who approved, requested changes or commented, and when. | read |
| List inline (line-level) review comments on a pull request, including the file path, line and the comment thread they belong to. | read |
| Add a single inline comment on a line of a pull request's diff, or reply to an existing review comment (in_reply_to). | write |
| Request reviews on a pull request from users and/or teams (team slugs). | write |
| Merge the latest base branch into the pull request's head branch (the 'Update branch' button). | write |
| Mark a draft pull request as ready for review (draft: false), or convert a pull request back to a draft (draft: true). | write |
issues (20)
Tool | What it does | Access |
| List issues in a repository filtered by state, labels, assignee, creator or update time. | read |
| Get an issue's full details including its body. | read |
| Create a new issue. | write |
| Edit an issue: title, body, close/reopen (state), close reason, labels (REPLACES all labels), assignees (REPLACES all) or milestone. | write |
| Add assignees to an issue or pull request (keeps existing assignees). | write |
| Remove assignees from an issue or pull request. | write |
| Add labels to an issue or pull request (keeps existing labels). | write |
| Remove one label from an issue or pull request. | write |
| List the conversation comments on an issue or pull request (oldest first). | read |
| Add a comment to an issue or a pull request's conversation (use the PR number as issue_number). | write |
| Replace the text of an existing issue/PR conversation comment. | write |
| Delete an issue/PR conversation comment by its comment ID (from list_issue_comments). | write ⚠️ destructive |
| List the labels defined in a repository (name, color, description). | read |
| Create a repository label that can then be added to issues and pull requests. | write |
| Rename a label or change its color/description. | write |
| Delete a label from the repository (it is removed from all issues and PRs). | write ⚠️ destructive |
| List milestones with their open/closed issue counts and due dates. | read |
| Create a milestone. | write |
| Change a milestone's title, description, due date, or close/reopen it. | write |
| Delete a milestone (issues keep existing but lose the milestone). | write ⚠️ destructive |
discussions (6)
Tool | What it does | Access |
| List a repository's discussion categories with their IDs (needed by create_discussion). | read |
| List discussions in a repository, newest first, optionally in one category. | read |
| Get a discussion's body and its comments (with replies). | read |
| Create a new discussion in a category (get category_id from list_discussion_categories). | write |
| Add a comment to a discussion, or reply to an existing comment (reply_to_comment_id from get_discussion). | write |
| Close a discussion (reason RESOLVED, OUTDATED or DUPLICATE) or reopen it. | write |
search (7)
Tool | What it does | Access |
| Search GitHub repositories by name, description, topic, language, owner, stars, etc. | read |
| Search file CONTENTS across GitHub (default branches only, files under 384 KB). | read |
| Search commit messages and metadata. | read |
| Search issues across repositories (pull requests excluded automatically). | read |
| Search pull requests across repositories. | read |
| Search GitHub users/organizations. | read |
| Search GitHub topics (the tags repositories use), e.g. | read |
actions (14)
Tool | What it does | Access |
| List the GitHub Actions workflows defined in a repository (name, file path, state). | read |
| Get a workflow's details (ID, name, path, state). | read |
| Trigger a workflow that has an 'on: workflow_dispatch' trigger, on a branch or tag, with optional inputs. | write |
| List recent workflow runs for the whole repository or one workflow, filtered by branch, event, status (e.g. | read |
| Get the status and conclusion of a workflow run, plus a summary of its jobs. | read |
| List the jobs (with steps) of a workflow run. | read |
| Get one job's status, conclusion, runner and steps. | read |
| Download the log output of one workflow job (last tail_lines lines by default, since errors are usually at the end). | read |
| For a workflow run, find the failed jobs and return the tail of each one's log — the quickest way to see why CI failed. | read |
| Cancel a queued or in-progress workflow run. | write |
| Re-run a completed workflow run — all jobs, or only the failed ones (only_failed: true). | write |
| Re-run one job of a workflow run (and jobs that depend on it). | write |
| List the artifacts a workflow run uploaded (name, size, expiry). | read |
| Enable or disable a workflow so it does or does not run on its triggers. | write |
releases (12)
Tool | What it does | Access |
| List releases (including drafts if you have push access), newest first. | read |
| Get a release with its notes and assets — by release_id, by tag, or the latest published release (omit both). | read |
| Create a release for a tag. | write |
| Edit a release's tag, title, notes, draft/prerelease flags. | write |
| Publish a draft release (makes it public and notifies watchers). | write |
| Delete a release and its uploaded assets (the git tag is kept unless delete_tag is true). | write ⚠️ destructive (needs confirm) |
| List the files (assets) attached to a release, with download URLs. | read |
| Attach a file to a release. | write |
| Delete a file attached to a release. | write ⚠️ destructive (needs confirm) |
| List the repository's git tags with the commit each points to. | read |
| Inspect a tag reference: whether it is lightweight or annotated, the tagger and message (annotated), and the commit it points to. | read |
| Create a git tag on a commit/branch (default: default branch head). | write |
webhooks (5)
Tool | What it does | Access |
| List a repository's webhooks (target URL, events, active, last delivery result). | read |
| Create a webhook that POSTs repository events to a URL. | write |
| Change a webhook's URL, events, content type, secret or active state. | write |
| Send a 'ping' event to a webhook to test delivery. | write |
| Delete a repository webhook. | write ⚠️ destructive (needs confirm) |
gists (5)
Tool | What it does | Access |
| List your gists, or another user's public gists. | read |
| Get a gist with the content of its files (files over ~1 MB are truncated; use raw_url). | read |
| Create a gist with one or more files. | write |
| Update a gist's description or files. | write |
| Delete a gist permanently. | write ⚠️ destructive (needs confirm) |
notifications (2)
Tool | What it does | Access |
| List your GitHub notifications (review requests, mentions, assignments, CI…), optionally for one repository. | read |
| Mark one notification thread (thread_id), all notifications in a repository (owner+repo), or all notifications as read. | write |
orgs (5)
Tool | What it does | Access |
| List organizations the authenticated user belongs to (fine-grained tokens only see organizations they were granted access to). | read |
| Get an organization's profile and settings visible to you. | read |
| List members of an organization, optionally filtered by role. | read |
| List teams in an organization (slug, name, privacy). | read |
| List the repositories an organization team has access to. | read |
13. Configuration
Non-secret settings live in wrangler.jsonc → vars. Change them and run npm run deploy again.
Variable | Default | Meaning |
|
| Comma-separated toolsets to expose, e.g. |
|
|
|
|
| For GitHub Enterprise Server use |
|
|
|
Tool list size. All 148 tool definitions add up to about 136 KB of JSON (roughly 35k tokens of Claude's context). If you mostly do code work, a smaller set such as GITHUB_TOOLSETS="repos,files,git,branches,pulls,issues,search" (99 tools, ~98 KB) keeps the context leaner.
Workers Free CPU limit. The free plan allows 10 ms of CPU per request. Tool calls use a few ms, but answering tools/list with all 148 tools measured about 9 ms in a local benchmark (JSON Schemas are pre-built once per isolate to keep this low) — close to the limit. If the connector ever fails to load its tools with Cloudflare error 1102 ("Worker exceeded resource limits"), either narrow GITHUB_TOOLSETS as above or switch the account to Workers Paid ($5/month, 30 s default CPU).
Secrets:
Secret | Set with |
|
|
| created by |
14. Security model
Token storage.
GITHUB_TOKENis a Cloudflare Worker Secret. It is only ever placed in theAuthorizationheader of requests to the GitHub API host. It is never logged; error messages and tool results pass through a redaction filter that removes the token and anything token-shaped. Signed log-download URLs that GitHub redirects to are fetched without the token.Endpoint protection. Requests without the correct
MCP_ACCESS_KEYget401; if the key secret is missing, the endpoint fails closed (503). Keys are compared in constant time. The key travels in the URL path (over HTTPS); it can appear in your own Cloudflare request logs, which only your account can see. Rotate it withnpm run rotate-keyif it leaks.Least privilege. Use a fine-grained token limited to the repositories Claude should touch, with the permissions in §5. Consider
GITHUB_READ_ONLY=truefor review-only use.Destructive operations require explicit confirmation values and are annotated
destructiveHint: true; the default branch can't be deleted; ref updates are fast-forward only unless forced with confirmation;commit_filesrefuses to overwrite a branch that moved meanwhile.Input validation. Every tool validates arguments (owner/repo/path/SHA formats, enums, sizes) before calling GitHub; path traversal segments (
..) are rejected.Browser access. The SDK handler validates
Origin/Hostheaders (DNS-rebinding protection); Claude's server-side requests are unaffected.
15. Troubleshooting
Symptom | Fix |
|
|
Deploy output has no URL | Find the Worker in the Cloudflare dashboard → Workers & Pages, then |
Error |
|
| Token expired/revoked or mistyped. Create a new one and run |
| Add that permission to the fine-grained token (and make sure the repository is selected). Org repos may also need the org to approve the token or SSO authorization. |
| Fine-grained token doesn't include that repository, or the name is wrong. GitHub returns 404 (not 403) for private repos the token can't see. |
Claude: "couldn't connect" / 401 from the endpoint | The URL must include |
| You deployed from another computer. Reuse your old URL, or |
Endpoint returns | Run |
| Wait until the reset time shown. Code search is limited to ~10 requests/minute. |
| Someone pushed in the meantime or the |
Can't edit | Give the token Workflows: write (classic: |
Notifications tools return 403 | GitHub supports them only for classic tokens. |
Check the live server end-to-end |
|
Connector fails to list tools, logs show error 1102 / "exceeded resource limits" | Workers Free CPU limit (10 ms). Set a smaller |
See server logs | Cloudflare dashboard → Workers & Pages → github-mcp-server → Logs, or |
16. Updating and redeploying
Change code or settings: edit, then
npm run deploy. The endpoint URL stays the same.Update dependencies:
npm update && npm run check && npm run deploy.Rotate the GitHub token: create a new token,
npx wrangler secret put GITHUB_TOKEN. Takes effect immediately; nothing to change in Claude.Rotate the endpoint key:
npm run rotate-key, then update the URL in Claude's connector settings.Remove everything:
npx wrangler delete, delete the connector in Claude, and revoke the token on GitHub.
17. Development and tests
cp .dev.vars.example .dev.vars # put a token and any local key in it
npm run dev # http://localhost:8787/mcp/<MCP_ACCESS_KEY from .dev.vars>
npm run smoke -- --endpoint=http://localhost:8787/mcp/<key>
npm run check # typecheck + tests + wrangler bundle dry-runAutomated tests (npm test, Vitest) need no network or token. A real MCP SDK client talks to the Worker's fetch handler over Streamable HTTP, and the Worker talks to a scripted fake GitHub API. They cover: initialization on the 2025-06-18, 2025-11-25 and 2026-07-28 protocol revisions; tool discovery; access-key auth; read-only mode; reading/decoding files; create/update with automatic sha; multi-file commits incl. deletes, executable bits, new branches, and concurrent-push detection; moves; branch create/delete with confirmation; compare; PR create/merge; revert (success and conflict); invalid token, missing token, missing permissions, rate limits, retries; token redaction; and deploy URL parsing.
Project layout:
src/
index.ts Worker entry: routing, access-key check, createMcpHandler
server.ts Builds the MCP server, registers tools, formats results/errors
auth.ts MCP endpoint access key (constant-time compare)
config.ts Toolsets, read-only mode, API URLs
github/
client.ts REST/GraphQL client: retries, rate limits, pagination, redaction
gitops.ts Commit/push via Git Data API, tree helpers, globbing
compact.ts Trims verbose GitHub JSON for Claude
encoding.ts UTF-8 safe base64, binary detection
errors.ts Typed errors with hints
tools/ One file per area; each tool = name, description, Zod schema, handler
scripts/
deploy.mjs npm run deploy / endpoint / rotate-key
smoke-test.mjs npm run smoke (live end-to-end check)
test/ Vitest suites + fake GitHub + MCP client helpersAdding a tool: add a defineTool({...}) entry to the right file in src/tools/ (it is registered automatically), then add a test.
18. Limitations
No local git. Operations use GitHub's APIs. There is no clone, working tree, rebase, cherry-pick, stash, interactive staging,
git blame -C, submodule updates, or LFS uploads. Merges happen viamerge_branch/merge_pull_request(server-side), not locally.Revert works for non-merge commits touching fewer than 300 files, and refuses (changing nothing) if any affected file changed afterwards. Merge commits: use GitHub's "Revert" button on the PR.
Large repositories: tools that read the full tree (
search_files,get_repository_tree,move_file,revert_commit,commit_filessafety checks) depend on GitHub's recursive tree API, which truncates at very large sizes; the tools say so when it happens.File sizes: reads up to GitHub's 100 MB raw limit (output truncated for Claude); writes are limited by MCP request size — fine for source code, not for large binaries.
Search is GitHub search: default branches only for code search, max 1000 results, code search ~10 requests/minute.
Workflow run logs: per-job logs only (
get_job_logs,get_failed_job_logs); the zipped full-run archive and artifacts are not downloaded.Notifications require a classic token. Branch protection tools manage classic protection; repository rulesets are shown read-only.
Release asset uploads are limited by the MCP request size (a few MB is safe).
Cloudflare free plan allows 50 outbound requests and 10 ms CPU per request. Tools stay well below 50 GitHub calls (a multi-file commit uses about 7, plus one per base64/binary file, capped at 40); the full 148-tool list is close to the CPU limit (see §13).
Elicitation-based confirmation isn't used because Claude's connectors don't support it yet; confirmation is enforced through the
confirmargument plus Claude's own tool-approval prompts.
License
MIT
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
This server cannot be deployed
Maintenance
Related MCP Connectors
Connect AI assistants to GitHub - manage repos, issues, PRs, and workflows through natural language.
Operate GitHub from your AI assistant: repos, PRs, issues, Actions. Previews and read-only mode.
Access the GitHub API, enabling file operations, repository management, search functionality, and…
Connect AI assistants to your GitHub-hosted Obsidian vault to seamlessly access, search, and analy…
Related MCP Servers
- AlicenseNot gradedqualityNot gradedmaintenanceConnects Claude Desktop to GitHub repositories, enabling users to perform git operations and GitHub API interactions through natural conversation.443 npm-
- AlicenseNot gradedqualityNot gradedmaintenanceConnects Claude Desktop directly to GitHub repositories and git commands, enabling users to clone repos, check status, commit changes, push code, create repositories, and manage GitHub resources through natural conversation.443 npm-
- FlicenseNot gradedqualityDmaintenanceEnables to interact with GitHub repositories directly from Claude, supporting actions like viewing repos, checking status, committing and pushing changes, and managing pull requests.-
- AlicenseAqualityDmaintenanceEnables Claude to access and manage GitHub repositories dynamically at runtime, including private repos, with tools for browsing files, searching code, and viewing commits, pull requests, and issues.111ISC