Announcing CIMD support for MCP Client registration
Learn more

GitHub MCP Server: Official, Self-Hosted and Per-User OAuth

GitHub MCP server options: GitHub's remote and local servers act as one developer, while a managed per-user layer acts as each end user with a session token per run
Nityashree Yadunath
Product Marketing Manager

The GitHub MCP server is GitHub's own open-source MCP server, available to every GitHub user on any plan. It runs remotely at https://api.githubcopilot.com/mcp/ or locally from the ghcr.io/github/github-mcp-server Docker image, and every call acts as the GitHub user whose OAuth sign-in or personal access token (PAT) it carries. That fits one developer in an editor; a product whose agent acts for many customers needs per-user OAuth.

TL;DR

  • GitHub's server is available to every GitHub user, whatever their plan. Individual tools keep the requirements of the feature behind them: Copilot cloud agent tools need a paid Copilot license, and code scanning on private repositories needs a GitHub Code Security license.
  • Claude Code, Cursor and Codex connect to the remote server with a PAT. Remote OAuth sign-in works in hosts that register their own GitHub app, such as Copilot in VS Code. The local server can run an OAuth login itself.
  • When one agent acts for many GitHub users, each call needs that user's own token, stored, refreshed and revocable per user. Scalekit's GitHub connector does this behind one MCP server URL, with a short-lived session token per user and run.

What the official GitHub MCP server does

GitHub maintains the server in the github/github-mcp-server repository under the MIT license; the latest release is v2.0.2, published October 8, 2026. Its tools read repositories and code, manage issues and pull requests, inspect GitHub Actions runs and job logs, and read security findings such as Dependabot and code scanning alerts. Every call goes through GitHub's API with the caller's credential, so the server reaches only what that user or token can reach.

Tools are grouped into toolsets. With no configuration, the server loads five: context, repos, issues, pull_requests and users. Others, such as actions, code_security, dependabot, discussions, gists, projects and notifications, are opt-in, and all turns on every toolset. GitHub recommends enabling only what the agent needs, because fewer tools improve tool selection and leave more of the model's context free.

The remote server

The hosted server lives at https://api.githubcopilot.com/mcp/ and speaks streamable HTTP. GitHub builds it from the same repository and updates it regularly. It also has tools the local server lacks: create_pull_request_with_copilot hands a task to Copilot coding agent, and the copilot_spaces and github_support_docs_search toolsets are remote only. The remote server docs list the ways to choose tools:

  • https://api.githubcopilot.com/mcp/readonly serves the default toolsets with read tools only.
  • https://api.githubcopilot.com/mcp/x/issues serves one toolset; add /readonly to restrict it.
  • The X-MCP-Toolsets, X-MCP-Tools, X-MCP-Readonly and X-MCP-Lockdown headers match the local server's flags and can combine several toolsets.

GitHub Enterprise Cloud with data residency uses https://copilot-api.<subdomain>.ghe.com/mcp. GitHub Enterprise Server has no hosted server, so GHES users run the server locally.

The local server

The local server runs as a stdio process from the Docker image or a release binary. It takes the same settings as flags or environment variables: --toolsets or GITHUB_TOOLSETS, --tools, --read-only or GITHUB_READ_ONLY=1, and --lockdown-mode. Its http command serves the same tools over streamable HTTP on port 8082 for containers and reverse proxies, and each request brings its own Authorization header. Run it locally when you use GitHub Enterprise Server, want to pin a version, or need the process inside your own network. Remote vs stdio MCP servers covers the general trade-off.

Is the GitHub MCP server free?

Yes. GitHub's setup documentation states that the server is available to all GitHub users regardless of plan type, and the code is open source under the MIT license. Tools inherit the access rules of the feature behind them: a tool that uses Copilot cloud agent needs a paid Copilot license, and code scanning on private repositories needs a GitHub Code Security license. Calls count against GitHub's normal API rate limits for the credential used, which for an authenticated user is 5,000 REST requests an hour.

Organizations on Copilot Business or Copilot Enterprise have one more switch. The "MCP servers in Copilot" policy is disabled by default and must be turned on before members can use MCP in Copilot. It does not apply to Copilot Free, Pro, Pro+ or Max users, or to third-party hosts such as Claude Code and Cursor; those are governed by organization OAuth app, GitHub App and personal access token policies.

OAuth or a personal access token

The remote server accepts both, but OAuth needs the host application to register its own GitHub App or OAuth app. GitHub's support table by host lists OAuth and PAT support for Copilot in VS Code, Visual Studio, JetBrains IDEs, Xcode and Eclipse. Claude Code, Claude Desktop, Cursor and Windsurf connect to the remote server with a PAT, and GitHub's Codex guide does the same.

The local server can sign you in with OAuth on its own. The official binary and Docker image include a registered GitHub OAuth app for github.com, open your browser on first use, and keep the token in memory only. In Docker you publish a fixed callback port, and a device-code flow covers machines without a browser. If GITHUB_PERSONAL_ACCESS_TOKEN is also set, the PAT takes precedence. For unattended jobs, the stdio server can authenticate as a GitHub App installation using the app's private key, and acts as that installation rather than as a person.

The credential also changes which tools appear. With a classic PAT, the server reads the token's scopes at startup and hides tools it cannot use. Fine-grained PATs and GitHub App tokens show every tool and leave GitHub's API to refuse calls the token is not allowed to make. Remote OAuth sessions also show every tool; when a call needs a scope the user has not granted, the server returns a scope challenge and the client asks the user to approve it.

If you use a PAT, GitHub recommends a fine-grained token: it can be limited to specific repositories and specific permissions, and GitHub recommends giving it an expiration. GitHub's governance guide also describes PATs as user-scoped and not recommended for production automation. Enterprise Managed Users cannot use PATs unless an enterprise administrator has enabled them.

Connect it to Claude Code, Cursor and Codex

Each setup below uses the remote server with a fine-grained PAT in an environment variable named GITHUB_PAT. For a read-only setup, change the URL to https://api.githubcopilot.com/mcp/readonly.

Claude Code. The Claude Code MCP docs use this form for GitHub. Run /mcp afterwards: a working server shows a checkmark, and a bad token shows the HTTP status, such as 401.

claude mcp add --transport http github https://api.githubcopilot.com/mcp/ \ --header "Authorization: Bearer $GITHUB_PAT"

Cursor. Add the server to ~/.cursor/mcp.json for all projects or .cursor/mcp.json for one. Cursor reads ${env:GITHUB_PAT} from your environment.

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

Codex. Add the server to ~/.codex/config.toml, which the Codex CLI and IDE extension share. Codex sends the variable's value as a bearer token.

[mcp_servers.github] url = "https://api.githubcopilot.com/mcp/" bearer_token_env_var = "GITHUB_PAT"

Each of these runs as the GitHub account that owns the PAT. That suits your own editor, but an agent your customers use needs each customer's own credential.

What changes when one agent serves many GitHub users

Take a code review assistant inside your product. Customer A connects it to their repositories, and customer B to theirs. If the agent runs on one shared PAT or a bot account:

  • Every call acts as the token owner, so the agent can reach any repository that account can reach, whichever customer asked.
  • GitHub's audit log shows one actor for every customer's actions.
  • All customers share one rate limit, 5,000 requests an hour for a personal token.
  • Removing one customer's access means rotating the token for everyone.

Per-user OAuth gives every call the requesting user's own token. GitHub then applies that user's repository permissions, their organization's SSO and OAuth app policies, and records the real person in its audit log. The work moves to your side: an OAuth app and consent flow, encrypted token storage keyed by your own user ID, detection of expired or revoked grants, a way to remove one user, and a guarantee that each run uses only its own user's token. The same work repeats for every app among your product's MCP integrations, and per-user OAuth for MCP integrations covers the design in depth.

You can build this on the official server. Its http mode takes a bearer token on each request, so a gateway you run can look up the user's GitHub token and attach it. The OAuth app, token store, refresh handling, revocation and isolation tests stay with you.

Managed per-user OAuth with Scalekit

Scalekit AgentKit runs the per-user layer as a service. Its GitHub connector has 217 tools (106 read, 76 write, 35 destructive) and uses OAuth 2.0 with Scalekit's OAuth app or your own. Each user signs in to GitHub once. Scalekit stores the tokens encrypted with AES-256-GCM under a key for each environment, refreshes them, and makes each call as that user, so the agent never holds a GitHub token. New environments include a GitHub connection named github-connect.

If you prefer GitHub's own tool definitions, the GitHub MCP connector routes calls to GitHub's MCP server through Scalekit with the same per-user sign-in. It has 46 tools and uses your own GitHub OAuth app.

Connect each user once. Use your app's internal user ID as the identifier, never an email address. The link opens GitHub's consent screen.

import os from scalekit import ScalekitClient scalekit_client = ScalekitClient( env_url=os.environ["SCALEKIT_ENVIRONMENT_URL"], client_id=os.environ["SCALEKIT_CLIENT_ID"], client_secret=os.environ["SCALEKIT_CLIENT_SECRET"], ) actions = scalekit_client.actions GITHUB = "github-connect" # the GitHub connection new environments include def github_link_if_needed(user_id: str) -> str | None: """Return an authorization link if this user has not connected GitHub yet.""" account = actions.get_or_create_connected_account( connection_name=GITHUB, identifier=user_id ).connected_account if account.status == "ACTIVE": return None return actions.get_authorization_link( connection_name=GITHUB, identifier=user_id ).link

Create one Virtual MCP server per agent role. All users share its mcp_server_url. This one lets a triage agent read repositories, issues and pull requests, and comment on issues. The agent also sees a connect_account tool it can use to send a user who has not connected GitHub an authorization link.

from scalekit.actions.models.mcp_config import McpConfigConnectionToolMapping response = actions.mcp.create_config( name="repo-triage", description="Reads a user's repositories, issues and pull requests", connection_tool_mappings=[ McpConfigConnectionToolMapping( connection_name=GITHUB, tools=[ "github_user_repos_list", "github_issues_list", "github_pull_requests_list", "github_issue_comment_create", ], ), ], ) config_id = response.config.id mcp_server_url = response.config.mcp_server_url

Mint a session token before each run. Check the user's account first, then mint a token for that user on that server.

from datetime import timedelta state = actions.mcp.list_mcp_connected_accounts( config_id=config_id, identifier="user_123", include_auth_link=True ) for a in state.connected_accounts: if a.connected_account_status != "ACTIVE": print(f"Send {a.authentication_link} to the user for {a.connection_name}") session = actions.mcp.create_session_token( mcp_config_id=config_id, identifier="user_123", expiry=timedelta(minutes=30), access_level="READ_ONLY", # leave out for runs that may comment )

Connect the agent. Any MCP client works with the server URL and the bearer header. With the Python MCP SDK 2.x:

import asyncio import httpx2 from mcp import Client from mcp.client.streamable_http import streamable_http_client async def run(server_url: str, token: str): headers = {"Authorization": f"Bearer {token}"} async with httpx2.AsyncClient(headers=headers, timeout=30) as http: async with Client(streamable_http_client(server_url, http_client=http)) as mcp: tools = await mcp.list_tools() print([t.name for t in tools.tools]) result = await mcp.call_tool( "github_issues_list", {"owner": "acme", "repo": "api", "state": "open"} ) print(result.content) asyncio.run(run(mcp_server_url, session.token))

How session tokens behave:

  • A token is bound to one user and one server. Used on any other server URL, it returns 401.
  • It lasts one hour by default; you can set anything from 60 seconds to 24 hours.
  • It is short-lived by design and is never refreshed. Mint a new one per run, per chat session, or on a schedule for a long-running host. Minting a new token does not revoke older ones.
  • A read-only token lists only the server's read-only tools and refuses the rest, so the run above cannot post the issue comment. Leave out access_level for a run where the user has approved a write.

For your own editor, every connection also has its own MCP server with all of its tools at <environment URL>/mcp/v3/connections/<connection name>. Mint a token with connection_name="github-connect" and add it to Claude Code the same way as GitHub's server. Tokens last at most 24 hours, so mint a fresh one each day for a config you edit by hand.

claude mcp add --transport http scalekit-github \ "$SCALEKIT_ENVIRONMENT_URL/mcp/v3/connections/github-connect" \ --header "Authorization: Bearer $SESSION_TOKEN"

Remove one user. Delete their connected account. Their next tool call fails until they authorize again, and other users keep working. Scalekit also sends a connected_account.status_updated webhook when an account changes status, for example from ACTIVE to EXPIRED, so you can send a new link before a call fails.

actions.delete_connected_account(connection_name=GITHUB, identifier="user_123")

Toolsets, scopes and permissions compared

Both paths limit the agent at two levels: which tools it can see, and what the credential behind each call allows.

Control
GitHub MCP server
Scalekit GitHub connector
Tools the agent sees
Toolsets and tool allow-lists: --toolsets, --tools, X-MCP-Toolsets, X-MCP-Tools
An exact tool list for each Virtual MCP server
Read-only
--read-only, X-MCP-Readonly or the /readonly URL; write tools are skipped even if listed
A READ_ONLY session token, chosen per run on the same server
What the credential allows
The PAT's repositories and permissions, or the OAuth scopes the user approved
The scopes set on the connection, shared by every user of that connection
Whose account
The one PAT owner or OAuth user in the client config
Each end user's connected account, selected by the session token

GitHub's own permission model applies on both paths: neither can reach more than the user could through GitHub's API. On Scalekit, scopes are set per connection, so create a second GitHub connection for a group of users that needs different scopes.

Which option fits

Option
Acts as
Credential
Best fit
Watch for
Remote server with a PAT
The PAT owner
Fine-grained PAT in the client config
One developer in Claude Code, Cursor or Codex
Expiry and rotation; one rate limit
Remote server with OAuth
The signed-in user
OAuth through the host's GitHub app
Copilot in VS Code, Visual Studio, JetBrains, Xcode or Eclipse
Available only in hosts with a registered GitHub app
Local server
The PAT owner, the OAuth user, or a GitHub App installation
PAT, built-in OAuth login, or an app private key
GitHub Enterprise Server, pinned versions, private networks
You run and update the process
Self-hosted http mode behind your gateway
Whichever user's token the gateway attaches
Bearer token on each request
Teams building their own per-user layer
You build OAuth, storage, refresh and revocation
Scalekit GitHub connector
Each end user
Session token per user and run; GitHub tokens stay in Scalekit
Products whose agent acts for many users
Mint a token per run; at most 24 hours

GitHub's server is the better fit when the agent works for you or your team in an editor or Copilot host, needs Copilot-only tools such as handing work to Copilot coding agent, or must reach GitHub Enterprise Server. A managed per-user layer such as the Scalekit GitHub connector fits when your product's agent acts in many customers' GitHub accounts. For calling GitHub through MCP versus its REST API, see GitHub MCP vs API for AI agents.

Security notes

  • Scopes. Limit fine-grained PATs to the repositories the agent needs and give them an expiration. For OAuth connections, request only the scopes the chosen tools need.
  • Write actions. GitHub notes that Copilot cloud agent calls configured MCP tools without asking for approval. Start agents read-only, keep destructive tools such as merging or deleting off the server unless the job needs them, and ask the user before a destructive call. Scalekit tool definitions carry read_only_hint and destructive_hint for this check.
  • Untrusted content. Issues and comments in public repositories can carry prompt injection. Lockdown mode hides content from authors without push access; GitHub describes it as a best-effort filter, not an authorization boundary.
  • Revocation. Delete a leaked PAT in GitHub's token settings. On Scalekit, delete the user's connected account; short session tokens also limit how long a leaked one works.
  • Audit. GitHub records MCP traffic in its audit log as ordinary API calls. Scalekit keeps tool call logs (tool, connected account, identifier, status, duration) for 90 days, and the logs never contain a tool's successful response.

Troubleshooting

Symptom
Likely cause
Fix
401 from api.githubcopilot.com
The PAT expired, was revoked or was pasted incompletely
Create a new PAT and update the environment variable
No OAuth prompt in Claude Code, Cursor or Codex
These hosts connect to the remote server with a PAT
Use a PAT, or run the local server with its OAuth login
An expected tool is missing
Its toolset is not enabled (five are on by default), or a classic PAT lacks the scope
Add the toolset with X-MCP-Toolsets or an /x/ URL, or add the scope
The server will not start after setting X-MCP-Tools
A tool name is misspelled; names must match exactly
Fix the name. Unknown toolsets in X-MCP-Toolsets are ignored silently, so check those too
Organization repositories are missing
The org has not approved the OAuth app or the fine-grained PAT, or the user had no active SSO session when signing in or creating the token
Ask an org admin to approve access, then sign in through the org's SSO and connect again
Scalekit returns 401 invalid or expired bearer token
The session token expired or was minted for another server
Mint a new token for this server

FAQs

What is the GitHub MCP server?

It is GitHub's official MCP server, open source under the MIT license, that gives AI agents tools for repositories, issues, pull requests, Actions and security alerts. It runs as a hosted server at api.githubcopilot.com/mcp/ or locally in Docker, and acts as the GitHub user whose credential it holds.

Does GitHub have an official MCP server?

Yes. GitHub maintains github/github-mcp-server and hosts a remote version at https://api.githubcopilot.com/mcp/. The older npm package @modelcontextprotocol/server-github is no longer supported as of April 2025.

Is the GitHub MCP server free?

Yes. GitHub makes it available to all users regardless of plan type, and the code is open source under the MIT license. Tools tied to paid features keep those requirements: Copilot cloud agent tools need a paid Copilot license, and code scanning on private repositories needs a GitHub Code Security license.

Is GitHub MCP useful?

It is useful when an agent needs live repository context, such as reading code, triaging issues, reviewing pull requests or checking failed Actions runs. Enable only the toolsets the task needs, since GitHub notes that fewer tools improve tool selection and save context.

Can I use GitHub MCP with Claude Code?

Yes. Run claude mcp add --transport http github https://api.githubcopilot.com/mcp/ with an Authorization: Bearer header that holds a fine-grained PAT, then check the server with /mcp. The local Docker server also works in Claude Code and supports an OAuth login.

How do I let each of my users connect their own GitHub account?

Use per-user OAuth: each user authorizes once, and every call runs with that user's token. With Scalekit, users share one MCP server URL, and each run carries a short-lived session token bound to one user and one server.

Can I make the GitHub MCP server read-only?

Yes. Use https://api.githubcopilot.com/mcp/readonly, the X-MCP-Readonly header, or --read-only on the local server. Write tools are then left out even if you list them.

Details checked October 2026.

No items found.
On this page
Share this article

Acquire enterprise customers with
‍zero upfront cost.

Every feature unlocked. No hidden fees.