Connect GitHub to Claude: Full Setup and Scoping Guide

By Yanni Papoutsis | 11 min read | 2026-07-23

TL;DR: Connecting GitHub to Claude gives the model the ability to read repositories, search code, inspect issues and pull requests, and in some configurations write to them. The connection runs over MCP, and you authenticate with either a personal access token or a GitHub App installation. Choose fine-grained personal access tokens over classic ones, because classic tokens grant blanket access to everything your account can reach, which is almost never what you want. Grant the minimum permissions for the work at hand, start read-only, and add write scopes only when a specific workflow needs them. Store the token outside your config file and never commit it. Most setup failures are one of three things: a token without the right repository selected, a fine-grained token that has not been approved by the organisation owner, or a resource owner mismatch where the token belongs to your personal account but the repository belongs to an org. Rotate on any suspicion of exposure.

What does connecting GitHub to Claude actually give you?

Once connected, Claude can enumerate your repositories, read file contents, search across code, list and read issues and pull requests, and inspect commit history. With write permissions it can open issues, comment, create branches and open pull requests. The exact tool surface depends on which GitHub MCP server you use, but the shape is consistent.

The value is context. Instead of pasting file contents into a conversation, you point Claude at a repository and it reads what it needs. For a code review, it can pull the diff itself. For a bug hunt, it can search the codebase for the symbol you are chasing. That is a meaningful upgrade over copy and paste, and it is why this connector tends to be the first one people set up after the filesystem one described in set-up-desktop-commander.

The cost is access. You are handing an automated system a credential to your source code. That deserves the same care you would give a CI runner, which is the framing to hold throughout this guide.

Should I use a personal access token or a GitHub App?

Both work. They suit different situations.

Fine-grained personal access tokens are the right default for individual use. You select exactly which repositories the token can reach and exactly which permissions it holds on them. You set an expiry date. If the token leaks, the blast radius is bounded by those selections. This is the option to reach for when connecting your own account to your own machine.

Classic personal access tokens grant coarse scopes like repo, which means every repository your account can access, public and private, across every organisation you belong to. There is no per-repository selection. Avoid these unless you have a specific reason, and if you must use one, treat it as a high-value secret.

GitHub Apps are the right choice for anything shared or organisational. Permissions are declared by the app and granted per installation, tokens are short-lived, and the audit trail attributes actions to the app rather than to a human. The setup cost is higher. For a team-wide connector, that cost is worth paying.

The rest of this guide assumes a fine-grained personal access token, because that is what most readers need.

How do I create a properly scoped token?

Work through this deliberately. The temptation to tick every box is strong and every extra permission is a liability.

  1. Go to your GitHub account developer settings and create a new fine-grained personal access token.
  2. Set the resource owner. This is the step people get wrong. If the repository belongs to an organisation, the resource owner must be that organisation, not your personal account. A token owned by your personal account cannot see org repositories no matter what permissions you grant it.
  3. Set an expiry. Ninety days is a reasonable default. An expiry that you have to renew is a feature, because it forces a periodic review of whether the connector still needs to exist.
  4. Select repository access. Choose "only select repositories" and pick the specific repositories Claude needs. Do not choose "all repositories" for convenience.
  5. Set permissions. Start with these read-only grants:
  6. Contents: Read
  7. Metadata: Read (this is mandatory and is usually granted automatically)
  8. Issues: Read
  9. Pull requests: Read
  10. Add write permissions only if you have a concrete workflow that needs them. Contents: Read and write lets Claude commit. Pull requests: Read and write lets it open PRs. Both are useful and both are consequential.
  11. Generate the token and copy it once. GitHub shows it exactly one time.

If the resource owner is an organisation with fine-grained token policies enabled, the token will sit in a pending state until an owner approves it. A token in that state produces a connector that authenticates but sees nothing, which is a confusing failure mode covered in mcp-connector-troubleshooting.

How do I store the token safely?

The token is now the most sensitive string on your machine. Handle it accordingly.

Never paste it directly into a config file you might commit. Use an environment variable sourced from your OS keychain or a secrets manager:

# macOS: store the token in the keychain, once
security add-generic-password -a "$USER" -s "github-mcp-token" -w

# Retrieve it when you need it, never echo it into a shared terminal
security find-generic-password -a "$USER" -s "github-mcp-token" -w

Your MCP config then references a placeholder that you hydrate at install time rather than a literal:

{
  "mcpServers": {
    "github": {
      "command": "/absolute/path/to/github-mcp-server",
      "args": [],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "YOUR_GITHUB_TOKEN"
      }
    }
  }
}

A real fine-grained token looks roughly like github_pat_xxxxxxxxxxxxxxxxxxxxxx and a classic one like ghp_xxxxxxxxxxxx. Those are the shapes; never write the real thing into anything that gets shared, screenshotted, or version controlled.

The rules that matter:

This is the same posture applied to skills in skill-security-best-practices, and the reasoning is identical: least privilege, bounded lifetime, no secrets in artefacts.

How do I configure the connector?

The GitHub MCP server is available both as a remote hosted server and as something you run locally. The remote option uses OAuth and avoids handling a token yourself, which is the simpler path if your client supports it. The local option gives you full control over the process and the credential.

For a locally run server, the pattern is the same as any stdio MCP server. Point the client at an absolute path to the binary, pass the token through the env block, and restart the client fully so it reads the config.

{
  "mcpServers": {
    "github": {
      "command": "/usr/local/bin/github-mcp-server",
      "args": ["stdio"],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "YOUR_GITHUB_TOKEN"
      }
    }
  }
}

Before wiring it into the client, prove the token works on its own:

# Confirm the token authenticates and see who it belongs to
curl -s -H "Authorization: Bearer YOUR_GITHUB_TOKEN" \
  https://api.github.com/user | head -20

# Confirm it can actually see the repository you care about
curl -s -o /dev/null -w "%{http_code}\n" \
  -H "Authorization: Bearer YOUR_GITHUB_TOKEN" \
  https://api.github.com/repos/YOUR_ORG/YOUR_REPO

A 200 means you are in business. A 401 means the token is wrong or revoked. A 404 on a repository you know exists almost always means the token cannot see it: wrong resource owner, repository not selected, or pending org approval. GitHub returns 404 rather than 403 for private resources you lack access to, deliberately, so a 404 is a permissions signal rather than a typo signal.

Why can Claude not see my organisation's repositories?

This is the most common complaint and it has a short list of causes.

  1. Resource owner mismatch. The token was created with your personal account as the resource owner. Fine-grained tokens only reach repositories owned by their resource owner. Create a new token with the organisation selected.
  2. Pending approval. Organisations can require owner approval for fine-grained tokens. Until an owner approves, the token exists but grants nothing. Check the pending requests area of the org settings.
  3. Fine-grained tokens not enabled for the org. Some organisations have not opted in. If so, your options are a GitHub App or a classic token, and the App is the better answer.
  4. Repository not selected. You chose "only select repositories" and forgot to add the one you are testing. Easy to do, easy to fix.
  5. SAML SSO not authorised. If the org enforces SAML, the token must be explicitly authorised for that organisation after creation.

Work through them in order. Each is a two minute check and one of them is your answer.

What should I let Claude write to?

Read access is low risk and high value. Write access needs a decision.

The useful middle ground is: allow Claude to create branches and open pull requests, but never push to your default branch. Enforce that with branch protection on the GitHub side rather than trusting the permission model alone, because branch protection is a server-side rule that no token can talk its way around.

Concretely:

If you are building tooling around this rather than just using the connector, the same reasoning applies to whatever you ship: the plugin patterns in build-claude-plugin-from-scratch and the server patterns in build-mcp-server-node-sdk both benefit from declaring the narrowest permission set that works.

How do I verify the connection is healthy?

After restarting the client, ask Claude to list the repositories it can see. If the list matches your selection, the token scope is correct. If it is empty, you have an auth problem. If it contains more than you selected, you have a classic token and should replace it.

Then ask for something specific: read a file from one of the repositories, or summarise the last three issues. A connector that lists repositories but cannot read contents has a permissions gap rather than an auth failure, and knowing which of the two you have saves a lot of time.

Set a calendar reminder a week before the token expires. The alternative is discovering the expiry mid-task, which is exactly the failure pattern described in the connector troubleshooting guide: a connector that worked yesterday and is empty today.

Frequently Asked Questions

What is the difference between a fine-grained and a classic personal access token?

A classic token uses broad scopes like repo that apply to everything your account can access, with no way to limit it to specific repositories. A fine-grained token lets you pick a resource owner, select individual repositories, and grant granular permissions such as Contents: Read without Issues: Write. Fine-grained tokens also require an expiry. For connecting GitHub to Claude, fine-grained is the correct choice in nearly every case.

Why does the API return 404 for a repository I can see in the browser?

GitHub deliberately returns 404 rather than 403 for private resources the token cannot access, so that the existence of private repositories is not leaked to unauthorised callers. If you get a 404 on a repository you know exists, treat it as a permissions problem: check the token's resource owner matches the repository owner, check the repository is in the token's selected list, and check whether the organisation is waiting on an owner to approve the token.

Should I give Claude write access to my repositories?

Only for the repositories where you want it to open pull requests, and only with branch protection enabled on your default branch. Read access covers most useful work: code review, search, understanding a codebase, summarising issues. Write access is worth enabling for automated PR workflows, but pair it with a server-side rule that prevents direct pushes to main. Never grant Administration or Secrets permissions.

Where should the token actually live?

Not in a config file you might commit, and not in your shell history. Store it in your operating system's keychain or a secrets manager, and reference it through an environment variable that your MCP config reads at launch. Keep a committed template with YOUR_GITHUB_TOKEN as a placeholder so the config shape is documented without the value. If the token has ever appeared in a commit, a log, or a screenshot, revoke it and generate a new one rather than hoping.

My token works with curl but the connector shows no tools. What now?

That combination means the credential is fine and the plumbing is not. Check that the MCP client is reading the config file you edited, that the command path is absolute rather than relying on your shell PATH, and that you fully quit and relaunched the client rather than just reloading a window. Then read the connector logs, which will tell you whether the server failed to start, crashed on initialisation, or started cleanly and registered nothing.