·

GitHub MCP With Gemini CLI

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

Gemini CLI's MCP support went from experimental to solid over its last several releases, and GitHub MCP is one of the combinations Google's own docs use as a worked example. Configuration lives in settings.json (project-level .gemini/settings.json or user-level ~/.gemini/settings.json), following a structure close enough to Claude Code's .mcp.json that porting a config between the two is mostly a key-rename exercise.


Installing and Connecting GitHub MCP to Gemini CLI

Add the server config directly, or use the CLI's built-in command if your installed version supports it (gemini mcp add shipped in more recent releases; check gemini --version and gemini mcp --help if the command isn't found).

Remote hosted server, HTTP transport:

{
  "mcpServers": {
    "github": {
      "httpUrl": "https://api.githubcopilot.com/mcp/",
      "trust": false
    }
  }
}

Local server via the official binary, stdio transport, PAT-based:

{
  "mcpServers": {
    "github": {
      "command": "github-mcp-server",
      "args": ["stdio"],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "$GITHUB_PAT",
        "GITHUB_TOOLSETS": "repos,issues,pull_requests"
      },
      "trust": false
    }
  }
}

The "trust": false field is Gemini CLI-specific and worth understanding: it's what forces a confirmation prompt before any tool call from this server executes, regardless of whether the tool is a read or a write. Setting "trust": true auto-approves every call from that server silently — do not do this for a server holding write access to your repos. Leave it false and handle finer-grained allow/deny via the CLI's tool policy config if you need less friction on reads specifically.

Verify the server loaded:

gemini
/mcp list
/mcp

You should see github listed with a connected status and its available tool count. If it shows zero tools, the most common cause with the local-binary setup is the env var not resolving — Gemini CLI's $VAR-style interpolation in env blocks requires the variable to be exported in the shell that launches gemini, not just set inline.

export GITHUB_PAT=github_pat_11ABCDEFG...
gemini

Tips
- Always leave "trust": false on the GitHub MCP entry — trusting a write-capable server bypasses confirmation prompts entirely, which is the opposite of what you want for a tool that can push commits and merge PRs.
- If /mcp list shows the server connected but with 0 tools, check that any $VAR referenced in the env block is actually exported in your shell, not just defined in a .env file Gemini CLI isn't reading.
- Project-level .gemini/settings.json config is a good place to commit a shared github server definition for a team, same pattern as Claude Code's .mcp.json — just remember trust: false.


Managing GitHub Repos and Pull Requests from Gemini CLI

With the server connected, Gemini CLI's model calls GitHub MCP tools inline during a conversation, prompting for confirmation on each one given trust: false. Typical repo and PR management prompts:

> list the 5 most recently updated open PRs in this repo and tell me which ones
  have failing status checks
> get file contents of package.json from the head of PR #63 and tell me
  if any dependency versions changed compared to what's on main

For repo browsing without a local clone — useful when you're on a machine without the repo checked out, or want to check a colleague's fork:

> list branches in acme/webapp matching the pattern "release/*" and show me
  the last commit on each

Creating a PR from Gemini CLI works the same shape as the other clients, but confirm you specify head and base branches explicitly — Gemini CLI's tool-call confirmation dialog shows the raw arguments, which is your last checkpoint to catch a swapped head/base before a PR gets opened against the wrong branch:

> create a pull request in acme/webapp: head branch "feature/csv-export",
  base branch "develop", title "Add CSV export for reports page",
  body summarizing the last 3 commits on feature/csv-export

The confirmation dialog will render something like:

{
  "tool": "create_pull_request",
  "owner": "acme",
  "repo": "webapp",
  "head": "feature/csv-export",
  "base": "develop",
  "title": "Add CSV export for reports page"
}

Read that base field before approving — it's the single most common mistake in AI-driven PR creation, especially on repos where develop and main coexist.

Tips
- Always read the rendered tool-call arguments in Gemini CLI's confirmation dialog before approving create_pull_request — specifically check base, since a PR opened against the wrong base branch is annoying to fix after the fact.
- For dependency-diff questions, get_file_contents against a PR's head ref beats asking the model to "guess" what changed from the PR title — always ground it in the actual file content.
- Branch-listing with a glob-like pattern description in your prompt works, but Gemini CLI translates it to list_branches and filters client-side — for large repos with hundreds of branches, be specific enough that it doesn't need to paginate excessively.


Practical Example: Auto-Generating a PR Description in Gemini CLI

A workflow every team wants automated eventually: you've finished a branch, commits are terse (fix bug, wip, address feedback), and you want a real PR description without writing one by hand.

> I'm about to open a PR from branch fix/pagination-offset-error into main
  in this repo. Get the diff between these branches, get the list of commits,
  and draft a PR description with: a Summary section (2-3 sentences),
  a "What Changed" bullet list grounded in the actual diff (not the commit
  messages, since they're not descriptive), and a Testing section describing
  what you'd verify manually.

Gemini CLI will call list_commits (or get_commit per SHA) to get the raw commit list, and get_pull_request_diff-equivalent repo comparison to see the actual line changes — note the explicit instruction to ground the description in the diff rather than commit messages, since "fix bug" and "wip" carry zero information and a model that summarizes commit messages alone produces an equally useless description.

A realistic output for a pagination fix:

## Summary
Fixes an off-by-one error in the pagination offset calculation that caused
the last page of results to be dropped when the total count was an exact
multiple of the page size.

## What Changed
- `src/pagination.py`: changed offset calculation from `page * size` to
  `(page - 1) * size`, correcting a boundary condition on the final page
- `tests/test_pagination.py`: added a regression test for total counts
  that are exact multiples of page size (20, 40, 100 items at size 20)

## Testing
- Ran the new regression test locally, confirmed it fails on main and
  passes on this branch
- Manually verified against the `/api/reports?page=5&size=20` endpoint
  with a 100-item dataset

Then create the actual PR with that generated body:

> create the PR using that description as the body

Tips
- Explicitly instruct the model to ground PR descriptions in the diff, not commit messages — terse or unhelpful commit history is the norm, not the exception, and a description built from it inherits the same vagueness.
- Ask for a "Testing" section even when you'll edit it — it forces the model to infer what changed behaviorally, which often surfaces an edge case worth double-checking before merge.
- Review the generated description before the create_pull_request confirmation fires — a hallucinated detail in a PR description is more likely to mislead a human reviewer than a hallucinated code comment, since PR descriptions are trusted at face value more often.


Comparing GitHub MCP Behavior Between Gemini CLI and Claude Code

Both clients talk to the identical GitHub MCP server, so tool availability is the same — the differences are in orchestration and confirmation UX, and they matter for which client you reach for on which task.

Confirmation granularity. Claude Code supports persisted per-tool allow/ask/deny rules in settings.json (Topic 2) — you can let list_issues run silently forever while merge_pull_request always prompts. Gemini CLI's trust flag is per-server, not per-tool: it's on or off for the whole github server. In practice this means Gemini CLI sessions involve more confirmation clicks for equivalent work, since there's no way to whitelist reads while gating writes at the config level — every call prompts if trust: false.

Multi-step planning verbosity. For chained tasks ("triage these 10 issues"), Claude Code's default behavior tends to narrate its plan more explicitly before executing tool calls, which incidentally gives you more chances to interrupt a bad interpretation. Gemini CLI executes more eagerly by default in the same scenario — combined with the coarser trust model, this means you'll want to lean on explicit "list your plan first" prompting (the pattern from Topic 2) more deliberately with Gemini CLI than you might with Claude Code, where the model volunteers it more often unprompted.

Diff rendering. Neither the Gemini CLI terminal nor a bare terminal Claude Code session renders diffs visually — both are text-in-terminal. If you want a rendered diff view, reach for the Claude Code VS Code extension or Cursor rather than either CLI's default rendering.

Config portability. Because both use a JSON mcpServers map with similar shape, porting a working config between the two is close to a find-and-replace: httpUrl (Gemini) vs. no equivalent field for HTTP in Claude Code's .mcp.json (which instead uses "type": "http" + "url"), and env (Gemini) vs. env (Claude Code — same key, convenient). The PAT and toolset env vars are identical across both since they're properties of the underlying github-mcp-server binary, not the client.

Aspect Claude Code Gemini CLI
Per-tool permission rules Yes, persisted in settings.json No — per-server trust only
Default eagerness on multi-step tasks Narrates plan more often Executes more eagerly
Native diff rendering Yes, in VS Code extension No (terminal text only)
Config file .mcp.json .gemini/settings.json

Tips
- Because Gemini CLI's trust model is per-server not per-tool, be more deliberate about prompting for a plan before multi-step write operations — the safety net Claude Code gives you via per-tool ask rules isn't available here.
- Don't expect Gemini CLI's terminal to render PR diffs visually — for review-heavy sessions, pull up the PR in a browser or a VS Code extension alongside the CLI session.
- When porting a .mcp.json config to Gemini CLI's settings.json, double-check the HTTP transport field name changes from type/url to httpUrl — a straight copy-paste will silently fail to connect.


Tips

Tips
- Keep "trust": false on the github server entry in Gemini CLI's config — it's the only gate you get given the lack of per-tool rules, so don't disable it for convenience.
- Ground every AI-generated PR description in the actual diff, explicitly instructed, since commit messages in most real repos are too terse to summarize from directly.
- For multi-step batch operations, ask Gemini CLI to state its plan before executing — its default eagerness plus coarse trust model make this habit more load-bearing here than in Claude Code.