← Developers

MCP server v1

The same operations as the HTTP API, over the Model Context Protocol — so an assistant can read a diary and book into it without anybody writing a client first.

See also the HTTP API and webhooks.

Connecting

The same key that opens the HTTP API. There is nothing separate to enable, and the scopes mean the same things here.

Server URL
https://torim.ai/api/mcp
Transport
Streamable HTTP
Header
Authorization: Bearer torim_…

Clients configured from a file usually take this shape:

{
  "mcpServers": {
    "torim": {
      "type": "http",
      "url": "https://torim.ai/api/mcp",
      "headers": {
        "Authorization": "Bearer torim_…"
      }
    }
  }
}

Command-line clients generally take the same three values as flags. Nothing here is specific to one client.

Tools

Ten, and this is all of them. Each is one call into the same code the matching endpoint uses, so the rules — the slot re-derivation, the notifications, the double-booking protection — cannot differ between the two.

get_business —Name, timezone, address and booking policy. Takes nothing: the key names the business. catalogue:read
list_services —Every service, retired ones included. A service `slug` is what the other tools take. catalogue:read
list_team —Who works here. An appointment is booked onto one of these by `id`. catalogue:read
get_availability service, from?, days?When a service can be booked. Ask this before booking or moving anything. catalogue:read
list_appointments from?, to?The diary, with customer names and phone numbers — cancelled appointments and pending requests included. `to` is inclusive, defaults to six days on, and the window may not exceed 62 days. appointments:read
get_appointment idOne appointment, to confirm what was actually written. appointments:read
create_appointment service, staff_id, start, customer_name, customer_phone?, customer_email?, note?, off_grid?Book somebody in. The price comes from the service, never from the call. appointments:write
cancel_appointment idCall one off. Frees the slot and tells the waiting list, which may keep it for whoever has waited longest. appointments:write
move_appointment id, start, off_grid?Reschedule. One update under the same lock a booking takes. appointments:write
list_closures —Days the business is shut, from today on. catalogue:read

An argument marked ? is optional. Instants are RFC 3339; dates are YYYY-MM-DD; unknown arguments are rejected rather than ignored. Every tool answers with the same JSON its endpoint would, as text content.

What a refusal looks like

A refusal comes back as a tool error result, not a JSON-RPC error, carrying the same stable code the HTTP surface uses:

{ "ok": false, "code": "slot_taken" }

That is deliberate. slot_taken is not a malformed request, it is an answer — a model that can read it can pick another time. Only a genuine server fault is raised as a protocol error, because there is nothing useful for a model to do about one.

Authentication is the exception: a missing or dead key is refused before the protocol is spoken at all, with the ordinary 401 and the ordinary { code, error } body.

Protocol notes

  • Stateless. No session to establish and no Mcp-Session-Id to keep alive — every call carries its own key and is answered on its own.
  • Plain JSON responses. Every tool is one question with one answer, so nothing streams.
  • Instructions. The server tells a model two things no single tool says: which business it is connected to, and that a time must come from get_availability.
  • No OAuth yet. Clients that insist on an OAuth flow rather than a header — some hosted connector UIs do — cannot connect today. Anything that accepts a bearer header can.
  • Tools only. No resources and no prompts are served.

Something not answered here? Get in touch.