Skip to content
CodeLifter Forum

Which token scopes does the GitHub MCP server need?

Staff answerWritten by CodeLifter editors · 0 replies

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.

CiteCodeLifter Forum, "Which token scopes does the GitHub MCP server need?", https://forum.codelifter.com/posts/which-token-scopes-does-the-github-mcp-server-need/, accessed 2026-10-16.
Written by CodeLifter editors · Staff, CodeLifter ·
  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

Write a reply

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