Goal: connect Claude Code to GitHub via MCP so the agent can read and write repository contents directly. This is the setup log, including the permission errors and how each was resolved.
What GitHub MCP Provides
The GitHub MCP server exposes GitHub's API as tools callable by Claude Code: read files, create branches, push commits, open PRs, manage issues. It runs as a local process and communicates over stdio.
Step 1: Create a Fine-Grained PAT
Classic tokens work, but fine-grained PATs scope access to specific repositories.
Path in GitHub:
- Settings > Developer settings > Personal access tokens > Fine-grained tokens
- New fine-grained token
- Token name: something identifiable (
claude-code-mcp-local) - Expiration: set a real date — 90 days is reasonable
- Resource owner: your account (or org if applicable)
- Repository access: select specific repositories, not "All repositories"
Required Permissions
Under Repository permissions:
- Contents: Read and write
- Metadata: Read (required by default, cannot be deselected)
- Pull requests: Read and write (if you want PR tools)
- Issues: Read and write (if you want issue tools)
Permission error 1 came from omitting Contents write. The MCP server connected but file write operations returned 403.
Generate the token. Copy it immediately — it won't be shown again.
Step 2: Install the MCP Server
The GitHub MCP server is distributed as a Docker image or as an npx-runnable package. The npx path is simpler for local use.
npx @modelcontextprotocol/server-github --help
If that resolves, the package is accessible.
Step 3: Register with Claude Code
Claude Code uses the claude mcp command to manage MCP server registrations.
The add-json subcommand accepts a JSON config directly:
claude mcp add-json github '{
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "github_pat_YOUR_TOKEN_HERE"
}
}'
Replace github_pat_YOUR_TOKEN_HERE with the actual token value.
This writes to the Claude Code MCP config (typically ~/.claude/mcp.json or project-level .claude/mcp.json). Verify:
claude mcp list
Output should show github as a registered server.
Step 4: Verify Connection
Start a Claude Code session and ask it to list files in a repository:
List the files in the root of the repo USERNAME/REPONAME
If the connection works, it returns the file listing. If not, you'll see one of three errors.
Permission Error 1: 403 on Contents
Token was missing Contents: Read and write. Regenerated with the correct permission. Replaced the token value in the MCP config.
claude mcp remove github
claude mcp add-json github '{ ... updated config ... }'
Permission Error 2: 404 on Repository
The fine-grained PAT was scoped to a different repository than the one being queried. Fixed by editing the token in GitHub Settings > Developer settings and adding the missing repository under Repository access.
No need to regenerate — token permissions can be updated in place for fine-grained PATs.
Permission Error 3: Server Not Starting
npx version mismatch. The MCP server required a newer version of the package. Cleared the npx cache:
npx clear-npx-cache
Then re-ran the add-json command. Server started cleanly.
Step 5: Project-Level vs Global Config
By default, claude mcp add-json writes to the global config. If you want the MCP server only for a specific project, add the --scope project flag:
claude mcp add-json --scope project github '{ ... }'
This writes to .claude/mcp.json in the current directory. Useful for team repos where you want the config committed (with the token excluded via .gitignore or env substitution).
Working Configuration (Redacted)
{
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_MCP_TOKEN}"
}
}
}
With GITHUB_MCP_TOKEN set in the shell environment, the token stays out of the committed config file.
Summary of Errors
| Error | Cause | Fix |
|---|---|---|
| 403 on file write | Missing Contents: write permission | Regenerate PAT with write access |
| 404 on repository | Repo not in PAT scope | Update token repository access |
| Server not starting | Stale npx cache | npx clear-npx-cache |
Total setup time from first attempt to working connection: approximately 40 minutes. Most of it was the permission errors.
Comments 0