-
Notifications
You must be signed in to change notification settings - Fork 3.5k
OAuth metadata implementation #1862
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: http-stack-2
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR implements OAuth 2.0 Protected Resource Metadata (RFC 9728) support for the GitHub MCP Server's HTTP mode, migrating functionality from the Remote MCP Server to the open-source repository. The changes enable OAuth-compliant authentication challenges and resource discovery for MCP clients.
Changes:
- Added new
pkg/http/oauthpackage with OAuth resource metadata endpoint handlers and URL builders - Enhanced authentication middleware to send WWW-Authenticate challenges with resource metadata URLs
- Added forwarding header support (X-Forwarded-Host, X-Forwarded-Proto, X-GitHub-Original-Path) for proxy environments
- Introduced
--base-urlCLI flag for configuring the public server URL
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| pkg/http/oauth/oauth.go | Core OAuth metadata implementation with route registration, metadata builders, and utility functions for determining effective host/scheme |
| pkg/http/oauth/oauth_test.go | Comprehensive test suite covering OAuth handler initialization, URL building, route registration, and metadata format compliance |
| pkg/http/server.go | Integrates OAuth handler registration into HTTP server initialization |
| pkg/http/handler.go | Adds OAuth config as an optional parameter to HTTPMcpHandler |
| pkg/http/middleware/token.go | Updates token extraction middleware to send OAuth-compliant auth challenges |
| pkg/http/headers/headers.go | Defines new header constants for proxy forwarding and original path preservation |
| cmd/github-mcp-server/main.go | Adds base-url CLI flag and passes it through to HTTP server config |
Comments suppressed due to low confidence (3)
pkg/http/oauth/oauth.go:111
- The buildMetadata function creates metadata at handler registration time with a static resource URL. This means the metadata will always use the BaseURL from the config and won't dynamically adapt to request headers like X-Forwarded-Host. This is a design decision that may be intentional for consistency, but it means that when BaseURL is not configured, the resource field will be empty. Consider whether the metadata should be built dynamically per-request or if BaseURL should be required when using OAuth metadata.
func (h *AuthHandler) buildMetadata(resourcePath string) *oauthex.ProtectedResourceMetadata {
baseURL := strings.TrimSuffix(h.cfg.BaseURL, "/")
resourceURL := baseURL
if resourcePath != "" && resourcePath != "/" {
resourceURL = baseURL + resourcePath
}
pkg/http/oauth/oauth.go:24
- The PR checklist indicates that linting was not run locally with
script/lint. Per the coding guidelines, linting is mandatory before committing Go code changes. Please runscript/lintto identify and fix any formatting or lint issues before merging.
// Package oauth provides OAuth 2.0 Protected Resource Metadata (RFC 9728) support
// for the GitHub MCP Server HTTP mode.
package oauth
import (
"fmt"
"net/http"
"net/url"
"strings"
"github.com/modelcontextprotocol/go-sdk/auth"
"github.com/github/github-mcp-server/pkg/http/headers"
"github.com/go-chi/chi/v5"
"github.com/modelcontextprotocol/go-sdk/oauthex"
)
const (
// OAuthProtectedResourcePrefix is the well-known path prefix for OAuth protected resource metadata.
OAuthProtectedResourcePrefix = "/.well-known/oauth-protected-resource"
// DefaultAuthorizationServer is GitHub's OAuth authorization server.
DefaultAuthorizationServer = "https://github.com/login/oauth"
)
pkg/http/oauth/oauth.go:54
- The ResourcePath field in the Config struct is defined but never used. The GetEffectiveResourcePath function doesn't reference cfg.ResourcePath. Either remove this unused field or implement its intended functionality.
// ResourcePath is the resource path suffix (e.g., "/mcp").
// If empty, defaults to "/"
ResourcePath string
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
3daa5c3 to
03a5082
Compare
…hub/github-mcp-server into oauth-handler-implementation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.
| // sendAuthChallenge sends a 401 Unauthorized response with WWW-Authenticate header | ||
| // containing the OAuth protected resource metadata URL as per RFC 6750 and MCP spec. | ||
| func sendAuthChallenge(w http.ResponseWriter, r *http.Request, oauthCfg *oauth.Config) { | ||
| resourceMetadataURL := oauth.BuildResourceMetadataURL(r, oauthCfg, "mcp") | ||
| w.Header().Set("WWW-Authenticate", fmt.Sprintf(`Bearer resource_metadata=%q`, resourceMetadataURL)) | ||
| http.Error(w, "Unauthorized", http.StatusUnauthorized) | ||
| } |
Copilot
AI
Jan 28, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new function sendAuthChallenge and the modified ExtractUserToken middleware function lack test coverage. The oauth package has comprehensive tests, but the middleware changes that use this package are not tested. This is inconsistent with the codebase's testing practices, as the oauth package itself has 11 test functions covering various scenarios.
Consider adding tests for:
- The
sendAuthChallengefunction to verify the WWW-Authenticate header format - The
ExtractUserTokenmiddleware with missing authorization headers to ensure proper 401 responses with OAuth metadata URLs - Different oauth config scenarios (nil config, custom BaseURL, etc.)
pkg/http/oauth/oauth.go
Outdated
| func (h *AuthHandler) buildMetadata(resourcePath string) *oauthex.ProtectedResourceMetadata { | ||
| baseURL := strings.TrimSuffix(h.cfg.BaseURL, "/") | ||
| resourceURL := baseURL | ||
| if resourcePath != "" && resourcePath != "/" { | ||
| resourceURL = baseURL + resourcePath | ||
| } |
Copilot
AI
Jan 28, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When BaseURL is not configured (empty string), the buildMetadata function will create OAuth metadata with an incomplete or invalid Resource field. For example, if BaseURL is empty and resourcePath is "/mcp", the resulting Resource will be just "/mcp" (a relative URL), which violates RFC 9728's requirement for an absolute URL.
Consider either:
- Validating that BaseURL is set when creating the AuthHandler
- Documenting that BaseURL is required for proper OAuth metadata
- Using a dynamic handler that builds the Resource URL from the incoming request's host (similar to how
BuildResourceMetadataURLworks)
Depends on: https://github.com/github/github-mcp-server-remote/pull/628
Summary
This pull request adds comprehensive support for OAuth 2.0 Protected Resource Metadata (RFC 9728) to the GitHub MCP server in HTTP mode. The main improvements include introducing a new
oauthpackage for serving OAuth resource metadata endpoints, updating server configuration to support a public base URL, and enhancing authentication middleware to comply with OAuth standards. The purpose of these changes is to migrate functionality from the Remote MCP Server to OSS as part of the upcoming HTTP handler changes.Why
Closes: https://github.com/github/copilot-mcp-core/issues/1206
What changed
MCP impact
Prompts tested (tool changes only)
Security / limits
Tool renaming
deprecated_tool_aliases.goNote: if you're renaming tools, you must add the tool aliases. For more information on how to do so, please refer to the official docs.
Lint & tests
./script/lint./script/testDocs