# The MCP sign-in chain, step by step

_2026-11-04_

When someone adds your MCP server to an AI host, the host signs in on their behalf. Before a login page ever appears, it walks a chain of five steps. Each step reads something your server publishes. If one is missing or wrong, the host stops, and the user sees a generic error.

Your own logs rarely show it. The request that fails is an ordinary anonymous call that got an ordinary `401`.

## 1. The 401 challenge

The host calls your MCP endpoint without credentials. Your server should answer `401` and say where to look next:

```http
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer resource_metadata="https://your-server.com/.well-known/oauth-protected-resource"
```

This is where most broken chains break. In our study of 1,000 registry servers, two thirds of the failures were a `401` with no usable pointer.

## 2. Protected-resource metadata

The host fetches the document the challenge pointed to (RFC 9728). It names your authorization server:

```json
{
  "resource": "https://your-server.com/mcp",
  "authorization_servers": ["https://auth.your-server.com"]
}
```

## 3. Authorization-server metadata

The host reads `/.well-known/oauth-authorization-server` on that server (RFC 8414) to find the authorization, token and registration endpoints.

## 4. PKCE

MCP hosts use PKCE with the S256 method. Your metadata should say so:

```json
"code_challenge_methods_supported": ["S256"]
```

## 5. Client registration

The host needs a client ID. It either registers one through your `registration_endpoint`, or uses a client metadata document if your server supports them. Each host registers its own callback:

- ChatGPT: `https://chatgpt.com/connector_platform_oauth_redirect`
- Claude: `https://claude.ai/api/mcp/auth_callback`
- Cursor: `cursor://anysphere.cursor-mcp/oauth/callback`
- Codex and Claude Code: a loopback address such as `http://127.0.0.1:33418/callback`
- Gemini CLI: a loopback address on a port the system picks, so your server must accept any loopback port

A server that only allows the callback it was tested with works in one host and fails in the others.

## Check your own chain

```sh
npx backwatch your-server.com
```

Backwatch follows steps 1 to 4 from outside, the same way for every host. On your own server, `--register` also registers one client per host callback, to prove each host can complete step 5, and lists every client it created so you can delete them.
