Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
feat(http): add --authorization-server flag to override OAuth AS URL
When deploying the MCP server behind an OAuth proxy (e.g. for GHES,
which does not natively support RFC 8414, RFC 7591, or PKCE), the
/.well-known/oauth-protected-resource endpoint currently always derives
the authorization_servers URL from GITHUB_HOST. There is no way to
point clients at a different authorization server without intercepting
that endpoint at the ingress/proxy layer.

The oauth.Config struct already has an AuthorizationServer field with
the conditional logic in place (pkg/http/oauth/oauth.go), but it was
never wired to any configuration surface.

This commit exposes it as:
- --authorization-server CLI flag on the http subcommand
- GITHUB_AUTHORIZATION_SERVER environment variable (via viper's
  existing GITHUB_ prefix + automatic env mapping)

When set, the value is passed through ServerConfig into oauth.Config,
and the protected resource metadata advertises it directly instead of
calling apiHost.AuthorizationServerURL().
  • Loading branch information
Anika-Sol authored and SamMorrowDrums committed Aug 20, 2026
commit b102004cad793a65503a181c56646e525ef04534
3 changes: 3 additions & 0 deletions cmd/github-mcp-server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ var (
ListenHost: viper.GetString("listen-host"),
BaseURL: viper.GetString("base-url"),
ResourcePath: viper.GetString("base-path"),
AuthorizationServer: viper.GetString("authorization-server"),
ExportTranslations: viper.GetBool("export-translations"),
EnableCommandLogging: viper.GetBool("enable-command-logging"),
LogFilePath: viper.GetString("log-file"),
Expand Down Expand Up @@ -264,6 +265,7 @@ func init() {
httpCmd.Flags().String("listen-host", "", "Host the HTTP server binds to (e.g. 127.0.0.1). Empty binds to all interfaces.")
httpCmd.Flags().String("base-url", "", "Base URL where this server is publicly accessible (for OAuth resource metadata)")
httpCmd.Flags().String("base-path", "", "Externally visible base path for the HTTP server (for OAuth resource metadata)")
httpCmd.Flags().String("authorization-server", "", "Override the authorization server URL in OAuth resource metadata. Useful when deploying behind an OAuth proxy (e.g. for GHES). Env: GITHUB_AUTHORIZATION_SERVER")
httpCmd.Flags().Bool("scope-challenge", false, "Enable OAuth scope challenge responses")
httpCmd.Flags().Bool("trust-proxy-headers", false, "Honor X-Forwarded-Host and X-Forwarded-Proto when constructing OAuth resource metadata URLs. Only enable when the server is deployed behind a trusted proxy that sets these headers. Ignored when --base-url is set.")

Expand Down Expand Up @@ -292,6 +294,7 @@ func init() {
_ = viper.BindPFlag("listen-host", httpCmd.Flags().Lookup("listen-host"))
_ = viper.BindPFlag("base-url", httpCmd.Flags().Lookup("base-url"))
_ = viper.BindPFlag("base-path", httpCmd.Flags().Lookup("base-path"))
_ = viper.BindPFlag("authorization-server", httpCmd.Flags().Lookup("authorization-server"))
_ = viper.BindPFlag("scope-challenge", httpCmd.Flags().Lookup("scope-challenge"))
_ = viper.BindPFlag("trust-proxy-headers", httpCmd.Flags().Lookup("trust-proxy-headers"))
// Add subcommands
Expand Down
25 changes: 25 additions & 0 deletions docs/streamable-http.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,31 @@ github-mcp-server http --trust-proxy-headers

Equivalent environment variable: `GITHUB_TRUST_PROXY_HEADERS=1`. Only enable this when the upstream proxy is trusted to set or strip these headers; otherwise prefer `--base-url`. When `--base-url` is set, it always takes precedence and `--trust-proxy-headers` has no effect.

### With an OAuth Proxy (GHES / non-standard authorization server)

When deploying against GitHub Enterprise Server, GHES does not natively support the OAuth extensions required by MCP (RFC 8414 metadata discovery, RFC 7591 Dynamic Client Registration, PKCE). In this case you can run a separate OAuth proxy that implements the MCP OAuth spec and forwards authentication to GHES. Use `--authorization-server` to advertise the proxy's URL in the protected resource metadata instead of the one derived from `--gh-host`:

```bash
github-mcp-server http \
--gh-host https://github.example.com \
--base-url https://mcp.example.com \
--authorization-server https://mcp.example.com/oauth-proxy
```

The `authorization_servers` field in the protected resource metadata will then point at your proxy:

```json
{
"resource": "https://mcp.example.com",
"authorization_servers": [
"https://mcp.example.com/oauth-proxy"
],
...
}
```

Equivalent environment variable: `GITHUB_AUTHORIZATION_SERVER=https://mcp.example.com/oauth-proxy`.

## Client Configuration

### Using OAuth Authentication
Expand Down
14 changes: 11 additions & 3 deletions pkg/http/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,13 @@ type ServerConfig struct {
// This is used to restore the original path when a proxy strips a base path before forwarding.
ResourcePath string

// AuthorizationServer overrides the authorization server URL advertised in the
// OAuth Protected Resource Metadata (/.well-known/oauth-protected-resource).
// When set, this URL is used instead of the one derived from the GitHub host.
// Useful when deploying behind an OAuth proxy (e.g. for GHES, which does not
// natively support RFC 8414 / RFC 7591 / PKCE).
AuthorizationServer string

// TrustProxyHeaders indicates whether X-Forwarded-Host and X-Forwarded-Proto
// should be honored when constructing OAuth resource metadata URLs. Only
// enable this when the server is deployed behind a trusted proxy that sets
Expand Down Expand Up @@ -191,9 +198,10 @@ func RunHTTPServer(cfg ServerConfig) error {

// Register OAuth protected resource metadata endpoints
oauthCfg := &oauth.Config{
BaseURL: cfg.BaseURL,
ResourcePath: cfg.ResourcePath,
TrustProxyHeaders: cfg.TrustProxyHeaders,
BaseURL: cfg.BaseURL,
ResourcePath: cfg.ResourcePath,
TrustProxyHeaders: cfg.TrustProxyHeaders,
AuthorizationServer: cfg.AuthorizationServer,
}

serverOptions := []HandlerOption{
Expand Down