The answer
A remote MCP server that requires sign-in acts as an OAuth protected resource. When a client calls it without a valid token, the server answers 401 with a WWW-Authenticate header that points to its protected resource metadata. The client then discovers the authorization server, registers or identifies itself, runs the authorization code flow with PKCE, and retries with a token issued for your server.
| Symptom | Likely cause | Check |
|---|---|---|
| Client never shows a sign-in prompt | No WWW-Authenticate header on the 401, or unreachable metadata. | Request the server without a token and read the header. |
| Sign-in fails before the consent screen | Redirect URI not allowed, or registration rejected. | Authorization server logs and allowed redirect URIs. |
| Token exchange fails | PKCE method not supported, or the code was reused. | That S256 is advertised and used. |
| Signed in, but every call returns 401 | Token audience or resource does not match your server URL. | Canonical URL, scheme and trailing slash on both sides. |
| Some tools return 403 | Scope not granted for that operation. | Requested scopes against what the tool requires. |
| Works, then fails later | Expired token and a failed refresh. | Token lifetime, refresh grant and clock skew. |
Compare your server with a working example. Flowlines publishes its own protected resource metadata and authorization server metadata. The MCP authorization specification defines each step; check the revision your server implements.
Never log tokens or authorization headers while debugging. Record authentication failures as their own error class, by client. A failed handshake never reaches a tool, so it will not appear as a failed tool call. In Flowlines, a sudden drop in calls from one client after an authentication change is the clue to look here.
Published