GitHub MCP Server Tutorial

Agents, MCP & Agentic DevelopmentAcademy lesson 83Cluster 7 · Lesson 8 of 13Intermediate → Advanced17 min readVersion-sensitive
Published
Updated
Last technically verified
GitHub MCP Server TutorialAgents, MCP & Agentic Development8Intermediate → Advanced/github-copilot/agents/github-mcp-server/

If you add one MCP server, add this one. GitHub’s own server closes the most common context gap there is: Copilot can read your code, and without it, cannot read the issues, pull requests and discussions that explain why the code is the way it is.

What it gives you

The server exposes GitHub itself as tools. The practical effect is that requests which previously required you to go and fetch something now work directly.

Issues and pull requests as context. “Why was this function written this way?” becomes answerable when the pull request that introduced it is reachable.

Code search across repositories. Not only the one you happen to have open, which is what makes questions about organisation-wide usage answerable at all.

Repository metadata. Branches, releases, workflow runs, review state, and the current-user and current-repository context that most requests turn out to need.

Writes, if you enable them. Creating issues, commenting, opening pull requests, and — if you go that far, which you generally should not — merging them.

That last category is where the decisions are. Everything before it is context; everything in it is action.

Setup by client

Copilot CLI

Nothing to do. The GitHub MCP server is built in and uses the CLI’s own authenticated session.

This is worth stating plainly because people spend time configuring what is already there. If you are in the CLI, you have it. Cluster 5 covers the CLI’s tool permission model, which is the finest-grained control over these tools available anywhere.

VS Code

Configuration goes in .vscode/mcp.json, whose top-level key is servers.

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

Starting the server prompts for authentication. Once started, VS Code discovers its tools and remembers them for later sessions.

That snippet uses OAuth, which is the path to prefer. Where a personal access token is required instead, it is supplied as an Authorization header — and it should come from an input prompt or an environment variable rather than being written into the file:

{
  "servers": {
    "github": {
      "type": "http",
      "url": "https://api.githubcopilot.com/mcp/readonly",
      "headers": {
        "Authorization": "Bearer ${input:github_mcp_pat}"
      }
    }
  }
}

Note the /readonly path. Making that the default in a committed configuration means the safe option is the one people get without thinking about it.

The cloud agent

Configuration is JSON entered in repository settings on GitHub by a repository administrator, not a file in the repository.

Other IDEs

Visual Studio, JetBrains, Xcode and Eclipse each have their own MCP configuration location, with growing remote-server support. The server itself is the same; only where the configuration lives changes.

Authentication

Two paths, and which is available depends on your client.

OAuth is the smoother option where supported: you authorise in a browser, no token is stored in a file, and access follows your account. IDEs support this. The cloud agent does not support remote MCP servers that use OAuth.

A personal access token is the fallback and the option that requires care. It is a credential with your access, and how you scope and store it is the whole security question.

Toolsets are the setting that matters

The server exposes a large number of tools. Enabling all of them is the default path of least resistance and is the wrong choice for two independent reasons.

Security. Every enabled tool is something the agent can be induced to call.

Quality. Every enabled tool’s name, description and schema occupies context on every request, and a longer list makes selection worse.

GitHub’s own guidance is to set the tools field to include only what you need rather than enabling everything, citing performance as well as safety.

Tool riskGitHub MCP server (representative tools)
GitHub MCP tools grouped by what they can affect
ToolClassWhat that means
search_codeRead onlyRetrieves information. Nothing changes as a result.
get_issueRead onlyRetrieves information. Nothing changes as a result.
list_pull_requestsRead onlyRetrieves information. Nothing changes as a result.
get_workflow_runRead onlyRetrieves information. Nothing changes as a result.
create_issueMutatingChanges state inside the system it belongs to. Usually reversible.
add_issue_commentMutatingPosted publicly under your identity. Not undoable once seen.
create_pull_requestMutatingChanges state inside the system it belongs to. Usually reversible.
merge_pull_requestExternal effectChanges the default branch and triggers whatever depends on it.

These four classes are this site's editorial framework for reasoning about tool permissions. GitHub does not publish a tool risk classification.

The pattern most teams should land on: everything read-only enabled, writes enabled selectively, merging never.

Choosing toolsets in practice

Two of those deserve comment.

context is the one to keep. It supplies information about the current user and repository, which is the context most requests turn out to need.

all is rarely the right answer. It is convenient, and it is the choice that maximises both the context cost and the number of tools available to a misdirected request.

Start read-only

The --read-only flag makes this a property of the server rather than a convention you maintain — write tools are skipped even when explicitly requested through --tools. On the remote server, the /readonly path segment and the X-MCP-Readonly header do the same thing.

A read-only configuration is not a training-wheels version. For most people it is the version that delivers nearly all of the value.

Consider what read-only tools actually let you ask:

Copilot promptQuestions a read-only GitHub server answersChat, agent mode or CLI

Why does src/auth/session.py refresh the token twice? Find the pull request that introduced that behaviour and summarise the discussion.

Copilot promptCross-repository searchChat, agent mode or CLI

Find every repository in this organisation that still calls the v1 billing endpoint, and list the files.

Copilot promptUnderstanding a failureChat, agent mode or CLI

The nightly workflow failed. Get the most recent run for .github/workflows/nightly.yml, find which step failed, and explain what the error means in terms of this repository.

None of those need write access. All of them close context gaps that otherwise mean tab-switching and pasting. If you never enable a write tool, you will still have got most of the benefit.

Adding write tools deliberately

When read-only genuinely is not enough, add tools one at a time and for a reason you can name.

create_issue is the safest write tool: an issue is visible, editable and closable, and a wrong one costs almost nothing beyond a little noise in the backlog. If you enable exactly one write tool, this is the one.

add_issue_comment is riskier than it looks because comments notify people and cannot be unseen. Fine for a repository your team owns; think harder for anything public.

create_pull_request is reasonable — a pull request is a proposal rather than a change, and the review step that protects you is still in place.

merge_pull_request should generally not be enabled. Merging is the step that makes changes real, and it is precisely the step a human should take.

Local or remote

The server can be run locally or reached as a hosted service, and the choice has practical consequences beyond preference.

Remote is the default worth taking. Nothing to install, nothing to keep updated, and OAuth works. The URL forms above make toolset and read-only selection a configuration detail rather than a deployment one.

Local gives you control and costs you maintenance. Running it yourself — in a container or as a binary — means you decide the version, you can restrict its network, and you can inspect exactly what it does. It also means you are now responsible for updating it, and a stale local server is a real failure mode because nothing tells you it is behind.

Local is the answer for GitHub Enterprise Server and for environments where outbound access to a hosted endpoint is not acceptable. Those are the cases where the maintenance cost is unavoidable rather than chosen.

What good configuration looks like

Concretely, for three common situations.

A developer’s editor, day to day. The remote server at the /readonly path, authenticated with OAuth, with the default toolset. This covers issue and pull request context, code search and repository metadata, and cannot change anything. Most people never need more.

A team repository with a committed configuration. The same, committed to .vscode/mcp.json so everyone gets it, with any token supplied through an input prompt rather than a literal. Adding create_issue is a reasonable next step when someone actually wants it.

The cloud agent. The default connection, unchanged. It is already read-only and scoped to the current repository, and that surface has no per-call approval to catch a mistake.

The common thread is that the safe configuration is also the simple one. Every step away from it should be traceable to something a person wanted to do and could not.

Security properties GitHub documents

Documented controls

  • Push protectionInteractions with the GitHub MCP server are covered by push protection, which blocks secrets in AI-generated responses.
  • Curated registryThe GitHub MCP Registry lists vetted servers, which narrows the trust problem without removing it.
  • Toolset limitingEnabling only the toolsets you need improves performance and reduces attack surface. GitHub recommends setting the tools field rather than enabling everything.
  • Read-only default tokenThe cloud agent's default GitHub MCP connection uses a specially scoped token with read-only access to the current repository.
  • Organization policyCopilot Business and Enterprise must enable the "MCP servers in Copilot" policy before MCP can be used.

Two are worth drawing out.

Push protection covers this server’s interactions, blocking secrets in AI-generated responses. That is a meaningful safety net and not a substitute for keeping credentials out of context in the first place.

The registry narrows the trust problem. GitHub’s own server is the one server where provenance is not a question at all, which is another reason it is the right first one.

Organisation policy

For Copilot Business and Enterprise, the “MCP servers in Copilot” policy must be enabled before any of this works.

If MCP appears broken in a work account, check this before debugging anything else. A disabled policy is indistinguishable from a bad configuration when you are looking at it from the inside, and people lose a lot of time to that.

The lockdown option

One header is worth calling out separately because it addresses a specific, non-obvious risk: X-MCP-Lockdown filters public issue details from users who do not have push access.

The reasoning connects directly to prompt injection. Issue and discussion content in a public repository is written by anyone, and it reaches the model as text. Someone who wants to influence an agent working in a public repository does not need access to it — they need only to open an issue.

Restricting what non-collaborator content the server surfaces narrows that channel without giving up the tool. It is a good example of the general principle: the useful controls reduce what untrusted content can reach, rather than trying to make the model resistant to it.

Verifying it works

Ask for something only the server can answer. A question about an issue by number is a clean test — the model cannot fabricate an issue it has no access to without the fabrication being obvious.

Check the tool list. Each client offers a way to see configured servers and their tools. If the tool you expect is absent, the problem is configuration or toolset scope, not phrasing.

Confirm the boundary. With a read-only configuration, ask for something that would require a write. It should decline or fail rather than succeed — and if it succeeds, your configuration is not what you thought.

Test with a repository you can afford to be wrong about. Not the production one, the first time — and ideally one where an accidentally created issue or comment would embarrass nobody.

Check what a colleague sees. Configuration that lives at personal scope works for exactly one person, and discovering that during a demonstration is worse than discovering it now.

Troubleshooting

Nothing happens at all. Check the configuration is in a file this client reads. For the CLI, remember the server is built in and .vscode/mcp.json is irrelevant.

Authentication fails. For OAuth, re-authorise. For a token, check it has not expired and that its scopes cover the repositories in question — a fine-grained token that omits a repository fails in a way that looks like the repository not existing.

Some tools are missing. Toolset configuration is narrower than you intended, the credential does not grant them, or read-only mode is filtering the write tools out — which it does even when they are named explicitly.

It works for you and not a colleague. Configuration is at personal scope, or their token has different scopes, or the organisation policy differs for their account.

It works in the editor and not in the cloud agent. Expected. That surface is configured separately, in repository settings, and does not support remote OAuth servers.

A note on identity

Write tools act as somebody, and it is worth being clear who.

With OAuth, actions are attributed to your account. An issue the agent opens is an issue you opened, as far as everyone else is concerned, and a comment it posts is a comment your colleagues will read in your voice.

With a personal access token, the same is true — the token carries your identity unless it belongs to a machine account.

Two implications. Anything the agent writes should be something you are willing to sign, which is a reason to keep write tools few and deliberate. And if you want agent-authored activity to be distinguishable, that needs a separate identity — which is a decision to make before enabling writes, not after someone asks why you posted something odd on a public issue.

Living with it

A few things that only become apparent after a few weeks of use.

It changes how you ask questions. Once issue and pull request history is reachable, “why is this like this” becomes a question worth asking Copilot rather than a colleague. That is a genuine shift in what the tool is for, and it takes a little while to start using.

Cross-repository search is the sleeper feature. Most people configure this for issue context and end up using it most for finding every place something is used across an organisation. It is worth trying deliberately rather than waiting to discover it.

The context cost is real. Enabling every toolset noticeably lengthens what is sent with each request. If quality seems to have dropped after adding the server, narrowing the toolsets is the first thing to try, and it usually works.

Stale answers happen. The server reads GitHub as it is now. An answer that draws on an issue closed months ago is accurate about the issue and possibly misleading about the present, which is a normal documentation problem rather than a tool problem — but it surprises people the first time.

Common questions

Do I need this if I already have gh installed? They serve different purposes. The CLI tool is for you; the MCP server is for the agent, and it is what lets Copilot fetch context without you running a command.

Does it work with private repositories? Yes, subject to whatever the credential you authenticated with is actually permitted to see. access.

Can it see repositories in other organisations? Whatever the credential grants. This is the argument for fine-grained tokens: the scope is a decision you make once, explicitly.

Should I enable it for the cloud agent? The default read-only connection is already there and is well chosen. Widening it is a decision to make deliberately, knowing there is no per-call approval on that surface.

Does the toolset list change? Yes, and it has grown steadily. Treat any list you read — including the one above — as a snapshot, and check the current set when something you expect is missing.

What is the insiders path for? Early-access features. Useful for trying things, and not what you want in a configuration your team depends on.

How many tools should I enable? Start with read-only, add write tools individually as specific needs appear, and leave merging out.

Next

Connecting MCP servers covers configuring servers other than this one, per client, including the format differences that break copied examples. The MCP guide covers the protocol and its security model in full.

Sources

Every version-sensitive claim on this page was checked against first-party documentation. Only sources actually used are listed.

Primary sources