Model Context Protocol
Chatto can expose a small tool catalog through the Model Context Protocol (MCP). The optional MCP integration uses the same public HTTP server, OAuth implementation, and version as the rest of Chatto.
The endpoint supports stateless MCP 2026-07-28. Hosts that start with
initialize cannot connect. See the MCP Reference for tools,
search arguments, response schemas, and retry rules.
Enable MCP
Section titled “Enable MCP”Add this section to chatto.toml:
[mcp]enabled = trueChatto mounts /mcp and /.well-known/oauth-protected-resource/mcp on its
existing public HTTP server. It uses the webserver.url origin and each exact
non-wildcard origin in webserver.allowed_origins. For example, a server at
https://chat.example has the MCP endpoint https://chat.example/mcp.
Each endpoint is a separate OAuth resource. A human access token for one
origin does not work on another origin. The authorization server always uses
the canonical webserver.url origin as its issuer. Bot API keys work on each
configured endpoint. A reverse proxy needs no separate MCP upstream.
Authenticate an agent host
Section titled “Authenticate an agent host”Human users authorize an MCP client through OAuth Authorization Code with S256 PKCE. Chatto resolves the client’s Client ID Metadata Document (CIMD), shows the requested scope capabilities on the consent page, and issues an access token bound to the exact MCP resource and approved scopes. A first-party Chatto bearer token without this resource and grant cannot use MCP.
Request only the scopes your host needs. Chatto accepts any nonempty subset of these scopes. A write scope does not include read access.
| Scope | Tools |
|---|---|
chatto:rooms:read | list_rooms |
chatto:rooms:write | join_room, leave_room |
chatto:messages:read | list_room_messages, search_messages (when search is enabled) |
chatto:messages:write | post_message |
Any valid grant also permits discovery, get_server_info, and
get_current_user. tools/list shows only the tools covered by your grant.
Initial discovery requests room-read access, so the default grant has three
tools. A host that needs message reads or writes must request those scopes.
Additional scopes require fresh consent. Refresh keeps the approved scope
set; the token response reports it in scope. Existing full grants still work.
Native hosts must publish client metadata with application_type: native and
an exact callback. Runtime callback ports require literal loopback IP addresses.
Named localhost callbacks must use the registered port.
An unattended integration can send a current bot API key as its bearer token. The bot acts as its own account. Its explicit permission allowlist and its owner’s current permission ceiling still apply. See Bot Accounts.
- Give your agent host the public Chatto URL with the
/mcppath. - Let the host read protected-resource and authorization-server metadata.
- Complete the Chatto consent screen when the host opens it.
- Confirm that the host discovers the tools covered by your grant.
- Ask the host to identify the server. Confirm that it reports the expected name and public URL.
- Ask the host to identify the connected account and list its visible rooms.
- To test all tools, approve all four scopes. In a test room, ask the host to join, post a unique test message, read the message, and leave.
Codex CLI
Section titled “Codex CLI”The setup below was tested with Codex CLI 0.160.1:
codex mcp add chatto --url https://chat.example.com/mcpcodex mcp login chatto --oauth-client-registration cimdComplete sign-in and consent in the browser. Then start Codex and use the identity and room checks above. Codex identifies itself with its public CIMD document. You do not need a client secret or a first-party Chatto token.
To grant all available tools, request all four scopes explicitly:
codex mcp login chatto --oauth-client-registration cimd \ --scopes chatto:rooms:read,chatto:rooms:write,chatto:messages:read,chatto:messages:writeFor a diagnostic client, see MCP Inspector.
Troubleshoot connection failures
Section titled “Troubleshoot connection failures”| Failure | Action |
|---|---|
/mcp returns 404 | Enable [mcp].enabled and check the public URL and reverse proxy. |
initialize returns method not found | Use a host with stateless 2026-07-28 support. In Inspector, select the modern protocol era. |
Consent rejects redirect_uri | Check the client’s CIMD document. Runtime ports require a native client and a literal loopback IP callback. Named localhost callbacks must match exactly. |
A tool request returns 401 | Authorize the exact MCP URL again. Check grant expiry, client blocking, and the valid MCP scopes. A first-party token or a grant for another origin cannot be used. |
A tool is absent or returns 403 insufficient_scope | Request its scope in a new OAuth consent flow. The Bearer challenge identifies the required scope. Keep any existing scopes that the host still needs. |
search_messages is absent with message-read access | Ask the operator to check that search is enabled on the server. |
Inspector --use-stored-auth reports no_stored_token | Use --stored-auth-only. This Inspector version can fail to load its stored credentials through the older flag. |
Claude Code 2.1.291 fails callback validation with its current CIMD document.
That document omits application_type: native, while the client requests a
callback with a runtime port. Use another tested host until the client and its
metadata document agree. Do not disable callback validation.
Understand permission failures
Section titled “Understand permission failures”An operation needs both the relevant OAuth scope and normal Chatto permissions and room membership. A scope error requires fresh consent; an account permission error requires a change to that account’s access. A bot also needs its owner’s current authority. See the MCP error reference for response fields and retry rules.
Disable access
Section titled “Disable access”Set [mcp].enabled = false and restart Chatto to remove the MCP routes. You
can also block an OAuth client in Server Admin or rotate a bot API key. These
actions invalidate the related authority without changing other Chatto
clients.
Removing Chatto from an agent host or deleting its local credentials does not guarantee that its server-side grant is revoked. Ask a server administrator to block that OAuth client when you must terminate its access. A revoked grant or blocked client cannot start another MCP request or refresh its credential, also when the request reaches another Chatto replica.
The network MCP server does not expose the Operator API, bootstrap, password reset, account management, or server management. Use the local Operator API for root-equivalent recovery tasks.