# MCP in Copilot CLI

Use Copilot CLI's built-in GitHub MCP server to read issue

Source: https://ai-sw-factory.mellicci.dev/fundamentals/mcp/copilot-cli

This page covers Copilot CLI. Unlike the other agents, it ships a GitHub MCP server built in, so the scenario needs no install step.

## At a glance

| | Copilot CLI |
|---|---|
| Term | MCP servers |
| Configured in | `~/.copilot/mcp-config.json` (user), `.mcp.json` or `.github/mcp.json` (project), `--additional-mcp-config` (one session); built-in `github-mcp-server` needs no file |
| Loads / runs | Servers start with the session; tool definitions are listed to the model, or held back by tool search when there are many |
| Scope & precedence | Project definitions beat user definitions; files nearer your working directory beat those higher up |

## Build the scenario

| Step | What you write or run | Where |
|---|---|---|
| 1 | Confirm the built-in server is connected: `/mcp show github-mcp-server` | Copilot CLI session |
| 2 | Narrow it to issue reads for this run (below) | Launch flags |
| 3 | Prompt: `Implement issue #42` | Session |

```shell
copilot \
  --add-github-mcp-tool=issue_read \
  --add-github-mcp-tool=list_issues \
  --add-github-mcp-tool=search_issues \
  --allow-tool='github-mcp-server(issue_read)'
```

The GitHub account you signed in with authenticates the server. The documentation lists `issue_read`, `list_issues` and `search_issues` as the issue tools, and says the `--add-github-mcp-tool` flags apply "instead of the default CLI subset". Without them, the default CLI subset applies. The documentation doesn't list that subset, but the server's tool table includes label writes (`label_write`), and it doesn't specify a read-only switch for the built-in server, so narrowing the tool list is the control shown here.

The model then calls `issue_read` for #42, reads the acceptance criteria, and edits `src/routes/` and `test/` with its built-in tools.

Adding another server, here with a token taken from an environment variable. The same `mcpServers` object works in `.mcp.json` at the repository root (project) and in `~/.copilot/mcp-config.json` (user):

```json
{
  "mcpServers": {
    "context7": {
      "type": "http",
      "url": "https://mcp.context7.com/mcp",
      "headers": { "CONTEXT7_API_KEY": "${CONTEXT7_API_KEY}" },
      "tools": ["*"]
    }
  }
}
```

## Specifics

### Config files and scopes

| Location | Scope | Notes |
|---|---|---|
| Built-in `github-mcp-server` | Always | Also built in: `playwright`, `fetch`, `time` |
| `~/.copilot/mcp-config.json` | User, all projects | Written by `/mcp add` and `copilot mcp add` |
| `.mcp.json` | Project, any directory from cwd up to the repo root | Wins over `.github/mcp.json` in the same directory |
| `.github/mcp.json` | Project, committed and shared | |
| `--additional-mcp-config=JSON` or `@file` | One session | Overrides a same-name server |
| Plugins | Plugin | Listed in `/mcp` with their source |

Project files load after you confirm folder trust; in `copilot -p` they load only in an already trusted directory, unless `GITHUB_COPILOT_PROMPT_MODE_WORKSPACE_MCP=true`. Project files accept `mcpServers` or bare server names at the top level. `.vscode/mcp.json` (key `servers`) is not read.

### Local and remote servers

| `type` | Transport | Required fields |
|---|---|---|
| `local` or `stdio` (default) | Child process over stdin/stdout | `command`, `args`, `tools` |
| `http` | Streamable HTTP | `url`, `tools` |
| `sse` | Legacy Server-Sent Events | `url`, `tools` |

| Command | What it does |
|---|---|
| `/mcp add`, `edit`, `delete` | Form-based management; `add` takes effect without a restart |
| `/mcp show [NAME]`, `list`, `enable`, `disable`, `auth`, `reload` | Inspect and toggle servers |
| `copilot mcp add\|list\|get\|remove\|enable\|disable` | Same from the terminal; `add` writes the user file |

### Authentication and secrets

| Server | How it authenticates |
|---|---|
| Built-in GitHub | The CLI's GitHub authentication: the signed-in account, or `COPILOT_GITHUB_TOKEN`, `GH_TOKEN` or `GITHUB_TOKEN` for headless use |
| Local server | `env` block; `$VAR`, `${VAR}` and `${VAR:-default}` expand. Only `PATH` is inherited |
| Remote server | `headers` (variable expansion supported), or OAuth; `/mcp auth NAME` restarts a sign-in |
| Headless | `oauthGrantType: "client_credentials"`, or `oidc: true` |

`--secret-env-vars=VAR` redacts a variable from shell and MCP server environments. Fallback secret and OAuth state lives under `~/.copilot/mcp-secrets/` and `mcp-oauth-config/` when no keychain is available.

### Tool allow and deny

| Control | Example | Effect |
|---|---|---|
| Per-server `tools` | `"tools": ["issue_read"]` | Only those tools are exposed |
| `--allow-tool` | `'github-mcp-server(issue_read)'` or `'github-mcp-server'` | No approval prompt for that tool or server |
| `--deny-tool` | `'github-mcp-server(label_write)'` | Blocked; beats any allow, even `--allow-all` |
| `--available-tools`, `--excluded-tools` | | Limit the tools the model sees at all |
| `--add-github-mcp-tool`, `--add-github-mcp-toolset`, `--enable-all-github-mcp-tools` | | Replace or widen the built-in GitHub subset |
| `--disable-builtin-mcps`, `--disable-mcp-server NAME` | | Turn off built-in or named servers |

All MCP tool calls need permission unless allowed. An organization's managed settings can add `allowedMcpServers` and `deniedMcpServers`; built-in first-party servers are exempt. A registry URL with an allowlist policy can also restrict which servers run.

### Context cost and inspection

| Topic | Behavior |
|---|---|
| Tool search | On by default on supported models; below roughly 30 tools everything loads up front, above that MCP tools are held back and looked up on first need |
| Opt out | `toolSearch: false` in user settings, or `"deferTools": "never"` on one server |
| Inspect | `/mcp show NAME` lists a server's tools; `/env` and `/context` show what is loaded |
| Tool snapshots | Local server tool lists are cached for fast startup; `disableToolCache: true` turns it off |

## Gotchas

- The built-in GitHub server is on by default, and the documentation doesn't list its default subset; the server also offers writes such as `label_write`. Narrow it with flags or `--deny-tool` before an unattended run.
- A project `.mcp.json` shadows a same-name user server, and `/mcp edit` refuses workspace servers; edit the file itself.
- Project servers are skipped in untrusted directories and in `-p` mode, which can look like a missing server in CI.
- Server names prefix tool names (`my-server-fetch`), and the combined name is capped at 64 characters.
- Only `PATH` is inherited by local servers; pass every other variable through `env`.
