OAuth Authentication Flow for the Remote GitHub MCP Server: Complete Guide
The remote GitHub MCP server implements an OAuth 2.0 Authorization Code flow with optional PKCE support and a custom scope-challenge mechanism that dynamically requests additional GitHub permissions when tools require scopes beyond those initially granted.
The github/github-mcp-server supports remote deployment scenarios where clients authenticate via OAuth 2.0 rather than personal access tokens. Understanding the OAuth authentication flow for the remote MCP server is essential for developers building integrations that interact with GitHub's API through the Model Context Protocol. This guide breaks down the complete authorization sequence—from initial app registration through dynamic scope challenges—based on the actual implementation in the repository source code.
OAuth 2.0 Authorization Code Flow with PKCE
The server follows the OAuth 2.0 Authorization Code flow with optional PKCE (Proof Key for Code Exchange) to prevent authorization code interception attacks. The implementation defines supported GitHub scopes in pkg/http/oauth/oauth.go within the SupportedScopes slice, which enumerates all available permissions the MCP server can request during authorization.
Step-by-Step Authentication Process
Register the OAuth Application
Before initiating authentication, you must register a GitHub OAuth App or GitHub App in your organization or user settings. This registration provides the client_id and client_secret required for the flow. For remote MCP server deployments, the redirect URI must point to your local or hosted callback endpoint capable of receiving the authorization code. Refer to docs/host-integration.md for detailed registration requirements.
Initiate Authorization with PKCE
Generate a PKCE code verifier and challenge to secure the authorization request. The client opens GitHub's authorization endpoint at https://github.com/login/oauth/authorize—defined as DefaultAuthorizationServer in pkg/http/oauth/oauth.go—including the challenge and requested scopes.
# Generate PKCE verifier and challenge
CODE_VERIFIER=$(openssl rand -base64 32 | tr -d '=+/')
CODE_CHALLENGE=$(echo -n "$CODE_VERIFIER" | openssl sha256 -binary | openssl base64 | tr -d '=+/')
# Open authorization URL (macOS)
open "https://github.com/login/oauth/authorize?client_id=YOUR_CLIENT_ID&redirect_uri=http://localhost:8080/callback&scope=repo%20read:user&code_challenge=$CODE_CHALLENGE&code_challenge_method=S256"
After user consent, GitHub redirects to your callback URL with a code parameter.
Exchange Code for Access Token
Exchange the temporary authorization code for a Bearer token (prefixed with gho_) by posting to GitHub's token endpoint. The client performs this exchange—not the MCP server—using the client credentials and PKCE verifier.
curl -X POST https://github.com/login/oauth/access_token \
-d client_id=YOUR_CLIENT_ID \
-d client_secret=YOUR_CLIENT_SECRET \
-d code=AUTH_CODE \
-d redirect_uri=http://localhost:8080/callback \
-d code_verifier=$CODE_VERIFIER \
-H "Accept: application/json"
The JSON response contains the access_token (e.g., gho_xxxxxxxx), token_type (Bearer), and granted scope.
Authenticate MCP Requests
Include the Bearer token in the Authorization header for every MCP JSON-RPC request. The server extracts and validates these tokens using middleware defined in pkg/http/middleware/token.go.
curl -X POST https://api.githubcopilot.com/mcp/x/repos \
-H "Authorization: Bearer gho_xxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"repo_get","arguments":{"owner":"octocat","repo":"Hello-World"}}}'
Dynamic Scope Challenges
The remote MCP server implements a scope-challenge mechanism that requests additional permissions when tools require GitHub scopes not present in the current token.
How Scope Challenges Work
When an MCP tool invocation requires additional scopes, the WithScopeChallenge middleware in pkg/http/middleware/scope_challenge.go intercepts the request. It returns a 403 Forbidden response with a WWW-Authenticate header containing error="insufficient_scope" and the missing permissions.
The middleware fetches the token's current scopes using scopeFetcher.FetchTokenScopes, then constructs the challenge header including:
error="insufficient_scope"scopeparameter listing current plus required scopesresource_metadataURL pointing to the OAuth protected resource endpointerror_descriptionexplaining the missing permissions
OAuth Protected Resource Metadata
The server advertises its OAuth configuration via the well-known endpoint /.well-known/oauth-protected-resource, implemented by the metadataHandler() function in pkg/http/oauth/oauth.go. This endpoint returns a JSON document containing:
resource: The full URL of the MCP serverauthorization_servers: Array containing GitHub's OAuth URL (https://github.com/login/oauth)scopes_supported: Complete list from theSupportedScopesconfiguration inpkg/http/oauth/oauth.go
Handling Insufficient Scopes
When receiving a 403 scope challenge, clients must:
- Parse the
WWW-Authenticateheader to extract thescopeparameter showing required permissions - Extract the
resource_metadataURL to confirm the server identity - Re-initiate the OAuth flow requesting the additional scopes listed in the challenge
- Retry the original MCP request with the new token containing the expanded permissions
# Example: Handling a scope challenge response
# Server returns 403 with header:
# WWW-Authenticate: Bearer error="insufficient_scope", scope="repo read:user workflow", resource_metadata="https://api.githubcopilot.com/.well-known/oauth-protected-resource", error_description="Additional scopes required: workflow"
# Re-authorize with the additional workflow scope
open "https://github.com/login/oauth/authorize?client_id=YOUR_CLIENT_ID&redirect_uri=http://localhost:8080/callback&scope=repo%20read:user%20workflow&code_challenge=$CODE_CHALLENGE&code_challenge_method=S256"
Key Implementation Files
The OAuth authentication system is implemented across these critical files in the github/github-mcp-server repository:
-
pkg/http/oauth/oauth.go: DefinesDefaultAuthorizationServer,SupportedScopes, and themetadataHandler()function for the OAuth protected resource endpoint. -
pkg/http/middleware/scope_challenge.go: Implements theWithScopeChallengemiddleware that handles insufficient scope errors and constructsWWW-Authenticatechallenge headers. -
pkg/http/middleware/token.go: Handles extraction and validation of Bearer tokens from incoming requests, containing the OAuth protected resource metadata URL configuration. -
docs/host-integration.md: Documentation for registering OAuth applications and host integration requirements. -
docs/scope-filtering.md: Detailed explanation of scope challenges and dynamic permission requests. -
docs/remote-server.md: Overview of remote server deployment and OAuth metadata endpoint specifications.
Summary
- The remote GitHub MCP server implements OAuth 2.0 Authorization Code flow with optional PKCE support for secure token exchange.
- Authentication requires registering a GitHub OAuth App to obtain
client_idandclient_secretbefore initiating the authorization sequence. - The server validates Bearer tokens (prefixed
gho_) via middleware inpkg/http/middleware/token.goon every MCP JSON-RPC request. - A scope-challenge mechanism in
pkg/http/middleware/scope_challenge.goenables dynamic permission requests when tools require additional GitHub scopes. - The OAuth protected resource metadata endpoint at
/.well-known/oauth-protected-resourceadvertises supported scopes and authorization server details.
Frequently Asked Questions
What OAuth flow does the remote GitHub MCP server use?
The server uses the OAuth 2.0 Authorization Code flow with optional PKCE (Proof Key for Code Exchange) support. This implementation is defined in pkg/http/oauth/oauth.go through the DefaultAuthorizationServer configuration, requiring clients to exchange a temporary authorization code for a Bearer token via GitHub's standard token endpoint at https://github.com/login/oauth/access_token.
How does the scope challenge mechanism work?
When an MCP tool requires GitHub scopes not present in the current token, the WithScopeChallenge middleware in pkg/http/middleware/scope_challenge.go returns a 403 Forbidden response with a WWW-Authenticate header containing error="insufficient_scope". The header includes a scope parameter listing the required permissions and a resource_metadata URL pointing to the OAuth protected resource endpoint, enabling clients to re-authenticate with elevated permissions.
Where is the OAuth protected resource metadata endpoint located?
The metadata endpoint is located at /.well-known/oauth-protected-resource relative to the MCP server base URL. Implemented by the metadataHandler() function in pkg/http/oauth/oauth.go, this endpoint returns a JSON document containing the resource identifier, authorization_servers array (pointing to GitHub's OAuth endpoint), and scopes_supported list from the SupportedScopes configuration.
What token format does GitHub return for MCP authentication?
GitHub returns Bearer tokens prefixed with gho_ (representing GitHub OAuth tokens). Clients must include these tokens in the Authorization: Bearer <token> header for every MCP JSON-RPC request. The server extracts and validates these tokens using the middleware defined in pkg/http/middleware/token.go before processing tool invocations.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →