Connect GitHub Copilot to MCP Servers
MCP configuration looks portable and is not. The JSON is similar enough across clients to invite copying and different enough that a copied file frequently does nothing at all — with no error, because a configuration file that is not read cannot complain.
This lesson covers each client’s actual format, and what to check when a server does not appear.
Key takeaways
- VS Code uses
serversas the top-level key. Copilot CLI usesmcpServers. That single difference accounts for a large share of failed setups. - Copilot CLI does not read
.vscode/mcp.json. GitHub states this explicitly. - The CLI has three locations, personal and project, and commands to manage them.
- The cloud agent is configured in repository settings, not in a file.
- Never put credentials in these files. Use inputs, environment variables, or the surface’s secret mechanism.
The landscape
| Client | Configuration | Authentication | Remote OAuth |
|---|---|---|---|
| VS Code | .vscode/mcp.jsonTop-level key is `servers`. This file is not read by Copilot CLI. | OAuth or personal access token for remote servers | Supported |
| Copilot CLI | ~/.copilot/mcp-config.json, .mcp.json, or .github/mcp.jsonDoes not read .vscode/mcp.json. Migrating one requires reformatting. | Per-server; the built-in GitHub server uses the CLI's own session | Not documented |
| Copilot cloud agent | JSON in repository settings on GitHubNot a file in the repository — configured by a repository administrator in settings. | Tokens supplied in configuration; the default GitHub server uses a read-only repo-scoped token | Not supported |
| Visual Studio, JetBrains, Xcode, Eclipse | Per-IDE MCP configuration | OAuth or personal access token for remote servers | Supported |
- VS Code. A Start button appears above the server list; starting a server discovers its tools and stores them for later sessions.
- Copilot CLI. The GitHub MCP server is built in and needs no configuration. `copilot mcp add` manages others.
- Copilot cloud agent. Only tools are supported — not resources or prompts. Copilot uses available tools autonomously without asking for approval.
- Visual Studio, JetBrains, Xcode, Eclipse. GitHub lists growing remote-server support across these editors.
Read that table before writing any JSON. Nearly every “MCP does not work” report resolves to configuration living somewhere the client in use does not read.
VS Code
Configuration lives in .vscode/mcp.json for a workspace.
{
"servers": {
"github": {
"type": "http",
"url": "https://api.githubcopilot.com/mcp/readonly"
}
}
}The top-level key is servers. A Start control appears above the server list;
starting a server discovers its tools and stores them for later sessions, so
tools are available without restarting each time.
For a local server started as a process:
{
"servers": {
"filesystem": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/home/me/projects"]
}
}
}Copilot CLI
{
"mcpServers": {
"sentry": {
"type": "http",
"url": "https://mcp.example-monitoring.com/",
"tools": ["list_issues", "get_issue"]
}
}
}Managing servers from the CLI
Rather than editing JSON, the CLI can manage configuration for you.
copilot mcp add SERVER-NAME -- COMMAND [ARGS...]
copilot mcp add --transport http SERVER-NAME URL
copilot mcp list
copilot mcp get SERVER-NAME
copilot mcp remove SERVER-NAMEOptions include --env KEY=VALUE, --header, --transport, --tools and
--timeout.
Inside an interactive session, the same operations are available as slash
commands — /mcp add opens a form, /mcp show lists servers or details for one,
and /mcp edit, /mcp delete, /mcp disable and /mcp enable do what their
names suggest.
The cloud agent
Configuration is JSON entered in repository settings on GitHub, by someone with administrative access to the repository. There is no file to commit and no local equivalent.
Three properties of this surface change what is worth configuring:
- Only tools are supported. Not resources, not prompts.
- Remote servers using OAuth are not currently supported.
- Copilot uses available tools autonomously and will not ask for approval before use.
Naming servers
A small thing that becomes annoying at scale: server names appear in tool
selection, in logs and in the mcp-servers field of agent profiles, so they are
worth choosing rather than accepting.
Name the system, not the vendor’s product name. monitoring is more useful
than the brand, because the brand may change and the role will not.
Keep names distinct across scopes. A personal server and a project server sharing a name is an ambiguity you do not need, and the resolution is not something to rely on.
Avoid names that collide conceptually. Two servers both plausibly called
search will be selected between arbitrarily, which reads as unreliability
rather than as a naming problem.
Other IDEs
Visual Studio, JetBrains, Xcode and Eclipse each have their own MCP configuration location, with growing support for remote servers. The server definitions are conceptually the same; the file and its schema are not.
Check your IDE’s own documentation for the location rather than assuming the VS Code path applies. This is the same class of mistake as the CLI case, with the same silent failure mode.
Transports, and which to pick
The type field selects how the client talks to the server, and the choice
follows from where the server runs rather than from preference.
Local process, standard input and output. The client starts the server as a
child process and communicates over its standard streams. Named stdio in VS
Code and local in Copilot CLI — the same idea with different labels, which is
one more reason copied configurations fail. This is what you use for a server
distributed as a package you run yourself.
HTTP. The server is reachable at a URL. This is the shape of hosted servers, including GitHub’s own remote endpoint, and it is where authentication headers and OAuth come in.
Server-sent events. An older streaming transport, still supported and still seen in existing configurations. New setups generally use HTTP.
The practical guidance is short. If a server publishes a URL, use HTTP. If it publishes a command, run it locally. If documentation shows both, prefer the hosted one unless you have a reason — a network policy, an air-gapped environment, a version you need to pin — to take on running it yourself.
Restricting tools in configuration
The tools field is where a configuration stops being a connection and becomes a
permission decision.
{
"mcpServers": {
"monitoring": {
"type": "http",
"url": "https://mcp.example-monitoring.internal/",
"tools": ["list_alerts", "get_alert", "search_logs"]
}
}
}Three named tools, all read-only. Whatever else that server exposes — silencing alerts, editing dashboards, changing routing rules — is not available, because it was not listed.
Contrast with the version that omits the field, or uses ["*"]. That grants every
tool the server offers today and every tool it adds in a future version, without
anyone revisiting the decision.
Credentials
Every client offers a way to supply a secret without writing it into the file. Use it.
Personal or project
Both scopes exist for the CLI, and choosing deliberately avoids two opposite problems.
Personal configuration — ~/.copilot/mcp-config.json — applies to everything
you do. It is the right place for a server tied to you rather than to a codebase:
your own notes system, a service you have credentials for that colleagues do not,
anything experimental.
Project configuration — .mcp.json or .github/mcp.json — applies to work in
that repository and can be committed. It is the right place for a server the
project genuinely needs, where everyone working on it should have the same setup.
The failure at one extreme: everything personal, so each developer has a different configuration and the same request behaves differently on different machines. Nobody can reproduce anyone else’s result, and the inconsistency gets blamed on Copilot.
The failure at the other: everything committed, including servers most people do not need, so the tool list is long, selection degrades, and someone eventually commits a credential because the file was already there.
Scoping servers to one agent
An agent profile’s mcp-servers field scopes MCP configuration to that agent.
This is worth using more than most people do. A server with genuinely powerful tools does not have to be present in every session — it can belong to one narrow agent whose job needs it, leaving ordinary work unaffected.
The pattern generalises: the more a server can do, the fewer sessions should have it. A monitoring server with read-only tools can reasonably be global. A server that can restart services should belong to exactly one agent, invoked deliberately.
Custom agents covers the profile format this field belongs to.
Migrating a VS Code configuration to the CLI
Since this is the failure everyone hits, here is the actual translation rather than a warning about it.
Start from a working VS Code file:
{
"servers": {
"monitoring": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@example/monitoring-mcp"],
"env": { "MONITORING_REGION": "eu-west-1" }
}
}
}Three changes make it a Copilot CLI personal configuration.
Move it. Into ~/.copilot/mcp-config.json, or into one of the two project
files. Not .vscode/mcp.json, which the CLI does not read under any circumstances.
Rename the top-level key. servers becomes mcpServers.
Rename the transport. The stdio type in VS Code is called local here.
{
"mcpServers": {
"monitoring": {
"type": "local",
"command": "npx",
"args": ["-y", "@example/monitoring-mcp"],
"env": { "MONITORING_REGION": "eu-west-1" },
"tools": ["list_alerts", "get_alert"]
}
}
}The tools list is an addition rather than a translation, and it is worth making
while you are here — a migration is a natural moment to narrow what was previously
unrestricted.
When a server does not appear
In order, because the first two resolve most cases.
Is the configuration in a file this client reads? For the CLI, that is one of
the three paths above and never .vscode/mcp.json. For the cloud agent, it is
repository settings and never a file.
Is the top-level key right? servers for VS Code, mcpServers for the CLI’s
personal file. A wrong key produces a valid JSON file describing nothing.
Does the client list the server? copilot mcp list, or the equivalent in your
IDE. If the server is absent here, nothing downstream is worth investigating.
Did the server start? Local servers are processes and can fail to launch — a missing runtime, a wrong path, an uninstalled dependency. Client logs usually say so plainly.
Did authentication succeed? A started server with a rejected credential looks like a server with no tools.
Are the tools filtered? A tools list narrower than intended, or a read-only
mode, will hide exactly the tools you are looking for.
Is an organisation policy blocking it? For Business and Enterprise, the “MCP servers in Copilot” policy gates everything. Check this early in a work account.
Verifying a new server
Adding a server and assuming it works is how people end up debugging the wrong thing a week later. Four checks, each taking seconds.
Confirm the client sees it. copilot mcp list or the IDE equivalent. Present
or absent — no interpretation required.
Confirm the tools you expect are exposed. A server can be connected and
exposing nothing useful, most often because the tools list or a read-only mode
is narrower than intended.
Ask for something only that server can answer. Not a question the model could answer from general knowledge — something specific to the system behind the server, where a fabricated answer would be obviously fabricated.
Confirm the boundary. Ask for something that would require a tool you did not enable. It should decline or fail. If it succeeds, your configuration grants more than you thought, and finding that out deliberately is much better than finding it out later.
Keeping configuration reviewable
Some habits that save trouble once more than one person is involved.
Commit project configuration; keep personal configuration personal. A server
the team needs belongs in .github/mcp.json. An experiment belongs in your home
directory.
Pin the tools list explicitly. A configuration that enumerates its tools
tells a reviewer exactly what was granted. One that omits the field grants
whatever the server offers today and whatever it adds tomorrow.
Review configuration changes as permission changes. A pull request adding a server is a pull request adding capability. The diff is small and the consequences are not.
Re-check after server updates. Servers gain tools between versions, and nothing announces it. A periodic look at what is actually exposed is worth more than a policy nobody re-reads.
Why the silence
It is worth understanding why these failures produce no error, because it changes how you debug them.
A client looks for configuration in the places it knows about. A file somewhere else is not a malformed configuration — it is not a configuration at all, as far as that client is concerned. There is nothing to report, because from the client’s position nothing happened.
The same applies within a file. A top-level key the client does not recognise describes no servers, so the client starts none. It is valid JSON and it parses cleanly. Nothing is wrong except that it means nothing here.
This is the same silent-ignore behaviour that agent profiles and skill frontmatter have, and it has the same consequence: absence of an error is not evidence that something worked. The only reliable signal is positive confirmation — the server appearing in a list, a tool actually being called, an answer that could only have come from the system behind it.
Build the habit of confirming rather than assuming, and MCP configuration stops being mysterious.
Common questions
Can I use the same file for VS Code and the CLI? No. Different locations, different top-level keys, different transport names, and the CLI does not read the VS Code file at all. Translate it once, following the migration section above.
Does the CLI need the GitHub MCP server configured? No. It is built into Copilot CLI and uses the CLI’s own authenticated session, so configuring it there is effort spent on something you already have.
What is the difference between .mcp.json and .github/mcp.json? Both are
project-level for the CLI; .github/mcp.json is the conventional place for
configuration meant to be shared with the repository.
Can a project configuration override a personal one? Both are read. If the same server name appears in more than one, expect the more specific location to apply, and avoid the ambiguity by not duplicating names.
Do I need to restart after changing configuration? Behaviour differs by client. VS Code discovers tools when a server starts and remembers them; the CLI picks up configuration when a session begins. When in doubt, start a fresh session before concluding a change had no effect.
Can I disable a server temporarily? In the CLI, /mcp disable SERVER-NAME
does exactly that without deleting the configuration, which is useful for
isolating whether a server is responsible for odd behaviour.
How do I remove a server cleanly? copilot mcp remove SERVER-NAME for the
CLI, or delete the entry. Also revoke any credential you created for it — a
removed server with a live token is a token nobody is managing.
A configuration review checklist
When an MCP configuration arrives in a pull request, six questions cover it.
Which server is this, and who maintains it? An official server from the vendor whose system it reaches, a registry-listed server, or an unfamiliar package are three different levels of trust.
What are its tools, and is the list enumerated? A tools field naming
specific tools is reviewable. An omitted field or a wildcard is a grant of whatever
exists now and whatever appears later.
Can any of those tools change something? Sort them mentally into read, mutate and act-outside. Anything in the third category needs a stated reason.
What credentials does it use, and where do they come from? A literal string in the file is a finding. An input prompt, an environment variable or a secret is fine.
Which surfaces does this configuration reach? A file committed to the repository affects everyone who works in it, including on surfaces with no per-call approval.
Is this replacing something simpler? If the context could have been a paste, a skill or a small script, the server is infrastructure that will need maintaining for a benefit that was already available.
Next
The GitHub MCP server is the one most worth configuring first. The MCP guide covers the protocol, tool risk and the injection surface these configurations open. From here, the cluster turns to complete agents: DevOps is the first.
Put this into practice
9-minute exercise
Connect a server with the narrowest useful scope
- Connect one MCP server you have not used before.
- Set its
toolsfield to the smallest set that does the job. - Ask the agent to do something that needs a tool you deliberately left out.
How you know it worked The agent could not do it. A refusal here is the exercise succeeding — it means the boundary you configured is real.
Full lab Build an MCP Integration for GitHub Copilot
Companion project MCP starter
Sources
Every version-sensitive claim on this page was checked against first-party documentation. Only sources actually used are listed.
Your progress
Saved in this browser only. No account, no server, and nothing leaves your device. Clearing site data resets it.Sync across devices if you want it everywhere.
Saved in this browser and synced to your account, so it follows you between devices. Manage or delete it.
Was this lesson helpful?
We record which lesson you rated and whether it helped. Nothing identifies you — no account, no cookie, no session.