github/github-mcp-server · error
Forbidden: insufficient scopes
Error message
Forbidden: insufficient scopes
What it means
WithScopeChallenge runs only for OAuth tokens (gho_) on tools/call requests: it looks up the OAuth scopes the target tool accepts (from the global tool scope map built at startup), fetches the token's actually-granted scopes from GitHub, and if none of the accepted scope sets is satisfied returns 403 'Forbidden: insufficient scopes'. The response carries WWW-Authenticate: Bearer error="insufficient_scope" with a superset of existing+required scopes and a resource_metadata URL (RFC 9727 style) so clients can re-authorize with the right scopes.
Source
Thrown at pkg/http/middleware/scope_challenge.go:141
// which is used to construct the well-known OAuth protected resource URL
resourcePath := oauth.ResolveResourcePath(r, oauthCfg)
resourceMetadataURL := oauth.BuildResourceMetadataURL(r, oauthCfg, resourcePath)
// Build recommended scopes: existing scopes + required scopes
recommendedScopes := make([]string, 0, len(activeScopes)+len(requiredScopes))
recommendedScopes = append(recommendedScopes, activeScopes...)
recommendedScopes = append(recommendedScopes, requiredScopes...)
// Build the WWW-Authenticate header value
wwwAuthenticateHeader := fmt.Sprintf(`Bearer error="insufficient_scope", scope=%q, resource_metadata=%q, error_description=%q`,
strings.Join(recommendedScopes, " "),
resourceMetadataURL,
"Additional scopes required: "+strings.Join(requiredScopes, ", "),
)
// Send scope challenge response with the superset of existing and required scopes
w.Header().Set("WWW-Authenticate", wwwAuthenticateHeader)
http.Error(w, "Forbidden: insufficient scopes", http.StatusForbidden)
}
return http.HandlerFunc(fn)
}
}
View on GitHub (pinned to 0ea1f775a7)
Solutions
- Read the WWW-Authenticate header: the scope="..." value lists exactly which scopes to request
- Re-run the OAuth flow requesting those scopes (or grant them via app settings) and retry with the new token
- As a client, implement the insufficient_scope challenge: parse resource_metadata and re-authorize instead of surfacing a generic 403
- Avoid narrow-scope consent for general-purpose MCP usage
Example fix
# before: client treats 403 as fatal
resp = call_tool('create_issue', args)
# after: handle the scope challenge
if resp.status == 403 and 'insufficient_scope' in resp.headers.get('WWW-Authenticate', ''):
needed = parse_scopes(resp.headers['WWW-Authenticate'])
token = reauthorize(requested_scopes=needed) # new OAuth flow
resp = call_tool('create_issue', args, token=token) Defensive patterns
Strategy: validation
Validate before calling
// pre-check before invoking a tool with an OAuth token
granted, err := scopeFetcher.FetchTokenScopes(ctx, token)
if err == nil {
if info, _ := scopes.GetToolScopeInfo(toolName); info != nil && !info.HasAcceptedScope(granted...) {
return fmt.Errorf("token lacks scopes for %s: need one of %v - re-authorize first",
toolName, info.GetRequiredScopesSlice())
}
} Try / catch
if resp.StatusCode == http.StatusForbidden {
if strings.Contains(resp.Header.Get("WWW-Authenticate"), "insufficient_scope") {
// parse scope= and resource_metadata= from the header, re-run the OAuth flow with those scopes, retry
}
} Prevention
- Request the full documented scope set at initial authorization rather than the minimum
- Parse WWW-Authenticate on 403 instead of surfacing a generic error
- Maintain a client-side map of tool to required scopes and pre-check before tools/call
When it happens
Trigger: A tools/call with a gho_ token whose granted scopes do not cover the tool - e.g. an issue-writing tool invoked with a token granted only read:user, because consent requested a minimal scope set or an org restricted the grant.
Common situations: Remote MCP clients authorized without 'repo'; enterprise OAuth apps with admin-restricted scopes; users declining optional scopes during consent and then invoking write tools.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- App not connected
- %w: missing required Authorization header
- authentication required: set GITHUB_PERSONAL_ACCESS_TOKEN, c
- authorization failed: %s
- no authorization code in callback
AI-assisted analysis of github/github-mcp-server@0ea1f775a7 (2026-08-15).
Data as JSON: /api/errors/6a588bf2ffa5ace0.
Report an issue: GitHub.