Skip to content
CodeLifter
Search/ Browse prompts
CodeLifter Forum

Which token scopes does the GitHub MCP server need?

Staff answerWritten by CodeLifter editors · MCP and tools2 repliesupdated

Short answer

Only the scopes for the tools you turn on. With a classic token, repo covers most repository, issue and pull request tools; add workflow, gist, notifications or read:org only when you need those tools. GitHub recommends a fine-grained token limited to selected repositories instead, but the server then shows every tool and leaves enforcement to the API.

Written by CodeLifter editors · Staff, CodeLifter ·
CiteCodeLifter Forum, "Which token scopes does the GitHub MCP server need?", https://codelifter.com/forum/posts/which-token-scopes-does-the-github-mcp-server-need/, accessed 2026-11-12.
  1. Staff, CodeLifter ·

    How the server reacts to each kind of token

    The official server behaves differently depending on how you sign in. Its scope filtering document sets it out:

    Token type Prefix What the server does
    Classic personal access token ghp_ Reads your scopes at startup and hides tools your token cannot use
    OAuth (hosted server) none to set Shows all tools, then prompts you to grant a missing scope when a tool needs it
    Fine-grained personal access token github_pat_ No filtering: "all tools shown, API enforces permissions"
    GitHub App installation token ghs_ No filtering; permissions come from the app installation

    Two details catch people out. If the server cannot read your classic token's scopes (the document gives network issues or rate limiting as examples), it "logs a warning and continues without filtering." And read-only repository tools that only need repo or public_repo stay visible even without those scopes, because they work on public repositories.

    Scopes by job

    The server's README lists the OAuth scopes each tool may ask for. The middle column below comes from that list. The right column gives the fine-grained permission named for the same resource in GitHub's personal access token documentation; that pairing is our reading, so confirm it against an API response (see the last section).

    What you want the assistant to do Classic scope Closest fine-grained permission
    Read files, commits, issues and pull requests in private repos repo Contents, Issues, Pull requests: read
    Open issues and add comments (issue_write, add_issue_comment) repo Issues: write
    Push files, open and merge pull requests (push_files, create_pull_request, merge_pull_request) repo Contents and Pull requests: write
    Change a file under .github/workflows/ repo plus workflow Workflows: write
    List or trigger Actions runs, read job logs (actions toolset, off by default) repo Actions: read, or write to trigger
    Code scanning and Dependabot alerts security_events (included in repo) Code scanning alerts, Dependabot alerts: read
    Create or update gists gist Gists: write (account permission)
    List or dismiss notifications notifications No notifications permission appears in GitHub's fine-grained list
    Read teams and members (get_teams, get_team_members) read:org Members (organization permission): read
    Delete a repository (delete_repository) delete_repo plus repo Do not grant it

    The scope filtering document notes that workflow is requested "only when the call changes a workflow file." That scope is worth keeping off unless you need it, because a workflow file decides what GitHub Actions runs in that repository.

    The README's own "Token Security Best Practices" list repo, read:packages (for "Docker image access") and read:org as minimum scopes. The same README says the Docker image at ghcr.io/github/github-mcp-server is public, so test whether you need read:packages before you add it.

    Set up a fine-grained token for one project

    1. On GitHub, open Settings, then Developer settings, then Personal access tokens, then Fine-grained tokens, and click Generate new token.
    2. Set an expiration. GitHub's documentation says infinite lifetimes "may be blocked by a maximum lifetime policy" in some organisations, and recommends an expiry in any case.
    3. Under Resource owner, pick your account or the organisation that owns the repository.
    4. Under Repository access, choose Only select repositories and pick the ones the assistant should touch. GitHub notes that tokens "always include read-only access to all public repositories on GitHub."
    5. Under Permissions, start with Contents: read, Issues: read and Pull requests: read. Add write permissions one at a time when a task fails for lack of them.
    6. Generate the token and store it in an environment variable, not in a committed file. The server reads it from GITHUB_PERSONAL_ACCESS_TOKEN.

    Because a fine-grained token disables the server's tool filtering, limit the tools on the server side too:

    github-mcp-server stdio --toolsets=repos,issues,pull_requests --read-only
    

    The server configuration guide says read-only mode disables write tools "even when explicitly requested," and that --exclude-tools removes listed tools "regardless of any other configuration." If you allow writes, exclude the riskiest tools by name, for example --exclude-tools=merge_pull_request,delete_file.

    When a classic token is the only option

    GitHub's documentation lists cases fine-grained tokens do not cover yet, including contributing to public repositories where you are not a member, working as an outside collaborator, and accessing several organisations at once. In those cases a classic token is needed. Remember that a classic token "will grant access to all repositories within the organizations that you have access to, as well as all personal repositories," so pair it with --read-only or a short toolset list.

    Check what your token actually has

    For a classic token, the scope filtering document gives this command:

    curl -sI -H "Authorization: Bearer $GITHUB_PERSONAL_ACCESS_TOKEN" \
      https://api.github.com/user | grep -i x-oauth-scopes
    

    For a fine-grained token, GitHub's REST documentation says responses carry an X-Accepted-GitHub-Permissions header naming the permissions an endpoint needs, which is the quickest way to settle a "Resource not accessible" error.

    Scopes are only half of the picture; where the server runs is the other half. See remote or local GitHub MCP server for that choice, and who is the author of a commit made through an MCP server for what happens to authorship once you allow writes. The CodeLifter GitHub MCP server page lists every toolset and what it can change.

    0
    ReplyLink

Plain text or simple Markdown. Links are nofollow. Your email is never shown.

  1. CodeLifter editorsStaffStaff, CodeLifter ·

    Can you use a GitHub App instead of a personal access token? Yes, and its tokens are shorter lived. A GitHub App authenticates as an installation by generating an installation access token. GitHub's installation token documentation says the token expires after 1 hour. When you request it, the repositories or repository_ids parameters can narrow it to specific repositories, up to 500, and the permissions parameter can narrow its permissions; without them it gets everything the installation was granted, and never more. The server's scope filtering document, quoted in the opening post, lists installation tokens by their ghs_ prefix and says the server does no tool filtering for them, because permissions come from the installation. So the same advice applies as for fine-grained tokens: limit tools on the server with --toolsets, --read-only or --exclude-tools. The one-hour expiry is the real gain, since a leaked token stops working quickly. The cost is setup: you register an app, install it on the repositories, and something has to mint a fresh token every hour, which GitHub's Octokit SDKs can do for you. For one person on one laptop, a fine-grained token is usually simpler.

  2. CodeLifter editorsStaffStaff, CodeLifter ·

    What should you do if a GitHub token leaks? Revoke it first, then clean up. GitHub's secret scanning documentation says secret scanning checks your entire Git history on all branches for known credential formats, and that it is free on public repositories. Its advice when a credential is found is to rotate the affected credential immediately, and it notes that removing the secret from history is often unnecessary once the credential no longer works. In order: delete the token on GitHub under Settings, Developer settings, Personal access tokens, so it is dead whatever else happens. Generate a replacement with the narrowest repositories and permissions the work needs. Check the account's security log and the affected repositories for actions you did not make, paying particular attention to anything under .github/workflows/. Then update the place the server reads it from, the GITHUB_PERSONAL_ACCESS_TOKEN variable or your client's input prompt, and restart the server. The README advice quoted in the opening post prevents the common cause: keep the token in an environment variable, add .env to .gitignore, run chmod 600 on any config file that holds it, and use a separate token for agent work so you only revoke that one.

CodeLifter

Reviewed vibe coding prompts, the JavaScript each one should produce, and sourced answers on AI-generated code: who wrote it, who owns it, and whether you can ship it. Free since 1999.

Browse the Prompt Shelf

Popular topics

© 1999 to 2026 CodeLifter

Independent. No ties to any software vendor.
Code MIT Text CC-BY-4.0 Back to top