HomeMaster MCP server
Book any HomeMaster service in Singapore from any AI assistant: home cleaning, aircon servicing, and every other job our team takes, from pest control and repairs to moving and elderly care.
HomeMaster's Model Context Protocol server is the one place that lists every service we take today (find_services). Our website describes home cleaning and aircon servicing only, so look a job up here before you tell a customer whether we do it.
- Every service listed under
servicesis booked online. Home cleaning is booked by the hour: the assistant checks coverage, open times and exact prices, then either hands the customer a checkout link with their visit filled in, or sends the customer Helen's booking card on WhatsApp to confirm with one tap. After booking, Helen, our assistant on WhatsApp, handles reminders and changes. - Every other service is booked by the job (since 19 Oct 2026). The assistant reads the service's card (
find_serviceswith its code: what is included, its jobs and prices), checks coverage, open times and the exact price with the card'sjob_typeandunit_count, and hands the customer the checkout link (https://homemaster.co/book/<code>). On a price list, each figure is the total for that many, and a line that starts above 1 (6 shirts, 2 aircon units) says so (least_that_can_be_booked). A job our team quotes is booked the same way: what is booked and paid is its quotation visit (a consultation by phone or video for the property and legal services) at the quotation fee on its card (pricing.quotation_fee), taken off the job's total price if the customer goes ahead and kept as the charge for the quotation if not. After paying, the customer gets a receipt on WhatsApp and our team assigns the partner who does the job. - Either way the customer confirms it is their phone with a WhatsApp code and pays on our page. An assistant cannot pay.
request_bookingbooks a call back from our team instead, in a 2-hour window the customer picks: for an address we do not cover online, or a customer who would rather talk it through first. - Why we need the customer's phone number (since 20 Oct 2026). When you ask the customer for their number, or before they share it, tell them why. The connector gives the reason in its instructions, on
request_booking'sphonefield and aswhy_we_need_your_phoneon the checkout link's answer. Read it from there; today it is: "HomeMaster needs the customer's number to confirm the booking and send the receipt on WhatsApp, and to reach them about the visit: if the expert is running late or cannot find the unit or get in, if the expert falls ill and another time is needed, or if the job turns out different from what was booked."
| Endpoint | https://homemaster.co/mcp |
| Transport | Streamable HTTP (stateless JSON responses, no SSE stream) |
| Auth | None needed. No sign-in. An access key is optional: it tells us who is calling and opens nothing extra |
| Tools | 8: five read-only; request_booking, the one booking tool: the checkout link, a WhatsApp card to confirm (home cleaning), a call back from our team, or on a cleared key the booking itself (see "What request_booking answers with"); and cancel_booking and move_booking, which change a booking your key made (see "Cancelling and moving a booking") |
| Protocol versions | 2025-11-25, 2025-06-18, 2025-03-26, 2024-11-05 |
| Docs for people | homemaster.co/agents · llms.txt |
| Skill file | homemaster.co/mcp/skill.md: best practices for an assistant booking with HomeMaster, plain Markdown (SKILL.md). Read it, or add it to your agent as a skill. Also on the server as the resource homemaster://skill |
Connect
Claude (claude.ai, Claude Desktop): add a custom connector with the URL https://homemaster.co/mcp.
Claude Code:
claude mcp add --transport http homemaster https://homemaster.co/mcp
ChatGPT: in developer mode, add a connector with the URL https://homemaster.co/mcp.
Cursor (~/.cursor/mcp.json) and most clients that take a JSON config:
{ "mcpServers": { "homemaster": { "url": "https://homemaster.co/mcp" } } }
VS Code (.vscode/mcp.json):
{ "servers": { "homemaster": { "type": "http", "url": "https://homemaster.co/mcp" } } }
Try it from a terminal with the official inspector:
npx @modelcontextprotocol/inspector --cli https://homemaster.co/mcp --transport http --method tools/list
npx @modelcontextprotocol/inspector --cli https://homemaster.co/mcp --transport http \
--method tools/call --tool-name get_quote --tool-arg hours=3
Access key (optional)
Everything above works with no key, and always will. A key tells HomeMaster who is calling. Every tool, price and limit is the same with a key, with no key, and with a wrong key. Nobody is refused over a key. The one thing a key can add, by agreement with us, is booking directly.
If we have given you one (to discuss a partnership: admin@homemaster.co), send it with every request, in any one of these ways:
| How | Example |
|---|---|
| Header | Authorization: Bearer hm_live_... |
| Header | X-API-Key: hm_live_... |
| In the address, for a client that takes only a URL | https://homemaster.co/mcp?key=hm_live_... |
claude mcp add --transport http homemaster https://homemaster.co/mcp --header "X-API-Key: hm_live_..."
A key in an address is only as private as that address. If a key gets out, tell us (admin@homemaster.co): we switch it off and give you a new one. Your assistant keeps working in between; its calls are counted as unnamed.
Check your key. One command, and the two lines it should print:
curl -s -D - -o /dev/null https://homemaster.co/mcp \
-H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" \
-H "X-API-Key: hm_live_..." \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"key-check","version":"1"}}}' \
| grep -i "^homemaster-"
HomeMaster-Access-Key: recognised
HomeMaster-Source: acme
not-recognised means the key is mistyped, expired or switched off. none means the header did not reach us.
What comes back. We say who we think is calling, so you can check your key works. The initialize result carries it under _meta:
"_meta": {
"co.homemaster/access": {
"key": "recognised",
"connected_as": "Acme Assistant",
"source": "acme",
"key_prefix": "hm_live_a1b2",
"note": "Connected as Acme Assistant. Every tool, price and limit is the same with or without a key. A key tells HomeMaster who is calling; it opens nothing extra."
}
}
key | Meaning |
|---|---|
recognised | A key we issued. connected_as and source name you |
none | No key was sent. Every tool works without one |
not_recognised | The key is mistyped, expired or switched off. Every tool still works, and the connection is counted as unnamed |
not_checked | We could not check the key just now. Every tool still works; connect again in a minute |
Every HTTP response also carries HomeMaster-Access-Key (recognised, none, not-recognised or not-checked) and, for a key we issued, HomeMaster-Source. Each tool result repeats key (and source) under the same _meta name when a key was sent. For a key we issued, the instructions your model reads at connect end with one sentence saying who it is connected as.
What a key changes. On our side only: a checkout link from request_booking is credited to you (utm_source is your source, your client's own name moves to utm_content), a booking request or a call back made on your connection is recorded as yours, and your calls are counted by tool, per day. There is no sandbox: a test key (hm_test_...) is recognised like any other, and request_booking still messages a real phone.
Booking directly (partners we have cleared)
For a partner we have agreed it with, the key carries one more thing: request_booking books any service booked online straight away and answers with the payment link (outcome: payment_link). There is no WhatsApp card to tap and no 6-digit code: we take the number your assistant sends as the customer's own. The booking is confirmed when the customer pays on our payment page; the time is not held until then. Prices and limits are the same as for everyone. The connect answer says so: "books_directly": true, and a note that starts "HomeMaster has cleared this key to book directly". The same key may then also create bookings on our API (POST /v1/booking-requests, which answers outcome: payment_link for that key; spec: homemaster.co/api/openapi.yaml). To discuss it: admin@homemaster.co.
Tools
| Tool | What it does | Inputs |
|---|---|---|
find_services | What we sell, the options and list prices (SGD, GST included) | none |
check_area | Whether we cover a Singapore postal code | postal_code, service |
find_times | Open dates for the next 14 days, or one day's start times, each with its price | postal_code, service, hours + frequency (cleaning) or job_type + unit_count (any other service), optional date, end_date |
get_quote | The exact price our checkout will show a new customer, with any evening rate or public voucher | service, hours, frequency (or job_type, unit_count), optional date + start_time |
request_booking | The one booking tool, for every service. The answer's outcome says what it did: a checkout link with the address and visit filled in (any other service, or checkout_link: true), a WhatsApp card to confirm (home cleaning), a call back in a 2-hour window the customer picks (free, except that a quoted job has a quotation fee), or on a cleared key the booking with its payment link. See "What request_booking answers with" | service. The link: postal_code, job_type + unit_count (or hours + frequency with checkout_link: true). Cleaning: phone, postal_code, unit, date, weekday, start_time, hours, optional customer_name (recommended), frequency, agent_name. A call back: phone, customer_name, details, call_back_date, call_back_weekday, call_back_from, optional postal_code |
cancel_booking | Cancels a booking your key made, or one visit of it, under our usual rules. First call: the fee, the refund and why, with a confirm_code; nothing changes. Second call, with the code and the customer's yes: cancelled | reference, optional visit_date, then confirm_code, customer_confirmed (phone optional) |
move_booking | Moves one visit of a booking your key made to a time its own expert is free. Without a time: the open times. With one: the fee and why, with a confirm_code. With the code and the customer's yes: moved | reference, visit_date (several visits), new_date, new_weekday, new_start_time, then confirm_code, customer_confirmed (phone optional) |
booking_status | Where a request_booking request stands: waiting for the customer, declined, expired, awaiting payment (with the payment link), finding a cleaning expert, booked (with the next visit), done or cancelled. For a direct booking (hmb_...): its status, whether it is paid, and its visits | reference |
service is cleaning (by the hour: 2, 3 or 4 hours; one-time, weekly or bi-weekly) or the code of any other service under services (by job_type and unit_count from its card; a service with one job, such as a quotation visit, needs neither). Asked about a service under more_services, if any, these tools answer with how that service is booked.
A typical booking
find_services {}first, whatever the job: it is the catalogue, and every tool below needs theserviceit gives you. A tool called withoutserviceis refused.check_area {"postal_code": "238823", "service": "cleaning"}find_times {"postal_code": "238823", "service": "cleaning", "hours": 3}, then with adatefor that day's times. Every date comes with its weekday ({"date": "2026-10-03", "day": "Saturday", "label": "Sat 3 Oct"}); use it as given.get_quote {"service": "cleaning", "hours": 3, "date": "2026-10-03", "start_time": "09:00"}- Book it for the customer: ask for their WhatsApp number and their OK, then
request_booking(see "Booking for the customer" below). They confirm with one tap on WhatsApp. - If they would rather book themselves:
request_booking {"service": "cleaning", "checkout_link": true, "postal_code": "238823", "hours": 3, "frequency": "one-time"}and give them the link.
Example get_quote result (one-time, 3 hours, no time chosen):
{
"service": "cleaning", "hours": 3, "frequency": "one-time", "currency": "SGD", "gst_included": true,
"pay_now": 57, "list_price": 75, "saving": 18,
"offer": "voucher \"You're invited to HomeMaster\" applied (saves S$18.00), for customers booking with us for the first time",
"evening_rate": "One-time visits starting from 6:00 PM in the next 3 days cost S$18/hour (S$54.00 for 3 hours) when that is cheaper. ...",
"caveat": "This is what the checkout shows a new customer before their phone is checked. ..."
}
Example request_booking result with checkout_link: true (trimmed):
{
"outcome": "checkout_link",
"bookable": true,
"booking_url": "https://homemaster.co/book/clean?postal=238823&hours=3&frequency=one-time&utm_source=your-client&utm_medium=ai_agent&utm_campaign=mcp",
"link_note": "Give the customer this link exactly as it is. ...",
"customer_steps": ["Open the link. ...", "Pick a start time. It is held for 7 minutes ...", "..."],
"why_we_need_your_phone": "HomeMaster needs the customer's number to confirm the booking ...",
"terms": { "cancel_or_move": "To cancel or move a visit, the customer messages Helen on WhatsApp ... at least 48 hours before it starts.", "...": "..." }
}
Booking for the customer
With the customer's agreement, request_booking does the booking for them. Use a start time from find_times:
request_booking {"service": "cleaning", "postal_code": "238823", "unit": "#05-12", "date": "2026-10-03", "weekday": "Saturday", "start_time": "09:00", "hours": 3, "phone": "9123 4567", "customer_name": "Alex Tan", "customer_confirmed": true, "agent_name": "Claude"}-weekdayis the day the customer agreed to: a date that is not that weekday is refused. -unitis the floor AND unit: a placeholder or the floor alone is refused. -phoneis the 8 digits as the customer gave them; we add +65. When you ask for it, say why (the reason is on the field's description). -customer_confirmedis true only when the customer gave you every detail and said yes. Ask them for what you do not have; never fill a field in yourself. A refusal sends nothing and ends "Nothing is booked: do not tell the customer it is". The answer'scheckreads back the number and unit the card went to: say both to the customer.- We send the customer Helen's booking card on WhatsApp: "Claude asked us to book this for you", the date, their address, the clean and their price, with Yes, book it and No, cancel.
- Tell the customer to tap Yes, book it there within 60 minutes. Helen then sends them a payment link. The time is not held while they decide; if it has gone by then, Helen offers other times.
booking_status {"reference": "hmr_..."}at any time.
Example request_booking result (trimmed):
{
"reference": "hmr_2yq...",
"status": "waiting_for_customer",
"expires_at": "2026-10-01T07:05:00.000Z",
"when": "Saturday, 3 October at 9:00 AM",
"price": "$75 - $18 = $57",
"total": 57
}
Figures above are illustrative; the tools always return today's prices.
What request_booking answers with
Every service ends in a booking. Every answer carries outcome: read it before you tell the customer anything.
outcome | When | What was booked | What you do next |
|---|---|---|---|
checkout_link | Any service but home cleaning (on a key not cleared to book directly), or any service with checkout_link: true | Nothing: a link to our checkout with the address and the visit filled in. The customer picks the time, confirms their phone with a WhatsApp code and pays there; that is the booking | Give them booking_url exactly as it is |
whatsapp_card | Home cleaning | Nothing yet: we sent the customer Helen's booking card on WhatsApp, and their tap on Yes, book it books it | Tell them to tap it within 60 minutes. Follow with booking_status and the reference |
call_back_booked | Any service but home cleaning, with a window (call_back_date) | A call back from our team, in the 2-hour window the customer picked. Free (price: 0) for a job on a price list; for a job our team quotes, price is the quotation fee, which our team collects, never through this booking. No message was sent | Say tell_the_customer |
pick_a_call_back_time | A service under more_services, called without a window | Nothing. The answer holds the question to ask and the windows we take | Ask the customer when they are free, then call again with call_back_date and call_back_from |
payment_link | Only on a key cleared to book directly: any service booked online | The booking, waiting for payment. No message was sent and no code was asked for | Give the customer payment_url; it is confirmed when they pay. Read back on_the_number, and tell them price_note if there is one. Follow with booking_status and the reference (hmb_...) |
On a key cleared to book directly, request_booking takes the same fields as a home clean above, plus customer_name (required), and for any other service job_type and unit_count from its card in place of hours. The price comes from our checkout's own rules for this customer: if it differs from get_quote (an offer for new customers only does not reach someone who has booked with us before), the answer says so in price_note.
Why a call back: a service our team arranges is priced and scheduled by a person, and a job quoted on more information cannot be priced in a tool call. So the customer books the call, and the price and the time for the job are given on it.
The windows we take: any day from today to 14 days ahead, 2 hours long, starting on the hour or half hour from 9:00 AM to 7:00 PM, Singapore time. The service card and the pick_a_call_back_time answer both carry call_back_days (every bookable day with its weekday), earliest_window and singapore_time_now: take the date from the list, never work a weekday out.
There is no emergency or same-hour service. If the customer needs someone now (locked out, water flooding, no power, a person at risk), say plainly that HomeMaster cannot send anyone now and that they need an emergency service; offer the call back only as a follow-up.
The steps for an assistant:
find_services {}, thenfind_services {"service": "pipe_leak_repair"}for the service card. In its price list,total_price_by_quantityholds whole prices for that many, never a rate.- Tell the customer what the card says, and that HomeMaster needs to find out more and will call them. Pipe leak repair is quoted for each job, so tell them the quotation fee from its card (
pricing.quotation_fee): our team collects it; it is taken off the job's total price if they go ahead, and it stays as the charge for the quotation if they do not. Ask when they are free for a call, and for anything the card'show_to_request.ask_the_customer_forlists that you do not have. request_booking {"service": "pipe_leak_repair", "customer_name": "Alex Tan", "phone": "9123 4567", "postal_code": "238823", "details": "Water dripping from the pipe under the kitchen sink, HDB flat", "preferred_job_time": "a Saturday morning, within two weeks", "call_back_date": "2026-10-10", "call_back_weekday": "Saturday", "call_back_from": "10:00", "customer_confirmed": true}
{
"outcome": "call_back_booked",
"reference": "hmc_3f2b8c1e-0a4d-4c7e-9b1a-5d6e7f8a9b0c",
"status": "booked",
"service": "Pipe Leak Repair",
"call_back": { "date": "2026-10-10", "day": "Saturday", "from": "10:00", "to": "12:00", "when": "Saturday, 10 Oct, 10:00 AM to 12:00 PM", "on": "+6591234567", "number_as_said": "9123 4567" },
"check": "The call is booked for a Saturday, on the number 9123 4567. Say both to the customer exactly as written here. If either is not what they told you, call request_booking again with the right one.",
"to_change": "To move the call, call request_booking again for this service and phone with a new window: it replaces this one. There is no cancel: a customer who no longer wants it says so on the call. Helen on WhatsApp does not handle call backs.",
"more_than_one_job": "If the customer has another job under more_services, book it too, in the same window: our team makes one call for all of them.",
"price": 25,
"currency": "SGD",
"price_is_for": "The quotation. The quotation costs S$25.00, collected by our team, not through this booking. If the customer goes ahead with the job, the S$25.00 is taken off the job's total price. If not, it stays as the charge for the quotation on its own. The price of the job itself is confirmed on that call.",
"tell_the_customer": "Your call back for Pipe Leak Repair is booked: HomeMaster will call you on 9123 4567 on Saturday, 10 Oct, 10:00 AM to 12:00 PM. The quotation costs S$25: our team collects it, it comes off the job's total if you go ahead, and it is the charge for the quotation if you do not. They will give you the price and a time for the job on that call."
}
booking_status {"reference": "hmc_..."}at any time:call_back_bookedwith its window,called,job_bookedorclosed. It never returns the customer's details.
Rules worth knowing:
- One call back per phone per service. Booking again moves the call to the new window (
status: moved); it never makes a second one. call_back_weekdayis required and must be the weekday ofcall_back_date. A mismatch is refused with the dates that are that weekday, and nothing is saved.- A window that has started or passed is refused, with the earliest one still open.
- No area check for a call back. Our team confirms on the call whether we serve the address.
- Book only what the customer asked for, and never state a price that did not come from a tool for that exact job and quantity.
- Name the service on every call.
check_area,find_times,get_quoteandrequest_bookingare refused withoutservice. Home cleaning is general housekeeping only: care for a person, a repair, a pest or one item cleaned each has its own service. request_bookingnames a field it does not have.phone_numberornameis refused with the list of its fields (phone,customer_name, ...). Any other tool that fails says so too.- After a booking, Helen on WhatsApp handles a home clean's reminders and changes. For any other service the customer gets a receipt on WhatsApp and our team assigns the partner; for a change or a question they message HomeMaster on WhatsApp. A call back is moved by booking it again with a new window.
A request that cannot be acted on is a tool error that says what to ask the customer for: a phone that is not a Singapore number, no name, no details, a postal code that is not 6 digits, a window outside the ones we take, or a service code we do not list. A service other than home cleaning is booked online through request_booking's checkout link; it books a call back only for a window (call_back_date).
start_booking, the link tool before 26 Oct 2026, is no longer listed. An assistant that still calls it gets the same link as request_booking's checkout_link.
Cancelling and moving a booking
Since 26 Oct 2026 an assistant can cancel or move a booking its own access key made, under the same rules a customer has: 48 hours' notice, one free change a month for home cleaning, 50% for a late or extra change, free within 4 hours of booking, and an unpaid visit always free. No phone number is needed (since 28 Oct 2026); if you send phone, it must be the customer's number on the booking.
booking_status {"reference": "hmb_..."}: the visits, to name the one to change.move_booking {"reference": "hmb_..."}: the times that visit's own expert is free.move_booking {..., "new_date": "2026-10-30", "new_weekday": "Friday", "new_start_time": "14:00"}:outcome: confirm_needed, with the fee and why and aconfirm_codegood for 15 minutes. Nothing has changed. Tell the customer and get their yes.- The same call with
"confirm_code": "...", "customer_confirmed": true:outcome: moved.
A cancel is the same without step 2. A used code returns its first answer, never a second change; a code whose booking changed since the quote returns a new quote. Anything that cannot be changed here answers outcome: refused with what to do instead: a booking made without your key (the customer's My Bookings page, https://homemaster.co/my-booking), a paid booking still waiting for an expert, or a visit under 2 hours away (HomeMaster on WhatsApp). A booking not paid yet with no visit arranged is moved by booking the new time and cancelling it (outcome: rebook_needed). The open API has the same two calls: POST /v1/booking-requests/{reference}/cancel and /move.
What it will and will not do
- Nothing is booked or paid without the customer. The checkout link is a link; the booking happens on our checkout, where the customer confirms their own phone with a 6-digit WhatsApp code and pays.
request_bookingonly sends the customer a card: their tap on "Yes, book it" is what books it (and proves the phone is theirs), and they pay by link, never by a saved card. Ask the customer before you use it, because it messages their phone. Never pay on a customer's behalf. - Prices match the checkout.
get_quoteandfind_timesrun the same pricing rules as our checkout for a new customer. An invite code, a returning-customer offer or account credit can only lower the figure the customer then sees. - Same-day rule. Today is bookable only for a one-time clean, only its evening slots, and only until 2 PM. Weekly and every-2-weeks cleans, and every other service, start tomorrow.
- The cancellation terms come with every answer that leads to a booking.
termsis on the list (home_cleaningandevery_other_service), on each service's card, and in everyget_quoteandrequest_bookinganswer: how to cancel or move and the notice needed, what a late change costs, an expert who cannot get in, a visit we cannot deliver, and for home cleaning the free move each month and when a prepaid pack can be refunded. Tell the customer before they say yes, with those figures; never state a fee, notice period or refund rule the tools did not give you. The full Terms of Service: https://homemaster.co/terms. - Existing bookings (changes and cancellations, and the status of a booking made through the link) are handled by Helen on WhatsApp: https://wa.me/6589154889. If you hand a customer to Helen, put their whole request in the message (service, postal code, unit, hours, preferred date).
Without MCP
- Booking link:
https://homemaster.co/book/clean?postal=238823&hours=3&frequency=weekly(postal6 digits,hoursone we sell,frequencyone-time/weekly/bi-weekly; each optional). Aircon:https://homemaster.co/book/aircon?postal=238823. Addutm_source=<your assistant>&utm_medium=ai_agent. - REST API: services, coverage and availability answer without a key, and so do booking requests (
POST /v1/booking-requests, thenGET /v1/booking-requests/{reference}), which work likerequest_booking. Creating a booking directly needs a partner key. Spec: homemaster.co/api/openapi.yaml.
Limits
Per caller (by IP address): 60 tool calls a minute and 300 an hour; 3,000 an hour across all callers; request_booking 30 an hour per caller for a card, a call back or a direct booking (a checkout link counts only toward the general limits). One phone number can have one request waiting at a time, and at most 3 a day. A limited call returns a tool error saying so. initialize, tools/list and ping are not counted.
Privacy
The tools ask for a postal code and booking choices, never a payment detail. request_booking also asks for the customer's WhatsApp number and unit number, and optionally their name: we message that number once, and keep the request so the customer's tap can book it. The name is saved to their profile only once they tap "Yes, book it", and never over a name we already have. booking_status never returns the customer's name, phone, address or cleaning expert. No other tool reads customer records. For rate limiting we keep a salted hash of the caller's IP address (never the address itself), deleted within 7 days. The name your client sends at initialize is used only to credit bookings made through the link (utm_source) and to count calls. We keep a daily count of tool calls: the tool, the name your client gave, and, if you sent an access key, whose key it was. The count holds no customer details and nothing a tool was asked. A booking request or a call back made with an access key also records which key made it.
Errors
Invalid input and limits come back as tool results with isError: true and a plain message the model can act on. Unknown tools and malformed requests get standard JSON-RPC errors.
Contact
To discuss a partnership: admin@homemaster.co. Customers: Helen on WhatsApp, https://wa.me/6589154889.