Skip to content
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
# Changelog

## [Unreleased]

### Added

- **Automatic Browser Launch for OAuth**
- The authorization URL is now opened automatically in the system's default browser (`open`/`xdg-open`/`start`) as soon as it's ready
- New `oauth.autoOpenBrowser` config option (default `true`) to disable this for headless/CI environments
- URL is still captured/printed as before, so AI agents can surface it if the browser can't be opened automatically
- **Non-Blocking OAuth Flow for AI Agents**
- `AuthRequiredError` now includes authorization URL for immediate action
- Callback server runs in background (5 min timeout) - CLI returns immediately
- `mcp-cli` (list all) shows working servers + auth URLs for servers needing login
- Random port by default to avoid conflicts with multiple OAuth servers
- Updated README with sequence diagram and AI agent guidance

## [0.3.0] - 2026-01-22

### Added
Expand Down
152 changes: 152 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,157 @@ Restrict which tools are available from a server using `allowedTools` and `disab
"disabledTools": ["delete_file"]
```

### OAuth Authentication

For HTTP MCP servers that require OAuth (like Notion, GitHub, etc.), the CLI handles authentication automatically:

```mermaid
sequenceDiagram
participant AI as AI Agent
participant CLI as mcp-cli
participant Server as Callback Server
participant User as User
AI->>CLI: mcp-cli
CLI->>CLI: Detect some servers need auth
CLI->>Server: Spawn background callback server
CLI->>User: Auto-opens auth URL in default browser
CLI-->>AI: List working servers + auth URL for others
User->>Server: Completes OAuth in browser
Server->>Server: Saves tokens to ~/.mcp-cli/tokens/
User->>AI: "Done"
AI->>CLI: mcp-cli (retry)
CLI-->>AI: All servers now listed
```

The authorization URL is automatically opened in the system's default
browser (`open` on macOS, `xdg-open` on Linux, `start` on Windows) as soon
as it's ready, so you usually don't need to copy/paste anything - just
complete the login/consent screen that pops up.

**Configuration:**

Most OAuth-enabled servers work with just a URL - the CLI handles dynamic client registration and PKCE automatically:

```json
{
"mcpServers": {
"notion": {
"url": "https://mcp.notion.com/mcp"
}
}
}
```

**OAuth Configuration Options:**

For servers requiring custom OAuth settings, use the `oauth` object:

```json
{
"mcpServers": {
"my-server": {
"url": "https://api.example.com/mcp",
"oauth": {
"callbackPort": 8095,
"clientId": "your-client-id",
"clientSecret": "your-client-secret",
"scope": "read write",
"grantType": "authorization_code"
}
}
}
}
```

| Option | Description | Default |
|--------|-------------|---------|
| `callbackPort` | Port for OAuth callback server | Random |
| `clientId` | Pre-registered OAuth client ID | (dynamic registration) |
| `clientSecret` | OAuth client secret (for confidential clients) | (none) |
| `scope` | OAuth scopes to request | (none) |
| `grantType` | `authorization_code` or `client_credentials` | `authorization_code` |
| `autoOpenBrowser` | Automatically open the auth URL in the default browser | `true` |

**Examples by scenario:**

1. **Public server with dynamic registration** (most common):
```json
{
"notion": { "url": "https://mcp.notion.com/mcp" }
}
```

2. **Server with pre-registered public client:**
```json
{
"github": {
"url": "https://mcp.github.com/mcp",
"oauth": { "clientId": "abc123" }
}
}
```

3. **Confidential client (client_credentials):**
```json
{
"internal-api": {
"url": "https://api.internal.com/mcp",
"oauth": {
"clientId": "service-account",
"clientSecret": "secret-key",
"grantType": "client_credentials"
}
}
}
```

4. **Headless/CI environment (disable auto-open browser):**
```json
{
"notion": {
"url": "https://mcp.notion.com/mcp",
"oauth": { "autoOpenBrowser": false }
}
}
```

**Token Storage:**

Tokens are persisted in `~/.mcp-cli/` with secure file permissions (0600):

```
~/.mcp-cli/
├── tokens/server-name.json # Access/refresh tokens
├── clients/server-name.json # Dynamic client registration
└── verifiers/server-name.txt # PKCE verifiers (temporary)
```

**Clearing cached tokens:**

```bash
rm ~/.mcp-cli/tokens/notion.json # Re-authenticate on next call
rm -rf ~/.mcp-cli/ # Clear all OAuth data
```

**For AI Agents (non-interactive mode):**

When listing multiple servers, working servers show their tools while auth-required servers display an actionable auth URL:

```
deepwiki
• read_wiki_structure
• read_wiki_contents
• ask_question

notion
• <error: [AUTH REQUIRED] notion
Authenticate at: https://mcp.notion.com/authorize?...
Callback server running in background (5 min timeout).
After authenticating, confirm "done" and retry this command.>
```

The callback server stays running in the background. After the user authenticates and confirms, retry the command to see all servers.

### Config Resolution

The CLI searches for configuration in this order:
Expand All @@ -360,6 +511,7 @@ The CLI searches for configuration in this order:
| `MCP_STRICT_ENV` | Error on missing `${VAR}` in config | `true` |
| `MCP_NO_DAEMON` | Disable connection caching (force fresh connections) | `false` |
| `MCP_DAEMON_TIMEOUT` | Idle timeout for cached connections (seconds) | `60` |
| `MCP_CLI_HOME` | Override OAuth storage directory (default: `$HOME`) | (none) |

## Using with AI Agents

Expand Down
Loading