·

GitHub MCP With Claude Code CLI and VS Code

Set up GitHub MCP in Claude Code CLI and VS Code so your AI agent can manage repositories, pull requests, and issues right from your editor.

Claude Code has the most mature MCP tooling of the four clients this course covers — native claude mcp subcommands, per-project and per-user config scoping, and a permission system granular enough to allow read tools while prompting on writes. That maturity is exactly why it's the reference implementation for this module: once you understand the patterns here, OpenCode, Gemini CLI, and Cursor are variations, not reinventions.


Installing and Connecting GitHub MCP to Claude Code

Claude Code supports both a local (stdio) and a remote (HTTP) GitHub MCP server. GitHub itself now hosts a remote server at https://api.githubcopilot.com/mcp/, which is the lowest-friction path — no binary to install, no Docker image to pull, auth handled via OAuth device flow the first time you connect.

claude mcp add --transport http github https://api.githubcopilot.com/mcp/

On first use, Claude Code opens a device-flow OAuth prompt in your browser to authorize against your GitHub account. This is different from the PAT-based auth described in Topic 1 — the hosted server manages token exchange for you, scoped to whatever the OAuth app requests.

If you'd rather run the binary locally (useful for air-gapped environments, or if you want the --toolsets and --read-only flags from Topic 1), pull the Docker image and wire it in via stdio:

claude mcp add github -- docker run -i --rm \
  -e GITHUB_PERSONAL_ACCESS_TOKEN=$GITHUB_PAT \
  -e GITHUB_TOOLSETS=repos,issues,pull_requests \
  ghcr.io/github/github-mcp-server

Verify the connection:

claude mcp list

claude mcp get github

Scope matters. claude mcp add defaults to local scope (this machine only, not checked into the repo). For a team, add --scope project so the .mcp.json config lands in the repo and every teammate who runs claude in that directory picks up the same server config (they still each authenticate with their own token/OAuth identity — the config is shared, the credentials are not).

claude mcp add --transport http --scope project github https://api.githubcopilot.com/mcp/

Inspect what got written:

{
  "mcpServers": {
    "github": {
      "type": "http",
      "url": "https://api.githubcopilot.com/mcp/"
    }
  }
}

Tips
- Use the remote hosted server (api.githubcopilot.com/mcp/) unless you have a specific reason to self-host — it's zero-maintenance and GitHub keeps it patched.
- --scope project writes .mcp.json into the repo so the whole team shares config — commit it, but never commit a token inside it (the hosted server needs none; the Docker-based local setup should read GITHUB_PAT from your shell env, not a hardcoded value in .mcp.json).
- Run claude mcp list after any change — a silently disconnected server (expired OAuth token, stopped Docker container) fails tool calls in a way that's easy to mistake for the model just "not trying."


Managing GitHub Issues and PRs from the Claude Code Terminal

Once connected, Claude Code exposes GitHub MCP tools under names like mcp__github__list_issues, mcp__github__create_pull_request, etc. You don't need to know these names to use them — natural language prompts are enough — but knowing them helps when you want to restrict permissions per-tool.

> list open issues labeled "bug" in this repo assigned to no one, sorted by oldest first

Claude Code will call mcp__github__list_issues with state: open, labels: ["bug"], assignee: "none", and render the result as a table in the terminal. From there you can chain:

> for the top 3 issues, read the full issue body and first 5 comments, then draft a
  one-paragraph triage summary for each, and add it as a comment on the issue

This is a multi-tool-call sequence — get_issue, list_issue_comments, then add_issue_comment per issue — and Claude Code will typically ask for confirmation before each write (see the permission notes below).

For PRs, the diff-reading tools are what make code review meaningfully useful over just reading files:

> get the diff for PR #482, summarize what changed and flag anything that looks like
  it's missing a test
> create a PR from branch fix/rate-limit-retry into main, titled
  "Fix exponential backoff overflow in retry client", with a description that
  summarizes the last 4 commits on this branch

Permission control: add a per-tool allow/deny rule in .claude/settings.json so read tools run silently but writes always prompt.

{
  "permissions": {
    "allow": [
      "mcp__github__list_issues",
      "mcp__github__get_issue",
      "mcp__github__get_pull_request",
      "mcp__github__get_pull_request_diff",
      "mcp__github__search_code"
    ],
    "ask": [
      "mcp__github__create_issue",
      "mcp__github__add_issue_comment",
      "mcp__github__create_pull_request",
      "mcp__github__merge_pull_request"
    ]
  }
}

Tips
- Prefix-match tool names in settings.json (mcp__github__*) if you want a blanket ask-before-write rule instead of listing every write tool individually.
- When asking Claude to draft PR descriptions from commit history, tell it explicitly how many commits to look at (last 4 commits, not recent commits) — otherwise it may summarize the whole branch history against a stale base.
- merge_pull_request should stay in ask (or be excluded from allow entirely) even on scratch repos — muscle memory from a side project has a way of leaking into a work session.


Using GitHub MCP Tools Inside the Claude Code VS Code Extension

The Claude Code VS Code extension shares the same MCP connection config as the CLI (same .mcp.json, same ~/.claude.json for user-scoped servers) — connect once via the terminal with claude mcp add, and the extension picks it up on next reload, no separate setup.

Inside the extension's chat panel, GitHub MCP tool calls render inline with the same confirmation UI as file edits — a diff-style card for anything the model is about to write (a new PR, a comment), which you approve or reject before it executes. This is the biggest practical advantage over the raw CLI for review work: you're looking at the actual PR diff pulled by get_pull_request_files side-by-side with your open editor tabs, rather than scrolling terminal output.

A workflow that benefits specifically from the editor context: open the file the PR touches, then ask the extension to cross-reference.

> compare what's in this open file against PR #501's version of the same file,
  and tell me if the PR's changes handle the token-refresh race condition
  we discussed in issue #488

The model will call get_pull_request_files (or get_file_contents at the PR's head ref) for src/auth/session.ts, plus get_issue for #488, and reason across both against your currently open buffer — something the terminal-only flow makes you do by pasting content manually.

The extension also surfaces MCP server status in its sidebar (green dot = connected), which is faster to spot-check than running claude mcp list every time something feels off.

Tips
- Keep a PR's target file open in the editor before asking for a cross-reference — the model uses your open buffer as grounding context alongside the MCP-fetched version, which produces sharper comparisons than fetching both sides blind.
- Approve/reject cards in the extension show the exact tool arguments (repo, PR number, comment body) — read them before clicking approve, especially for merge_pull_request, since the rendered summary can be shorter than the actual arguments sent.
- If the sidebar shows the GitHub server as disconnected after a VS Code restart, it's almost always an expired OAuth token from the remote server — re-run claude mcp get github in the integrated terminal to trigger re-auth.


Effective Prompting Patterns for GitHub MCP in Claude Code

The gap between a mediocre and a genuinely useful GitHub-MCP session comes down to how specific your prompts are about scope, format, and stopping conditions. A few patterns that consistently work well:

Constrain the search space explicitly. "Find issues about the login bug" makes the model guess a search query. "Search issues in this repo with is:open label:bug login in the title or body" gives it an exact search_issues query string to pass through.

> use search_issues with query "repo:acme/webapp is:open label:bug login in:title,body"
  and list the results with issue number, title, and last-updated date

Ask for a plan before write actions. For anything that touches more than one issue or PR, ask the model to enumerate what it intends to do before executing, so you can catch a bad interpretation before ten add_issue_comment calls fire.

> before doing anything, list exactly which issues you'd comment on and what
  each comment would say — don't call any tools yet

Pin the diff base explicitly for PR summaries. "Summarize this PR" without more context sometimes pulls the wrong base branch on repos with unusual default-branch setups. Be explicit.

> get the diff for PR #482 against main (not against develop), and summarize
  only the changes in src/, ignoring generated files in dist/

Chain read-then-write with an explicit checkpoint. For code review automation specifically, split "read the diff and form an opinion" from "post the comments" into two turns, so you review the opinion before it becomes public PR comments other engineers will see.

> review the diff for PR #501 and list the issues you'd flag, with file:line
  references, but don't post anything yet

> post those as inline review comments on the PR

Tips
- Give the model exact GitHub search syntax (is:open, label:, repo:) rather than describing intent in English — it reduces the chance of a mis-scoped search_issues/search_code call.
- For any batch action across multiple issues or PRs, force a "list your plan first" turn — it's the single highest-leverage habit for avoiding a wave of bad auto-generated comments.
- Be explicit about the diff base branch when a repo doesn't use a simple main-only flow; ambiguity here is the most common source of a wrong PR summary.


Tips

Tips
- Default to the remote hosted GitHub MCP server for Claude Code setups — claude mcp add --transport http github https://api.githubcopilot.com/mcp/ — and reserve the local Docker path for restricted-network environments.
- Use --scope project plus a committed .mcp.json so the whole team gets identical GitHub MCP config without sharing credentials.
- Split read tools (auto-allow) from write tools (ask) in .claude/settings.json, and never let merge_pull_request run unattended.