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
| URL | https://cal.example.com/api/mcp (your APP_URL plus /api/mcp) |
| Transport | Streamable HTTP |
| Authentication | OAuth 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.
OAuth (recommended)
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:
- Sign in (if you aren't already) and pick the workspace the agent may use.
- Review the permissions it asks for and untick anything you don't want to give.
- 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):
| Endpoint | Path |
|---|---|
| Protected resource metadata | /.well-known/oauth-protected-resource/api/mcp |
| Authorization server metadata | /.well-known/oauth-authorization-server |
| Registration | POST /api/oauth/register |
| Authorization | /oauth/authorize |
| Token | POST /api/oauth/token (authorization_code, refresh_token) |
| Revocation | POST /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.
| Area | Scopes |
|---|---|
| Workspace | workspace:read, availability:write |
| Booking links | booking_links:read, booking_links:write, booking_links:delete |
| Teams | teams:read, teams:write, teams:delete |
| Routers | routers:read, routers:write (includes duplicating), routers:delete |
| Leads | leads:read, leads:route |
| Meetings | meetings:read, meetings:write, meetings:cancel |
| Reports and webhooks | reports: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
claude mcp add --transport http cauliflower https://cal.example.com/api/mcpRun /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:
{
"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:
{
"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.
| Tool | What it does | Hint |
|---|---|---|
get_workspace | The workspace, its time zone and public booking URL | read-only |
list_members | People in the workspace and their user ids | read-only |
get_availability | A member's working hours and date overrides | read-only |
update_availability | Replace a member's weekly hours or overrides | |
list_teams | Round robin teams with members and counts | read-only |
get_team | One team with distribution stats | read-only |
create_team | Create a team | |
update_team | Change a team's name, distribution or mode | |
set_team_members | Replace the roster, weights, priorities and paused reps | |
delete_team | Delete a team | destructive |
list_booking_links | Booking links with public URLs | read-only |
get_booking_link | One booking link | read-only |
create_booking_link | Create a booking link | |
update_booking_link | Change any field of a booking link | |
delete_booking_link | Delete a booking link | destructive |
find_available_slots | Open times for a booking link, optionally for one host, or for a routed lead with its routing_token | read-only |
list_routers | All routers | read-only |
get_router | A router's fields and flow | read-only |
create_router | Create a router from a flow | |
update_router | Replace a router's flow or settings | |
delete_router | Delete a router | destructive |
route_lead | Run a lead through a router, optionally as a dry run | |
list_meetings | Meetings by status, host, lead, source or search | read-only |
get_meeting | One meeting with routing info and manage URL | read-only |
book_meeting | Book with a booking link or a routing token | |
cancel_meeting | Cancel a meeting and notify everyone | destructive |
reschedule_meeting | Move a meeting to a new time | |
update_meeting_status | Mark a past meeting completed or no-show | |
list_leads | Leads, newest first | read-only |
get_lead | A lead by id or email, with routing history and meetings | read-only |
enrich_lead | Look a lead up in Attio and Apollo | |
list_routing_events | Router decisions | read-only |
get_report | Overview, reps, routers, disqualifications, teams or handoffs | read-only |
list_webhooks | Webhook endpoints | read-only |
create_webhook | Register a webhook endpoint | |
delete_webhook | Delete a webhook endpoint | destructive |
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.
Book or hand over the link
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.
Book a known booking link
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_meetinganddelete_webhookcarrydestructiveHint. 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
mcpas 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_meetingandreschedule_meetingemail invitees and update calendars just like a person would. Have agents usedry_runwhile you iterate on prompts. - Rate limits. Each key or OAuth token can make 600 requests per minute; beyond that the server returns
429.