Skip to main content
Glama
dragosh29

Appointedd MCP Server

by dragosh29

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

find_available_intervals

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.

POST /availability/intervals/search

find_available_dates

Dates with availability for a service between two dates/times. Also a POST that changes nothing.

POST /availability/days/search

list_services

Services with category, booking type, occupancy, durations and prices, buffers and booking questions; ids filter; range-paginated.

GET /services

get_service

One service.

GET /services/{id}

list_service_categories

Categories (id, name); ids filter.

GET /services/categories

list_resources

Staff, rooms and equipment with the services each is assigned to and its groups; services, ids, sort_by, order_by filters.

GET /resources

list_resource_groups

Resource groups (id, name); ids, order_by.

GET /resources/groups

list_bookings

Bookings with status, service, resource, times, price, spaces and participants; every documented filter (after/before, created_*, updated_*, statuses, ids, services, categories, customers, resources, return_matching_customers_only, timezone, sort_by, order_by); range-paginated. The API has no single-booking endpoint, so one booking is fetched with booking_ids.

GET /bookings

get_customer

One customer with tags, marketing opt-in and custom fields, plus their bookings with the latest start first unless max_bookings is 0.

GET /customers/{id}, GET /bookings?customers=…

find_customers

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.

GET /customers

create_reservation

Holds a start time for a service (and optionally a resource) for a few minutes so it cannot be double-booked. Writes only.

POST /availability/slots

create_booking

Turns a reservation into a booking with zero or more customers. Writes only.

POST /bookings

cancel_booking

Cancels a booking and every customer's place on it. Writes only, marked destructive.

POST /bookings/{id}/cancel

create_customer

Adds a customer (name, optional email, mobile, phone, tags). Writes only.

POST /customers

update_customer

Changes a customer's name, email, mobile, phone or tags (tags replace the existing ones). Writes only.

PUT /customers/{id}

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 build

You 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.js

Variable

Required

Meaning

APPOINTEDD_API_KEY

yes

Your organisation's API key, sent as the X-API-KEY header.

APPOINTEDD_ALLOW_WRITES

no

true to register create_reservation, create_booking, cancel_booking, create_customer and update_customer. Off by default.

APPOINTEDD_BASE_URL

no

Defaults to https://api.appointedd.com/v1. Used by the tests.

Safety defaults

  • Read-only unless APPOINTEDD_ALLOW_WRITES=true. Read tools carry the MCP readOnlyHint annotation, including the two availability searches, which are POSTs that change nothing; cancel_booking is marked destructive; update_customer is 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 of create_customer and update_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 as Date of birth, E-mail, homeAddress or nhsnumber) 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=true returns all of it as stored. The phone match is a heuristic: it covers international numbers written with + or 00 (including the +44 (0)7700 … form), UK numbers written with a bare 44 country code such as 448787981295 (the form Appointedd's own Create Customer example uses), UK numbers with a bracketed area code such as (020) 7946 0958, and UK-style 0… numbers of 9 to 11 digits with spaces, dots or hyphens between groups. Other digit strings that happen to start with 0 (an order number, say) are redacted too; 24-character hex IDs, timestamps and references such as LOY-0001 are 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 unless include_contact_details is 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_price and the paid flag are returned as the API gives them.

  • create_booking sends send_payment_request: false unless asked otherwise. The API's own default is true, 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}$), so 12345, ../customers or 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 the T (2026-10-05 09:00:00Z) or an impossible date such as 2026-02-30 (which Node's Date.parse would 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, or UTC) 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 the X-API-KEY header 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 for Retry-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 GET only; 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_bookings for a booking, find_customers/get_customer for 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 data list where a list endpoint documents one, is reported as an error naming APPOINTEDD_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/message text and the names of the invalid fields when the API lists them.

Tests

npm test

The test suite:

  1. 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.mjs fetches 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 into spec.json on 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.json is not committed, so the first npm test on 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.

  2. Starts a local mock of the API under /v1 that serves those fixtures with the documented range-based pagination (limit, start = the previous page's next, end = the previous page's prev; data, total, prev, next out; 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 first GET /resources/groups with 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.

  3. 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: null with start carrying the previous next and limit what is still wanted, max_results with an exact continuation (following next_start yields every booking exactly once), every documented list_bookings filter passed through exactly (array filters as the key repeated once per value), sort_by/order_by on bookings, resources and groups, the ids and services filters, local refusal of an inverted range, malformed dates (including 2026-02-30 and 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 as dateOfBirth, E-mail, homeAddress and nhsnumber), emails and phone numbers in tags, names, descriptions, group names, question labels, options and answers (the +44 (0)…, bare 44…, 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_customers matching name, email and UK phone forms across three pages, both availability searches with their bodies validated against the spec's request schemas (including resource_group_ids sent as a single string, parts, buffers, spaces and every ignore_* flag), create_reservation, create_booking (with and without customers, send_payment_request false by default), cancel_booking, create_customer and update_customer with 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 for Retry-After in the seconds, fractional-seconds and HTTP-date forms, giving up after three attempts on a persistent 429 and at once on a Retry-After above the cap, a 429 on POST /bookings retried once, a gateway error (502/503/504) retried for GET and never for POST /bookings, POST /availability/slots, the availability searches or a PUT, a GET failing three times with 503 reported with advice and without the gateway HTML, a 200 with a non-JSON body or with JSON whose data is 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 to false, the 401 message, the server refusing to start without a key, and that every request used the X-API-KEY header, application/json for 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 next is null or absent on the last page (the client treats both, and an empty string, as the end); whether total counts the filtered set, as the Pagination page says ("matches your current request"); what the API answers for a start ID that no longer exists (the mock answers an empty page); and what the default sort_by=natural with order_by=descending means in practice (the server keeps whatever order the API returns and passes the sort parameters through).

  • Query arrays: the spec types ids, services, categories, customers and resources as 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: statuses is 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_only is documented against "the IDs in the ids query parameter" although it clearly concerns customers, and is passed through as is; and whether after/before compare with start_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_ids is typed as a single string although its description says "one or more", so the tool takes one resource_group_id and sends it as that string. The default result timezone is documented as Europe/London for the searches and for a reservation's start, and as UTC for POST /bookings (Create Booking) only; GET /bookings documents no default (its example shows +00:00 offsets). The server passes timezone through and converts nothing.

  • POST /bookings: the spec's request schema has data.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 singular data.customer. Whether send_payment_request: false suppresses 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 a duration property on the reservation data that the schema does not list, so the server does not send it (parts covers the same need). A 429 on this endpoint or on POST /bookings is 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[].price is typed as an integer and the booking price/total_price as numbers (example 0.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 tools
find_available_datesFind available datesA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
toYesEnd of the range to search (ISO 8601), after from
fromYesStart of the range to search (ISO 8601)
partsNoParts of the potential booking (block = booked time, free = gap); when given, duration is ignored. Omit to use the service's own duration or parts
spacesNoSpaces required (excludes group bookings with fewer spaces left); the API defaults to 1
buffersNoMinutes before/after a potential booking that must be free; omit to use the service's buffers
durationNoMinutes that must be free from the start of an interval; omit to use the service's default duration
timezoneNoIANA timezone to return the results in; the API defaults to Europe/London
service_idYesService ID (24 hexadecimal characters)
max_resultsNoMaximum number of intervals to return
resource_idsNoOnly these resources; omit for every resource assigned to the service
ignore_bookingsNoBooking IDs to ignore for this search (they neither block availability nor count as available group bookings)
resource_group_idNoOnly 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_settingNoReturn group bookings with space even if online group bookings are off
ignore_past_restrictionNoDo not exclude times before now
ignore_service_scheduleNoIgnore the service's schedule
ignore_notice_restrictionNoIgnore the organisation's and service's notice-period settings
ignore_service_assignmentNoDo not fail when a resource is not assigned to the service

TDQS

A3.8/5.0
Behavior3/5

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.

Conciseness4/5

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.

Completeness3/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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 timesA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
toYesEnd of the range to search (ISO 8601), after from
fromYesStart of the range to search (ISO 8601)
partsNoParts of the potential booking (block = booked time, free = gap); when given, duration is ignored. Omit to use the service's own duration or parts
spacesNoSpaces required (excludes group bookings with fewer spaces left); the API defaults to 1
buffersNoMinutes before/after a potential booking that must be free; omit to use the service's buffers
durationNoMinutes that must be free from the start of an interval; omit to use the service's default duration
timezoneNoIANA timezone to return the results in; the API defaults to Europe/London
service_idYesService ID (24 hexadecimal characters)
max_resultsNoMaximum number of intervals to return
resource_idsNoOnly these resources; omit for every resource assigned to the service
ignore_bookingsNoBooking IDs to ignore for this search (they neither block availability nor count as available group bookings)
resource_group_idNoOnly 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_settingNoReturn group bookings with space even if online group bookings are off
ignore_past_restrictionNoDo not exclude times before now
ignore_service_scheduleNoIgnore the service's schedule
ignore_block_restrictionNoIgnore the organisation's 'block after' setting
ignore_notice_restrictionNoIgnore the organisation's and service's notice-period settings
ignore_service_assignmentNoDo not fail when a resource is not assigned to the service

TDQS

A3.7/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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 customersA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
queryYesName, email or phone fragment
max_pagesNoPages of 100 customers to scan
max_resultsNo
include_contact_detailsNoInclude each match's email, mobile, phone, address and gender, and custom fields that look like contact data

TDQS

A4.4/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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 customerA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
customer_idYesCustomer ID (24 hexadecimal characters)
max_bookingsNoHow many of the customer's bookings to include (0 for none)
include_contact_detailsNoInclude the customer's email, mobile, phone, address and gender, custom fields that look like contact data, and their question answers on bookings

TDQS

A3.8/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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 serviceA
Read-only

One service by ID, with its booking settings (type, occupancy, durations and prices, buffers, group bookings) and booking questions.

ParametersJSON Schema
NameRequiredDescriptionDefault
service_idYesService ID (24 hexadecimal characters)
include_contact_detailsNoInclude emails and phone numbers typed into the name, description and question text

TDQS

A3.8/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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 bookingsA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
afterNoOnly bookings that start at or after this date/time (ISO 8601)
startNoID of the first booking of the page to return: the next_start of a previous call
beforeNoOnly bookings that end at or before this date/time (ISO 8601)
statusNoOnly bookings with this status (the API's statuses parameter, typed as one value)
sort_byNoSort property (the API defaults to natural)
order_byNoSort direction (the API defaults to descending)
timezoneNoIANA timezone to return every date and time in; the documentation gives no default for this endpoint (its example shows +00:00 offsets)
booking_idsNoOnly these bookings (the API's ids filter); the API has no single-booking endpoint, so use this to fetch one booking
max_resultsNoMaximum number of bookings to return
service_idsNoOnly bookings for these services
category_idsNoOnly bookings whose service is in one of these categories
customer_idsNoOnly bookings with one of these customers on them
resource_idsNoOnly bookings for these resources
created_afterNo
updated_afterNo
created_beforeNo
updated_beforeNo
include_contact_detailsNoInclude participants' question answers as stored, and each participant's single-use reschedule link
return_matching_customers_onlyNoThe 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

A3.8/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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 groupsA
Read-only

Resource groups (id and name), e.g. teams or locations that resources belong to. Useful as resource_group_id in the availability searches.

ParametersJSON Schema
NameRequiredDescriptionDefault
startNoID of the first resource group of the page to return: the next_start of a previous call
order_byNoSort direction (the API defaults to descending; the only sort property is natural)
group_idsNoOnly these groups (the API's ids filter)
max_resultsNoMaximum number of groups to return
include_contact_detailsNoInclude emails and phone numbers typed into group names

TDQS

A3.5/5.0
Behavior3/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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)A
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
startNoID of the first resource of the page to return: the next_start of a previous call
sort_byNoSort property (the API defaults to natural)
order_byNoSort direction (the API defaults to descending)
max_resultsNoMaximum number of resources to return
service_idsNoOnly resources assigned to at least one of these services (the API's services filter)
resource_idsNoOnly these resources (the API's ids filter)
include_contact_detailsNoInclude each resource's email, phone and address, and stop redacting emails and phone numbers in names and descriptions

TDQS

A4.2/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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 categoriesC
Read-only

Service categories (id and name) used to group services.

ParametersJSON Schema
NameRequiredDescriptionDefault
startNoID of the first service category of the page to return: the next_start of a previous call
max_resultsNoMaximum number of categories to return
category_idsNoOnly these categories (the API's ids filter)
include_contact_detailsNoInclude emails and phone numbers typed into category names

TDQS

C2.7/5.0
Behavior2/5

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.

Conciseness4/5

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.

Completeness3/5

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.

Parameters3/5

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.

Purpose3/5

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.

Usage Guidelines2/5

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 servicesA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
startNoID of the first service of the page to return: the next_start of a previous call
max_resultsNoMaximum number of services to return
service_idsNoOnly these services (the API's ids filter)
include_contact_detailsNoInclude emails and phone numbers typed into service names, descriptions and question text

TDQS

A3.5/5.0
Behavior4/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines2/5

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.

  1. 10 tool updatesv0.1.0
    • First observedfind_available_dates
    • First observedfind_available_intervals
    • First observedfind_customers
    • First observedget_customer
    • First observedget_service
    • First observedlist_bookings
    • First observedlist_resource_groups
    • First observedlist_resources
    • First observedlist_service_categories
    • First observedlist_services

TDQS

A3.6/5.0

Scored across 10 tools

Disambiguation4/5

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.

Naming Consistency5/5

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.

Tool Count5/5

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.

Completeness3/5

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

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    MCP 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.
    5
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Exposes 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