# Client compatibility

Two ways in, and both resolve to the same account: OAuth 2.1 with dynamic
registration and PKCE, or a bearer token minted at [/connect](/connect).

## The matrix

**Rows marked "not tried" are untested.** They are expectations from what the
client documents, not results. A compatibility matrix that mixes tested and
assumed rows is worse than none, because the reader cannot tell which is which.

| client                                                                                                                                                                 | OAuth   | token | tested?   |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | ----- | --------- |
| **Claude (web, desktop, Code)** — verified end to end over OAuth 2.1 with dynamic registration                                                                         | yes     | yes   | tried     |
| **ChatGPT connectors** — works. A client registered BEFORE 2026-09-03 cannot request `openid` and fails; remove and re-add the connector to force a fresh registration | yes     | —     | tried     |
| **Codex CLI**                                                                                                                                                          | likely  | yes   | not tried |
| **Cursor**                                                                                                                                                             | likely  | yes   | not tried |
| **VS Code / Copilot**                                                                                                                                                  | likely  | yes   | not tried |
| **Windsurf, Cline, Goose, Gemini CLI**                                                                                                                                 | unknown | yes   | not tried |
| **curl / your own code**                                                                                                                                               | yes     | yes   | tried     |

## Constraints that bite

- **The trailing slash.** `/mcp/`, always. Without it the origin answers 308 and a client that does not replay a POST body across a redirect fails in a way that looks like a server bug.
- **Protocol version.** Sending `2026-07-28` in the header alone is not enough — that spec carries the version in `params._meta` too. Older versions work from the header.
- **A stale OAuth registration cannot heal itself.** Clients register once and cache it. If authorization fails persistently, remove and re-add the connector.
