Skip to content

Conversation

@SamMorrowDrums
Copy link
Collaborator

@SamMorrowDrums SamMorrowDrums commented Jan 5, 2026

Summary

Automatically filter tools based on the user's PAT OAuth scopes. This ensures users only see tools their token has permission to use, reducing clutter and preventing errors from attempting operations without the required scopes.

How It Works

  1. At startup: Server detects if token is a classic PAT (ghp_ prefix)
  2. Scope discovery: Makes HTTP HEAD request to GitHub API, reads X-OAuth-Scopes header
  3. Tool filtering: Tools requiring scopes the token doesn't have are hidden from the tool list

Token Type Behavior

Token Type Behavior
Classic PAT (ghp_) Full scope filtering - tools hidden based on scopes
Fine-grained PAT (github_pat_) No filtering - all tools shown, API enforces permissions
Other tokens No filtering - all tools shown

Changes

New Components in pkg/scopes/

  • filter.go: HasRequiredScopes() checks if user scopes satisfy tool requirements using the scope hierarchy
  • fetcher.go: FetchTokenScopes() gets token scopes via HTTP HEAD request (reads X-OAuth-Scopes header)

New Components in pkg/github/

  • scope_filter.go: CreateScopeFilter() creates an inventory.ToolFilter for scope-based filtering

Integration

  • Server automatically fetches token scopes on startup for classic PATs
  • Gracefully continues without filtering if scope fetch fails (logs warning)
  • Added documentation at docs/scope-filtering.md

Library Usage (for Remote Server)

The scope filtering logic is designed to be reusable:

import (
    "github.com/github/github-mcp-server/pkg/scopes"
    "github.com/github/github-mcp-server/pkg/github"
)

// Check if user scopes satisfy tool requirements  
hasAccess := scopes.HasRequiredScopes(userScopes, tool.AcceptedScopes)

// Or create an inventory filter
filter := github.CreateScopeFilter(userScopes)

Testing

  • Unit tests for HasRequiredScopes
  • Unit tests for FetchTokenScopes with mock HTTP server
  • Unit tests for CreateScopeFilter

Stacked On

This PR is stacked on #1740 (scope hierarchy PR) which provides the ExpandScopes function and scope definitions used here.

@SamMorrowDrums SamMorrowDrums requested a review from a team as a code owner January 5, 2026 12:57
Copilot AI review requested due to automatic review settings January 5, 2026 12:57
Copy link
Contributor

Copilot AI left a 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 adds PAT (Personal Access Token) scope filtering for the stdio server, enabling the server to hide tools that require OAuth scopes not granted to the token. The implementation fetches token scopes via an HTTP HEAD request to GitHub's API and applies filtering at server startup.

Key changes:

  • New pkg/scopes package with scope hierarchy-aware filtering and HTTP-based scope fetching
  • Integration with the inventory system to filter tools based on token scopes
  • Opt-in --enable-scope-filtering CLI flag (disabled by default for graceful degradation)

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
pkg/scopes/filter.go Package documentation for scope filtering utilities
pkg/scopes/scopes.go Adds HasRequiredScopes function and internal expandScopeSet helper for hierarchy-aware scope checking
pkg/scopes/scopes_test.go Comprehensive test coverage for scope expansion and filtering logic
pkg/scopes/fetcher.go HTTP fetcher implementation that retrieves token scopes via HEAD request to GitHub API
pkg/scopes/fetcher_test.go Unit tests for scope fetcher with mock HTTP servers
pkg/github/scope_filter.go Creates CreateToolScopeFilter function that bridges scopes package with inventory system
pkg/github/scope_filter_test.go Tests for scope filter integration with inventory builder
internal/ghmcp/server.go Integrates scope filtering into server startup, adding TokenScopes config field and fetchTokenScopesForHost helper
cmd/github-mcp-server/main.go Adds --enable-scope-filtering CLI flag with viper binding
README.md Auto-generated documentation updates showing reordered accepted scopes (cosmetic)

@SamMorrowDrums SamMorrowDrums force-pushed the copilot/add-oauth-scopes-documentation branch from c4c6491 to 742dfe3 Compare January 5, 2026 13:31
@SamMorrowDrums SamMorrowDrums force-pushed the copilot/pat-scope-filtering branch 2 times, most recently from a496f06 to 7c31fda Compare January 5, 2026 13:44
omgitsads
omgitsads previously approved these changes Jan 5, 2026
Copy link
Member

@omgitsads omgitsads left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀

Base automatically changed from copilot/add-oauth-scopes-documentation to main January 5, 2026 15:54
@SamMorrowDrums SamMorrowDrums dismissed omgitsads’s stale review January 5, 2026 15:54

The base branch was changed.

SamMorrowDrums and others added 13 commits January 5, 2026 16:59
Add the ability to filter tools based on token scopes for PAT users.
This uses an HTTP HEAD request to GitHub's API to discover token scopes.

New components:
- pkg/scopes/filter.go: HasRequiredScopes checks if scopes satisfy tool requirements
- pkg/scopes/fetcher.go: FetchTokenScopes gets scopes via HTTP HEAD to GitHub API
- pkg/github/scope_filter.go: CreateScopeFilter creates inventory.ToolFilter

Integration:
- Add --filter-by-scope flag to stdio command (disabled by default)
- When enabled, fetches token scopes on startup
- Tools requiring unavailable scopes are hidden from tool list
- Gracefully continues without filtering if scope fetch fails (logs warning)

This allows the OSS server to have similar scope-based tool visibility
as the remote server, and the filter logic can be reused by remote server.
Scope filtering is now a built-in feature rather than a configurable option.
The server automatically fetches token scopes at startup and filters tools
accordingly. If scope detection fails, it logs a warning and continues with
all tools available.
- Scope filtering only applies to classic PATs which return X-OAuth-Scopes
- Fine-grained PATs and other token types skip filtering (all tools shown)
- Updated docs to clarify PAT filtering vs OAuth scope challenges
The README already has auto-generated tool documentation with scopes.
Keep only the scope hierarchy explanation which is structural.
@SamMorrowDrums SamMorrowDrums force-pushed the copilot/pat-scope-filtering branch from e04a578 to 9bf0cf5 Compare January 5, 2026 15:59
@SamMorrowDrums SamMorrowDrums merged commit 7d4a4a6 into main Jan 5, 2026
16 checks passed
@SamMorrowDrums SamMorrowDrums deleted the copilot/pat-scope-filtering branch January 5, 2026 16:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants