The Connect button now connects

Approving an assistant did nothing. The page said the form had not come from here, and it was right in a way that was wrong: the approval page asked browsers not to send a referrer, and Chrome takes a page’s origin off the same setting — so the page’s own form arrived claiming to come from nowhere, and the check that stops another site approving things for you stopped the page itself.

Nothing had ever been connected through it. The tests could not see this, because a test is not a browser and sends whichever headers it is told to; the database could, and said so plainly: every request shown, none ever approved.

Behind that sat a second one. The page tells the browser it may only send you to the assistant that asked — and it had been saying it may send you nowhere but back to us, so approving worked and the trip back to the assistant was refused by the page itself. It now names that one address, and nothing else.

Approving an assistant is one page and one button, and this is what is behind them.

What approving actually does

You sign in here with the account you already use, read a page that names the client and the address it is about to act as, and press Connect. What the client walks away with is a token issued by this site — not your session, not an API key. It reaches the documents on the account and nothing else: not the account, not the sign-in, not your API keys. A read-only connection cannot save, share or delete, and that is enforced on the credential rather than on the tools.

TransformPipe has to be its own authorization server for this: the MCP specification forbids a resource accepting a token issued by somebody else, so the sign-in session cannot simply be handed over.

The order of events

  1. The assistant POSTs /api/mcp with no token and gets a 401 naming where to look.
  2. It reads /.well-known/oauth-protected-resource, then /.well-known/oauth-authorization-server, to find the endpoints.
  3. It identifies itself — by a metadata document it publishes, or by registering here. No secret either way: a client running on somebody else's machine cannot keep one, which is what PKCE is for.
  4. It sends you to /authorize with a challenge. code_challenge_method=S256 is required; a plain challenge is refused outright.
  5. You approve with a POST from the page you were shown, so a link on its own authorises nothing.
  6. It exchanges the code and its verifier at /token.

What the tokens do afterwards

A code lives five minutes and is burnt at the start of its exchange, before anything is checked against it, so a copy replayed while the first call is still in flight gets nothing. Refresh tokens rotate: handing one in revokes it and issues a fresh pair. Handing in one that has already been rotated ends the whole grant — the access token, the refresh token beside it and every rotation before them — because a refresh token presented twice is the only signal anyone gets that it has been copied.

Take it back from the account menu, under MCP connector; it stops working on the next call.

Why the button had done nothing

Two headers on our own page. It asked browsers to send no referrer, and Chrome derives a form POST's Origin from that same setting, so the page's own submission arrived claiming to come from nowhere — and the check that stops another site approving things for you stopped the page itself. Behind that, the page's form-action named only this site, so the trip back to the assistant was refused by the policy after the code had already been minted. It now names the one address the request will actually be sent to, and nothing else.

Related: converting documents from an assistant, and whether an online converter is safe.