Appointedd MCP Server
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Appointedd MCP ServerWhen is the next free slot for a haircut with Sam this week?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Appointedd MCP server
An MCP server that lets Claude, ChatGPT and other MCP clients work with an Appointedd booking organisation: availability, services and categories, resources (staff, rooms), bookings and customers, and (when enabled) reserving a slot, creating and cancelling bookings, and adding or updating customers. It is built from Appointedd's public API documentation and the OpenAPI 3.1 definitions it publishes, one per reference page, on developers.appointedd.com.
Once it's connected, someone in the organisation can ask things like:
"What's booked for tomorrow, and who is coming?"
"When is the next free slot for a haircut with Sam this week?"
"Which services does Priya deliver, and how long is each?"
"Find Jo Bloggs and show me their last few bookings."
With writes enabled: "Book Jo Bloggs in for a haircut at 9:30 on Monday." / "Cancel the 2pm massage on the 7th."
Tools
Tool | What it does | API calls |
| Available start times for a service between two dates/times, with the free resources and any group bookings with space. A query, sent as a POST because that is how the API takes it; it changes nothing. |
|
| Dates with availability for a service between two dates/times. Also a POST that changes nothing. |
|
| Services with category, booking type, occupancy, durations and prices, buffers and booking questions; |
|
| One service. |
|
| Categories (id, name); |
|
| Staff, rooms and equipment with the services each is assigned to and its groups; |
|
| Resource groups (id, name); |
|
| Bookings with status, service, resource, times, price, spaces and participants; every documented filter ( |
|
| One customer with tags, marketing opt-in and custom fields, plus their bookings with the latest start first unless |
|
| Search by part of a name, email, mobile or phone. The API has no search parameter, so this pages through the customer list (100 per call). Names only by default; a match on an email or phone fragment still confirms such a detail exists on the account. |
|
| Holds a start time for a service (and optionally a resource) for a few minutes so it cannot be double-booked. Writes only. |
|
| Turns a reservation into a booking with zero or more customers. Writes only. |
|
| Cancels a booking and every customer's place on it. Writes only, marked destructive. |
|
| Adds a customer (name, optional email, mobile, phone, tags). Writes only. |
|
| Changes a customer's name, email, mobile, phone or tags (tags replace the existing ones). Writes only. |
|
Making a booking is the three-step flow from Appointedd's own "Creating a new booking" guide: find_available_intervals, then create_reservation for one of the returned start times, then create_booking with the reservation's id.
Not covered on purpose: GET /services/categories/{id} (its documented response schema and example are both empty objects), get and delete reservation, delete customer, delete and update resource, update booking, update and cancel a single customer on a booking, and booking-customer invoices.
Related MCP server: booking-mcp
Setup
Requires Node 18 or later.
npm install
npm run buildYou need your organisation's API key from Appointedd (Settings > API, app.appointedd.com/management/settings/api). The API authenticates with that key in the X-API-KEY header. Appointedd's Authentication page warns that anyone with the key can perform any operation on the organisation, so treat the key like a password.
Claude Desktop: add this to claude_desktop_config.json:
{
"mcpServers": {
"appointedd": {
"command": "node",
"args": ["/absolute/path/to/appointedd-mcp/dist/index.js"],
"env": { "APPOINTEDD_API_KEY": "your-key" }
}
}
}Claude Code:
claude mcp add appointedd -e APPOINTEDD_API_KEY=your-key -- node /absolute/path/to/appointedd-mcp/dist/index.jsVariable | Required | Meaning |
| yes | Your organisation's API key, sent as the |
| no |
|
| no | Defaults to |
Safety defaults
Read-only unless
APPOINTEDD_ALLOW_WRITES=true. Read tools carry the MCPreadOnlyHintannotation, including the two availability searches, which are POSTs that change nothing;cancel_bookingis marked destructive;update_customeris marked idempotent.Customers are third parties. By default a customer's email, mobile, phone, postal address and gender are not returned (
get_customer,find_customers, and the results ofcreate_customerandupdate_customer, even though the caller has just supplied them); a custom field whose name looks like contact data (email, phone, mobile, name, address, postcode, date of birth, IP, NHS or passport number and the like, whether written asDate of birth,E-mail,homeAddressornhsnumber) is replaced by a placeholder; and in free-text fields (customer names and tags, other custom-field values, participants' question answers, service descriptions, resource names and descriptions, category and group names, booking question labels and options) email addresses are replaced with[email redacted]and phone-number-like sequences with[phone redacted].include_contact_details=truereturns all of it as stored. The phone match is a heuristic: it covers international numbers written with+or00(including the+44 (0)7700 …form), UK numbers written with a bare44country code such as448787981295(the form Appointedd's own Create Customer example uses), UK numbers with a bracketed area code such as(020) 7946 0958, and UK-style0…numbers of 9 to 11 digits with spaces, dots or hyphens between groups. Other digit strings that happen to start with0(an order number, say) are redacted too; 24-character hex IDs, timestamps and references such asLOY-0001are left alone, and a non-UK number written with a bare country code (33612345678) is not recognised. The same redaction is applied to Appointedd's own error messages before they are passed on.Participants on a booking carry a
reschedule_url, which the Bookings page documents as a single-use link that reschedules that customer's booking. It is withheld unlessinclude_contact_detailsis set. Resources are usually people, so a resource's email, phone and address are withheld the same way. A booking's video conferencing link is the organisation's own meeting link and is returned as stored.No documented response carries card, bank or payment details; prices,
total_priceand thepaidflag are returned as the API gives them.create_bookingsendssend_payment_request: falseunless asked otherwise. The API's own default istrue, which emails a payment request to every customer on the booking.IDs are checked before any call is made: every ID in the API is 24 hexadecimal characters (the documented 400 for a malformed reservation ID quotes the regex
^[0-9a-fA-F]{24}$), so12345,../customersor a 23-character value is refused locally. Date filters and availability ranges must be an ISO 8601 date or date-time (2026-10-05,2026-10-05T09:00:00Z,2026-10-05T10:00:00+01:00) and are passed through unchanged;12/08/2026, a bare year, a Unix timestamp, a space instead of theT(2026-10-05 09:00:00Z) or an impossible date such as2026-02-30(which Node'sDate.parsewould silently roll over to 2 March) is refused rather than guessed, as is a range whose end is not after its start. Timezones must be IANA names (Area/Location, orUTC) that Node's Intl data recognises; an offset such as+01:00, which Intl would accept, is refused because the API asks for IANA names.No documented endpoint redirects, so the client does not follow redirects: a 3xx (from a misconfigured
APPOINTEDD_BASE_URL, say) is reported as an error and theX-API-KEYheader is only ever sent to the configured base URL, never to a second host.Appointedd does not document a rate limit anywhere in its Introduction, Authentication, Pagination or Limitations pages or on any reference page. Requests are spaced 250 ms apart (about four per second). A 429 is retried at most twice for any method, including
POST /bookings, on the assumption that a rate-limited request was not processed (see Status). The retry waits forRetry-After(whole or fractional seconds, or an HTTP-date; 2 s then 4 s when the header is absent or unreadable). Each wait is capped at 10 seconds so a tool call stays under the MCP client's default 60-second request timeout: if Appointedd asks for a longer wait the call gives up at once and the message says how long to wait.502, 503 and 504 are retried the same way for
GETonly; when all three attempts fail the error says the service may be unavailable and to try again in a few minutes, without the gateway's HTML. No POST or PUT is retried after a gateway error, because the request may already have been processed and a retry could create a booking or hold a slot twice; the error says what to check before repeating it (list_bookingsfor a booking,find_customers/get_customerfor a customer). The two availability searches are not retried either, and their error says they are queries that are safe to call again.The Limitations page sets a hard limit of 10240 bytes on request size. A body larger than that is refused locally with a message saying which fields to shorten, before anything is sent.
A 200 whose body is not JSON (a proxy or a login page in the way), or whose JSON has no
datalist where a list endpoint documents one, is reported as an error namingAPPOINTEDD_BASE_URL, never as an empty list or an empty record.A rejected API key (401 or 403) produces a message that says which variable to fix and where the key comes from; a 400 or 422 from the API is passed on with Appointedd's own
error/messagetext and the names of the invalid fields when the API lists them.
Tests
npm testThe test suite:
Validates every fixture record against the inline response schemas in Appointedd's published OpenAPI definitions (Get Bookings, Get Customers, Get Customer, Get Services, Get Service, Get Service Categories, Get Resources, Get Resource Groups, Find Available Intervals, Find Available Dates, Create Reservation and Get Reservation, Create Booking, Create Customer, Update Customer). Appointedd publishes one OpenAPI document per reference page;
test/assemble-spec.mjsfetches the 30 pages listed in it (developers.appointedd.com/reference/<slug>.md), takes the "OpenAPI definition" block from the 25 that have one, merges them intospec.jsonon the first run, and refuses to continue if two pages define the same operation or component differently. The definitions are assembled this way because the single "OpenAPI 3 specification" document the Introduction page links to (developers.appointedd.com/openapi/6130b17d1447b2003acc5216) answered 404 when this was built (28 September 2026).spec.jsonis not committed, so the firstnpm teston a fresh clone needs network access to developers.appointedd.com (30 small page fetches, a few seconds); later runs use the saved file. The definitions carry no component schemas: every request and response schema is inline in its operation.Starts a local mock of the API under
/v1that serves those fixtures with the documented range-based pagination (limit,start= the previous page'snext,end= the previous page'sprev;data,total,prev,nextout; bookings are capped at 3 per page and customers at 50 whatever is asked, so lists span several pages), X-API-KEY 401s, the documented 400 (bad limit, non-hex ID), 404 and 422 shapes, a single-use reservation store, and answers the firstGET /resources/groupswith a 429. The mock's list, detail, action and error responses are validated against the response schemas the spec gives for each operation and status, the documented pagination keys are asserted explicitly (the schemas mark nothing as required), and the availability, reservation, booking and customer bodies it is sent are validated against the request schemas.Starts the built server and drives it over stdio with the official MCP client: 28 checks (30 in the whole suite) covering every tool, tool annotations, range pagination to
next: nullwithstartcarrying the previousnextandlimitwhat is still wanted,max_resultswith an exact continuation (followingnext_startyields every booking exactly once), every documentedlist_bookingsfilter passed through exactly (array filters as the key repeated once per value),sort_by/order_byon bookings, resources and groups, theidsandservicesfilters, local refusal of an inverted range, malformed dates (including2026-02-30and a space-separated date-time), a bad timezone (an unknown name and an offset) and malformed IDs before any request, redaction of contact details, contact-like custom fields (and the name heuristic behind them, for spellings such asdateOfBirth,E-mail,homeAddressandnhsnumber), emails and phone numbers in tags, names, descriptions, group names, question labels, options and answers (the+44 (0)…, bare44…, bracketed,00-prefixed, dot-separated and hyphenated phone forms), reschedule links and staff contact details by default and their return on request,create_customer's result withholding the contact details just supplied unless asked,find_customersmatching name, email and UK phone forms across three pages, both availability searches with their bodies validated against the spec's request schemas (includingresource_group_idssent as a single string,parts,buffers,spacesand everyignore_*flag),create_reservation,create_booking(with and without customers,send_payment_requestfalse by default),cancel_booking,create_customerandupdate_customerwith their bodies validated against the request schemas, the documented 404 for an unavailable reservation time and 422s for a used reservation and an already cancelled booking, the local refusal of an empty update and of a body over 10240 bytes, the 429 retry waiting forRetry-Afterin the seconds, fractional-seconds and HTTP-date forms, giving up after three attempts on a persistent 429 and at once on aRetry-Afterabove the cap, a 429 onPOST /bookingsretried once, a gateway error (502/503/504) retried forGETand never forPOST /bookings,POST /availability/slots, the availability searches or aPUT, aGETfailing three times with 503 reported with advice and without the gateway HTML, a 200 with a non-JSON body or with JSON whosedatais missing or not a list reported as an error (never as an empty list), a 302 not followed (one request reaches the mock and the error names the base URL as the only place the key goes), Appointedd's own error text passed on with contact details redacted, the write gate with the variable unset and set tofalse, the 401 message, the server refusing to start without a key, and that every request used theX-API-KEYheader,application/jsonfor bodies, and a documented method and path.
Two places where the published definitions disagree with themselves are handled as follows. The Pagination page (and the categories, resources and resource-groups examples) say prev and next are null on the first and last page, while the bookings, customers and services schemas type next as a string; the mock follows the documented behaviour and step 2 drops a null prev/next before validating those pages. The Get Services example shows "description": null while its schema types description as a string; the fixtures follow the schema and the server treats a missing, null or empty description the same way.
Status
This is a working prototype. It has not yet been run against the live API, because it was built without an Appointedd account. Everything below is taken from the published documentation and should be confirmed on a real account:
Authentication: the body of a 401 is not documented (the mock answers with the
{statusCode, error, message}shape every other documented error uses), and whether a wrong key gives 401 or 403.Unknown IDs: only
GET /services/{id}documents a 404 ("ID does not exist");GET /customers/{id}documents a 400 for a non-hex ID and nothing for an unknown one. The server reports any 404 as "Not found" with the API's message.Pagination: whether
nextisnullor absent on the last page (the client treats both, and an empty string, as the end); whethertotalcounts the filtered set, as the Pagination page says ("matches your current request"); what the API answers for astartID that no longer exists (the mock answers an empty page); and what the defaultsort_by=naturalwithorder_by=descendingmeans in practice (the server keeps whatever order the API returns and passes the sort parameters through).Query arrays: the spec types
ids,services,categories,customersandresourcesas arrays of strings without saying how to serialise them. The server sends the key repeated once per value (services=a&services=b), the OpenAPI 3 default; the descriptions say a single value is accepted too.GET /bookings:statusesis typed as a single enum value although its description says "at least one of the provided statuses", so the tool takes one status;return_matching_customers_onlyis documented against "the IDs in theidsquery parameter" although it clearly concerns customers, and is passed through as is; and whetherafter/beforecompare withstart_buffer/end_buffer("including the after buffer") as the mock does.Date filters and ranges are documented as "a valid ISO8601 formatted date and time". A date without a time (
2026-10-05) is passed through as given; whether the API accepts it, and in which timezone it reads it, is not documented.Timezones are documented as "a valid, non-deprecated, IANA Timezone". The server checks the shape and that Node's Intl data knows the name; whether a name is deprecated (
Asia/Calcutta,EST) it cannot tell, so such a value is sent and the API's answer decides.Availability searches:
resource_group_idsis typed as a single string although its description says "one or more", so the tool takes oneresource_group_idand sends it as that string. The default result timezone is documented asEurope/Londonfor the searches and for a reservation'sstart, and asUTCforPOST /bookings(Create Booking) only;GET /bookingsdocuments no default (its example shows+00:00offsets). The server passestimezonethrough and converts nothing.POST /bookings: the spec's request schema hasdata.customers(an array of{customer, notes, questions, …}objects), which is what the server sends, while the "Creating a new booking" guide's example posts a singulardata.customer. Whethersend_payment_request: falsesuppresses every payment email, and how customers are matched to existing ones "using the name, email, and/or mobile fields".POST /availability/slots: the 404 message is the documented one; the guide also mentions adurationproperty on the reservation data that the schema does not list, so the server does not send it (partscovers the same need). A 429 on this endpoint or onPOST /bookingsis retried on the assumption that a rate-limited request was not processed; Appointedd documents no 429 and no rate limit at all, so the 250 ms spacing here is a guess on the polite side.Money:
service.durations[].priceis typed as an integer and the bookingprice/total_priceas numbers (example0.01); the currency and units are not documented, and the server passes the numbers through.Custom fields on customers: an object keyed by field name whose "date" fields the docs say come back as UNIX timestamps; the server passes numbers through and applies the contact-data rules to the names. Which field names real organisations use decides how well the withholding heuristic fits.
Video conferencing: the Bookings page says Zoom meeting properties appear asynchronously after a booking is created; the server returns whatever is present.
The Limitations page documents the 10240-byte request limit but not the status the API answers with when it is exceeded (the mock uses 413).
The wording of Appointedd's error messages and whether any of them echo request data such as a customer's email address; the texts here are the spec's examples, and the server redacts contact details from them regardless.
Going to production
This version runs locally over stdio, with the organisation's own API key. For customers to connect from claude.ai or ChatGPT without handling keys, the next step is a remote server (Streamable HTTP) behind OAuth, hosted by Appointedd, and then a listing in the Claude and ChatGPT connector directories.
Licence
MIT. Built by Alexandru Dragoș (alexandru.dragos96@gmail.com) with an AI agent (Claude) working under his direction.
Available Tools
10 toolsfind_available_datesFind available datesARead-only
Dates on which a service has availability between two dates/times, with the resources free on each. This is a query sent as POST /availability/days/search; it changes nothing. Use find_available_intervals for the start times within a date.
| Name | Required | Description | Default |
|---|---|---|---|
| to | Yes | End of the range to search (ISO 8601), after from | |
| from | Yes | Start of the range to search (ISO 8601) | |
| parts | No | Parts of the potential booking (block = booked time, free = gap); when given, duration is ignored. Omit to use the service's own duration or parts | |
| spaces | No | Spaces required (excludes group bookings with fewer spaces left); the API defaults to 1 | |
| buffers | No | Minutes before/after a potential booking that must be free; omit to use the service's buffers | |
| duration | No | Minutes that must be free from the start of an interval; omit to use the service's default duration | |
| timezone | No | IANA timezone to return the results in; the API defaults to Europe/London | |
| service_id | Yes | Service ID (24 hexadecimal characters) | |
| max_results | No | Maximum number of intervals to return | |
| resource_ids | No | Only these resources; omit for every resource assigned to the service | |
| ignore_bookings | No | Booking IDs to ignore for this search (they neither block availability nor count as available group bookings) | |
| resource_group_id | No | Only resources in this resource group (the API's resource_group_ids field, which its spec types as a single string). Not with resource_ids | |
| ignore_group_setting | No | Return group bookings with space even if online group bookings are off | |
| ignore_past_restriction | No | Do not exclude times before now | |
| ignore_service_schedule | No | Ignore the service's schedule | |
| ignore_notice_restriction | No | Ignore the organisation's and service's notice-period settings | |
| ignore_service_assignment | No | Do not fail when a resource is not assigned to the service |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=true, so the safety profile is covered. The description adds the HTTP endpoint (POST /availability/days/search) and reaffirms 'it changes nothing', which is useful context, but says nothing about result caps/pagination behavior despite the max_results parameter, so the added value is modest.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences with the core purpose front-loaded and the sibling routing last. The POST endpoint aside is arguably expendable but is short and contextual, so there is little waste.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 17-parameter tool with no output schema, the description only gesture at the return shape ('with the resources free on each') and omits pagination/max_results behavior. Annotations and the exhaustive schema carry most of the burden, so it is adequate but thin for the tool's complexity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all 17 parameters thoroughly (parts, buffers, spaces, ignore_* flags, etc.). The description adds no parameter-level meaning beyond what the schema provides, which is the correct baseline of 3.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific resource (available dates for a service) with its scope (between two dates/times, plus which resources are free), and explicitly contrasts with the sibling find_available_intervals. An agent can distinguish this from the interval-level tool without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Names the alternative tool and the condition that selects it ('for the start times within a date'), which is genuine routing guidance. It doesn't cover when-not-to-use or other siblings (e.g., get_service to resolve service_id), so it falls just short of the top band.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
find_available_intervalsFind available start timesARead-only
Available start times (intervals) for a service between two dates/times, with the resources free at each and any group bookings with space. This is a query sent as POST /availability/intervals/search; it changes nothing. Use one of the returned start times with create_reservation.
| Name | Required | Description | Default |
|---|---|---|---|
| to | Yes | End of the range to search (ISO 8601), after from | |
| from | Yes | Start of the range to search (ISO 8601) | |
| parts | No | Parts of the potential booking (block = booked time, free = gap); when given, duration is ignored. Omit to use the service's own duration or parts | |
| spaces | No | Spaces required (excludes group bookings with fewer spaces left); the API defaults to 1 | |
| buffers | No | Minutes before/after a potential booking that must be free; omit to use the service's buffers | |
| duration | No | Minutes that must be free from the start of an interval; omit to use the service's default duration | |
| timezone | No | IANA timezone to return the results in; the API defaults to Europe/London | |
| service_id | Yes | Service ID (24 hexadecimal characters) | |
| max_results | No | Maximum number of intervals to return | |
| resource_ids | No | Only these resources; omit for every resource assigned to the service | |
| ignore_bookings | No | Booking IDs to ignore for this search (they neither block availability nor count as available group bookings) | |
| resource_group_id | No | Only resources in this resource group (the API's resource_group_ids field, which its spec types as a single string). Not with resource_ids | |
| ignore_group_setting | No | Return group bookings with space even if online group bookings are off | |
| ignore_past_restriction | No | Do not exclude times before now | |
| ignore_service_schedule | No | Ignore the service's schedule | |
| ignore_block_restriction | No | Ignore the organisation's 'block after' setting | |
| ignore_notice_restriction | No | Ignore the organisation's and service's notice-period settings | |
| ignore_service_assignment | No | Do not fail when a resource is not assigned to the service |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and openWorldHint, so the safety profile is covered; the description reinforces this ('it changes nothing') and adds the transport detail (POST /availability/intervals/search). It also discloses what a result contains (free resources per interval, group bookings with space), which is behavioral value beyond the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, front-loaded with the core purpose, then endpoint/read-only context, then the follow-up action. No wasted text, though it is slightly short given the tool's 18-parameter surface.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a fairly complex query with 18 parameters and no output schema, the description covers purpose, read-only nature, endpoint, and return content well enough to invoke correctly. A brief note on result shape/limits would close the remaining gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% across all 18 parameters, including conditional notes such as the parts/duration interaction, so the schema carries the parameter burden. The description adds no additional parameter semantics, making the baseline 3 appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific resource and scope: available start times (intervals) for a service between two dates/times, listing what each result carries (free resources, group bookings with space). It is clear, but it never explicitly distinguishes itself from the sibling find_available_dates, so the interval-vs-date choice must be inferred.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives a concrete next step ('Use one of the returned start times with create_reservation'), which is useful downstream guidance. However, it offers no when-not or alternative-tool guidance, so the agent gets no help deciding between this and find_available_dates.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
find_customersFind customersARead-only
Search customers by part of their name, email, mobile or phone (UK numbers match with 0 or +44). The API has no search parameter, so this pages through the customer list (100 per call) up to max_pages. Names only by default; contact details with include_contact_details. Note that a match on an email or phone fragment still confirms that such a detail exists on the account.
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Name, email or phone fragment | |
| max_pages | No | Pages of 100 customers to scan | |
| max_results | No | ||
| include_contact_details | No | Include each match's email, mobile, phone, address and gender, and custom fields that look like contact data |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond readOnlyHint/openWorldHint, it discloses non-obvious behavior: 100 results per page scanned up to max_pages, and that a match on an email/phone fragment still confirms that detail exists on the account. This is real operational context (cost/latency and match semantics) not derivable from annotations, though it omits anything about rate limits or result ordering.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four tight sentences, front-loaded with the core search behavior followed by the paging constraint, the default projection, and a subtle caveat. Nothing is wasted and each sentence carries distinct information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description usefully explains what is and isn't returned (names vs. contact details on request) and how paging bounds the scan. The only omission is the role of max_results, which is undocumented in both the schema and the description.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Adds meaning beyond the 75% schema coverage: the 'query' parameter accepts name/email/phone fragments with the UK 0/+44 spelling rule, and 'include_contact_details' is explained as returning contact fields plus contact-like custom fields (what 'names only by default' means). It leaves 'max_results' unaddressed in both description and schema, a minor gap.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Starts with a specific verb+resource: 'Search customers by part of their name, email, mobile or phone.' It clearly distinguishes a multi-match search from the single-record sibling get_customer, and states the matching scope (name/email/phone fragments, UK number formats).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear context for when to use it (fragment search, with the UK 0/+44 matching rule) and explains the fallback strategy since 'the API has no search parameter, so this pages through the customer list.' It does not explicitly name get_customer as the direct-lookup alternative, which keeps it short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_customerGet a customerARead-only
One customer by ID: name, tags, marketing opt-in, custom fields and, unless max_bookings is 0, their bookings with the latest start first. Email, mobile, phone and address are only returned with include_contact_details.
| Name | Required | Description | Default |
|---|---|---|---|
| customer_id | Yes | Customer ID (24 hexadecimal characters) | |
| max_bookings | No | How many of the customer's bookings to include (0 for none) | |
| include_contact_details | No | Include the customer's email, mobile, phone, address and gender, custom fields that look like contact data, and their question answers on bookings |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare readOnlyHint and openWorldHint, so safety is already covered. The description goes further by disclosing return-behavior conditionals: bookings are included unless max_bookings is 0, ordered latest-start-first, and contact fields are suppressed unless include_contact_details is set. That is real behavioral context beyond the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single dense sentence that front-loads the core operation (one customer by ID) before the return-field details. No filler, though the packed clause structure is slightly taxing.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the burden of describing the response and does so adequately by listing returned fields and the conditional gating of contact data. Minor gaps remain (pagination, error behavior for an unknown ID), but the essential calling information is present.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description adds outcome-level semantics not in the schema: it links max_bookings=0 to the absence of bookings in the response and specifies the sort order (latest start first), which is genuinely new information.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('One customer by ID') and enumerates the returned fields, so an agent can immediately tell this is a single-record retrieval. It contrasts implicitly with the plural find_customers sibling but never names it, so sibling differentiation is not explicit.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'by ID' implies the precondition (you must already have the customer_id), which is implied usage guidance. However, it never states when to use this versus find_customers, and gives no exclusions or alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_serviceGet a serviceARead-only
One service by ID, with its booking settings (type, occupancy, durations and prices, buffers, group bookings) and booking questions.
| Name | Required | Description | Default |
|---|---|---|---|
| service_id | Yes | Service ID (24 hexadecimal characters) | |
| include_contact_details | No | Include emails and phone numbers typed into the name, description and question text |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=true, so the safety profile is covered. The description adds genuine behavioral value by disclosing what the record contains (booking settings, types, occupancy, durations/prices, buffers, group bookings, questions), which matters because there is no output schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence with the resource first and the return contents second; no filler or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description usefully enumerates what comes back, and annotations cover the read-only profile. It is close to complete for a simple 2-param lookup, though a hint about missing/not-found behavior would round it out.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, with both parameters documented including the 24-hex-char pattern and the include_contact_details semantics, so the schema does the heavy lifting. The description adds no extra parameter meaning, making the baseline 3 appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('One service by ID') and enumerates the returned facets (booking settings, buffers, group bookings, booking questions). It is clear, though it never distinguishes itself from the sibling list_services beyond the implied singular vs. plural.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied: the phrase 'by ID' signals a single-record lookup, and the sibling list_services implies the plural alternative, but there is no explicit when-to-use or when-to-prefer-list guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_bookingsList bookingsARead-only
Bookings with status, service, resource, times, price, spaces and participants (customer IDs, spaces, arrival status, source). Filter by a date range (after/before compare with the booking's start/end including buffers), creation or update time, status, service, category, resource, customer or booking IDs. Participants carry customer_id only; use get_customer for names. Customers' free-text answers and single-use reschedule links are withheld unless include_contact_details is set.
| Name | Required | Description | Default |
|---|---|---|---|
| after | No | Only bookings that start at or after this date/time (ISO 8601) | |
| start | No | ID of the first booking of the page to return: the next_start of a previous call | |
| before | No | Only bookings that end at or before this date/time (ISO 8601) | |
| status | No | Only bookings with this status (the API's statuses parameter, typed as one value) | |
| sort_by | No | Sort property (the API defaults to natural) | |
| order_by | No | Sort direction (the API defaults to descending) | |
| timezone | No | IANA timezone to return every date and time in; the documentation gives no default for this endpoint (its example shows +00:00 offsets) | |
| booking_ids | No | Only these bookings (the API's ids filter); the API has no single-booking endpoint, so use this to fetch one booking | |
| max_results | No | Maximum number of bookings to return | |
| service_ids | No | Only bookings for these services | |
| category_ids | No | Only bookings whose service is in one of these categories | |
| customer_ids | No | Only bookings with one of these customers on them | |
| resource_ids | No | Only bookings for these resources | |
| created_after | No | ||
| updated_after | No | ||
| created_before | No | ||
| updated_before | No | ||
| include_contact_details | No | Include participants' question answers as stored, and each participant's single-use reschedule link | |
| return_matching_customers_only | No | The API's return_matching_customers_only flag: only list the participants whose customer IDs were given in the filter (useful for large group bookings) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and openWorldHint, and the description adds non-obvious behaviour: free-text answers and single-use reschedule links are withheld unless include_contact_details is set. That data-exposure disclosure goes meaningfully beyond the annotations, though pagination/result-shape behaviour is only covered by the schema's 'start' parameter.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three dense but front-loaded sentences: return shape first, then filter dimensions, then the permission caveat. No filler, though the filter enumeration is a long run-on that could be tightened.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 19-parameter, no-required-argument list tool with no output schema, the description covers return fields, filter scope, and the sensitive-data gate. Remaining gaps (pagination via 'start', sort defaults) are documented in the schema itself.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 79%, but the description still adds real semantics: after/before are compared against the booking's start/end including buffers, and 'Participants carry customer_id only'. These clarify filter meaning beyond the ISO-8601 phrasing in the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description enumerates exactly what a booking record contains (status, service, resource, times, price, spaces, participants) and what can be filtered, so an agent knows this is the paginated booking-retrieval endpoint. It distinguishes itself from find_available_* siblings implicitly by being the only one returning bookings, but never names an alternative list tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied rather than stated: it tells the agent which filters exist and routes one sub-need ('use get_customer for names'), but gives no when-to-use vs when-not guidance or exclusions relative to siblings like find_available_intervals or list_services.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_resource_groupsList resource groupsARead-only
Resource groups (id and name), e.g. teams or locations that resources belong to. Useful as resource_group_id in the availability searches.
| Name | Required | Description | Default |
|---|---|---|---|
| start | No | ID of the first resource group of the page to return: the next_start of a previous call | |
| order_by | No | Sort direction (the API defaults to descending; the only sort property is natural) | |
| group_ids | No | Only these groups (the API's ids filter) | |
| max_results | No | Maximum number of groups to return | |
| include_contact_details | No | Include emails and phone numbers typed into group names |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=true, so the safety profile is covered. The description adds only that the result carries id and name; it says nothing about pagination behavior or the size/ordering characteristics of the result set, which the schema only partly covers.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two compact sentences, front-loaded with what a resource group is and followed by the practical usage hint. No filler, though the second sentence is thin enough that it could carry a bit more substance.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only list tool whose annotations cover the safety profile and whose schema fully documents parameters, the definition is nearly sufficient; it names the returned fields and the downstream identifier. Only pagination/ordering expectations are left implicit.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all five parameters (start, order_by, group_ids, max_results, include_contact_details) are already documented. The description adds no syntax or format detail beyond the schema, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource (list resource groups) and clarifies what a group is plus what is returned (id and name). It lacks explicit sibling differentiation beyond a passing mention of availability searches, but an agent can still tell what it retrieves.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
"Useful as resource_group_id in the availability searches" implies the downstream use case and loosely routes toward find_available_intervals/find_available_dates, but there is no explicit when-to-use or when-not framing, and no mention of alternatives for listing groups.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_resourcesList resources (staff, rooms)ARead-only
Resources in the organisation (staff members, rooms, equipment) with the services each is assigned to and its resource groups. Filter by service to see who can deliver it. A resource's email, phone and address are only returned with include_contact_details.
| Name | Required | Description | Default |
|---|---|---|---|
| start | No | ID of the first resource of the page to return: the next_start of a previous call | |
| sort_by | No | Sort property (the API defaults to natural) | |
| order_by | No | Sort direction (the API defaults to descending) | |
| max_results | No | Maximum number of resources to return | |
| service_ids | No | Only resources assigned to at least one of these services (the API's services filter) | |
| resource_ids | No | Only these resources (the API's ids filter) | |
| include_contact_details | No | Include each resource's email, phone and address, and stop redacting emails and phone numbers in names and descriptions |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare readOnly and openWorld, so safety is covered; the description adds valuable non-obvious behavior: email/phone/address are redacted unless include_contact_details is set, and names/descriptions are also redacted otherwise.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences, contents front-loaded, then filtering purpose, then the conditional-return caveat. No filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description usefully sketches the return shape (services, groups) and the conditional contact fields; pagination/sorting are left to the well-documented schema, a minor omission.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the schema already documents include_contact_details redaction and the service/ids filters; the description mostly restates this, adding only the intent of service filtering. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States the specific resource (staff, rooms, equipment) plus the enrichment returned (assigned services, resource groups), which cleanly separates it from list_services, list_resource_groups and find_customers siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a concrete use case (filter by service to find who can deliver it) and a prerequisite for contact data, but does not state when to prefer find_available_intervals/find_available_dates or any exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_service_categoriesList service categoriesCRead-only
Service categories (id and name) used to group services.
| Name | Required | Description | Default |
|---|---|---|---|
| start | No | ID of the first service category of the page to return: the next_start of a previous call | |
| max_results | No | Maximum number of categories to return | |
| category_ids | No | Only these categories (the API's ids filter) | |
| include_contact_details | No | Include emails and phone numbers typed into category names |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and openWorldHint, so the safety profile is covered. The description adds only the returned fields (id and name) and says nothing about pagination via start/max_results or the privacy implication of include_contact_details, which is the main non-obvious behavioral trait here.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single short, front-loaded sentence with no wasted words. It is efficient, though the brevity tips into under-specification rather than genuine conciseness.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only list tool with full schema coverage and annotations, the description is minimally adequate. It omits pagination guidance and sibling routing, but nothing critical to invocation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all four parameters are documented in the schema itself, including the cursor semantics of start. The description adds no parameter detail beyond the schema, which is the expected baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names the resource (service categories) and clarifies they group services and carry id and name. However it never states the verb 'list' and gives no differentiation from siblings like list_services or get_service, so an agent must infer the operation from the tool name alone.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no when-to-use guidance, no mention of when to prefer list_services or get_service, and no note that this is a paginated browse operation. Usage is only implied by the name.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_servicesList servicesARead-only
Services offered by this organisation: name, category, booking type, occupancy, durations with prices, buffers, and the booking questions asked. Emails and phone numbers in names, descriptions and question text are redacted unless include_contact_details is set.
| Name | Required | Description | Default |
|---|---|---|---|
| start | No | ID of the first service of the page to return: the next_start of a previous call | |
| max_results | No | Maximum number of services to return | |
| service_ids | No | Only these services (the API's ids filter) | |
| include_contact_details | No | Include emails and phone numbers typed into service names, descriptions and question text |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and openWorldHint, so the safety profile is covered. The description adds a genuinely non-obvious behavioral trait: contact details in names, descriptions, and question text are redacted unless include_contact_details is set. That redaction behavior is not derivable from the schema or annotations and is the kind of context this dimension rewards.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single dense sentence that front-loads the resource and the returned fields, with the redaction caveat placed last as a conditional. Every clause carries information; the only minor cost is that the field enumeration runs long.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description usefully enumerates the returned fields, and it discloses the redaction behavior an agent must know before interpreting results. Pagination via the start/next_start contract and the filter behavior are left to the schema, which is acceptable but leaves a small gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all four parameters are already documented (including start as next_start chaining and the ids filter semantics), establishing the baseline of 3. The description only reinforces the include_contact_details flag rather than adding format or range detail beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Names the resource (services) and enumerates the concrete fields returned (name, category, booking type, occupancy, durations with prices, buffers, booking questions), which is far more specific than a restatement of the title. It does not, however, distinguish itself from nearby siblings like get_service or list_service_categories.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description never says when to use this tool versus find_available_intervals, get_service, or list_service_categories. It implies bulk listing but offers no exclusions, prerequisites, or routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
10 tool updates
v0.1.0- First observed
find_available_dates - First observed
find_available_intervals - First observed
find_customers - First observed
get_customer - First observed
get_service - First observed
list_bookings - First observed
list_resource_groups - First observed
list_resources - First observed
list_service_categories - First observed
list_services
TDQS
Scored across 10 tools
Most tools have clearly distinct purposes: get_customer (single by ID) vs find_customers (search), and list_services vs get_service are well separated. The one near-pair, find_available_dates vs find_available_intervals, is explicitly distinguished in the descriptions (dates vs start times), so confusion risk is low.
All ten tools follow a consistent snake_case verb_noun pattern (find_*, get_*, list_*), and the verbs match the semantics (find for search, get for single fetch, list for collections). No style mixing.
Ten tools is well-scoped for a booking/availability API, with each tool covering a distinct resource or query (availability, customers, services, categories, resources, groups, bookings). Nothing feels redundant or bolted on.
The surface is essentially read-only: availability search plus listing/getting customers, services, resources, groups and bookings. No mutation operations exist even though find_available_intervals explicitly points users to create_reservation, implying booking creation (and cancel/reschedule/update) is a notable missing part of the lifecycle.
Maintenance
Related MCP Connectors
Read appointments, types, calendars and availability; create, cancel or reschedule bookings.
Find local services, read availability, and create short-lived booking holds.
Discover, read and book verified real-world businesses through one endpoint.
Discover local services and availability, then create, track, reschedule, or cancel bookings.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables natural language interaction with SimplyBook.me API to manage bookings, services, and performers through MCP.2-
- AlicenseAqualityDmaintenanceMCP server exposing a PostgreSQL booking datastore to MCP clients, enabling read/write operations on staff, schedules, clients, and bookings with optional human-approval workflow integration.5MIT
- AlicenseNot gradedqualityBmaintenanceProvides MCP tools for operations desk tasks including calendar availability, customer lookup, quote calculation, and notification sending. Includes an internal agentic orchestrator that consumes the same MCP tools via protocol.MIT
- AlicenseNot gradedqualityCmaintenanceExposes the Appointment Scheduler API to AI agents as an MCP server, enabling them to list users and services, check availability, book, list, and cancel appointments via natural language.Apache 2.0