If you searched "mcp server github," you almost certainly want one of two things: connect your AI agent to GitHub, or build a server that lives on GitHub. This piece answers the first — the one most people mean — and points you at the second at the end.

The short version: you don't build a GitHub MCP server. GitHub already ships one. It's called github/github-mcp-server, it's official, and the fastest way to use it is the hosted endpoint:

https://api.githubcopilot.com/mcp/

Point Claude, Copilot, or Cursor at that URL, authenticate, and your agent can read your repos, triage issues, open and review pull requests, read Actions logs, and run code and secret scanning — about 80 tools across 20 toolsets, no server to run. Below is the exact config for each client, then how to scope it so an agent can't do more than you meant.

What an MCP server actually is (30 seconds)#

An MCP server is a small program that exposes three kinds of things to an AI app over the Model Context Protocol — an open client–server standard:

The point of the standard is write-once: any MCP-compatible client can talk to the same server, so GitHub writes one server and Claude, Copilot, and Cursor all use it. (If you want the deeper cut on the three primitives, we wrote MCP Tools vs Resources vs Prompts.)

The fastest path: connect the official server#

Two ways to run it. Prefer the remote server unless you have a reason not to — there's nothing to install and OAuth means no token on disk.

VS Code (Copilot)

Create .vscode/mcp.json. Note the key is servers, not mcpServers:

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

On first use, VS Code (1.101+) runs a browser OAuth login — no token to paste. If you'd rather use a token, add a header and an input prompt instead:

{
  "servers": {
    "github": {
      "type": "http",
      "url": "https://api.githubcopilot.com/mcp/",
      "headers": { "Authorization": "Bearer ${input:github_mcp_pat}" }
    }
  },
  "inputs": [
    { "type": "promptString", "id": "github_mcp_pat", "description": "GitHub Personal Access Token", "password": true }
  ]
}

Claude Code (CLI)

One command adds the remote server with a token header:

claude mcp add-json github '{"type":"http","url":"https://api.githubcopilot.com/mcp","headers":{"Authorization":"Bearer YOUR_GITHUB_PAT"}}'

Prefer to keep the token off the network and run locally? Point Claude Code at the Docker image over stdio:

claude mcp add github -e GITHUB_PERSONAL_ACCESS_TOKEN=YOUR_GITHUB_PAT \
  -- docker run -i --rm -e GITHUB_PERSONAL_ACCESS_TOKEN ghcr.io/github/github-mcp-server

Claude Desktop

Edit claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/; Windows: %APPDATA%\Claude\; Linux: ~/.config/Claude/). Desktop uses mcpServers:

{
  "mcpServers": {
    "github": {
      "command": "docker",
      "args": ["run", "-i", "--rm", "-e", "GITHUB_PERSONAL_ACCESS_TOKEN", "ghcr.io/github/github-mcp-server"],
      "env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "YOUR_GITHUB_PAT" }
    }
  }
}

Cursor

Edit ~/.cursor/mcp.json (Cursor 0.48+ for Streamable HTTP):

{
  "mcpServers": {
    "github": {
      "url": "https://api.githubcopilot.com/mcp/",
      "headers": { "Authorization": "Bearer YOUR_GITHUB_PAT" }
    }
  }
}

Authentication: OAuth or a token#

For the full auth picture — OAuth 2.1, resource indicators, and the confused-deputy trap that catches most first attempts — see MCP Authorization Explained.

Scope it before you trust it#

The moment an agent has write tools on your repo, "what could it do?" is a security question, not a hypothetical. Two levers keep it honest.

Read-only. Let the agent look but not write:

# local flag
./github-mcp-server --read-only
# env var
GITHUB_READ_ONLY=1 ./github-mcp-server

On the remote server, append /readonly to the URL (e.g. https://api.githubcopilot.com/mcp/x/issues/readonly) or send the X-MCP-Readonly header.

Narrow the toolset. Don't expose 80 tools to a task that only reads issues:

# flag
./github-mcp-server --toolsets repos,issues,pull_requests
# env var
GITHUB_TOOLSETS="repos,issues,pull_requests" ./github-mcp-server

On the remote server, target a single toolset with the path https://api.githubcopilot.com/mcp/x/{toolset} (e.g. /x/issues), or send X-MCP-Toolsets. The available toolsets: context, actions, code_quality, code_security, copilot, dependabot, discussions, gists, git, issues, labels, notifications, orgs, projects, pull_requests, repos, secret_protection, security_advisories, stargazers, users.

Least privilege is the whole game. A read-only, issues-only connection can't force-push to main no matter how a tool description or a poisoned issue tries to talk it into it — see how to harden your repo against agent-poisoned PRs.

What you get: ~80 tools across 20 toolsets#

Once connected, the agent can (subject to your scoping): browse repos, files, branches, commits, tags, and releases; create and triage issues, including sub-issues; open, review, and auto-merge pull requests; read Actions workflow runs and job logs; run code and secret scanning; search code; read users, orgs, and teams; manage notifications, gists, discussions, and projects. It already tracks the current 2026-07-28 MCP spec, so it works with stateless clients and load-balanced hosts out of the box.

When to build your own instead#

Build your own MCP server when the thing you want an agent to reach is yours — an internal API, a database, a private service. For GitHub itself, the official server already covers the surface, so a hand-rolled one is wasted effort.

If you do need to wrap your own system, the SDKs are small. A minimal TypeScript server (current v2 package, @modelcontextprotocol/server) exposing one tool over stdio:

import { McpServer } from '@modelcontextprotocol/server';
import { StdioServerTransport } from '@modelcontextprotocol/server/stdio';
import * as z from 'zod/v4';

const server = new McpServer({ name: 'greeting-server', version: '1.0.0' });

server.registerTool(
  'greet',
  {
    description: 'Greet someone by name',
    inputSchema: z.object({ name: z.string() })
  },
  async ({ name }) => ({
    content: [{ type: 'text', text: `Hello, ${name}!` }]
  })
);

async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
}

main();

The same server in Python (package mcp, v2 — note the class is now MCPServer, renamed from v1's FastMCP):

from mcp.server import MCPServer

mcp = MCPServer("Demo")

@mcp.tool()
def add(a: int, b: int) -> int:
    """Add two numbers."""
    return a + b

@mcp.resource("greeting://{name}")
def greeting(name: str) -> str:
    """Greet someone by name."""
    return f"Hello, {name}!"

Run it against the MCP Inspector to poke at your tools before wiring a client:

uv run mcp dev server.py

That's the outline; for the full walkthrough — transports, testing, and deployment — see How to Build an MCP Server, and if you already have a REST API, turn it into an MCP server without rewriting it. Still deciding whether you even need a server? MCP vs REST for agents draws the line.

The one-line answer#

For GitHub, don't build — connect github/github-mcp-server at https://api.githubcopilot.com/mcp/, log in with OAuth, and scope it read-only with a narrow toolset until you trust the task. Build your own MCP server only for systems GitHub doesn't already cover: yours.