MCP tools reference
ZenMaid MCP tools
13 tools for ZenMaid on the Cotlet MCP server. Your agent picks them from tools/list.
- MCP server
- https://cotlet.dev/mcp/v1
- Connects with
- Your ZenMaid owner or office manager account
- Integration page
- ZenMaid
| Endpoint | Access | Description |
|---|---|---|
| zenmaid_list_appointments | read | Appointments in a date range with customer, time, cleaners, price and paid flag. |
| zenmaid_get_appointment | read | Full appointment: address, service type, frequency, work items, billing, notes and cleaners. |
| zenmaid_list_contacts | read | Contacts with email, phone, address and status. |
| zenmaid_get_contact | read | One contact with notes, custom fields, and past and upcoming appointments. |
| zenmaid_list_cleaners | read | Active cleaners and teams with their IDs. |
| zenmaid_create_contact | write | Add a new contact. ZenMaid starts it as a lead. |
| zenmaid_create_appointment | write | Schedule a one-time or recurring appointment for a contact. |
| zenmaid_reschedule_appointment | write | Move one appointment to a new date or time. |
| zenmaid_assign_cleaners | write | Set the cleaners or team on one appointment, replacing the current ones. |
| zenmaid_add_note | write | Add a note to an appointment or to a contact. |
| zenmaid_cancel_appointment | write | Set an appointment to Cancelled, optionally notifying the client and cleaner. |
| zenmaid_mark_appointment_paid | write | Record an offline payment such as cash, Venmo or PayPal. Does not charge a card. |
| zenmaid_send_message | write | Send a customer an email, text or both from one of your communication templates. |
List appointments
readMCP tool zenmaid_list_appointments
Returns appointments between two dates, in date and time order. An appointment with nobody assigned has an empty cleaners list. Filter by payment status to find unpaid jobs, or search by customer name, cleaner name, street address or a custom field, as ZenMaid's List View does. Cancelled appointments are included only when you ask for them.
Parameters
| Name | Type | Description |
|---|---|---|
| from required | date | First day of the range. |
| to required | date | Last day of the range. |
| query | string | Customer name, cleaner name, street address or custom field value. |
| paid | enum | all, paid or unpaid. Default: all. |
| include_cancelled | boolean | Also return cancelled appointments. Default: false. |
| limit | integer | 1 to 100. Default: 50. |
| cursor | string | Next page cursor from the previous call. |
tools/call
JSON-RPC
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "zenmaid_list_appointments",
"arguments": {
"from": "2026-10-01",
"to": "2026-10-01"
}
}
} Example response
{
"content": [
{
"type": "text",
"text": "{ ... same JSON as structuredContent ... }"
}
],
"structuredContent": {
"appointments": [
{
"appointment_id": "a_993102",
"contact": "Sample Customer",
"date": "2026-10-16",
"start_time": "09:00",
"end_time": "12:00",
"cleaners": [],
"price": "180.00",
"paid": false
},
{
"appointment_id": "a_993140",
"contact": "Sample Household",
"date": "2026-10-16",
"start_time": "13:00",
"end_time": "15:00",
"cleaners": [
"Cleaner A"
],
"price": "120.00",
"paid": false
}
],
"next_cursor": null
},
"isError": false
} Get appointment
readMCP tool zenmaid_get_appointment
Returns one appointment with the service address, service type, whether it belongs to a recurring service, work items, billing (price before tax, tip, paid flag) and its appointment and customer notes. Use it before changing or cancelling an appointment.
Parameters
| Name | Type | Description |
|---|---|---|
| appointment_id required | string | Appointment ID from list_appointments. |
tools/call
JSON-RPC
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "zenmaid_get_appointment",
"arguments": {
"appointment_id": "appointment_8c41d2"
}
}
} Example response
{
"content": [
{
"type": "text",
"text": "{ ... same JSON as structuredContent ... }"
}
],
"structuredContent": {
"appointment_id": "a_993102",
"contact": {
"contact_id": "c_48213",
"name": "Sample Customer"
},
"address": "12 Sample Street, Springfield",
"date": "2026-10-16",
"start_time": "09:00",
"end_time": "12:00",
"service_type": "Deep Clean",
"recurring": false,
"cleaners": [],
"work_items": [
"Kitchen",
"Bathrooms"
],
"billing": {
"price": "180.00",
"tip": "0.00",
"paid": false
},
"notes": [
{
"visibility": "public",
"body": "Gate code is on the contact."
}
]
},
"isError": false
} List contacts
readMCP tool zenmaid_list_contacts
Searches contacts by name, email, phone or address. Status is one of ZenMaid's four: lead, one_time_customer, recurring_customer or former_customer. ZenMaid sets it from the appointments on the calendar, so a new contact stays a lead until someone books them.
Parameters
| Name | Type | Description |
|---|---|---|
| query | string | Name, email, phone or address to search. |
| status | enum | lead, one_time_customer, recurring_customer or former_customer. |
| limit | integer | 1 to 100. Default: 50. |
| cursor | string | Next page cursor from the previous call. |
tools/call
JSON-RPC
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "zenmaid_list_contacts",
"arguments": {}
}
} Example response
{
"content": [
{
"type": "text",
"text": "{ ... same JSON as structuredContent ... }"
}
],
"structuredContent": {
"contacts": [
{
"contact_id": "c_48213",
"name": "Sample Customer",
"email": "customer@example.com",
"phone": "+1 555 0100",
"address": "12 Sample Street, Springfield",
"status": "lead"
}
],
"next_cursor": null
},
"isError": false
} Get contact
readMCP tool zenmaid_get_contact
Returns one contact profile: addresses, customer notes (public and private), contact custom fields, revenue to date, unpaid balance and a list of their appointments, newest first. Private notes are returned only to owner and office manager accounts.
Parameters
| Name | Type | Description |
|---|---|---|
| contact_id required | string | Contact ID from list_contacts. |
tools/call
JSON-RPC
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "zenmaid_get_contact",
"arguments": {
"contact_id": "contact_8c41d2"
}
}
} Example response
{
"content": [
{
"type": "text",
"text": "{ ... same JSON as structuredContent ... }"
}
],
"structuredContent": {
"contact_id": "c_48213",
"name": "Sample Customer",
"email": "customer@example.com",
"phone": "+1 555 0100",
"status": "one_time_customer",
"revenue_to_date": "180.00",
"unpaid_balance": "0.00",
"notes": [
{
"visibility": "private",
"body": "Prefers morning visits."
}
],
"appointments": [
{
"appointment_id": "a_993102",
"date": "2026-10-16",
"paid": false
}
]
},
"isError": false
} List cleaners
readMCP tool zenmaid_list_cleaners
Returns the cleaners and teams in your account with their IDs, which assign_cleaners and create_appointment need. Inactive staff are left out unless you ask for them.
Parameters
| Name | Type | Description |
|---|---|---|
| include_inactive | boolean | Also list inactive staff. Default: false. |
tools/call
JSON-RPC
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "zenmaid_list_cleaners",
"arguments": {}
}
} Example response
{
"content": [
{
"type": "text",
"text": "{ ... same JSON as structuredContent ... }"
}
],
"structuredContent": {
"cleaners": [
{
"cleaner_id": "cl_1207",
"name": "Cleaner A",
"type": "cleaner",
"active": true
},
{
"cleaner_id": "cl_1344",
"name": "Cleaner B",
"type": "cleaner",
"active": true
},
{
"cleaner_id": "tm_21",
"name": "Team One",
"type": "team",
"active": true
}
]
},
"isError": false
} Create contact
writeMCP tool zenmaid_create_contact
Adds a contact profile. ZenMaid starts a new contact as a Lead until an appointment is booked. It reaches no one and is undone in one call, so it does not ask for your OK.
Parameters
| Name | Type | Description |
|---|---|---|
| first_name required | string | First name. |
| last_name | string | Last name. |
| string | Email address. | |
| phone | string | Phone number. |
| address | string | Service address. |
| notes | string | Customer note, public by default. |
tools/call
JSON-RPC
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "zenmaid_create_contact",
"arguments": {
"first_name": "first name"
}
}
} Example response
{
"content": [
{
"type": "text",
"text": "{ ... same JSON as structuredContent ... }"
}
],
"structuredContent": {
"contact_id": "c_48290",
"name": "Sample Lead",
"email": "lead@example.com",
"phone": "+1 555 0111",
"status": "lead"
},
"isError": false
} MCP tool zenmaid_create_appointment
Books an appointment for an existing contact with a start and end time. Leave cleaner_ids empty to keep it unassigned, and price empty to let ZenMaid calculate it if your account is set up for that. A recurring frequency creates a recurring service. The contact becomes a customer once the appointment is on the calendar. By default you confirm each call; you can switch that off for this tool.
Parameters
| Name | Type | Description |
|---|---|---|
| contact_id required | string | Contact ID from list_contacts. |
| date required | date | Day of the appointment. |
| start_time required | string | Start time, HH:MM. |
| end_time required | string | End time, HH:MM. |
| service_type | string | Service type as set up in your account. |
| frequency | string | one_time or a recurring frequency from your account. Default: one_time. |
| cleaner_ids | string[] | Cleaner or team IDs from list_cleaners. Empty leaves it unassigned. |
| price | string | Price before tax. Empty lets ZenMaid calculate it if configured. |
| notes | string | Appointment note. |
tools/call
JSON-RPC
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "zenmaid_create_appointment",
"arguments": {
"contact_id": "c_48213",
"date": "2026-10-16",
"start_time": "09:00",
"end_time": "12:00",
"service_type": "Deep Clean",
"frequency": "one_time",
"cleaner_ids": [
"cl_1207"
]
}
}
} Example response
{
"content": [
{
"type": "text",
"text": "{ ... same JSON as structuredContent ... }"
}
],
"structuredContent": {
"appointment_id": "a_993102",
"contact": "Sample Customer",
"date": "2026-10-16",
"start_time": "09:00",
"end_time": "12:00",
"service_type": "Deep Clean",
"cleaners": [
"Cleaner A"
],
"price": "180.00",
"paid": false
},
"isError": false
} MCP tool zenmaid_reschedule_appointment
Moves one appointment, as the Reschedule window does in ZenMaid. It keeps work items, price and status. The length stays the same unless you pass end_time. One-time appointment notes do not carry over, so add them again with add_note. For a recurring appointment, apply_to chooses this one or all future appointments. By default you confirm each call; you can switch that off for this tool.
Parameters
| Name | Type | Description |
|---|---|---|
| appointment_id required | string | Appointment ID from list_appointments. |
| date required | date | New day. |
| start_time required | string | New start time, HH:MM. |
| end_time | string | New end time, HH:MM. Default: keeps the length. |
| recalculate_price | boolean | Recalculate the amount owed for the new length. Default: false. |
| apply_to | enum | this_appointment or all_future, for recurring appointments. Default: this_appointment. |
tools/call
JSON-RPC
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "zenmaid_reschedule_appointment",
"arguments": {
"appointment_id": "a_993102",
"date": "2026-10-20",
"start_time": "09:00",
"apply_to": "this_appointment"
}
}
} Example response
{
"content": [
{
"type": "text",
"text": "{ ... same JSON as structuredContent ... }"
}
],
"structuredContent": {
"appointment_id": "a_993102",
"date": "2026-10-19",
"start_time": "10:00",
"end_time": "13:00",
"price": "180.00",
"price_recalculated": false
},
"isError": false
} Assign cleaners
writeMCP tool zenmaid_assign_cleaners
Replaces the cleaners on one appointment. It does not deactivate a cleaner and does not touch the default cleaner of a recurring service. One more call undoes it, so it does not ask for your OK.
Parameters
| Name | Type | Description |
|---|---|---|
| appointment_id required | string | Appointment ID from list_appointments. |
| cleaner_ids required | string[] | Cleaner or team IDs from list_cleaners. |
tools/call
JSON-RPC
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "zenmaid_assign_cleaners",
"arguments": {
"appointment_id": "a_993102",
"cleaner_ids": [
"cl_1344"
]
}
}
} Example response
{
"content": [
{
"type": "text",
"text": "{ ... same JSON as structuredContent ... }"
}
],
"structuredContent": {
"appointment_id": "a_993102",
"cleaners": [
"Cleaner B"
]
},
"isError": false
} Add note
writeMCP tool zenmaid_add_note
Adds an Appointment Note or a Customer Note, as in ZenMaid. A public note goes on the work orders sent to cleaners; a private note is visible only to owners and office managers. It reaches no one and is undone by editing the note, so it does not ask for your OK.
Parameters
| Name | Type | Description |
|---|---|---|
| appointment_id | string | Appointment to note. Give this or contact_id. |
| contact_id | string | Contact to note. |
| body required | string | Note text. |
| visibility | enum | public or private. Default: public. |
tools/call
JSON-RPC
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "zenmaid_add_note",
"arguments": {
"body": "body"
}
}
} Example response
{
"content": [
{
"type": "text",
"text": "{ ... same JSON as structuredContent ... }"
}
],
"structuredContent": {
"note_id": "n_5521",
"appointment_id": "a_993102",
"visibility": "public",
"body": "Moved one day because of rain."
},
"isError": false
} MCP tool zenmaid_cancel_appointment
Sets the status to Cancelled and keeps the record; it never deletes. notify takes none, client, cleaner or both, the same choices ZenMaid offers when you cancel. A cancelled appointment may be hidden by the calendar filters. By default you confirm each call; you can switch that off for this tool.
Parameters
| Name | Type | Description |
|---|---|---|
| appointment_id required | string | Appointment ID from list_appointments. |
| notify | enum | none, client, cleaner or both. Default: none. |
tools/call
JSON-RPC
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "zenmaid_cancel_appointment",
"arguments": {
"appointment_id": "appointment_8c41d2"
}
}
} Example response
{
"content": [
{
"type": "text",
"text": "{ ... same JSON as structuredContent ... }"
}
],
"structuredContent": {
"appointment_id": "a_993102",
"status": "Cancelled",
"notified": [
"client",
"cleaner"
]
},
"isError": false
} MCP tool zenmaid_mark_appointment_paid
Marks one appointment as paid, like the Mark as paid button in its Billing section. It never charges the card on file. Appointments paid by card cannot be changed this way. The customer's Revenue To Date and Unpaid Balance update. By default you confirm each call; you can switch that off for this tool.
Parameters
| Name | Type | Description |
|---|---|---|
| appointment_id required | string | Appointment ID from list_appointments. |
tools/call
JSON-RPC
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "zenmaid_mark_appointment_paid",
"arguments": {
"appointment_id": "a_991870"
}
}
} Example response
{
"content": [
{
"type": "text",
"text": "{ ... same JSON as structuredContent ... }"
}
],
"structuredContent": {
"appointment_id": "a_991870",
"paid": true,
"total": "120.00"
},
"isError": false
} MCP tool zenmaid_send_message
Sends from a template under Type of communication, as the Send Text/Email action does. You can replace the template text with your own. ZenMaid only sends if the contact has an email address or phone number on file, and manual texts count toward your SMS usage. By default you confirm each call; you can switch that off for this tool.
Parameters
| Name | Type | Description |
|---|---|---|
| appointment_id | string | Appointment the message is about. Give this or contact_id. |
| contact_id | string | Contact to message. |
| template required | string | Communication template name. |
| channels | enum | email, sms or both. Default: email. |
| body | string | Replace the template text with your own. |
tools/call
JSON-RPC
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "zenmaid_send_message",
"arguments": {
"template": "template"
}
}
} Example response
{
"content": [
{
"type": "text",
"text": "{ ... same JSON as structuredContent ... }"
}
],
"structuredContent": {
"appointment_id": "a_993102",
"template": "Appointment Reminder",
"channels": [
"email",
"sms"
],
"sent": true
},
"isError": false
}