Skip to content

Conversation

@attehuhtakangas
Copy link

@attehuhtakangas attehuhtakangas commented Jan 28, 2026

Summary

Adds OAuth authentication support for HTTP MCP servers, enabling authorization code flow with PKCE and client credentials flow. This allows mcp-cli to work with OAuth-protected servers like Datadog, Notion, and Linear.

Features

  • Authorization code flow with PKCE - Full browser-based OAuth flow with secure code exchange
  • Client credentials flow - For machine-to-machine authentication
  • Automatic token refresh - Tokens are persisted and refreshed automatically
  • Port fallback with redirect_uri validation - Tries ports 80, 8080, 3000, 8095 in order; detects and invalidates stale client registrations when ports change
  • Concurrent auth protection - Disables interactive OAuth when listing multiple servers to prevent chaos
  • Pretty HTML callback pages - Nice success/error pages shown in browser after OAuth

Improvements over #18

Feature This PR #18
Redirect URI mismatch detection ✅ Detects when stored client's redirect_uri doesn't match current port, automatically re-registers ❌ No detection, fails with "Invalid redirect_uri"
Pre-start callback server ✅ Starts server before client registration to ensure correct port ❌ Starts after, can cause race conditions
Concurrent auth handling list command disables interactive auth for multiple servers ❌ No handling
Runtime compatibility ✅ Uses Node.js http module (works everywhere) ❌ Uses Bun.serve (Bun-only)
Test coverage ✅ 38 unit tests for OAuth module ❌ No tests
Retry integration ✅ Integrates with existing retry/backoff mechanism ❌ Separate handling

Configuration

OAuth is automatic for HTTP servers. Optional config:

{
  "mcpServers": {
    "datadog": {
      "type": "http",
      "url": "https://mcp.datadoghq.com/api/unstable/mcp-server/mcp",
      "oauth": {
        "callbackPort": 3000,
        "scope": "read write"
      }
    }
  }
}

Test plan

  • OAuth flow works with Datadog MCP server
  • OAuth flow works with Notion MCP server
  • Port fallback works when preferred port is in use
  • Redirect URI mismatch is detected and handled
  • mcp-cli list works with multiple OAuth servers without prompting
  • All 38 OAuth unit tests pass
  • Existing tests still pass

🤖 Generated with Claude Code

attehuhtakangas and others added 5 commits January 27, 2026 22:59
- Add McpCliOAuthProvider implementing OAuthClientProvider interface
- File-based token storage in ~/.mcp-cli/{tokens,clients,verifiers}
- Support authorization_code and client_credentials grant types
- Auto-create OAuth provider for all HTTP servers (enables server-initiated OAuth)
- Handle OAuth callback with local HTTP server on configurable port
- Cross-platform browser opening for authorization flow
- Detect OAuth errors from UnauthorizedError and invalid_token responses

This enables MCP servers like Linear that require OAuth authentication.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Start callback server BEFORE opening browser to fix race condition
  where browser redirects before server is ready
- Add allowInteractiveAuth option to disable OAuth prompts when
  listing multiple servers (prevents multiple browsers opening)
- Show helpful "requires authentication" message for unauthenticated
  servers when listing, with command to authenticate individually
- Export AuthRequiredError and ConnectOptions from client module

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add port fallback mechanism: tries 80 → 8080 → 3000 → 8095 → random
- Port 80 as default with standard URL format (http://localhost/callback)
- Add pretty styled HTML pages for success/error callbacks
- Add callbackPorts config option for custom port fallback list
- Pre-start callback server to determine actual port before auth flow
- Add comprehensive tests for new port fallback features

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When the callback server port changes between sessions (e.g., port 3000
was used during registration but port 8080 is available now), the OAuth
authorization would fail with "Invalid redirect_uri" because the server
expects the originally registered redirect_uri.

Changes:
- clientInformation() now validates stored redirect_uris match current
  redirectUrl, invalidating stale registrations that would cause errors
- redirectToAuthorization() reuses pre-started callback server instead
  of starting a new one, ensuring consistent port usage throughout the
  OAuth flow

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Split the 850-line oauth.ts into smaller, focused modules:
- types.ts: Interfaces (OAuthConfig, OAuthCallbackResult) and constants
- storage.ts: File storage utilities for tokens, clients, verifiers
- browser.ts: Cross-platform browser opening utility
- callback-server.ts: HTTP callback server with HTML templates
- provider.ts: Main McpCliOAuthProvider class
- index.ts: Re-exports for backwards compatibility

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
CLI NEVER opens browser - always returns auth URL for AI agents.

Key changes:
- Removed allowInteractiveAuth option entirely (CLI is for AI agents)
- redirectToAuthorization() now captures auth URL, never opens browser
- AuthRequiredError includes authorization URL for immediate action
- Callback server runs in background (5 min timeout) - CLI returns immediately
- List command shows working servers + auth URLs for servers needing login
- Random port by default to avoid conflicts with multiple OAuth servers
- Added comprehensive OAuth configuration docs to README

This builds on the previous OAuth commits in this branch.
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