diff --git a/MCP-Servers.md b/MCP-Servers.md index 24f8519..cee0df2 100644 --- a/MCP-Servers.md +++ b/MCP-Servers.md @@ -93,12 +93,13 @@ For remote MCP servers that support the Streamable HTTP transport: } ``` -| Field | Required | Description | -|-------------------|----------|------------------------------------------------------------------------------------------------| -| `type` | yes | Must be `"http"` | -| `url` | yes | The server endpoint URL | -| `headers` | no | Custom HTTP headers to include with every request | -| `oauth_client_id` | no | OAuth client ID. Omit to use Dynamic Client Registration (auto-registers on first `.mcp auth`) | +| Field | Required | Description | +|----------------------|----------|---------------------------------------------------------------------------------------------------------------| +| `type` | yes | Must be `"http"` | +| `url` | yes | The server endpoint URL | +| `headers` | no | Custom HTTP headers to include with every request | +| `oauth.clientId` | no | OAuth client ID. Omit to use Dynamic Client Registration (auto-registers on first `.mcp auth`) | +| `oauth.callbackPort` | no | Callback port for the OAuth redirect listener. Required when the server enforces a specific redirect URI port | ## SSE Servers @@ -119,12 +120,13 @@ prefer `http` where the server supports it): } ``` -| Field | Required | Description | -|-------------------|----------|------------------------------------------------------------------------------------------------| -| `type` | yes | Must be `"sse"` | -| `url` | yes | The server SSE endpoint URL | -| `headers` | no | Custom HTTP headers to include with every request | -| `oauth_client_id` | no | OAuth client ID. Omit to use Dynamic Client Registration (auto-registers on first `.mcp auth`) | +| Field | Required | Description | +|----------------------|----------|---------------------------------------------------------------------------------------------------------------| +| `type` | yes | Must be `"sse"` | +| `url` | yes | The server SSE endpoint URL | +| `headers` | no | Custom HTTP headers to include with every request | +| `oauth.clientId` | no | OAuth client ID. Omit to use Dynamic Client Registration (auto-registers on first `.mcp auth`) | +| `oauth.callbackPort` | no | Callback port for the OAuth redirect listener. Required when the server enforces a specific redirect URI port | **Note:** Both `http` and `sse` types use the same underlying transport, which auto-negotiates the protocol with the server. The `type` field primarily serves as documentation of which protocol the @@ -170,7 +172,8 @@ automatically. When the token expires it is refreshed silently. 2. **Dynamic Client Registration (RFC 7591):** If the server supports it (the Notion MCP server used in this example does), Coyote registers itself automatically and caches the client ID in `~/.cache/coyote/oauth/mcp__registration.json`. The `oauth_client_id` field is only needed when DCR is unavailable. -3. **PKCE authorization code flow:** A localhost callback server is bound on an ephemeral port. Your browser opens for login. +3. **PKCE authorization code flow:** A localhost callback server is bound on an ephemeral port (or the port specified by + `oauth.callbackPort` if the server requires a fixed redirect URI). Your browser opens for login. The token is exchanged and stored in `/oauth/mcp__oauth_tokens.json`. 4. **Token injection:** On every connection to the server, Coyote loads the stored token (refreshing if expired) and injects it as an `Authorization: Bearer` header. No changes to `mcp.json` required. @@ -196,13 +199,33 @@ If your organization pre-registers a client with the server (this is rare, as DC "my-server": { "type": "http", "url": "https://mcp.example.com/mcp", - "oauth_client_id": "your-registered-client-id" + "oauth": { + "clientId": "your-registered-client-id" + } } } } ``` -When `oauth_client_id` is set, DCR is skipped and the provided ID is used directly. +When `oauth.clientId` is set, DCR is skipped and the provided ID is used directly. + +Some servers (e.g. Slack) pre-register an OAuth app with a specific redirect URI and require the callback to land on a +fixed port. Use `oauth.callbackPort` in that case: + +```json +{ + "mcpServers": { + "slack": { + "type": "http", + "url": "https://mcp.slack.com/mcp", + "oauth": { + "clientId": "1601185624273.8899143856786", + "callbackPort": 3118 + } + } + } +} +``` ### Using a static token instead of OAuth diff --git a/REPL.md b/REPL.md index 74e559c..79ce622 100644 --- a/REPL.md +++ b/REPL.md @@ -352,7 +352,7 @@ where `` matches the key in your `mcp.json` file. Tab completion is **What happens:** 1. Coyote discovers the server's OAuth endpoints automatically via [RFC 9728](https://www.rfc-editor.org/rfc/rfc9728) metadata discovery. -2. If the server supports [Dynamic Client Registration (RFC 7591)](https://www.rfc-editor.org/rfc/rfc7591), Coyote registers itself automatically, meaning no `oauth_client_id` configuration is required. +2. If the server supports [Dynamic Client Registration (RFC 7591)](https://www.rfc-editor.org/rfc/rfc7591), Coyote registers itself automatically, meaning no `oauth.clientId` configuration is required. 3. Your browser opens to the server's authorization page. Log in and approve access. 4. The token is saved to `/coyote/oauth/` and loaded automatically on subsequent startups. 5. Tokens are refreshed automatically when they expire.