Developers / MCP server

Developers

MCP server

Let Claude and other AI agents route leads and book meetings, with OAuth and scoped permissions.

Cauliflower includes a Model Context Protocol server, so Claude and other AI agents can work with your scheduling and routing directly: route a lead and book the meeting, find a free slot with a specific rep, pause someone in a round robin, add a path to a router, or answer "why did we disqualify so many leads last week?".

The MCP server exposes the same operations as the REST API, as tools. It runs inside your Cauliflower installation — there is nothing extra to deploy.

Endpoint and authentication

URLhttps://cal.example.com/api/mcp (your APP_URL plus /api/mcp)
TransportStreamable HTTP
AuthenticationOAuth 2.1 (recommended), or Authorization: Bearer cf_live_... with a workspace API key

The server is stateless: every request is a POST that carries its own token, and responses come back as plain JSON. There are no server-initiated streams, so GET and DELETE requests return 405.

Clients that support MCP authorization — Claude Code, Claude Desktop, Cursor and most others — need only the URL. On the first request the server answers 401 with a WWW-Authenticate header pointing at its metadata, the client registers itself, and your browser opens a consent screen:

  1. Sign in (if you aren't already) and pick the workspace the agent may use.
  2. Review the permissions it asks for and untick anything you don't want to give.
  3. Click Allow. The agent acts as you, with the permissions you approved.

Under the hood this is OAuth 2.1 with PKCE (S256), dynamic client registration (RFC 7591), authorization server metadata (RFC 8414) and protected resource metadata (RFC 9728):

EndpointPath
Protected resource metadata/.well-known/oauth-protected-resource/api/mcp
Authorization server metadata/.well-known/oauth-authorization-server
RegistrationPOST /api/oauth/register
Authorization/oauth/authorize
TokenPOST /api/oauth/token (authorization_code, refresh_token)
RevocationPOST /api/oauth/revoke

Access tokens last one hour; refresh tokens last 60 days and rotate on every use. Redirect URIs must be https or a loopback address (http://localhost / 127.0.0.1) for desktop clients.

Developers → MCP server → Connected apps lists every agent that has access to the workspace, who approved it, its permissions and when it was last used. People can disconnect their own apps; admins can disconnect anyone's.

Permissions (scopes)

Every OAuth token and every API key carries scopes. A tool call without the scope it needs fails with 403 insufficient_scope and names the missing scope.

AreaScopes
Workspaceworkspace:read, availability:write
Booking linksbooking_links:read, booking_links:write, booking_links:delete
Teamsteams:read, teams:write, teams:delete
Routersrouters:read, routers:write (includes duplicating), routers:delete
Leadsleads:read, leads:route
Meetingsmeetings:read, meetings:write, meetings:cancel
Reports and webhooksreports:read, webhooks:read, webhooks:write, webhooks:delete

Deleting and cancelling (*:delete, meetings:cancel) are destructive. They're never part of the default set, and AI agents can only receive them when a workspace admin turns on Allow deleting and cancelling (Developers → MCP server → What agents may do). Turning it off again takes effect immediately, for tokens that were already issued too. Members (not admins) can grant agents read access plus routing leads and booking meetings.

Clients that ask for a generic scope such as mcp get the standard set: everything except deleting and cancelling.

API keys

For scripts and servers, create a key under Developers → API keys (see API keys) and choose its permissions: Standard (everything except deleting and cancelling), Read only, Full access or a custom set. A key works for one workspace, so create a separate key for each agent, give it an expiry, and revoke it when it's no longer needed. Developers → MCP server shows the exact URL of your installation and copy-paste configuration for the clients below.

Connect a client

Claude Code

Terminal
claude mcp add --transport http cauliflower https://cal.example.com/api/mcp

Run /mcp inside Claude Code, choose cauliflower and authenticate in the browser. To use an API key instead, add --header "Authorization: Bearer cf_live_...".

Claude Desktop

Add Cauliflower as a custom connector (Settings → Connectors → Add custom connector) with the URL above, then click Connect to approve access. Older versions connect through the mcp-remote bridge; add this to claude_desktop_config.json and restart the app:

JSON
{
  "mcpServers": {
    "cauliflower": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://cal.example.com/api/mcp"]
    }
  }
}

Cursor, Windsurf and other clients

Clients that support remote HTTP servers take a URL — and, if you use an API key, headers:

JSON
{
  "mcpServers": {
    "cauliflower": {
      "type": "http",
      "url": "https://cal.example.com/api/mcp",
      "headers": { "Authorization": "Bearer cf_live_..." }
    }
  }
}

If the client reports 401, the token is missing, mistyped, expired or revoked; OAuth clients refresh or sign in again automatically.

Tools

Every tool maps to one REST endpoint and takes the same parameters. The server also sends the agent short instructions describing booking links, teams, routers (ordered paths, each with a rule and steps, plus the catch-all) and the typical flows below, including find_available_slots with a routing_token after route_lead, so you rarely need to explain the product in your prompt.

ToolWhat it doesHint
get_workspaceThe workspace, its time zone and public booking URLread-only
list_membersPeople in the workspace and their user idsread-only
get_availabilityA member's working hours and date overridesread-only
update_availabilityReplace a member's weekly hours or overrides
list_teamsRound robin teams with members and countsread-only
get_teamOne team with distribution statsread-only
create_teamCreate a team
update_teamChange a team's name, distribution or mode
set_team_membersReplace the roster, weights, priorities and paused reps
delete_teamDelete a teamdestructive
list_booking_linksBooking links with public URLsread-only
get_booking_linkOne booking linkread-only
create_booking_linkCreate a booking link
update_booking_linkChange any field of a booking link
delete_booking_linkDelete a booking linkdestructive
find_available_slotsOpen times for a booking link, optionally for one host, or for a routed lead with its routing_tokenread-only
list_routersAll routersread-only
get_routerA router's fields and flowread-only
create_routerCreate a router from a flow
update_routerReplace a router's flow or settings
delete_routerDelete a routerdestructive
route_leadRun a lead through a router, optionally as a dry run
list_meetingsMeetings by status, host, lead, source or searchread-only
get_meetingOne meeting with routing info and manage URLread-only
book_meetingBook with a booking link or a routing token
cancel_meetingCancel a meeting and notify everyonedestructive
reschedule_meetingMove a meeting to a new time
update_meeting_statusMark a past meeting completed or no-show
list_leadsLeads, newest firstread-only
get_leadA lead by id or email, with routing history and meetingsread-only
enrich_leadLook a lead up in Attio and Apollo
list_routing_eventsRouter decisionsread-only
get_reportOverview, reps, routers, disqualifications, teams or handoffsread-only
list_webhooksWebhook endpointsread-only
create_webhookRegister a webhook endpoint
delete_webhookDelete a webhook endpointdestructive

Tool results are the same JSON the REST API returns, except that results the REST API wraps in a data property come back as a plain array. When something goes wrong — an unknown router, a time that was just taken, a validation error — the tool returns an error result with a readable message, and the agent can correct itself and try again.

Example prompts

  • "Route [email protected] (Globex, 800 employees) through the inbound router and send me the booking link."
  • "Book a 30 minute demo with Alex for [email protected] tomorrow afternoon, Eastern time."
  • "Add a path to the inbound router: companies with 1000+ employees go to the Enterprise team. Test it with a dry run before saving."
  • "How many leads did we disqualify last month, and why?"
  • "Pause Jordan in the Sales round robin while they're on vacation."
  • "List my meetings this week and mark yesterday's no-shows."

Common flows

Route a lead, then book

This is the flow for agents that qualify and schedule on someone's behalf — an SDR assistant, a support bot, or an inbox agent replying to demo requests.

Route

The agent calls route_lead with the router slug and the lead's details. The router must accept the API & AI agents trigger. Lead matching, enrichment and your paths run exactly as they would for a website form.

Read the outcome

If outcome is book, the response includes booking_url (a hosted page where the lead picks a time), routing_token, the meeting_type and the candidate_hosts. Other outcomes come with an assigned_user, a disqualification message or a redirect_url.

To let the lead choose, the agent shares booking_url. To book directly, it calls find_available_slots with the routing_token (no meeting type needed), which returns only the times this lead can book: the hosts the router chose, under the booking link's public rules such as minimum notice. It picks a time and calls book_meeting with the same routing_token, start_time, the invitee's timezone and invitee. The meeting is credited to the router, and the invitee gets the usual confirmation and calendar invite.

A routing token books one meeting and expires after 7 days. See Book a meeting for the rules that apply.

list_booking_links → find_available_slots → book_meeting with meeting_type_id (and host_user_id to pin a rep). Meetings booked this way are recorded with the source AI agent (MCP) in meeting lists and reports.

Change routing safely

get_router → edit the flow → route_lead with dry_run: true against a few sample leads → update_router with the complete flow. A dry run returns a per-path trace showing which conditions passed, saves nothing and sends no notifications or webhooks.

Safety

  • Annotated tools. Read-only tools carry the MCP readOnlyHint; delete_team, delete_booking_link, delete_router, cancel_meeting and delete_webhook carry destructiveHint. Clients use these hints to decide what to auto-approve and what to confirm with you first.
  • Scoped access. Agents only get the permissions approved on the consent screen (or set on the API key), and destructive tools stay unavailable unless an admin allows them for the workspace. You can additionally restrict tools in the client, for example in Claude Code's permission settings.
  • Everything is attributed. Changes made through MCP are logged in Settings → Audit log under the person who approved the agent (OAuth) or the key's name. Routing decisions made through MCP record mcp as their source, and so do meetings booked with a booking link (meetings booked with a routing token count as router bookings).
  • Real side effects. book_meeting, cancel_meeting and reschedule_meeting email invitees and update calendars just like a person would. Have agents use dry_run while you iterate on prompts.
  • Rate limits. Each key or OAuth token can make 600 requests per minute; beyond that the server returns 429.