# WhatsDo MCP tools reference | WhatsDo Docs

URL: https://whatsdo.ai/docs/tools

Skip to contentDocumentationTools reference

Sign inGet API key

Search the docs menu

Get started
- Overview
- Quickstart
- Connect your agent
- Keys and sign-in

Guides
- Book a table
- Shortlist restaurants
- Café and a walk
- Massage, salon, yoga
- Local market signals

Reference
- Tools
- Booking statuses
- Limits
- Errors and fixes

# Tools

The tools on the WhatsDo MCP server and what to expect from them.

Each call is a JSON-RPC tools/call to https://app.whatsdo.com/mcp/.

| Tool | What it does | Scope | Changes data |
| --- | --- | --- | --- |
| search | Ranked places for a request and a location | search | No |
| place_details | Full record for one place | search | No |
| get_booking_requirements | Fields a booking at this place needs | search | No |
| book | Booking request for the signed-in person | bookings:write | Yes |
| my_bookings | Recent bookings and their current status | bookings:read | No |
| cancel_booking | Cancels or asks to cancel a booking | bookings:write | Yes |
| continue_booking | Answers a question the booking system asked | bookings:write | Yes |
| set_location | Saves a default search location | profile:write | Profile |
| remember_preference | Saves taste preferences for later searches | profile:write | Profile |
| calendar_free_slots | Free slots on the person’s Google Calendar | bookings:read | No |
| calendar_check_conflict | Whether a time clashes with the calendar | bookings:read | No |

## Replies and errors

- The reply carries result.content[] with a short text. The object described below is in result.structuredContent when present, otherwise it is the JSON text in result.content[0].text.
- A tool error comes back as isError: true, with the message in result.content[0].text.
- Send Content-Type: application/json and Accept: application/json, text/event-stream. The reply can be plain JSON or an event stream.

## search

Finds places in San Francisco: restaurants, cafes, bars and nightlife, gyms, yoga, fitness, spas, salons, massage, parks and things to do.

| Input | Type | Notes |
| --- | --- | --- |
| query | string | The person’s words: cuisine, mood, category or venue name. Required. For “things to do”, search two or three concrete categories such as live music or attractions. |
| location | string | City plus neighborhood, e.g. "Mission District, San Francisco, CA". Put the neighborhood here, not in query. Leave it out on follow-ups to reuse the last one. |
| exclude | string[] | What the person ruled out in this request, e.g. ["bar"]. |
| bookable_only | boolean | Only places that can be booked through WhatsDo. Default false. |
| open_at | string | ISO 8601 time the place must be open at. |
| limit | integer | 1 to 20, default 5. Keep it at 3 to 5: each place is a large object. |
| offset | integer | Pass the previous reply’s next_offset for the next page. |

Returns results[], best first, plus location_missing, next_offset while more results may exist, and applied_preferences, the saved preferences that shaped the ranking. Keep the order of results.

Each result includes id, item_type, name, rating, review_count, price (a band from $ to $$$$), tags (the first five), categories (every tag in one string), phone, photos (up to three), hours[] as {day, start, end}, is_closed, is_bookable, bookable_via[], booking_source, tagline, sources[] and google_place_id. distance_km is always null.

### Good to know

- WhatsDo search covers San Francisco. For another city, tell the person once that it is available on request and offer to send a city request.
- location_missing: true means the server had no location. Ask the person where they are and search again.
- Results can include places outside the named neighborhood.
- No address, coordinates or distance in the reply.
- hours and price can be empty. Treat both as unknown. A 00:00 to 00:00 row also means unknown.
- open_at filters by listed hours. A place with empty hours can pass the filter.
- is_bookable is a hint. Confirm with get_booking_requirements before booking.
- categories repeats every tag. Parse it once and do not show it to the person.json

```
{"name": "search",
 "arguments": {"query": "quiet dinner for four",
               "location": "Hayes Valley, San Francisco, CA",
               "bookable_only": true, "exclude": ["bar"], "limit": 3}}
```

A real reply, trimmed to one place:

json

```
{
  "results": [
    {
      "id": "c585fcc9-9714-4ac7-972a-5ecfc0ca68d6",
      "item_type": "restaurant",
      "name": "Ganji",
      "rating": 4.32,
      "review_count": 95,
      "price": "$$",
      "tags": ["restaurant", "casual", "cozy", "warm", "$$"],
      "categories": "restaurant, casual, cozy, ..., japanese, sushi, outdoor_seating, wait_time_short",
      "phone": "<venue phone>",
      "photos": ["https://app.whatsdo.com/media/c585fcc9-.../3a569587-....jpg"],
      "hours": [
        {"day": "friday", "start": "12:00", "end": "22:00"},
        {"day": "saturday", "start": "12:00", "end": "22:00"}
      ],
      "is_closed": false,
      "is_bookable": true,
      "booking_source": "<pass to book unchanged>",
      "distance_km": null,
      "tagline": "Close",
      "sources": ["review_site", "catalog"]
    }
  ],
  "location_missing": false,
  "next_offset": 10,
  "applied_preferences": ["italian", "coffee"]
}
```

## place_details

Full record for one place: most search fields plus website, location_services and found. Input: item_id, the id from a search result. Use it for hours, website and contact.

tags, bookable_via and booking_source come only from search. Keep them from the search result.

- Returns found: false when the id is unknown.
- No address, coordinates or description in the reply.json

```
{"name": "place_details", "arguments": {"item_id": "c585fcc9-9714-4ac7-972a-5ecfc0ca68d6"}}
```

## get_booking_requirements

The fields a booking at this place needs, so the person is asked once. Input: item_id. Returns available, item_id, provider, booking_kind, required[], optional[] and policies. Each field has kind, required, label, description, options and depends_on.

- booking_kind: "restaurant_reservation" needs party_size, date_time, customer_name and customer_phone.
- booking_kind: "appointment" (salons, spas, massage, yoga) has no party_size. The service goes in special_requests as free text, labelled “Service or notes”.
- customer_name and customer_phone come from the profile. Do not ask the person for them.
- available: false comes with reason and no field lists. Read reason: either the place cannot be booked through WhatsDo (offer its phone number) or the rules could not be read right now (try again later).A real reply for a restaurant:

json

```
{
  "available": true,
  "item_id": "c585fcc9-9714-4ac7-972a-5ecfc0ca68d6",
  "booking_kind": "restaurant_reservation",
  "required": [
    {"kind": "party_size", "required": true, "label": "Party size", "description": "How many people"},
    {"kind": "date_time", "required": true, "label": "Date and time", "description": "ISO 8601 with timezone"},
    {"kind": "customer_name", "required": true, "label": "Name", "description": "Booking name"},
    {"kind": "customer_phone", "required": true, "label": "Phone", "description": "E.164 phone"}
  ],
  "optional": [
    {"kind": "special_requests", "required": false, "label": "Special requests", "description": "Optional notes"}
  ],
  "policies": {}
}
```

## book

Sends a real booking request at once, as the signed-in person. There is no draft and no second confirmation step. Call it only for a place with is_bookable: true, after the person agreed to the place, date, time and party size.

| Input | Type | Notes |
| --- | --- | --- |
| item_name | string | Place name. Required. |
| date_time | string | ISO 8601 with an offset, e.g. 2026-10-09T19:00:00-07:00. Required. San Francisco is -07:00 in summer time and -08:00 in winter time. |
| source | string | The search result’s booking_source, unchanged. Required. |
| item_id | string | The search result’s id. Always send it. |
| party_size | integer | Guests. Default 1. |
| special_requests | string | Free text for the venue. For salons, spas and massage this carries the service, e.g. “60-minute deep tissue massage”. |
| duration_minutes | integer | Appointment length, when the venue asks for one. |
| phone | string | The person’s own phone, only after a booking failed asking for one and the profile has none. |

Returns reservation_id, status, place_name, date_time, party_size, confirmation_number, alternatives[] and calendar_link, plus message when the booking system sent one. What each status means: Booking statuses.

json

```
{"name": "book",
 "arguments": {"item_name": "Ganji", "item_id": "c585fcc9-9714-4ac7-972a-5ecfc0ca68d6",
               "date_time": "2026-10-09T19:00:00-07:00", "party_size": 2,
               "source": "<booking_source from search>"}}
```

A real reply from a place that books instantly:

json

```
{
  "reservation_id": "00000000-0000-4000-8000-000000000001",
  "status": "confirmed",
  "place_name": "Ganji",
  "date_time": "2026-10-09T19:00:00-07:00",
  "party_size": 2,
  "confirmation_number": null,
  "alternatives": [],
  "calendar_link": null
}
```

A real reply from a place that books through its own page. pending is not booked yet: poll my_bookings.

json

```
{
  "reservation_id": "00000000-0000-4000-8000-000000000002",
  "status": "pending",
  "place_name": "The Massage Garage",
  "date_time": "2026-10-07T12:00:00-07:00",
  "party_size": 1,
  "confirmation_number": null,
  "alternatives": []
}
```

## my_bookings

Recent bookings, newest first, with their current status. Input: limit, default 10. Each row has reservation_id, place_name, item_id, date_time, party_size, source, status, confirmation_number, special_requests, message, created_at and updated_at.

- Nothing is pushed. Call my_bookings again to see a status change.
- source can change after booking. manual means a WhatsDo team member is finishing it.
- Rows also carry the guest’s email, phone, user id and session links. Do not show them to the person or write them to logs.A real row, personal fields removed. The booking failed and message names the time the venue offered instead:

json

```
{
  "bookings": [
    {
      "reservation_id": "00000000-0000-4000-8000-000000000003",
      "place_name": "Penny Roma",
      "status": "failed",
      "date_time": "2026-10-09T19:00:00-07:00",
      "party_size": 4,
      "confirmation_number": null,
      "message": "... showed no 7:00 PM table for 4 ... The only offered time I saw was 9:30 PM in the Dining Room."
    }
  ]
}
```

## cancel_booking

Cancels one of the person’s bookings. Input: reservation_id. The only tool that removes something: confirm with the person first. Returns cancelled, status, message and venue_phone.

- status: "cancelled": the booking is cancelled on WhatsDo.
- status: "cancellation_requested": a WhatsDo team member cancels it by hand. The booking stays confirmed in my_bookings until then.
- A pending booking made through the venue’s page is cancelled on WhatsDo only; nothing is sent to the venue. If the venue already emailed a confirmation, the person should use that email or call. See Booking statuses.A real reply for a confirmed instant booking:

json

```
{
  "cancelled": false,
  "status": "cancellation_requested",
  "message": "This booking was made on the venue's own site and can't be cancelled automatically. Our team has been asked to cancel it.",
  "venue_phone": null
}
```

## continue_booking

Answers a follow-up question from the booking system so a booking can finish. Use it after book returned requires_payment or another reply that asks something. Used by places that book instantly.

| Input | Type | Notes |
| --- | --- | --- |
| booking_id | string | From the previous book or continue_booking reply. Required. |
| message | string | The person’s answer: a time, a party size, a seating preference. Required. |
| latitude, longitude | number | Only when the venue asks where the guest is coming from. |

- Returns the booking system’s reply in response, with booking_id again while it still needs more.
- Each call sends another message. Do not retry blindly.
- Carries no payment details. A venue that wants a card collects it on its own page.

## set_location

Saves a default search location on the profile. Input: location, such as "San Francisco, CA". Returns saved: true. Call it only when the person asks to save or remember a default; search already reuses the last location within a conversation.

## remember_preference

Saves what the person likes so later searches lean toward it. Inputs, all optional: dietary, cuisines, vibes and interests (string arrays) and price_range (e.g. "$$"). Returns saved, remembered and now.

- Every value is stored as a like. Pass dislikes to search as exclude instead.
- Not for one-off constraints such as “tonight” or “for four”.json

```
{"name": "remember_preference", "arguments": {"cuisines": ["japanese"], "dietary": ["vegetarian"]}}
```

## calendar_free_slots

Open slots on the person’s Google Calendar for one day. Input: date as YYYY-MM-DD. Returns free_slots, a list of start times such as "19:00". When free_slots has no times, the day is fully booked.

## calendar_check_conflict

Whether a proposed time clashes with the person’s Google Calendar. Inputs: date_time (ISO 8601) and duration_mins, default 90. Returns has_conflict and busy_intervals[] of {start, end}.

Both calendar tools need a connected Google Calendar. Without one the call fails with this text. Skip the calendar step and book without it:

text

```
Error executing tool calendar_check_conflict: No Google Calendar connected for this user. They can connect one in the whatsdo app, or you can book without checking their calendar.
```

## Place record: facts and inferences

What your agent may say about a place, and how. Fields come from search and place_details.

| What | Field | Notes |
| --- | --- | --- |
| Id | id | The item_id for every other tool. |
| Name and type | name, item_type | item_type values include restaurant (also cafes), gym, massage, beauty_spa, active_life (parks). |
| Cuisine and services | tags, categories | Salon and spa services are not a structured field. |
| Hours | hours[] | Empty or 00:00 to 00:00 means unknown. |
| Price | price | A band from $ to $$$$, often empty. Not a per-person amount. |
| Rating | rating, review_count, sources[] | Sources are listed per place, not per field. |
| Booking | is_bookable, bookable_via[], booking_source | From search only. booking_source is what book takes as source. |
| Contact | phone, website (details only) | The fallback when a place is not bookable. |
| Address, coordinates, distance | Not returned | Withheld from the agent. Chat widgets show the map. |
| Description | Not returned | Use tags and categories. |
| Freshness | Not returned | No timestamp per tag or per place. |

### Tags from reviews

- Quality, each with _good, _mixed or _bad: staff_, service_, food_quality_, value_, atmosphere_, cleanliness_.
- Wait and noise: wait_time_short, wait_time_mixed, wait_time_long, noise_level_quiet.
- Diet: vegetarian_options, vegan_options, gluten_free_options, kid_menu.
- Who it suits: kids, families, date_night.
- Amenities and policy: outdoor_seating, free_wifi, wifi, coffee_and_work, working_remotely, pet_friendly, parking, wheelchair_accessible, reservations_required.
- Tags are evidence, not facts. When two tags on one axis disagree, say “mixed”.

### State as fact, naming WhatsDo as the source

- name, item_type, rating, review_count, the price band, phone, is_closed, is_bookable.
- hours when present and not the placeholder.
- That a place has a tag: “tagged outdoor_seating”.

### Label as inferred

- Atmosphere, vibe and who it suits, from tags such as cozy or date_night.
- Any per-person price. “About $30 a head” is an estimate from the $$ band.
- Fit for a stated need, e.g. “fine for a laptop afternoon” from coffee_and_work and free_wifi.
- Why a place matches. The reasons are your agent’s own.

### Do not state

- Address, distance or travel time.
- Menu items or dish prices.
- That a table is free before book returns.
- Anything a tool did not return.

On this page

- Replies and errors
- search
- place_details
- get_booking_requirements
- book
- my_bookings
- cancel_booking
- continue_booking
- set_location
- remember_preference
- calendar_free_slots
- calendar_check_conflict
- Place record: facts and inferencesCopy page

© WhatsDo

## Product

MCPPlacesBookingPayments

## Build

ConnectDocsUse cases

## WhatsDo

For businessesTalk to usPrivacy policyTerms of serviceCookie policySite map
