
Show who a calendar is shared with and at what access level. Use this before sharing or unsharing to see the current state, and to find the ruleid that get/update/patch/deleteacl_rule need. Each rule pairs a scope (a person, group, domain, or the public) with a role. Supports pagination.
Get one calendar-sharing rule: who it grants access to and at what level. Use listaclrules to find the rule_id. IDs look like 'user:email@example.com' or 'group:group@example.com'.
Share a calendar by granting access to a user, group, or Workspace domain. scopetype='default' publishes it to ANYONE on the internet, including people not signed in, and requires confirmpublic=true. The grantee is emailed unless sendnotifications=false. Use listacl_rules to see current sharing. Safe to repeat: re-granting the same scope updates the existing rule.
Completely replace an ACL rule. For partial updates, use patchaclrule instead. Safe to repeat. Use listaclrules to find rule IDs and to confirm the new role afterwards.
Partially update an ACL rule. Only provided fields are modified. Safer than updateaclrule for simple permission changes. Safe to repeat. Use listaclrules to find rule IDs and to confirm the new role afterwards.
Stop sharing a calendar with someone by deleting their access rule. Cannot be undone; re-share with createaclrule. Use listaclrules to find the ruleid. The person is NOT notified that access was removed. Safe to repeat. Confirm with listacl_rules afterwards.
Send a POST to your HTTPS endpoint whenever this calendar's sharing changes. The endpoint must be publicly reachable. Keep both channel.id and channel.resourceid from the response - stopwatchchannel needs both and they cannot be looked up later. Repeating with the same channelid fails; choose a fresh one.
Get a calendar's shared properties: title, description, timezone and location. These are the same for everyone with access. For YOUR OWN view of it - custom colour, display name, notification preferences, whether it is hidden - use getcalendarfrom_list instead.
Create a new secondary calendar you own. IMPORTANT: omitting timezone creates it in UTC, not your local zone, which makes every event time look wrong - call getusersetting with 'timezone' and pass it explicitly. Repeating this creates another calendar with the same name; check listcalendar_list first.
Replace a calendar's shared metadata. Any field you omit is CLEARED, so prefer patchcalendar for a single change. Owner only, and affects everyone with access. For your own colour or visibility use updatecalendarinlist. Safe to repeat.
Update some of a calendar's metadata (title, description, location, timezone), leaving fields you omit unchanged. Prefer this over updatecalendar, which is a full replace that clears anything you do not send. Omit calendarid for the user's main calendar ('primary'); use listcalendarlist only when another calendar is named. Safe to repeat; the response carries the updated calendar.
Transfer a secondary calendar to another user in the same Google Workspace organisation. The caller must hold the Manage Calendars admin privilege. Cannot transfer the primary calendar. Use listcalendarlist to find calendar IDs. Repeating is harmless, but once ownership moves you may no longer have access to verify it.
Permanently delete a secondary calendar and all its events. Cannot be undone. calendarid is REQUIRED and cannot be 'primary'; use listcalendarlist to get the ID. To empty the main calendar instead, use clearcalendar. For temporary removal, use removecalendarfrom_list. Safe to repeat: a second call reports not found and the calendar is still gone.
Permanently delete ALL events from the account's PRIMARY calendar. Cannot be undone. Only the primary calendar is supported, so calendarid must be 'primary'. To empty a secondary calendar, delete it with deletecalendar or remove its events individually with delete_event. Safe to repeat, but repeating cannot undo anything.
Lists your calendars - primary, ones you own, and ones you subscribe to - with your access role for each. NOT needed for the user's main calendar: most tools default to 'primary' when calendarid is omitted. Call this only when a request names another calendar, or for an ID for deletecalendar, removecalendarfromlist or transfercalendar_ownership, which reject 'primary'. Paginated.
Get YOUR view of a calendar: custom colour, display-name override, notification preferences, whether it is hidden or selected. These are yours alone and invisible to others. For the calendar's shared title, timezone and description use get_calendar instead.
Subscribe to an existing calendar so it appears in your list, optionally setting your own colour, display name and notifications. Needs the calendarid, which you must already have - this cannot search. Does not create a calendar; use createcalendar for that. Safe to repeat. Use getcolors for colorid, or backgroundcolor plus foregroundcolor for an exact hex colour.
Replace YOUR settings for a subscribed calendar - colour, display name, visibility, notifications. Any field you omit is CLEARED, so prefer patchcalendarinlist for a single change. Affects only you. Use getcolors for colorid, or backgroundcolor plus foreground_color for an exact hex colour. Safe to repeat.
Change individual settings of YOUR view of a subscribed calendar - colour, display name, hidden, selected, notifications - leaving anything you omit untouched. Affects only you, never other people's view. Use getcolors for colorid, or backgroundcolor plus foregroundcolor for an exact hex colour. Safe to repeat.
Unsubscribe yourself from a calendar. The calendar and its events are untouched and others keep access. Only works on calendars you do NOT own - Google rejects removing one you are the data owner of; use deletecalendar for those. calendarid is REQUIRED and cannot be 'primary'; use listcalendarlist for the ID to drop. Re-subscribe with addcalendarto_list. Safe to repeat.
Send a POST to your HTTPS endpoint whenever your calendar list changes. The endpoint must be publicly reachable. Keep both channel.id and channel.resourceid from the response - stopwatchchannel needs both and they cannot be looked up later. Repeating with the same channelid fails; choose a fresh one.
List events. Pass calendarid='primary' for the main calendar; listcalendarlist only for other calendars. IMPORTANT: Always set timemin and timemax to bound your query, otherwise returns all events across all time. IMPORTANT: Always set fields to only what you need, e.g. 'items(id,summary,start,end),nextPageToken'; unmasked is far larger. Use singleevents=true with order_by=startTime.
Get one event in full: times, attendees and their RSVPs, recurrence, reminders and conferencing. Use listevents or searchevents to find the eventid first. For a recurring series, this returns the series rule; use getevent_instances to see individual dated occurrences.
Create an event. Omit calendarid for the user's main calendar ('primary'). start/end are required and must match form (both 'date' for all-day, both 'datetime' for timed). Attendees ARE emailed unless sendupdates='none'. To generate a Meet link check getcalendar's conferenceproperties first; Teams/Zoom links attach via conferencedata. Repeats duplicate; pass event_id for safe retries.
Replace an event in full. Any field you omit is CLEARED, including attendees and recurrence, so prefer patchevent unless you intend to reset the event. start/end must use identical form (both 'date' or both 'datetime'). Safe to repeat: the end state is the same. Check the returned event to confirm what survived.
Update specific fields of an event; fields you omit are left alone. WARNING: attendees and recurrence are list fields, and supplying one REPLACES it entirely, uninviting any guest you leave out. To add or drop individual guests use this tool's addattendees / removeattendees parameters, which preserve everyone else and their RSVPs. Safe to repeat.
Find events matching search text on one calendar. Pass calendarid='primary' for the main calendar; listcalendarlist only for other calendars. Matching is LITERAL and not semantic - synonyms will not match. IMPORTANT: Always set fields to only what you need; unmasked is far larger. Use listevents instead to browse a date range without a search term.
RSVP to an event you have been invited to: accept, decline, or mark tentative, optionally with a note to the organiser. Only changes your own response and leaves every other guest's RSVP intact. Use listevents to find invitations. To change who is invited, use patchevent instead. Safe to repeat; your latest response wins.
Cancel and permanently delete an event. IMPORTANT: only delete an event consistent with everything the user specified (title, time, guests). If none is, say so and stop; do NOT delete the closest match, or report an event cancelled under another name. IDs from listevents. Guests emailed only per sendupdates. clearcalendar empties primary; moveevent relocates. Repeats report not found.
Move an event to a different calendar, changing its organizer. The event keeps its ID. Both calendars must belong to the same account. Use listcalendarlist to find the destination ID. To copy rather than move, create a new event instead. Safe to repeat; moving it to the calendar it already sits on is a no-op.
Import an event that already exists elsewhere, keeping its original iCalUID so it is not duplicated. For migrations and historical backfill; use createevent for new events. Requires ical_uid, start and end. Never emails anyone. Safe to repeat: re-importing the same UID updates that event. Always produces a 'default' event - Google downgrades other event types here.
Create an event from natural language, e.g. 'Lunch with John tomorrow at 12pm'; Google parses date, time and title. Omit calendarid for the user's main calendar ('primary'). Prefer createevent when you know exact times or need attendees, reminders or conferencing. Repeating creates a duplicate; check the returned start/end.
Send a POST to your HTTPS endpoint whenever events on this calendar change. The endpoint must be publicly reachable. Keep both channel.id and channel.resourceid from the response - stopwatchchannel needs both, and there is no way to look them up later. Repeating with the same channelid fails; choose a fresh one.
Retrieve all instances of a recurring event within a time range. Expands recurring events into actual occurrences with specific dates and times.
Stop a push notification channel. Needs both the channelid and resourceid returned when the watch was created; neither can be looked up afterwards. Cannot be restarted - create a new watch instead. Safe to repeat.
Find meeting slots when everyone is free, by reading each attendee's busy times and returning bookable openings. Honours working hours and skips weekends. Returns start/end you can pass straight to createevent. Check unavailablecalendars: any calendar listed there was unreadable and its conflicts are NOT accounted for.
List every Calendar preference for the signed-in user with its current value, including timezone, locale, weekStart and format24HourTime. Use this to discover valid setting IDs, or getusersetting to read one directly.
Read one of the signed-in user's Calendar preferences by ID, such as 'timezone', 'weekStart', 'format24HourTime' or 'locale'. Use listusersettings to see every setting and its value at once. Call this for 'timezone' before scheduling rather than assuming UTC.
List the colour IDs valid for color_id on events and calendars, with their hex values. Call this before setting a colour: IDs are numeric strings like '11', not names, and the event and calendar palettes differ. Read-only and the same for every user.
Get raw busy periods for up to 50 calendars in a time range. ALWAYS check each calendar's errors[] before trusting an empty busy list: an unreadable calendar returns no busy times and looks identical to a free one. Prefer suggest_time, which inverts these into bookable slots and reports unreadable calendars for you.
Send a POST to your HTTPS endpoint whenever the user's Calendar preferences change. The endpoint must be publicly reachable. Keep both channel.id and channel.resourceid from the response - stopwatchchannel needs both and they cannot be looked up later. Repeating with the same channelid fails; choose a fresh one.
Validate Google Calendar credentials. Verifies credentials during setup.

In an mcp.json file, add the configuration below, and restart Cursor.
Learn more in the official documentation ↗
1{
2 "mcpServers": {
3 "agent-handler": {
4 "url": "https://ah-api-develop.merge.dev/api/v1/tool-packs/{TOOL_PACK_ID}/registered-users/{REGISTERED_USER_ID}/mcp",
5 "headers": {
6 "Authorization": "Bearer yMt*****"
7 }
8 }
9 }
10}
11Open your Claude Desktop configuration file and add the server configuration below. You'll also need to restart the application for the changes to take effect.
Make sure Claude is using the Node v20+.
Learn more in the official documentation ↗
1{
2 "mcpServers": {
3 "agent-handler": {
4 "command": "npx",
5 "args": [
6 "-y",
7 "mcp-remote@latest",
8 "https://ah-api-develop.merge.dev/api/v1/tool-packs/{TOOL_PACK_ID}/registered-users/{REGISTERED_USER_ID}/mcp",
9 "--header",
10 "Authorization: Bearer ${AUTH_TOKEN}"
11 ],
12 "env": {
13 "AUTH_TOKEN": "yMt*****"
14 }
15 }
16 }
17}Open your Windsurf MCP configuration file and add the server configuration below.
Click on the refresh button in the top right of the Manage MCP server page or in the top right of the chat box in the box icon.
Learn more in the official documentation ↗
1{
2 "mcpServers": {
3 "agent-handler": {
4 "command": "npx",
5 "args": [
6 "-y",
7 "mcp-remote@latest",
8 "https://ah-api.merge.dev/api/v1/tool-packs/<tool-pack-id>/registered-users/<registered-user-id>/mcp",
9 "--header",
10 "Authorization: Bearer ${AUTH_TOKEN}"
11 ],
12 "env": {
13 "AUTH_TOKEN": "<ah-production-access-key>"
14 }
15 }
16 }
17 }In Command Palette (Cmd+Shift+P on macOS, Ctrl+Shift+P on Windows), run "MCP: Open User Configuration".
You can then add the configuration below and press "start" right under servers. Enter the auth token when prompted.
Learn more in the official documentation ↗
1{
2 "inputs": [
3 {
4 "type": "promptString",
5 "id": "agent-handler-auth",
6 "description": "Agent Handler AUTH_TOKEN", // "yMt*****" when prompt
7 "password": true
8 }
9 ],
10 "servers": {
11 "agent-handler": {
12 "type": "stdio",
13 "command": "npx",
14 "args": [
15 "-y",
16 "mcp-remote@latest",
17 "https://ah-api-develop.merge.dev/api/v1/tool-packs/{TOOL_PACK_ID}/registered-users/{REGISTERED_USER_ID}/mcp",
18 "--header",
19 "Authorization: Bearer ${input:agent-handler-auth}"
20 ]
21 }
22 }
23}The "best" use cases will naturally depend on your agents, but here are a few common scenarios:
Like the previous question, the best complementary MCP servers will depend on your agentic use cases. That said, here are a few that you’ll likely need to use with the Google Calendar MCP server:
Here are a few common tools across data categories:
You can easily set a wide range of rules. Here are just a few examples:
Here are just a few reasons:
Merge Agent Handler provides a security gateway and data loss protection (DLP) that scans tool inputs and outputs for sensitive data and automatically blocks/redacts according to configured rules. This prevents data misuse and enforces strong governance.
Merge Agent Handler manages authentication, credential prompting, and validation for each registered user, ensuring that agents only act with approved permissions across MCP connectors.
If you need custom Google Calendar actions or extended behaviors, Connector Studio allows you to add and modify its tools, whether it's a tool's description, name, or schema.
Merge Agent Handler logs every tool call and underlying API request, giving your team full auditability and visibility into your agents' behaviors.
Whether you're an engineer experimenting with agents or a product manager looking to add tools, you can get started for free now