Build a voice agent that collects what the caller wants, reads a Google Calendar for free time, offers two concrete slots, books the chosen one, and transfers to a person when booking is not what they need or the calendar fails. The example is Northside Dental, a practice on Asia/Kolkata. Substitute your own account, calendar address and numbers.

What you need

1

Connect Google Calendar

In the dashboard, go to Integrations → Add integration → Google Calendar and sign in as the account that owns the calendar. Then read the integration id and the tools it exposes:
Nine tools come back, all approved on a fresh connection. See Google Calendar for each one’s arguments.
2

Approve only the tools this agent needs

Booking on the account’s primary calendar needs two: suggest_time to find free periods and create_event to write the appointment. Every approved tool is described to the model on every turn, so fewer tools means fewer input tokens and fewer wrong choices. Shorten the namespace too, so the model sees calendar_suggest_time instead of google_calendar_suggest_time:
  • allowed_tools takes the tool’s own name (create_event), never the exposed one.
  • The prompt must use the exposed name (calendar_create_event).
  • allowed_tools replaces the list wholesale and applies to every agent attached to the integration on its next turn, without a republish.
See MCP servers.
3

Create the two tools of your own

record_booking writes the booked appointment into userdata, so it is readable for the rest of the call, stored on the call record, and visible to post-call analysis as an unambiguous tool call:
No operation returns a result, so the tool is silent: the agent says nothing extra after it.transfer_to_reception reaches a person. Its description is the escalation policy:
POST it to /v1/tools the same way. Publish both (POST /v1/tools/{tool_id}/publish) — an unpublished tool cannot be attached. See transfer.
4

Write the prompt

Save as reception-prompt.txt:
The clock tokens resolve in config.timezone and are a save error without it; in a prompt they are fixed when the call is answered. {{system_vars.now}} is a machine timestamp for building arguments. See variables.

Calendar rules the prompt relies on

5

Create and publish the agent

Save the config as reception-agent.json, with your integration id and the two tool ids:
Fold in the prompt, create, validate and publish:
  • mcps is part of the published version: the calendar tools reach calls only after you publish. allowed_tools on the integration is live.
  • clinic_email has a default because an inbound call supplies no vars. A required var without a default makes assigning the agent to a number fail. See variables.
To answer a phone line, assign the agent to a number as in phone numbers.

Test it

Book something, then check the calendar. Use the agent editor’s test panel (it runs the latest published version): give a name, a reason, “sometime Thursday morning”, and accept the first slot. In Google Calendar, confirm:
  1. The event is at the time the agent said aloud. An hour off means a missing timeZone.
  2. The title is service and name.
  3. The duration matches the prompt.
Read the call. GET /v1/calls/{session_id} returns:
  • the function_call items for calendar_suggest_time and calendar_create_event, with the arguments the model chose;
  • session.userdata with the four booking_* keys;
  • session.analysis once the call ends, with appointment_at matching the calendar.
A web test call cannot exercise the transfer (transfer is phone-only), and {{system_vars.human_phone_number}} is empty there, so the event description is blank. Test the failure path too: disable the integration and confirm the agent offers a person instead of claiming a booking.

What to watch in the first week

  • Offers, not lists. Read the turn after calendar_suggest_time in a few transcripts. Two concrete times is the target; anything longer is a prompt fix.
  • Calls with no booking. GET /v1/calls?outcome=failure, then group not_booked_reason. “No time suited” means the preferred hours are wrong; “calendar error” means read the tool results.
  • What the voice says. Listen to a few recordings: dates and times read wrongly are fixed in the SPEAKING section.

Limits of this setup

  • No confirmation message. There is no SMS, and with no attendees Google emails nobody. Add the caller as an attendee (they must spell an email aloud), or post the booking to your own system from an http tool.
  • No rescheduling or cancelling. That needs search_events plus update_event/delete_event approved and prompted for. An eventId from a search names one occurrence of a recurring event, not the series.
  • Two concurrent callers can be offered the same slot. suggest_time reads free/busy when it runs and nothing holds the slot until create_event; Google accepts both bookings. If double-booking is unacceptable, book through a system of yours that can hold a slot, from an http tool.
  • suggest_time takes at most 50 addresses, and calendars Google will not share come back as unreadable.

Next

Google Calendar

All nine native tools, argument by argument.

Call analysis

Tune the extraction against a finished call.

Phone numbers

Put the agent on a number.