Skip to content

Connect an AI client

An AI client connects to a Cahut with its address alone: https://cahut.example.com/mcp. The client sends you to the console of the Cahut, where you sign in and choose what it may do. Then it acts for you, within what you granted, and every call it makes goes to the Logbook.

This works with the MCP clients that sign in with OAuth: claude.ai, Claude Desktop, Claude Code, ChatGPT, Le Chat and others. For a client that cannot, such as a script, use a personal token.

The address to give is on the AIs and access screen of the console, ready to copy.

Client Where
claude.ai, Claude Desktop Settings, Connectors, Add custom connector: the address of the Cahut, nothing else
Claude Code claude mcp add --transport http cahut https://cahut.example.com/mcp, then /mcp and Authenticate. See Connect Claude Code
ChatGPT On the web, Plugins, the plus button, Add custom MCP server: the address of the Cahut, and OAuth as its authentication. Custom MCP servers need a Business, Enterprise or Edu plan
Le Chat Connectors, add a custom MCP connector with the address of the Cahut. Le Chat finds OAuth by itself
Others The address of the Cahut. The client finds the rest by itself

A Cahut on my.cahut.cloud needs no address in claude.ai and Claude Desktop: My Cahut is in the directory of connectors of Claude. Search for it, then select Connect. See Try Cahut on My Cahut.

The client opens a page of the console in your browser, at https://<domain>/console/oauth/authorize. The servers of the client, and your browser, reach the Cahut on port 443 only.

ChatGPT does not connect to a Cahut at the IP address of its server: its servers never call the Cahut, and ChatGPT says that it cannot find the OAuth settings. Move the Cahut to a domain first, then add it to ChatGPT at its new address.

Every client gets the same tools. Each tool has a title, such as Publish a Window, and says whether it only reads: ChatGPT shows the title when it asks you to confirm a call that changes something, and Le Chat lets you allow each tool always or ask each time. That confirmation comes on top of Knock first, which no client can skip.

If you are not signed in to the console, you sign in first. Then the console shows:

  • Who asks: the name of the AI client, as it gives it, and the host the browser goes back to once you answer, such as claude.ai. Some clients, such as Claude Code, describe themselves in a document on their own site, and the console names that site. A client that registered by itself could have chosen any name: connect it only if you started from it.
  • What it may do: read and publish, which is everything you can do in your Rooms, or read only, which is your Rooms, their Windows and the Logbook. A client that asks for read access cannot get more.
  • Where: all your Rooms, including those you join later, or a list of them.

Connect sends the browser back to the client, which receives its tokens. Refuse sends it back with nothing.

An AI never gets more than its person: if you leave a Room, or an administrator disables you, it loses that too. An AI limited to some Rooms does not see the others, cannot publish in them and cannot create a Room. An AI that may only read sees only the tools that read.

AIs and access lists your connected AIs: the client, what it may do, its Rooms, when it last acted and its state. Change sets what it may do and where, as on the consent screen. Disconnect cuts one off: its next call is refused.

An AI can ask for more itself, such as write access or another Room, with set_ai_reach: it knocks first, and gets it once you approve. An AI that may only read is offered this tool too, for that. Narrowing what it reaches, it does at once.

State What it means
Active The AI can act
Expired The AI has not been used for 30 days: connect it again
Disconnected You, an administrator, or the client itself ended the connection

An administrator of the Cahut sees the connected AIs of others too, and can disconnect them.

Each connection is in the Logbook: your consent, every call the AI makes, under its name and the person it acts for, such as Claude Code (claude-code 2.1.307) for you, and the end of the connection.

Each Cahut is its own OAuth 2.1 authorization server, as the MCP authorization specification asks:

What Where
Protected resource metadata (RFC 9728) https://cahut.example.com/.well-known/oauth-protected-resource/mcp
Issuer https://cahut.example.com
Authorization server metadata (RFC 8414) https://cahut.example.com/.well-known/oauth-authorization-server
Token, registration, revocation https://cahut.example.com/oauth/token, /oauth/register, /oauth/revoke
Authorization https://cahut.example.com/console/oauth/authorize, a page of the console

Everything is on port 443. The servers of a client call the endpoints of the protocol, and the person’s browser opens the authorization page, in the console.

  • Clients register with a Client ID Metadata Document or by dynamic registration (RFC 7591). Both make public clients, which authenticate with none: there is no client secret. A metadata document may prefer another method, such as private_key_jwt for ChatGPT, as long as it lists none in token_endpoint_auth_methods_supported.
  • Cahut fetches a metadata document as Cahut/<version>, from public addresses only, and keeps it in memory for an hour. It also keeps the last valid copy of each document a person connected: when the document no longer answers, the copy stands in for 30 days. A document that answers but is invalid is refused.
  • Authorization codes need PKCE with S256, live 5 minutes and are used once.
  • Access tokens start with cahut_oat_ and live one hour. Refresh tokens start with cahut_ort_ and live 30 days; each refresh replaces the refresh token. A refresh token used twice ends the connection.
  • The scopes are read and write, and offline_access for the refresh token, which every connection has. A token granted write states read write offline_access, and one granted read states read offline_access. The resource is https://cahut.example.com/mcp; a token of one Cahut opens nothing in another.
  • Redirect URIs match exactly, except loopback addresses in http, whose port may change.

ADR 16 and ADR 17 give the details. The service logs each request to these endpoints, with its status and the error of a refused one: journalctl -u cahut shows them while a client connects.