From c8759de51b757665051b311f271d5f336189e9bd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 19 Dec 2025 06:11:10 +0000 Subject: [PATCH 1/7] Initial plan From 3c695b945856a615d114ae9d3e0ab7f504ca0242 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 19 Dec 2025 06:20:54 +0000 Subject: [PATCH 2/7] Address PR review feedback and add OAuth authentication documentation - Fix OAuth client ID comment to clarify it's production-ready - Replace custom joinScopes function with strings.Join - Fix URL parsing fallback to avoid double-https:// prefix - Fix typo in auth success message - Update server instructions to remove auth_verify references - Add comprehensive OAuth authentication documentation - Update README with authentication method comparison and links to OAuth docs Co-authored-by: SamMorrowDrums <4811358+SamMorrowDrums@users.noreply.github.com> --- README.md | 57 ++++- docs/oauth-authentication.md | 460 +++++++++++++++++++++++++++++++++++ internal/ghmcp/server.go | 2 +- pkg/github/auth.go | 25 +- pkg/github/auth_tools.go | 4 +- 5 files changed, 526 insertions(+), 22 deletions(-) create mode 100644 docs/oauth-authentication.md diff --git a/README.md b/README.md index ce6eb81cb..0d4b2ca39 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,8 @@ Built for developers who want to connect their AI tools to GitHub context and ca The remote GitHub MCP Server is hosted by GitHub and provides the easiest method for getting up and running. If your MCP host does not support remote MCP servers, don't worry! You can use the [local version of the GitHub MCP Server](https://github.com/github/github-mcp-server?tab=readme-ov-file#local-github-mcp-server) instead. +> **Note:** The remote server does not support OAuth device flow authentication. For OAuth authentication, use the [local GitHub MCP Server](#local-github-mcp-server) with the [OAuth authentication guide](/docs/oauth-authentication.md). + ### Prerequisites 1. A compatible MCP host with remote server support (VS Code 1.101+, Claude Desktop, Cursor, Windsurf, etc.) @@ -130,10 +132,57 @@ GitHub Enterprise Server does not support remote server hosting. Please refer to ### Prerequisites -1. To run the server in a container, you will need to have [Docker](https://www.docker.com/) installed. -2. Once Docker is installed, you will also need to ensure Docker is running. The image is public; if you get errors on pull, you may have an expired token and need to `docker logout ghcr.io`. -3. Lastly you will need to [Create a GitHub Personal Access Token](https://github.com/settings/personal-access-tokens/new). -The MCP server can use many of the GitHub APIs, so enable the permissions that you feel comfortable granting your AI tools (to learn more about access tokens, please check out the [documentation](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens)). +**For OAuth Device Flow Authentication (Recommended):** +1. Docker installed and running (or build from source) +2. A web browser to complete authentication +3. Network access to GitHub.com (or your GitHub Enterprise instance) + +**For Personal Access Token (PAT) Authentication:** +1. Docker installed and running (or build from source) +2. [Create a GitHub Personal Access Token](https://github.com/settings/personal-access-tokens/new) with appropriate permissions + +> **💡 Tip**: New users should try [OAuth device flow authentication](/docs/oauth-authentication.md) first - it requires no pre-configuration! Simply start the server without a token and authenticate through your browser. See the [authentication guide](/docs/oauth-authentication.md) for detailed instructions. + +### Authentication Methods + +The local GitHub MCP Server supports two authentication methods: + +#### 1. OAuth Device Flow (Recommended for Interactive Use) + +No pre-configuration needed! Start the server without a token: + +```json +{ + "github": { + "command": "docker", + "args": ["run", "-i", "--rm", "ghcr.io/github/github-mcp-server", "stdio"] + } +} +``` + +The server will guide you through browser-based authentication when you first use it. [Learn more in the OAuth authentication guide](/docs/oauth-authentication.md). + +#### 2. Personal Access Token (For Automation & Offline Use) + +Create a [GitHub Personal Access Token](https://github.com/settings/personal-access-tokens/new) and configure it: + +```json +{ + "github": { + "command": "docker", + "args": ["run", "-i", "--rm", "-e", "GITHUB_PERSONAL_ACCESS_TOKEN", "ghcr.io/github/github-mcp-server"], + "env": { + "GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_your_token_here" + } + } +} +``` + +See the [OAuth vs PAT comparison](/docs/oauth-authentication.md#comparison-with-pat-authentication) to choose the best method for your use case. + +### Personal Access Token Configuration + +If you choose to use a Personal Access Token, the MCP server can use many of the GitHub APIs, so enable the permissions that you feel comfortable granting your AI tools (to learn more about access tokens, please check out the [documentation](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens)).
Handling PATs Securely diff --git a/docs/oauth-authentication.md b/docs/oauth-authentication.md new file mode 100644 index 000000000..8aaa4e16a --- /dev/null +++ b/docs/oauth-authentication.md @@ -0,0 +1,460 @@ +# OAuth Device Flow Authentication + +The GitHub MCP Server supports OAuth device flow authentication as an alternative to Personal Access Tokens (PATs). This provides a streamlined authentication experience where users can authenticate directly through the MCP server without pre-configuring tokens. + +## Table of Contents + +- [Overview](#overview) +- [How It Works](#how-it-works) +- [Getting Started](#getting-started) +- [Configuration](#configuration) + - [Using Default OAuth App](#using-default-oauth-app) + - [Using Custom OAuth Apps](#using-custom-oauth-apps) + - [GitHub Enterprise Server (GHES)](#github-enterprise-server-ghes) + - [GitHub Enterprise Cloud (GHEC)](#github-enterprise-cloud-ghec) +- [CLI Flags](#cli-flags) +- [Environment Variables](#environment-variables) +- [Scopes and Permissions](#scopes-and-permissions) +- [Security Considerations](#security-considerations) +- [Troubleshooting](#troubleshooting) +- [Comparison with PAT Authentication](#comparison-with-pat-authentication) + +## Overview + +OAuth device flow authentication allows users to authenticate with GitHub by: +1. Starting the authentication process through the MCP server +2. Receiving a user code and verification URL +3. Visiting the URL in a browser and entering the code +4. Automatically completing authentication once approved + +This method eliminates the need to manually create and configure Personal Access Tokens, making it easier for users to get started with the GitHub MCP Server. + +## How It Works + +The OAuth device flow follows these steps: + +1. **User requests authentication**: When the server starts without a token, only the `auth_login` tool is available. The user (or their AI agent) calls this tool to initiate authentication. + +2. **Server requests device code**: The server requests a device code from GitHub's OAuth device flow endpoint (`https://github.com/login/device/code` or your enterprise equivalent). + +3. **User receives verification URL**: The server displays a verification URL and user code to the user via MCP's URL elicitation feature (if supported by the client). + +4. **User authorizes in browser**: The user opens the verification URL in their browser, enters the code, and authorizes the application. + +5. **Server polls for token**: While the user is authorizing, the server polls GitHub's token endpoint (`https://github.com/login/oauth/access_token`) until the user completes authorization or the request expires. + +6. **Authentication completes**: Once the user authorizes the app, the server receives an access token and automatically registers all GitHub tools. + +The entire process is handled by a single `auth_login` tool call that blocks until authentication completes or fails. + +## Getting Started + +### Quick Start (No Configuration Needed) + +The simplest way to use OAuth authentication is to start the server without providing a token: + +**Docker:** +```json +{ + "github": { + "command": "docker", + "args": ["run", "-i", "--rm", "ghcr.io/github/github-mcp-server", "stdio"] + } +} +``` + +**Binary:** +```json +{ + "github": { + "command": "/path/to/github-mcp-server", + "args": ["stdio"] + } +} +``` + +When the server starts without a `GITHUB_PERSONAL_ACCESS_TOKEN`, it will automatically enter authentication mode. Your AI agent can then call the `auth_login` tool to initiate the OAuth flow. + +### Backward Compatibility + +OAuth authentication is completely optional. If you provide a `GITHUB_PERSONAL_ACCESS_TOKEN`, the server will use it and skip OAuth authentication entirely. This means existing configurations continue to work without modification. + +```json +{ + "github": { + "command": "docker", + "args": ["run", "-i", "--rm", "-e", "GITHUB_PERSONAL_ACCESS_TOKEN", "ghcr.io/github/github-mcp-server"], + "env": { + "GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_your_token_here" + } + } +} +``` + +## Configuration + +### Using Default OAuth App + +The GitHub MCP Server includes a default OAuth App registered and managed by GitHub. This OAuth App works with: +- GitHub.com (https://github.com) +- GitHub Enterprise Cloud with data residency (ghe.com) +- GitHub Enterprise Server (GHES) 3.0+ + +**No additional configuration is required** to use the default OAuth App. Simply omit the PAT token when starting the server. + +The default OAuth App client ID is embedded in the source code (which is safe per OAuth 2.0 specifications for public clients) and requires no client secret. + +### Using Custom OAuth Apps + +For enterprise scenarios, you may want to use your own OAuth App. This is useful when: +- You want to customize the app name and branding +- You need to restrict access to specific organizations +- You want to use a confidential client (with client secret) +- Your organization's policies require using organization-owned OAuth Apps + +#### Creating a Custom OAuth App + +1. **Navigate to OAuth App settings:** + - For personal apps: https://github.com/settings/developers + - For organization apps: https://github.com/organizations/YOUR_ORG/settings/applications + +2. **Create a new OAuth App:** + - Click "New OAuth App" + - **Application name**: "GitHub MCP Server (Custom)" + - **Homepage URL**: https://github.com/github/github-mcp-server (or your fork) + - **Authorization callback URL**: Not used for device flow, but required. Use: `http://localhost:8080/callback` + - **Enable Device Flow**: Make sure this is checked + +3. **Configure the scopes**: The OAuth App will request the scopes defined in the server (see [Scopes and Permissions](#scopes-and-permissions)). + +4. **Get your credentials:** + - **Client ID**: Copy the client ID (e.g., `Ov23liAbcdefg1234567`) + - **Client Secret** (optional): Generate a client secret if you want to use a confidential client + +#### Using Your Custom OAuth App + +Provide the client ID (and optionally client secret) using CLI flags or environment variables: + +**CLI Flags:** +```json +{ + "github": { + "command": "/path/to/github-mcp-server", + "args": [ + "stdio", + "--oauth-client-id", "Ov23liYourClientID", + "--oauth-client-secret", "your_client_secret_if_needed" + ] + } +} +``` + +**Environment Variables:** +```json +{ + "github": { + "command": "docker", + "args": ["run", "-i", "--rm", "-e", "GITHUB_OAUTH_CLIENT_ID", "-e", "GITHUB_OAUTH_CLIENT_SECRET", "ghcr.io/github/github-mcp-server"], + "env": { + "GITHUB_OAUTH_CLIENT_ID": "Ov23liYourClientID", + "GITHUB_OAUTH_CLIENT_SECRET": "your_client_secret_if_needed" + } + } +} +``` + +### GitHub Enterprise Server (GHES) + +To use OAuth device flow with GitHub Enterprise Server: + +1. **Ensure GHES supports device flow**: Device flow is available in GHES 3.0 and later. + +2. **Create an OAuth App** on your GHES instance: + - Navigate to: `https://YOUR_GHES_HOSTNAME/settings/developers` + - Follow the steps in [Creating a Custom OAuth App](#creating-a-custom-oauth-app) + +3. **Configure the server** with your GHES hostname: + +```json +{ + "github": { + "command": "docker", + "args": [ + "run", "-i", "--rm", + "-e", "GITHUB_HOST", + "-e", "GITHUB_OAUTH_CLIENT_ID", + "ghcr.io/github/github-mcp-server" + ], + "env": { + "GITHUB_HOST": "https://github.yourcompany.com", + "GITHUB_OAUTH_CLIENT_ID": "your_ghes_oauth_client_id" + } + } +} +``` + +**Important**: Always prefix GHES hostnames with `https://` to ensure proper URL construction. + +#### Example: Full GHES Configuration + +```json +{ + "github": { + "command": "/path/to/github-mcp-server", + "args": ["stdio", "--gh-host", "https://github.yourcompany.com", "--oauth-client-id", "Ov23liGHESClientID"] + } +} +``` + +### GitHub Enterprise Cloud (GHEC) + +GitHub Enterprise Cloud with data residency (ghe.com) works with the default OAuth App. However, you may want to create a custom OAuth App for organization-specific branding or policies. + +1. **Create an OAuth App** on your GHEC organization: + - Navigate to: `https://YOUR_SUBDOMAIN.ghe.com/settings/developers` or your organization settings + - Follow the steps in [Creating a Custom OAuth App](#creating-a-custom-oauth-app) + +2. **Configure the server** with your GHEC hostname: + +```json +{ + "github": { + "command": "docker", + "args": [ + "run", "-i", "--rm", + "-e", "GITHUB_HOST", + "-e", "GITHUB_OAUTH_CLIENT_ID", + "ghcr.io/github/github-mcp-server" + ], + "env": { + "GITHUB_HOST": "https://yourcompany.ghe.com", + "GITHUB_OAUTH_CLIENT_ID": "your_ghec_oauth_client_id" + } + } +} +``` + +## CLI Flags + +The GitHub MCP Server provides the following CLI flags for OAuth configuration: + +| Flag | Description | Default | Example | +|------|-------------|---------|---------| +| `--oauth-client-id` | OAuth App client ID for device flow authentication | Default GitHub MCP OAuth App | `--oauth-client-id Ov23liYourClientID` | +| `--oauth-client-secret` | OAuth App client secret (optional, for confidential clients) | None | `--oauth-client-secret your_client_secret` | +| `--gh-host` | GitHub hostname for API requests and OAuth endpoints | `github.com` | `--gh-host https://github.yourcompany.com` | + +### Usage Examples + +**Minimal configuration (uses defaults):** +```bash +github-mcp-server stdio +``` + +**Custom OAuth App:** +```bash +github-mcp-server stdio --oauth-client-id Ov23liYourClientID +``` + +**GHES with custom OAuth App:** +```bash +github-mcp-server stdio --gh-host https://github.yourcompany.com --oauth-client-id Ov23liGHESClientID +``` + +**Confidential client with secret:** +```bash +github-mcp-server stdio --oauth-client-id Ov23liYourClientID --oauth-client-secret your_secret +``` + +## Environment Variables + +All CLI flags can also be configured via environment variables with the `GITHUB_` prefix: + +| Environment Variable | Equivalent CLI Flag | Example | +|---------------------|---------------------|---------| +| `GITHUB_OAUTH_CLIENT_ID` | `--oauth-client-id` | `export GITHUB_OAUTH_CLIENT_ID=Ov23liYourClientID` | +| `GITHUB_OAUTH_CLIENT_SECRET` | `--oauth-client-secret` | `export GITHUB_OAUTH_CLIENT_SECRET=your_secret` | +| `GITHUB_HOST` | `--gh-host` | `export GITHUB_HOST=https://github.yourcompany.com` | +| `GITHUB_PERSONAL_ACCESS_TOKEN` | N/A (disables OAuth) | `export GITHUB_PERSONAL_ACCESS_TOKEN=ghp_token` | + +**Note**: If `GITHUB_PERSONAL_ACCESS_TOKEN` is set, the server will use PAT authentication and skip OAuth device flow entirely. + +### Environment Variable Priority + +The server uses the following priority for configuration: +1. CLI flags (highest priority) +2. Environment variables +3. Default values (lowest priority) + +## Scopes and Permissions + +The OAuth device flow requests the following scopes by default (defined in `DefaultOAuthScopes`): + +| Scope | Description | Required For | +|-------|-------------|--------------| +| `repo` | Full control of private repositories | Repository operations, issues, PRs | +| `repo:status` | Access commit status | CI/CD workflow monitoring | +| `repo_deployment` | Access deployment status | Deployment operations | +| `public_repo` | Access public repositories | Public repository operations | +| `gist` | Create and manage gists | Gist operations | +| `notifications` | Access notifications | Notification tools | +| `user` | Read and write user profile data | User information | +| `user:email` | Access user email addresses | User contact information | +| `user:follow` | Follow and unfollow users | Social features | +| `read:org` | Read organization data | Organization and team access | +| `read:gpg_key` | Read GPG keys | Signature verification | +| `project` | Read and write project data | Project board management | + +These scopes form a superset of the `gh` CLI minimal scopes (`repo`, `read:org`, `gist`) to support all GitHub MCP tools while following least-privilege principles. + +### Customizing Scopes + +Currently, scopes are not customizable via CLI flags or environment variables. They are defined in the source code (`pkg/github/auth.go`) as `DefaultOAuthScopes`. To customize scopes, you would need to: + +1. Fork the repository +2. Modify the `DefaultOAuthScopes` variable +3. Build your custom version + +## Security Considerations + +### Token Storage + +- **In-memory only**: Access tokens obtained via OAuth device flow are stored only in memory and are never written to disk. +- **Ephemeral sessions**: Tokens are lost when the server process terminates (e.g., when a Docker container is stopped with `--rm`). +- **No persistent storage**: This design prioritizes security over convenience, making it ideal for short-lived sessions. + +### Public vs. Confidential Clients + +- **Public clients**: The default OAuth App is a public client (no client secret). The client ID can be safely embedded in source code per OAuth 2.0 specifications. +- **Confidential clients**: If you provide a client secret via `--oauth-client-secret`, the app becomes a confidential client with additional security but requires secure secret storage. + +### User Authorization + +- **Explicit consent**: Users must explicitly authorize the OAuth App in their browser, providing full visibility into what access is being granted. +- **Revocable access**: Users can revoke access at any time from their GitHub settings: https://github.com/settings/applications + +### Best Practices + +1. **Use organization-owned OAuth Apps** for enterprise deployments to maintain control +2. **Regularly review authorized applications** in GitHub settings +3. **Use confidential clients** (with secrets) only when you can securely store the secret +4. **Prefer ephemeral tokens** (OAuth) over long-lived PATs when possible +5. **Enable organization policies** to restrict which OAuth Apps can access your organization's data + +## Troubleshooting + +### Common Issues + +#### "Device code expired" + +**Cause**: The user didn't complete authorization within the expiration time (typically 15 minutes). + +**Solution**: Call `auth_login` again to start a new authentication flow. + +#### "Authorization was denied by the user" + +**Cause**: The user clicked "Cancel" or "Deny" during the authorization flow. + +**Solution**: Call `auth_login` again and ensure the user completes the authorization. + +#### "Failed to start authentication" + +**Possible causes**: +- Network connectivity issues +- Invalid OAuth App configuration +- GitHub service issues + +**Solutions**: +- Check network connectivity to GitHub +- Verify your OAuth client ID is correct +- Check GitHub's status page: https://www.githubstatus.com + +#### OAuth not working with GHES + +**Possible causes**: +- GHES version doesn't support device flow (requires GHES 3.0+) +- OAuth App not properly configured on GHES +- Incorrect hostname format + +**Solutions**: +- Verify GHES version: `https://YOUR_GHES_HOSTNAME/api/v3/meta` +- Ensure OAuth App has device flow enabled in GHES settings +- Use full URL with scheme: `--gh-host https://github.yourcompany.com` + +#### "Elicitation failed" message in logs + +**Cause**: The MCP client doesn't support URL elicitation (an optional MCP feature). + +**Effect**: The authentication flow still works, but the user won't see a clickable link. They'll need to manually copy/paste the verification URL. + +**Solution**: No action needed - this is expected for some MCP clients. + +### Debug Logging + +Enable debug logging to troubleshoot authentication issues: + +```json +{ + "github": { + "command": "/path/to/github-mcp-server", + "args": ["stdio", "--log-file", "/tmp/github-mcp-server.log"] + } +} +``` + +Check the log file for detailed information about the authentication flow. + +## Comparison with PAT Authentication + +| Feature | OAuth Device Flow | Personal Access Token | +|---------|------------------|---------------------| +| **Initial Setup** | No pre-configuration needed | Must manually create token | +| **Token Storage** | In-memory only | Stored in config files | +| **Token Lifetime** | Session-based (ephemeral) | Long-lived (until revoked) | +| **Security** | Explicit browser authorization | Token visible in config | +| **User Experience** | Interactive flow | Copy/paste token | +| **Enterprise Control** | Organization OAuth App policies | Token-level restrictions | +| **Offline Use** | Requires initial online auth | Works offline after setup | +| **Multiple Clients** | Each client needs separate auth | Same token can be reused | + +### When to Use Each Method + +**Use OAuth Device Flow when:** +- You want the simplest setup experience +- You're using Docker with `--rm` (ephemeral containers) +- You prefer not storing tokens in config files +- Your organization uses OAuth App policies + +**Use PAT when:** +- You need offline access after initial setup +- You want to reuse the same token across multiple MCP clients +- You need long-lived credentials for automation +- You're using an environment where interactive authentication isn't possible + +### Migration Between Methods + +You can switch between authentication methods at any time: + +**From PAT to OAuth**: Simply remove the `GITHUB_PERSONAL_ACCESS_TOKEN` environment variable from your configuration and restart the server. + +**From OAuth to PAT**: Add `GITHUB_PERSONAL_ACCESS_TOKEN` to your configuration with your token. The server will use PAT authentication and skip OAuth entirely. + +## Additional Resources + +- [OAuth 2.0 Device Authorization Grant (RFC 8628)](https://datatracker.ietf.org/doc/html/rfc8628) +- [GitHub OAuth Apps Documentation](https://docs.github.com/en/apps/oauth-apps) +- [GitHub Device Flow Documentation](https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/authorizing-oauth-apps#device-flow) +- [Creating a Personal Access Token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens) +- [GitHub MCP Server Documentation](https://github.com/github/github-mcp-server) + +## Need Help? + +If you encounter issues not covered in this guide: + +1. Check the [GitHub Discussions](https://github.com/github/github-mcp-server/discussions) +2. Search [existing issues](https://github.com/github/github-mcp-server/issues) +3. [Open a new issue](https://github.com/github/github-mcp-server/issues/new) with: + - Your server configuration (redact sensitive data) + - Error messages or unexpected behavior + - Debug logs (if available) + - GitHub environment (github.com, GHES, GHEC) diff --git a/internal/ghmcp/server.go b/internal/ghmcp/server.go index bd159233c..1c277ca3d 100644 --- a/internal/ghmcp/server.go +++ b/internal/ghmcp/server.go @@ -291,7 +291,7 @@ func NewUnauthenticatedMCPServer(cfg MCPServerConfig) (*UnauthenticatedServerRes // Create the MCP server with capabilities advertised for dynamic tool registration serverOpts := &mcp.ServerOptions{ - Instructions: "GitHub MCP Server - Authentication Required\n\nYou are not currently authenticated with GitHub. Use the auth_login tool to start the authentication process, then auth_verify to complete it.", + Instructions: "GitHub MCP Server - Authentication Required\n\nYou are not currently authenticated with GitHub. Use the auth_login tool to complete authentication. This is a single, blocking call that will guide you through the entire device authorization flow and return once authentication has finished.", Logger: cfg.Logger, // Advertise capabilities since tools will be added after auth Capabilities: &mcp.ServerCapabilities{ diff --git a/pkg/github/auth.go b/pkg/github/auth.go index 347f32690..6b3b0a25c 100644 --- a/pkg/github/auth.go +++ b/pkg/github/auth.go @@ -84,17 +84,20 @@ func NewOAuthHostFromAPIHost(hostname string) OAuthHost { // Parse the hostname to extract the base u, err := url.Parse(hostname) + var host string if err != nil || u.Hostname() == "" { - // Fallback: treat as hostname directly (shouldn't happen with scheme added) + // Fallback: strip scheme if it was added, use original hostname + host = strings.TrimPrefix(hostname, "https://") + host = strings.TrimPrefix(host, "http://") return OAuthHost{ - DeviceCodeURL: fmt.Sprintf("https://%s/login/device/code", hostname), - TokenURL: fmt.Sprintf("https://%s/login/oauth/access_token", hostname), - Hostname: hostname, + DeviceCodeURL: fmt.Sprintf("https://%s/login/device/code", host), + TokenURL: fmt.Sprintf("https://%s/login/oauth/access_token", host), + Hostname: host, } } // For GHEC (ghe.com) and GHES, OAuth endpoints are on the main host - host := u.Hostname() + host = u.Hostname() scheme := u.Scheme if scheme == "" { scheme = "https" @@ -108,10 +111,9 @@ func NewOAuthHostFromAPIHost(hostname string) OAuthHost { } // DefaultOAuthClientID is the OAuth App client ID for the GitHub MCP Server. -// This OAuth App is registered by GitHub for use with this server. +// This OAuth App is registered and managed by GitHub for use with this server. // The client ID is safe to embed in source code per OAuth 2.0 spec for public clients. // Users can override this with --oauth-client-id for enterprise scenarios. -// currently a testing app. const DefaultOAuthClientID = "Ov23ctTMsnT9LTRdBYYM" // DefaultOAuthScopes are the standard scopes needed for complete MCP functionality. @@ -389,12 +391,5 @@ func (a *AuthManager) SetToken(token string) { } func joinScopes(scopes []string) string { - result := "" - for i, s := range scopes { - if i > 0 { - result += " " - } - result += s - } - return result + return strings.Join(scopes, " ") } diff --git a/pkg/github/auth_tools.go b/pkg/github/auth_tools.go index aced38d79..841ef4bc5 100644 --- a/pkg/github/auth_tools.go +++ b/pkg/github/auth_tools.go @@ -166,11 +166,11 @@ func pollAndComplete(ctx context.Context, session *mcp.ServerSession, authDeps A return utils.NewToolResultText(`✅ Successfully authenticated with GitHub! -All GitHub tools are now available. You can now most likely: +All GitHub tools are now available. You can now: - Create and manage repositories - Work with issues and pull requests - Access your organizations and teams -- And much more, depending on configuration (mention the success and new tools to the user! +- And much more, depending on your GitHub configuration Call get_me to see who you're logged in as.`), nil } From c4e5b4f19e0bccc8babcc435eaa7dbc571071295 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 19 Dec 2025 06:32:18 +0000 Subject: [PATCH 3/7] Add OAuth scopes customization via CLI flag and environment variable - Add --oauth-scopes CLI flag to allow users to limit requested scopes - Add GITHUB_OAUTH_SCOPES environment variable support - Update OAuth authentication documentation with scopes customization guide - Add examples for minimal, read-only, and custom scope configurations - Update OAuth client ID comment to indicate it's a testing app (TODO for production) Co-authored-by: SamMorrowDrums <4811358+SamMorrowDrums@users.noreply.github.com> --- cmd/github-mcp-server/main.go | 11 ++++++ docs/oauth-authentication.md | 72 +++++++++++++++++++++++++++++++++-- internal/ghmcp/server.go | 11 +++++- pkg/github/auth.go | 3 +- 4 files changed, 91 insertions(+), 6 deletions(-) diff --git a/cmd/github-mcp-server/main.go b/cmd/github-mcp-server/main.go index 11d09a2d1..3f6a6935e 100644 --- a/cmd/github-mcp-server/main.go +++ b/cmd/github-mcp-server/main.go @@ -65,6 +65,14 @@ var ( } } + // Parse OAuth scopes (similar to toolsets) + var oauthScopes []string + if viper.IsSet("oauth-scopes") { + if err := viper.UnmarshalKey("oauth-scopes", &oauthScopes); err != nil { + return fmt.Errorf("failed to unmarshal oauth-scopes: %w", err) + } + } + ttl := viper.GetDuration("repo-access-cache-ttl") stdioServerConfig := ghmcp.StdioServerConfig{ Version: version, @@ -83,6 +91,7 @@ var ( RepoAccessCacheTTL: &ttl, OAuthClientID: viper.GetString("oauth-client-id"), OAuthClientSecret: viper.GetString("oauth-client-secret"), + OAuthScopes: oauthScopes, } return ghmcp.RunStdioServer(stdioServerConfig) }, @@ -110,6 +119,7 @@ func init() { rootCmd.PersistentFlags().Duration("repo-access-cache-ttl", 5*time.Minute, "Override the repo access cache TTL (e.g. 1m, 0s to disable)") rootCmd.PersistentFlags().String("oauth-client-id", "", "OAuth App client ID for device flow authentication (optional, uses default if not provided)") rootCmd.PersistentFlags().String("oauth-client-secret", "", "OAuth App client secret for device flow authentication (optional, for confidential clients)") + rootCmd.PersistentFlags().StringSlice("oauth-scopes", nil, "Comma-separated list of OAuth scopes to request during device flow authentication (optional, uses default if not provided)") // Bind flag to viper _ = viper.BindPFlag("toolsets", rootCmd.PersistentFlags().Lookup("toolsets")) @@ -126,6 +136,7 @@ func init() { _ = viper.BindPFlag("repo-access-cache-ttl", rootCmd.PersistentFlags().Lookup("repo-access-cache-ttl")) _ = viper.BindPFlag("oauth-client-id", rootCmd.PersistentFlags().Lookup("oauth-client-id")) _ = viper.BindPFlag("oauth-client-secret", rootCmd.PersistentFlags().Lookup("oauth-client-secret")) + _ = viper.BindPFlag("oauth-scopes", rootCmd.PersistentFlags().Lookup("oauth-scopes")) // Add subcommands rootCmd.AddCommand(stdioCmd) diff --git a/docs/oauth-authentication.md b/docs/oauth-authentication.md index 8aaa4e16a..83f81d268 100644 --- a/docs/oauth-authentication.md +++ b/docs/oauth-authentication.md @@ -242,6 +242,7 @@ The GitHub MCP Server provides the following CLI flags for OAuth configuration: |------|-------------|---------|---------| | `--oauth-client-id` | OAuth App client ID for device flow authentication | Default GitHub MCP OAuth App | `--oauth-client-id Ov23liYourClientID` | | `--oauth-client-secret` | OAuth App client secret (optional, for confidential clients) | None | `--oauth-client-secret your_client_secret` | +| `--oauth-scopes` | Comma-separated list of OAuth scopes to request | Default scopes (see below) | `--oauth-scopes repo,read:org,gist` | | `--gh-host` | GitHub hostname for API requests and OAuth endpoints | `github.com` | `--gh-host https://github.yourcompany.com` | ### Usage Examples @@ -256,6 +257,11 @@ github-mcp-server stdio github-mcp-server stdio --oauth-client-id Ov23liYourClientID ``` +**Limiting scopes (minimal permissions):** +```bash +github-mcp-server stdio --oauth-scopes repo,read:org,gist +``` + **GHES with custom OAuth App:** ```bash github-mcp-server stdio --gh-host https://github.yourcompany.com --oauth-client-id Ov23liGHESClientID @@ -266,6 +272,11 @@ github-mcp-server stdio --gh-host https://github.yourcompany.com --oauth-client- github-mcp-server stdio --oauth-client-id Ov23liYourClientID --oauth-client-secret your_secret ``` +**Custom scopes with custom OAuth App:** +```bash +github-mcp-server stdio --oauth-client-id Ov23liYourClientID --oauth-scopes repo,read:org,user:email +``` + ## Environment Variables All CLI flags can also be configured via environment variables with the `GITHUB_` prefix: @@ -274,6 +285,7 @@ All CLI flags can also be configured via environment variables with the `GITHUB_ |---------------------|---------------------|---------| | `GITHUB_OAUTH_CLIENT_ID` | `--oauth-client-id` | `export GITHUB_OAUTH_CLIENT_ID=Ov23liYourClientID` | | `GITHUB_OAUTH_CLIENT_SECRET` | `--oauth-client-secret` | `export GITHUB_OAUTH_CLIENT_SECRET=your_secret` | +| `GITHUB_OAUTH_SCOPES` | `--oauth-scopes` | `export GITHUB_OAUTH_SCOPES=repo,read:org,gist` | | `GITHUB_HOST` | `--gh-host` | `export GITHUB_HOST=https://github.yourcompany.com` | | `GITHUB_PERSONAL_ACCESS_TOKEN` | N/A (disables OAuth) | `export GITHUB_PERSONAL_ACCESS_TOKEN=ghp_token` | @@ -309,11 +321,63 @@ These scopes form a superset of the `gh` CLI minimal scopes (`repo`, `read:org`, ### Customizing Scopes -Currently, scopes are not customizable via CLI flags or environment variables. They are defined in the source code (`pkg/github/auth.go`) as `DefaultOAuthScopes`. To customize scopes, you would need to: +You can customize the requested scopes using the `--oauth-scopes` CLI flag or `GITHUB_OAUTH_SCOPES` environment variable: + +**CLI Flag:** +```bash +github-mcp-server stdio --oauth-scopes repo,read:org,gist +``` + +**Environment Variable:** +```bash +export GITHUB_OAUTH_SCOPES=repo,read:org,user:email +github-mcp-server stdio +``` -1. Fork the repository -2. Modify the `DefaultOAuthScopes` variable -3. Build your custom version +**Docker with environment variable:** +```json +{ + "github": { + "command": "docker", + "args": ["run", "-i", "--rm", "-e", "GITHUB_OAUTH_SCOPES", "ghcr.io/github/github-mcp-server"], + "env": { + "GITHUB_OAUTH_SCOPES": "repo,read:org,gist" + } + } +} +``` + +#### Minimal Recommended Scopes + +For basic functionality, you can use a minimal set of scopes: + +```bash +--oauth-scopes repo,read:org,gist +``` + +This provides: +- `repo`: Access to repositories, issues, and PRs +- `read:org`: Read organization and team information +- `gist`: Manage gists + +**Note**: Some MCP tools may not function properly with reduced scopes. Review the scopes table above to understand which scopes are required for specific functionality. + +#### Common Scope Combinations + +**Read-only operations:** +```bash +--oauth-scopes repo,read:org,read:user +``` + +**Full repository access with notifications:** +```bash +--oauth-scopes repo,read:org,notifications,user:email +``` + +**Enterprise with minimal scopes:** +```bash +--oauth-scopes repo,read:org,read:gpg_key +``` ## Security Considerations diff --git a/internal/ghmcp/server.go b/internal/ghmcp/server.go index 1c277ca3d..186d558fd 100644 --- a/internal/ghmcp/server.go +++ b/internal/ghmcp/server.go @@ -74,6 +74,10 @@ type MCPServerConfig struct { // OAuthClientSecret is the OAuth App client secret (optional, for confidential clients). OAuthClientSecret string + + // OAuthScopes is a list of OAuth scopes to request during device flow authentication. + // If empty, the default scopes defined in DefaultOAuthScopes are used. + OAuthScopes []string } // githubClients holds all the GitHub API clients created for a server instance. @@ -287,7 +291,7 @@ func NewUnauthenticatedMCPServer(cfg MCPServerConfig) (*UnauthenticatedServerRes oauthHost := github.NewOAuthHostFromAPIHost(cfg.Host) // Create auth manager - authManager := github.NewAuthManager(oauthHost, cfg.OAuthClientID, cfg.OAuthClientSecret, nil) + authManager := github.NewAuthManager(oauthHost, cfg.OAuthClientID, cfg.OAuthClientSecret, cfg.OAuthScopes) // Create the MCP server with capabilities advertised for dynamic tool registration serverOpts := &mcp.ServerOptions{ @@ -456,6 +460,10 @@ type StdioServerConfig struct { // OAuthClientSecret is the OAuth App client secret (optional, for confidential clients). OAuthClientSecret string + + // OAuthScopes is a list of OAuth scopes to request during device flow authentication. + // If empty, the default scopes defined in DefaultOAuthScopes are used. + OAuthScopes []string } // RunStdioServer is not concurrent safe. @@ -494,6 +502,7 @@ func RunStdioServer(cfg StdioServerConfig) error { Logger: logger, OAuthClientID: cfg.OAuthClientID, OAuthClientSecret: cfg.OAuthClientSecret, + OAuthScopes: cfg.OAuthScopes, // Pass config for use after authentication EnabledToolsets: cfg.EnabledToolsets, EnabledTools: cfg.EnabledTools, diff --git a/pkg/github/auth.go b/pkg/github/auth.go index 6b3b0a25c..3de5e69b4 100644 --- a/pkg/github/auth.go +++ b/pkg/github/auth.go @@ -111,7 +111,8 @@ func NewOAuthHostFromAPIHost(hostname string) OAuthHost { } // DefaultOAuthClientID is the OAuth App client ID for the GitHub MCP Server. -// This OAuth App is registered and managed by GitHub for use with this server. +// TODO: This is currently a testing OAuth App. An official GitHub-managed OAuth App +// will be registered before production release. // The client ID is safe to embed in source code per OAuth 2.0 spec for public clients. // Users can override this with --oauth-client-id for enterprise scenarios. const DefaultOAuthClientID = "Ov23ctTMsnT9LTRdBYYM" From 75c76ead2b37343f0f77e013d08fdc958749ac5e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 19 Dec 2025 06:43:22 +0000 Subject: [PATCH 4/7] Add GitHub Apps support documentation to OAuth authentication guide - Add new "Using GitHub Apps" section explaining device flow with GitHub Apps - Document key differences between OAuth Apps and GitHub Apps - Explain that scopes are controlled by app configuration, not --oauth-scopes flag - Include instructions for creating and using GitHub Apps - Update table of contents and overview to mention GitHub Apps support - No code changes needed - existing implementation already supports both OAuth Apps and GitHub Apps Co-authored-by: SamMorrowDrums <4811358+SamMorrowDrums@users.noreply.github.com> --- docs/oauth-authentication.md | 46 ++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/docs/oauth-authentication.md b/docs/oauth-authentication.md index 83f81d268..ade5580b9 100644 --- a/docs/oauth-authentication.md +++ b/docs/oauth-authentication.md @@ -10,6 +10,7 @@ The GitHub MCP Server supports OAuth device flow authentication as an alternativ - [Configuration](#configuration) - [Using Default OAuth App](#using-default-oauth-app) - [Using Custom OAuth Apps](#using-custom-oauth-apps) + - [Using GitHub Apps](#using-github-apps) - [GitHub Enterprise Server (GHES)](#github-enterprise-server-ghes) - [GitHub Enterprise Cloud (GHEC)](#github-enterprise-cloud-ghec) - [CLI Flags](#cli-flags) @@ -29,6 +30,8 @@ OAuth device flow authentication allows users to authenticate with GitHub by: This method eliminates the need to manually create and configure Personal Access Tokens, making it easier for users to get started with the GitHub MCP Server. +The device flow authentication works with both **OAuth Apps** and **GitHub Apps**. OAuth Apps use scope-based permissions that can be customized via the `--oauth-scopes` flag, while GitHub Apps use fine-grained permissions that are controlled by the app's configuration in GitHub settings. + ## How It Works The OAuth device flow follows these steps: @@ -163,6 +166,49 @@ Provide the client ID (and optionally client secret) using CLI flags or environm } ``` +### Using GitHub Apps + +The GitHub MCP Server also supports authentication via GitHub Apps using the device flow. GitHub Apps provide more granular permissions and better security controls compared to OAuth Apps. + +**Key Differences:** + +- **Permissions Model**: GitHub Apps use fine-grained permissions instead of OAuth scopes. The `--oauth-scopes` flag does not apply when using GitHub Apps, as permissions are controlled by the GitHub App's configuration in GitHub's settings. +- **App-Controlled Access**: When authenticating via a GitHub App, the available repositories, organizations, and resources are determined by the app's installation and permissions, not by the scopes requested during authentication. +- **Installation-Based**: GitHub Apps must be installed on organizations or repositories before users can authenticate through them. + +#### Creating a GitHub App + +1. **Navigate to GitHub App settings:** + - For personal apps: https://github.com/settings/apps + - For organization apps: https://github.com/organizations/YOUR_ORG/settings/apps + +2. **Create a new GitHub App:** + - Click "New GitHub App" + - **GitHub App name**: "GitHub MCP Server (Custom)" + - **Homepage URL**: https://github.com/github/github-mcp-server + - **Callback URL**: Not used for device flow, but required. Use: `http://localhost:8080/callback` + - **Request user authorization (OAuth) during installation**: Uncheck this + - **Enable Device Flow**: Make sure this is checked + - **Webhook**: Can be set to inactive if not needed + +3. **Configure permissions**: Set the repository and organization permissions based on your needs (equivalent to the scopes in OAuth Apps). + +4. **Get your credentials:** + - **Client ID**: Copy the client ID from the app settings + - **Client Secret**: Generate a client secret if needed + +5. **Install the GitHub App**: Install the app on the organizations or repositories where you want to use it. + +#### Using Your GitHub App + +Use the same `--oauth-client-id` and `--oauth-client-secret` flags with your GitHub App's credentials: + +```bash +github-mcp-server stdio --oauth-client-id Iv1.your_github_app_client_id +``` + +**Note**: When using GitHub Apps, the `--oauth-scopes` flag is ignored. Access and permissions are controlled by the GitHub App's configuration and installation settings. + ### GitHub Enterprise Server (GHES) To use OAuth device flow with GitHub Enterprise Server: From f39e730348557cd8fde5b806e41677005d3696c6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 19 Dec 2025 06:52:39 +0000 Subject: [PATCH 5/7] Improve code documentation and architectural clarity - Add comprehensive doc comments explaining NewMCPServer initialization steps - Document the two-phase initialization pattern in NewUnauthenticatedMCPServer - Explain architectural tradeoffs and acknowledge code duplication - Add notes about future refactoring opportunities for common setup logic - Clarify manual tool filtering approach and suggest toolset-based alternative - Document MCPServerConfig as shared configuration struct - No functional changes - documentation and comments only Co-authored-by: SamMorrowDrums <4811358+SamMorrowDrums@users.noreply.github.com> --- internal/ghmcp/server.go | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/internal/ghmcp/server.go b/internal/ghmcp/server.go index 186d558fd..b231f6996 100644 --- a/internal/ghmcp/server.go +++ b/internal/ghmcp/server.go @@ -25,6 +25,9 @@ import ( "github.com/shurcooL/githubv4" ) +// MCPServerConfig contains all configuration needed to create an MCP server. +// This config struct is used by both NewMCPServer and NewUnauthenticatedMCPServer +// to ensure consistent configuration across authentication modes. type MCPServerConfig struct { // Version of the server Version string @@ -158,6 +161,17 @@ func resolveEnabledToolsets(cfg MCPServerConfig) []string { return nil } +// NewMCPServer creates a fully initialized MCP server with GitHub API access. +// This constructor is used when a token is available at startup (PAT authentication). +// For OAuth device flow authentication without a pre-configured token, use NewUnauthenticatedMCPServer instead. +// +// The server creation involves several steps: +// 1. Parse API host configuration and create GitHub clients +// 2. Resolve which toolsets to enable +// 3. Create MCP server with appropriate capabilities +// 4. Add middleware for error handling, user agents, and dependency injection +// 5. Build and register the tool/resource/prompt inventory +// 6. Optionally register dynamic toolset management tools func NewMCPServer(cfg MCPServerConfig) (*mcp.Server, error) { apiHost, err := parseAPIHost(cfg.Host) if err != nil { @@ -284,8 +298,17 @@ type UnauthenticatedServerResult struct { } // NewUnauthenticatedMCPServer creates an MCP server with only authentication tools available. -// After successful authentication via the auth tools, call OnAuthenticated to initialize -// GitHub clients and register all other tools. +// This constructor is used for OAuth device flow when no token is available at startup. +// After successful authentication via the auth tools, the OnAuthenticated callback +// initializes GitHub clients and registers all other tools dynamically. +// +// Architecture note: This shares significant setup logic with NewMCPServer. The duplication +// exists because the two modes have different initialization timing: +// - NewMCPServer: All setup happens at construction time (clients + tools) +// - NewUnauthenticatedMCPServer: Setup happens in two phases (auth tools first, then clients + tools after auth) +// +// Future improvement: Consider extracting common setup logic into shared helper functions +// to reduce duplication while maintaining the two-phase initialization pattern. func NewUnauthenticatedMCPServer(cfg MCPServerConfig) (*UnauthenticatedServerResult, error) { // Create OAuth host from the configured GitHub host oauthHost := github.NewOAuthHostFromAPIHost(cfg.Host) @@ -387,7 +410,11 @@ func NewUnauthenticatedMCPServer(cfg MCPServerConfig) (*UnauthenticatedServerRes return nil }, OnAuthComplete: func() { - // Remove auth_login tool now that authentication is complete + // Remove auth tools after authentication completes. + // Note: This manual removal ensures auth tools don't remain available after login. + // The auth_login tool is removed by name here to keep the tool list clean. + // Future improvement: Consider using toolset-based filtering to automatically + // exclude auth toolset after authentication, removing the need for manual cleanup. ghServer.RemoveTools("auth_login") if cfg.Logger != nil { cfg.Logger.Info("auth tools removed after successful authentication") From 8a48cad8e679289ff7d5083b954df7c5789013ad Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 19 Dec 2025 07:13:55 +0000 Subject: [PATCH 6/7] Refactor to build inventory once before authentication fork - Move inventory building outside OnAuthenticated callback in NewUnauthenticatedMCPServer - Build inventory once before creating auth tools, eliminating duplication - Reuse the same inventory instance in OnAuthenticated via closure - Tool filters are now applied only once, preventing stale auth tools - Reduces code duplication without changing architecture - All tests pass, 0 lint issues Co-authored-by: SamMorrowDrums <4811358+SamMorrowDrums@users.noreply.github.com> --- internal/ghmcp/server.go | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/internal/ghmcp/server.go b/internal/ghmcp/server.go index b231f6996..a61b0ceee 100644 --- a/internal/ghmcp/server.go +++ b/internal/ghmcp/server.go @@ -316,6 +316,20 @@ func NewUnauthenticatedMCPServer(cfg MCPServerConfig) (*UnauthenticatedServerRes // Create auth manager authManager := github.NewAuthManager(oauthHost, cfg.OAuthClientID, cfg.OAuthClientSecret, cfg.OAuthScopes) + // Build the tool inventory once before forking - this ensures tool filters are applied once + enabledToolsets := resolveEnabledToolsets(cfg) + inventory := github.NewInventory(cfg.Translator). + WithDeprecatedAliases(github.DeprecatedToolAliases). + WithReadOnly(cfg.ReadOnly). + WithToolsets(enabledToolsets). + WithTools(github.CleanTools(cfg.EnabledTools)). + WithFeatureChecker(createFeatureChecker(cfg.EnabledFeatures)). + Build() + + if unrecognized := inventory.UnrecognizedToolsets(); len(unrecognized) > 0 { + fmt.Fprintf(os.Stderr, "Warning: unrecognized toolsets ignored: %s\n", strings.Join(unrecognized, ", ")) + } + // Create the MCP server with capabilities advertised for dynamic tool registration serverOpts := &mcp.ServerOptions{ Instructions: "GitHub MCP Server - Authentication Required\n\nYou are not currently authenticated with GitHub. Use the auth_login tool to complete authentication. This is a single, blocking call that will guide you through the entire device authorization flow and return once authentication has finished.", @@ -377,33 +391,16 @@ func NewUnauthenticatedMCPServer(cfg MCPServerConfig) (*UnauthenticatedServerRes } }) - // Resolve enabled toolsets - enabledToolsets := resolveEnabledToolsets(authenticatedCfg) - - // Build and register the tool/resource/prompt inventory - inv := github.NewInventory(cfg.Translator). - WithDeprecatedAliases(github.DeprecatedToolAliases). - WithReadOnly(cfg.ReadOnly). - WithToolsets(enabledToolsets). - WithTools(github.CleanTools(cfg.EnabledTools)). - WithFeatureChecker(createFeatureChecker(cfg.EnabledFeatures)). - Build() - - // Log how many tools we're about to register - availableTools := inv.AvailableTools(ctx) - if cfg.Logger != nil { - cfg.Logger.Info("registering tools after authentication", "count", len(availableTools)) - } - - // Register all GitHub tools/resources/prompts - inv.RegisterAll(ctx, ghServer, deps) + // Register all GitHub tools/resources/prompts using the pre-built inventory + inventory.RegisterAll(ctx, ghServer, deps) // Register dynamic toolset management tools if enabled if cfg.DynamicToolsets { - registerDynamicTools(ghServer, inv, deps, cfg.Translator) + registerDynamicTools(ghServer, inventory, deps, cfg.Translator) } if cfg.Logger != nil { + availableTools := inventory.AvailableTools(ctx) cfg.Logger.Info("authentication complete, tools registered", "toolCount", len(availableTools)) } From f3b0d1b55dc7bf055a1bf685a4a950f309f7eebf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 19 Dec 2025 07:37:14 +0000 Subject: [PATCH 7/7] Remove server instructions for unauthenticated mode - Remove custom Instructions text from unauthenticated server - Tool schema is sufficient - auth tool describes itself - Auth tool is conditionally present only when needed - Simplifies server initialization Co-authored-by: SamMorrowDrums <4811358+SamMorrowDrums@users.noreply.github.com> --- internal/ghmcp/server.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/internal/ghmcp/server.go b/internal/ghmcp/server.go index a61b0ceee..7fe526869 100644 --- a/internal/ghmcp/server.go +++ b/internal/ghmcp/server.go @@ -332,8 +332,7 @@ func NewUnauthenticatedMCPServer(cfg MCPServerConfig) (*UnauthenticatedServerRes // Create the MCP server with capabilities advertised for dynamic tool registration serverOpts := &mcp.ServerOptions{ - Instructions: "GitHub MCP Server - Authentication Required\n\nYou are not currently authenticated with GitHub. Use the auth_login tool to complete authentication. This is a single, blocking call that will guide you through the entire device authorization flow and return once authentication has finished.", - Logger: cfg.Logger, + Logger: cfg.Logger, // Advertise capabilities since tools will be added after auth Capabilities: &mcp.ServerCapabilities{ Tools: &mcp.ToolCapabilities{ListChanged: true},