Skip to content

Conversation

@SamMorrowDrums
Copy link
Collaborator

Summary

This PR adds OAuth scope metadata to all MCP tools, enabling clients to know which scopes are required for each tool before calling them.

Changes

New Package: pkg/scopes

  • scopes.go: OAuth scope constants based on GitHub's OAuth app scopes documentation

    • Scope type with constants for all GitHub OAuth scopes (Repo, PublicRepo, Notifications, Gist, SecurityEvents, Project, ReadProject, ReadOrg, etc.)
    • ScopeHierarchy map defining parent-child relationships (e.g., repo includes public_repo, security_events, etc.)
    • WithScopes() helper to create mcp.Tool.Meta maps
    • GetScopesFromMeta() to extract scopes from tool metadata
    • ScopeIncludes(), HasRequiredScopes() for scope checking
  • scopes_test.go: Comprehensive test coverage for all utilities

Tool Updates (~90 tools)

Added Meta: scopes.WithScopes(...) to all tool definitions:

Scope Tools
repo Most repository, issue, PR, actions, discussions, search tools
public_repo star_repository, unstar_repository
notifications All notification tools
gist create_gist, update_gist
security_events Code scanning, dependabot, secret scanning, security advisories
project Project write operations
read:project Project read operations
read:org get_teams, get_team_members, list_issue_types
No scope get_me, list_gists, get_gist (public reads)

Documentation Updates

  • generate_docs.go: Updated to include scope information in README output
  • README.md: Now shows (scopes: \repo`)` after each tool description
  • Toolsnaps: All updated with _meta.requiredOAuthScopes array

Testing

  • All existing tests pass
  • New test file pkg/scopes/scopes_test.go with tests for:
    • TestScopeString - Scope string conversion
    • TestScopeIncludes - Hierarchy checking
    • TestHasRequiredScopes - Multiple scope validation
    • TestWithScopes - Meta map creation
    • TestGetScopesFromMeta - Meta extraction
    • TestGetAcceptedScopes - Parent scope lookup
    • TestScopeStringsAndParseScopes - Round-trip conversion

Part of OAuth Scopes Work (Phase 1 of 4)

  • Phase 1 (this PR): Add OAuth scopes to tool metadata ✅
  • Phase 2: Add fine-grained permissions to metadata
  • Phase 3: Create script to list required scopes for enabled tools
  • Phase 4: Export Go map for library usage

- Add pkg/scopes package with OAuth scope constants and utilities
- Add scopes to all ~90 tool definitions using mcp.Tool.Meta field
- Update generate_docs.go to include scopes in README output
- Add comprehensive test coverage for scopes package
- Update all toolsnaps to include _meta.requiredOAuthScopes

Scope assignments follow GitHub OAuth app documentation:
- repo: Most repository operations (private repos)
- public_repo: Star/unstar operations
- notifications: Notification operations
- gist: Gist write operations
- security_events: Code scanning, dependabot, secret scanning
- project/read:project: Project operations
- read:org: Organization/team read operations
- No scope: Public read operations (get_me, list_gists)
Copilot AI review requested due to automatic review settings November 25, 2025 13:00
@SamMorrowDrums SamMorrowDrums requested a review from a team as a code owner November 25, 2025 13:00
Copilot finished reviewing on behalf of SamMorrowDrums November 25, 2025 13:05
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 implements Phase 1 of OAuth scope support by adding scope metadata to all MCP tools, enabling clients to determine required permissions before making tool calls.

Key Changes:

  • New pkg/scopes package with OAuth scope constants, hierarchy definitions, and utility functions for scope validation
  • Added Meta: scopes.WithScopes(...) to ~90 MCP tools across the codebase with appropriate scope assignments
  • Updated documentation generation to include scope information in README
  • All toolsnaps updated with _meta.requiredOAuthScopes field

Reviewed changes

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

Show a summary per file
File Description
pkg/scopes/scopes.go New package defining OAuth scopes, hierarchy, and utility functions (MetaKey, WithScopes, GetScopesFromMeta, ScopeIncludes, HasRequiredScopes, GetAcceptedScopes)
pkg/scopes/scopes_test.go Comprehensive test coverage for all scope utilities including hierarchy checks and metadata handling
pkg/github/*.go (multiple files) Added scope metadata to tools - repo for most operations, security_events for security features, notifications for notification tools, gist for gist writes, read:org/project for reads, NoScope for public access
pkg/github/toolsnaps/*.snap (many files) Added _meta.requiredOAuthScopes arrays to all tool snapshots
cmd/github-mcp-server/generate_docs.go Enhanced doc generation to append scope information (e.g., "(scopes: `repo`)") to tool descriptions
README.md Updated with scope annotations for all tools in documentation

Comment on lines +153 to +176
// GetAcceptedScopes returns all scopes that satisfy the given required scope.
// This includes the scope itself plus any parent scopes that include it.
func GetAcceptedScopes(required Scope) []Scope {
accepted := []Scope{required}

// Find all scopes that include the required scope
for parent, children := range ScopeHierarchy {
for _, child := range children {
if child == required {
accepted = append(accepted, parent)
// Also check if this parent is included by another scope
for grandparent, grandchildren := range ScopeHierarchy {
for _, gc := range grandchildren {
if gc == parent {
accepted = append(accepted, grandparent)
}
}
}
}
}
}

return accepted
}
Copy link

Copilot AI Nov 25, 2025

Choose a reason for hiding this comment

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

[nitpick] The GetAcceptedScopes function only handles up to 2 levels of hierarchy (parent and grandparent) using nested loops, while ScopeIncludes properly handles arbitrary depth using recursion. Although this works for the current GitHub OAuth scope hierarchy (which has at most 3 levels), consider refactoring to use recursion for consistency and future-proofing:

func GetAcceptedScopes(required Scope) []Scope {
    accepted := []Scope{required}
    seen := make(map[Scope]bool)
    seen[required] = true
    
    // Recursively find all parent scopes
    var findParents func(Scope)
    findParents = func(child Scope) {
        for parent, children := range ScopeHierarchy {
            for _, c := range children {
                if c == child && !seen[parent] {
                    seen[parent] = true
                    accepted = append(accepted, parent)
                    findParents(parent) // Recursively find parents of this parent
                }
            }
        }
    }
    findParents(required)
    return accepted
}

This approach would handle hierarchies of any depth and avoid potential issues if the scope hierarchy is extended in the future.

Copilot uses AI. Check for mistakes.
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.

2 participants