FastMCP server for voice assistant integration with BarberControl appointment system. Enables external voice agents to check availability and book appointments.
The server provides 4 tools with basic descriptions and input schemas, but significant quality gaps prevent higher scoring. All tools have descriptions (good baseline), but they lack specificity on return formats, error handling guidance, and parameter constraints. Naming is verb-first (get_, check_, book_) which is correct. However, descriptions are often generic, parameter descriptions are minimal, and output schemas are not formally documented. The tools operate on a booking domain (barbers, appointments) which is coherent, but the implementation lacks the polish expected for production use. No tool annotations (readOnlyHint, destructiveHint, idempotentHint) despite having clear READ_ONLY and WRITE semantics. Error handling is basic, errors return string messages with no structured guidance or recovery paths.
Book an appointment for a client with a barber. Automatically sends push notification to the barber. Enforces 2-client-per-hour limit.
Check availability for a specific barber on a specific date. Shows time slots and how many appointments are already booked per slot (max 2 per slot).
Get available time slots across a date range (useful for finding next available appointment). Shows slots with remaining capacity for each date.
Get list of all barbers in the system. Returns barber details including name, email, and phone.
No formal output schema documentation. All tools return unstructured strings (e.g., 'Found N barber(s):\n\n- Name...'). LLMs cannot reliably parse or chain results. Return types should be documented as structured JSON objects or arrays.
Missing tool annotations. Tools clearly have READ_ONLY semantics (get_*, check_*) and WRITE semantics (book_appointment), but no readOnlyHint or destructiveHint attributes. This prevents the client from enforcing safety policies.
Parameter descriptions are too generic. 'UUID of the barber', 'Date in YYYY-MM-DD format' lack context on why the parameter matters or what to do if it's invalid. Example: check_barber_availability date param says 'Date in YYYY-MM-DD format (e.g., "2025-01-15")' but does not explain what happens if the date is in the past, or how far ahead bookings are allowed.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | C | 61 | 2026-07-28+ | v2 |
| 2026-03-09 | F | 7 | - | v1 |
Error handling returns raw exception strings with no recovery guidance. Example: 'Error fetching barbers: ...' or 'Error checking availability: ...'. Per pattern:recovery-guide, errors should tell the LLM what to do next. E.g., 'Barber not found. Available barber IDs: [...]' or 'Invalid date format. Use YYYY-MM-DD. Example: 2025-01-15'.
book_appointment combines multiple concerns: validation, booking, AND push notification. This violates single-responsibility. If the push fails, does the booking rollback? Consider splitting into create_appointment (idempotent booking) and separately handle notifications via a side-channel.
No idempotency guidance. book_appointment performs WRITE operations (creates appointments, sends notifications). If the LLM retries due to a transient error, will it double-book? No description states whether the call is idempotent. Per pattern:idempotent-operation, critical WRITE tools must document retry behavior.
No pagination or result limits on get_barbers or get_available_slots. If a barbershop has hundreds of barbers or months of availability, response context explosion risks LLM degradation. Per pattern:paginated-result, list tools must support limit/offset and return a total count.
Parameter 'client_email' in book_appointment is optional with no default behavior described. Does the system require an email to send confirmations? Will bookings silently fail if email is missing? Undocumented parameter dependencies confuse LLM usage.
No natural-identifier support. Tools require 'barber_id' (UUID), not barber names. Users say 'Check Jack's availability', but the tool needs a UUID. Per pattern:natural-identifiers, tools should accept human-readable names and resolve them internally.