Skip to main content
Glama
cotletdev

Fresha MCP Server

Fresha API and MCP server, self-hosted

A Fresha API and a Fresha MCP server you run on your own computer, in Python, on the session of your own Google Chrome. All 17 Fresha tools we run in production at Cotlet: appointments, free slots, booking, rescheduling and cancelling, blocked time, clients and client notes, services and team, the Sales summary and Sales list reports, and reviews with replies.

Fresha has no public API and no official MCP server. Its only data connection is the paid Data Connector add-on, which copies your data out to a Snowflake database and cannot book anything. This repo gives you:

  • MCP server for Claude Code, Claude Desktop, Cursor, Codex and any MCP client, over stdio or HTTP. Setup

  • REST API on http://127.0.0.1:8787/api/v1/fresha, with OpenAPI docs at /docs. Setup

  • Python: call("list_appointments", {"from": "2026-10-27", "to": "2026-10-27"}), plus 9 ready scripts in examples/.

It is for technical people who want to run it themselves, for noncommercial use only (license). If you want it running 24/7 on a server, kept working when Fresha changes its panel, for a team or a business, use the hosted version at cotlet.dev.

Fresha MCP server Python 3.11+ License: PolyForm Noncommercial 1.0.0

git clone https://github.com/cotletdev/fresha-api-mcp-server.git && cd fresha-api-mcp-server
python3 -m venv .venv && . .venv/bin/activate && pip install -e .
fresha-mcp connect                                 # reads your Fresha session from Chrome
fresha-mcp call list_services
claude mcp add fresha -- "$PWD/.venv/bin/fresha-mcp" mcp

Contents

Related MCP server: salonrunner-mcp

How it works

AI agent (MCP) / script (REST, Python) ──▶ fresha-mcp on your computer ──your cookies──▶ *.fresha.com
                                                  ▲
                         fresha-mcp connect ──────┘ reads them once from your Chrome (DevTools Protocol)
  1. You sign in to Fresha for business in your own Chrome at partners.fresha.com, the way you always do: an email code, then a text message code. Tick Trust this device.

  2. fresha-mcp connect attaches to that Chrome through the Chrome DevTools Protocol, reads the fresha.com cookies and saves them to ~/.config/fresha-api-mcp/session.json, readable by your user only. It never sees or stores your password or the codes.

  3. Every tool call is a request to the APIs the Fresha partner panel itself calls (partners-api, the partners-api-gateway GraphQL, customers-api, reports.fresha.com and a few more *.fresha.com hosts) with those cookies, sent with curl_cffi, which copies Chrome's TLS fingerprint. No headless browser runs.

The session lives in one cookie, fresha_partners_session. Fresha keeps it for 25 days and renews it while you use the panel or the tools. When Fresha signs you out, the server reads the cookies from Chrome again, if Chrome is open with remote debugging on.

Requirements

  • Python 3.11 or newer.

  • Google Chrome 144 or newer, signed in to partners.fresha.com. Any Chrome or Chromium works with a debugging port.

  • macOS, Linux or Windows.

  • A Fresha for business account. We build and test with the workspace owner. A team member login sees what Fresha shows that team member, and the two sales tools need its reporting permissions.

Install

git clone https://github.com/cotletdev/fresha-api-mcp-server.git
cd fresha-api-mcp-server
python3 -m venv .venv
. .venv/bin/activate              # Windows: .venv\Scripts\activate
pip install -e .
fresha-mcp --version

With uv: uv venv && uv pip install -e ., then uv run fresha-mcp ....

Setting it up with an AI agent (Claude Code, Codex, Cursor)? Open it in this folder and ask it to set up the repo: AGENTS.md tells it every step, and it asks you only for the steps in Chrome.

To update: git pull && pip install -e .. We copy every change of the hosted Fresha tools into this repo.

Connect your Chrome

  1. Open chrome://inspect/#remote-debugging in Chrome and switch remote debugging on. Chrome then accepts DevTools connections from programs on this computer, and asks you before each one.

  2. Make sure you are signed in at partners.fresha.com.

  3. Run:

    fresha-mcp connect
  4. Chrome asks whether to allow the connection. Click Allow.

Saved 24 Fresha cookies to /Users/you/.config/fresha-api-mcp/session.json
Signed in to Fresha as Daniel Hughes (daniel@example.com)

You can switch remote debugging off again afterwards. Leave it on if you want the server to pick up a new session by itself after Fresha signs you out.

connect looks for Chrome's DevToolsActivePort file in the default profile folder. For Chrome Beta, Canary or a custom profile folder, pass --profile-dir "<folder>".

Option B: a Chrome with a debugging port

Chrome does not open a debugging port on your default profile, so start a separate one, sign in to Fresha there once, and connect to it:

# macOS
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" --remote-debugging-port=9222 --user-data-dir="$HOME/.chrome-fresha"
# Linux
google-chrome --remote-debugging-port=9222 --user-data-dir="$HOME/.chrome-fresha"
# Windows
"C:\Program Files\Google\Chrome\Application\chrome.exe" --remote-debugging-port=9222 --user-data-dir="%USERPROFILE%\.chrome-fresha"

fresha-mcp connect --cdp http://127.0.0.1:9222

--cdp also takes a ws:// DevTools URL, for example of a Chrome on another machine reached over an SSH tunnel.

For a server with no Chrome: in Chrome open DevTools on partners.fresha.com, Application > Cookies > https://partners.fresha.com, copy the value of fresha_partners_session, then:

fresha-mcp connect --token          # paste it, input is hidden
# or, without a session file:
export FRESHA_AUTH_TOKEN=...

A pasted cookie is not read again from Chrome. Paste a new one when Fresha signs you out.

Check the session at any time:

fresha-mcp status

MCP server

The MCP server lists every tool with its input schema, a description written for agents, and hints. Read tools are marked read-only, and the tools that can reach clients (booking, rescheduling, cancelling, review replies) are marked so your client asks before running them.

Claude Code

claude mcp add fresha -- /path/to/fresha-api-mcp-server/.venv/bin/fresha-mcp mcp
# read only:
claude mcp add fresha -- /path/to/fresha-api-mcp-server/.venv/bin/fresha-mcp mcp --read-only

Claude Desktop

~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):

{
  "mcpServers": {
    "fresha": {
      "command": "/path/to/fresha-api-mcp-server/.venv/bin/fresha-mcp",
      "args": ["mcp"]
    }
  }
}

Cursor

~/.cursor/mcp.json, the same block as Claude Desktop. A ready copy is in mcp.json.

Codex

~/.codex/config.toml:

[mcp_servers.fresha]
command = "/path/to/fresha-api-mcp-server/.venv/bin/fresha-mcp"
args = ["mcp"]

Over HTTP

fresha-mcp serve also serves MCP over streamable HTTP at http://127.0.0.1:8787/mcp, for clients that take a URL:

fresha-mcp serve
claude mcp add --transport http fresha http://127.0.0.1:8787/mcp

Then ask your agent things like:

Anna Smith emailed asking for a cut and colour with Sam on Friday afternoon. Find her, check the free times for both services and book the first one after my OK.

Sam is sick tomorrow. Block his day and show me which of his clients a colleague can take at the same time.

Yesterday's sales by sale type against the same day last week. Flag refunds over £50.

List the reviews without a reply and draft a short answer to each.

REST API

fresha-mcp serve                   # http://127.0.0.1:8787, MCP at /mcp, docs at /docs

Each tool has its own route under /api/v1/fresha, the same paths as the hosted API at cotlet.dev, so code written against one works with the other. Path parts and the query string are arguments, and a JSON body adds the rest.

curl 'http://127.0.0.1:8787/api/v1/fresha/services'
curl 'http://127.0.0.1:8787/api/v1/fresha/appointments?from=2026-10-27&to=2026-10-31'
curl 'http://127.0.0.1:8787/api/v1/fresha/sales-summary?from=2026-10-01&to=2026-10-31'
curl -X POST http://127.0.0.1:8787/api/v1/fresha/blocked-times \
  -H 'Content-Type: application/json' \
  -d '{"team_member_id": "5652945", "start_at": "2026-11-03T13:00", "end_at": "2026-11-03T14:00", "title": "Lunch"}'

Any tool by name, body as its arguments:

curl -X POST http://127.0.0.1:8787/api/v1/fresha/tools/list_clients -d '{"search": "smith"}'
  • GET /api/v1/fresha/tools: every tool with its route, input schema and an example answer.

  • GET /docs: interactive OpenAPI docs, GET /openapi.json the schema, for n8n, Postman or a generated client.

  • Answers are JSON. List tools return next_cursor; pass it back as cursor for the next page.

The server listens on 127.0.0.1 only. To reach it from another device of yours, set a token, and every request then needs Authorization: Bearer <token>:

FRESHA_MCP_TOKEN=$(openssl rand -hex 24) fresha-mcp serve --host 0.0.0.0

Python and the example scripts

Straight from Python, no server needed:

from fresha_api_mcp import call
from fresha_api_mcp.scripting import paginate, write_rows

services = call("list_services")["services"]
day = call("list_appointments", {"from": "2026-10-27", "to": "2026-10-27"})["appointments"]
clients = list(paginate("list_clients", {"sort": "name"}, "clients"))
write_rows(clients, "clients.csv")
call("add_blocked_time", team_member_id="5652945", start_at="2026-11-03T13:00", end_at="2026-11-03T14:00")

Or one tool from the shell: fresha-mcp call find_available_slots service_ids='["25979401"]' date=2026-10-27 days=3, or with a JSON object. An ID stays text where the tool takes text.

Times are wall clock in the business's time zone. 2026-11-03T14:30 means 14:30 at the salon. A time with an offset is converted to it, and answers carry time_zone.

Ready scripts in examples/. Each prints JSON or a short list, takes --out file.csv or --out file.json where it makes sense, and --help:

Script

What it does

tomorrows_appointments.py

Tomorrow's appointments grouped by team member. --date, --all for cancelled ones too.

book_from_message.py

Matches a client by name, email or phone, finds free starts for several services in a time window, and with --book books the first after you confirm.

team_member_out.py

A team member is out: blocks their hours and moves each client to a colleague free at the same time. Prints the plan; --apply asks before each change.

cancel_day.py

Cancels a team member's appointments on a day with your cancellation reason. Lists them; --apply asks before each one.

daily_sales.py

One day's Sales summary by sale type against the same weekday a week earlier, refunds over a limit flagged.

lapsed_clients.py

Clients with no appointment for N days and nothing booked, with their marketing consent. --email-consent-only.

export_clients.py

Every client to CSV or JSON. --search, --sort.

export_sales.py

The Sales list for a date range to CSV or JSON.

unanswered_reviews.py

Reviews without a reply, lowest rating first; --reply-to posts a reply.

python examples/tomorrows_appointments.py
python examples/team_member_out.py --team-member-id 5652945 --date 2026-10-30 --block 09:00-18:00
python examples/lapsed_clients.py --days 90 --out lapsed.csv

On a schedule, cron on your own computer works while it is on: 0 8 * * * cd ~/fresha-api-mcp-server && .venv/bin/python examples/daily_sales.py.

All 17 tools

IDs come from the list tools: service_id from list_services, team_member_id from list_team_members, client_id from list_clients, appointment_id from list_appointments, review_id from list_reviews. fresha-mcp tools prints this list, fresha-mcp tools --json adds the input schemas.

Appointments

Tool

Access

REST route

What it does

list_appointments

read

GET /appointments

Appointments in a date range, with client, service, team member, price and status.

get_appointment

read

GET /appointments/{appointment_id}

One appointment: client, services, team member, times, status, price and notes.

find_available_slots

read

GET /available-slots

Free start times for one or more services with a team member, day by day.

create_appointment

write

POST /appointments

Book an appointment for a client: services, team member and start time.

reschedule_appointment

write

POST /appointments/{appointment_id}/reschedule

Move an appointment to a new start time, optionally to another team member.

cancel_appointment

write

POST /appointments/{appointment_id}/cancel

Cancel an appointment without a charge, optionally telling the client.

add_blocked_time

write

POST /blocked-times

Block a time slot in a team member's calendar so nobody books it.

Clients

Tool

Access

REST route

What it does

list_clients

read

GET /clients

Clients of the business, searchable by name, email or phone.

get_client

read

GET /clients/{client_id}

One client: contact, notification settings, booking stats, upcoming appointments, notes.

add_client

write

POST /clients

Add a client to the business's client list.

add_client_note

write

POST /clients/{client_id}/notes

Add a note to a client's profile, seen by the team only.

Catalogue and team

Tool

Access

REST route

What it does

list_services

read

GET /services

Services of the business with category, duration and price.

list_team_members

read

GET /team-members

Team members with role, contact, services they do and whether they take bookings.

Sales

Tool

Access

REST route

What it does

get_sales_summary

read

GET /sales-summary

Sales summary for a period: sales, refunds, discounts, taxes and payments by type.

list_sales

read

GET /sales

Sales (invoices) in a date range: number, date, client, status and totals.

Reviews

Tool

Access

REST route

What it does

list_reviews

read

GET /reviews

Client reviews of the business with rating, text and replies.

reply_to_review

write

POST /reviews/{review_id}/replies

Post a public reply to a client's review.

create_appointment lets Fresha send its booking confirmation by the client's notification settings; the tool has no switch for it. reschedule_appointment and cancel_appointment tell the client unless you pass notify_client: false. A review reply is public and the reviewer is told. Adding a client, a note or blocked time sends nothing. In list_appointments the status, team member and client filters apply to the first 100 rows of the date range, so narrow the dates for a busy salon.

Not in this version: payouts and the wallet (Fresha Payments), checkout and refunds, products, gift cards, memberships, the waitlist, marketing campaigns and shifts. create_appointment takes no appointment note, add_blocked_time blocks one day with no repeats, and cancel_appointment refuses an appointment with a cancellation fee or a paid deposit.

Never built, on purpose: your Fresha sign-in, email, password and user account, and anything that moves money (subscription, billing, payouts, payment methods). Every request passes a guard that refuses any change to those Fresha paths.

Configuration

Variable

Default

What it does

FRESHA_MCP_HOME

~/.config/fresha-api-mcp

Folder of session.json.

FRESHA_AUTH_TOKEN

The fresha_partners_session cookie value, used instead of session.json.

FRESHA_PROXY

Proxy for every request to Fresha, e.g. http://user:pass@host:port.

FRESHA_MCP_READ_ONLY

1 hides and refuses every tool that changes Fresha (same as --read-only).

FRESHA_MCP_TOKEN

Bearer token required by serve; needed to listen beyond 127.0.0.1.

FRESHA_MCP_HOST, FRESHA_MCP_PORT

127.0.0.1, 8787

Address of serve.

Security and your Fresha account

  • Your password never reaches this code. Only the cookies Chrome already holds are read, and only those of fresha.com.

  • The session file is yours. session.json is created with mode 0600. Anyone who has it can act as you in Fresha for business, so keep it out of git and shared folders.

  • Local by default. serve binds to 127.0.0.1 and refuses another address without FRESHA_MCP_TOKEN.

  • fresha.com only. Requests and redirects outside fresha.com are refused.

  • Read-only mode. --read-only or FRESHA_MCP_READ_ONLY=1 exposes the 10 read tools only.

  • Actions reach real people. A booking, a move or a cancellation can message your client, and a review reply is public. MCP clients ask before running those tools; a script does not, so try it on a test client of your own first.

Errors

The REST API answers {"error": "<code>", "message": "..."}. The MCP server returns the same code and message as a tool error.

Status

Code

What to do

401

auth_required, auth_expired

No session, or Fresha signed you out. Sign in at partners.fresha.com in Chrome and run fresha-mcp connect.

403

app_permission_denied

Your Fresha role cannot do this, e.g. reports without the reporting permissions.

403

scope_denied

The server runs read-only, or the request would change your Fresha account itself.

403

target_blocked

Fresha refused the request or showed a bot check. Open the panel in Chrome once, then retry.

409

captcha_required

Fresha asks for a CAPTCHA. Solve it in Chrome.

422

invalid_input

An argument is missing or wrong; the message names it.

429

rate_limited

Fresha is limiting the account. Wait a few minutes.

502

target_error

Fresha answered with an error (its own message is in message), or changed its panel. git pull for the latest tools, or open an issue.

Self-hosted or hosted

This repo

Cotlet, hosted

Tools

the same 17

the same 17

Runs

on your computer, while it is on

in the cloud, 24/7

Fresha session

your Chrome, saved in a local file

your own Cloud Browser in the EU, profile encrypted with AES-256-GCM

When Fresha changes its panel

git pull once we have fixed it

fixed for you, every tool tested daily

Approvals

your MCP client asks per call

bookings, moves, cancellations and review replies wait for your OK, switchable per tool

Works with

MCP clients on your machine, local scripts

Claude.ai and ChatGPT connectors, n8n, Make, Zapier, any HTTP client

Who may use it

you, for noncommercial use

teams, businesses, agencies

Price

free

free 7-day trial with 2,000 credits, no card; then one-time packs from $29 for 5,000 credits

On the hosted version a successful call uses 10 credits, failed calls are free, and the Cloud Browser uses 50 credits a day while it has an app enabled for agents. Full pricing.

FAQ

Does Fresha have an official API? No public one. Fresha publishes no API and no developer docs (checked 11 Oct 2026). Its Data Connector add-on, paid per location, syncs your data out to reporting tools through a Snowflake connection, and it cannot book, move or cancel appointments. Details: cotlet.dev/integrations/fresha-api-mcp-server.

Is there a Fresha MCP server for Claude, ChatGPT or Cursor? Yes, this one runs on your machine: fresha-mcp mcp for Claude Code, Claude Desktop, Cursor and Codex. ChatGPT and Claude.ai connectors need a public HTTPS URL, which the hosted Fresha MCP server gives you. A community server on GitHub reads Data Connector tables from Snowflake; it needs the add-on and does not write anything.

Do I need the Data Connector add-on? No. The tools work on your own partners.fresha.com session, the same requests the panel sends.

Can it find free slots and book for me? find_available_slots returns the free start times for one or more services done back to back, with one team member, for up to 14 days. create_appointment books one of them. Fresha books over other appointments if you ask it to, so check the slot first.

Can I export my Fresha clients or sales to CSV? Yes: python examples/export_clients.py --out clients.csv and python examples/export_sales.py --from 2026-10-01 --to 2026-10-31 --out sales.csv.

Does it work outside the UK? Yes. The tools read the time zone and currency of your workspace from Fresha. With several locations, the calendar tools use the first one.

Why does it need my Chrome? To read your Fresha session without your password and the two sign-in codes. Chrome is used once per sign-in, not for each call.

What happens when Fresha signs me out? Calls fail with auth_expired. With Chrome remote debugging on, the server reads the new session on the next call (click Allow when Chrome asks). Otherwise run fresha-mcp connect again.

Can it run on a VPS or in Docker? Technically yes, with a pasted cookie or a session.json copied from your computer. Fresha then sees your session from a datacenter IP, which looks less like you. For an always-on setup the hosted version keeps your session in your own Cloud Browser on a fixed IP.

Will my Fresha account get banned? Requests carry Chrome's fingerprint and go out one at a time, as you would click. Nobody can promise a platform never acts. Keep to your normal use.

Can I use it for my salon or for my clients? No. The license allows noncommercial use only, and running your own business counts as business use. For a salon, a team or client work, use Cotlet or write to contact@cotlet.dev.

Can I use the code for anything I like? No. The source is public, but the license allows noncommercial use only: no business use.

A tool broke or I need another one. Open an issue with the tool name and the error message.

License

PolyForm Noncommercial License 1.0.0. In short:

  • Allowed: noncommercial use: you, for your own personal purposes with your own Fresha account, or a charity, school, public research or government body. Changing the code, and sharing it under the same license.

  • Not allowed: any commercial use, your own business included; client work; selling or offering it, or a service built on it.


Maintained by Cotlet (@cotletdev). Fresha is a trademark of its owner. This project is unofficial and not affiliated with, endorsed or sponsored by Fresha.

Available Tools

17 tools
add_blocked_timeAdd blocked timeAInspect

Block a time slot in a team member's calendar so nobody books it.

Adds blocked time as Add > Blocked time in the calendar does: one block on one day for one team member, with a title and a note for the team. It does not repeat. Clients cannot book it online unless allow_online_booking is true. Nobody is told.

ParametersJSON Schema
NameRequiredDescriptionDefault
titleNoReason shown on the calendar, e.g. Lunch.
end_atYesEnd on the same day. ISO 8601 like start_at.
start_atYesStart, ISO 8601: 2026-11-03T14:30 is wall clock in the business's time zone; with an offset (2026-11-03T14:30:00+01:00) it is converted.
descriptionNoNote your team sees on the block.
team_member_idYesTeam member id from list_team_members.
allow_online_bookingNoClients may still book this time online. Default: false.

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations (readOnly=false, idempotent=false, destructive=false), the description discloses concrete side effects: single non-recurring block, one day only, no notification sent to anyone, and client bookability gated by allow_online_booking. It does not cover edge behavior such as overlapping an existing appointment or validation failures, which keeps it off a 5.

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?

Two short sentences in the first paragraph carry the core purpose and scope, followed by a compact paragraph of behavioral caveats. No filler, no restatement of the title, and the most important constraint (blocks booking) is front-loaded.

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 six-parameter mutation with no output schema, the description covers purpose, scope limits, notification behavior, and the booking flag — enough to invoke it correctly. The remaining gap is what a caller gets back and how conflicts with existing appointments are handled.

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 baseline is 3; the description still adds intent-level meaning by framing the record as 'one block on one day for one team member' (constraining end_at to the same day) and explaining the practical consequence of allow_online_booking rather than just its default. The 'title and a note for the team' phrasing also clarifies the split between title and description.

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?

Opens with a specific verb and resource plus the user-visible effect: 'Block a time slot in a team member's calendar so nobody books it.' This is clearly distinguishable from booking siblings like create_appointment and from find_available_slots, which read availability rather than create blocks.

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?

Anchors the tool to the product's 'Add > Blocked time' action and states key exclusions ('It does not repeat', 'Nobody is told'), which tell an agent this is not a recurring or notifying operation. It stops short of naming sibling tools or an explicit when-not-to-use condition (e.g. vs. reschedule_appointment).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

add_clientAdd clientAInspect

Add a client to the business's client list.

Adds a client as Add client in the Client list does: name, email, mobile and gender. With appointment_messages (default true) Fresha sends the client booking confirmations and reminders to the email and mobile given; marketing (default false) records consent to marketing messages. Nothing is sent when the client is added.

ParametersJSON Schema
NameRequiredDescriptionDefault
emailNoEmail.
phoneNoMobile number with country code, e.g. +44 7700 900123.
genderNoGender.
last_nameNoLast name.
marketingNoThe client agreed to marketing messages. Default: false.
first_nameYesFirst name.
appointment_messagesNoLet Fresha send this client booking confirmations and reminders by email, SMS and WhatsApp. Default: true.

TDQS

A3.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare non-readOnly, non-destructive, non-idempotent and open-world. The description adds genuinely useful behavior beyond that: nothing is sent at creation time, while appointment_messages=true triggers booking confirmations and reminders across email/SMS/WhatsApp, and marketing records consent. It does not cover duplicate-client handling or failure modes.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The second sentence opens with a circular restatement ('Adds a client as Add client in the Client list does'), which wastes space before the genuinely useful message-consent explanation. The final sentence is well placed and front-loads the important 'nothing is sent' fact late.

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 7-parameter mutation with no output schema, the description covers the essential creation semantics and the non-obvious messaging side effects. Gaps are modest: no mention of duplicate-email behavior or what identifying data comes back.

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 seven parameters including defaults and the phone pattern. The description adds only light reinforcement of the appointment_messages/marketing effect, and even refers to 'mobile' where the schema calls the field 'phone'.

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: 'Add a client to the business's client list.' An agent can distinguish it from list_clients/get_client/add_client_note by the verb, though no sibling is named explicitly.

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 by the create verb, but there is no explicit guidance on when to use this versus alternatives (e.g., checking for an existing client first, or using add_client_note for notes). No exclusions or prerequisites are stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

add_client_noteAdd client noteAInspect

Add a note to a client's profile, seen by the team only.

Adds a note to the client's Notes tab for all locations, as the profile's Add note does. Only the team sees it; the client is not told. Line breaks become paragraphs.

ParametersJSON Schema
NameRequiredDescriptionDefault
textYesNote text.
client_idYesClient id from list_clients.

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already establish that this is a non-read-only, non-idempotent, non-destructive mutation with open-world behavior. The description adds meaningful behavioral context beyond annotations: the note is visible to the team only, the client is not notified, it applies across all locations, and line breaks become paragraphs. It does not cover permissions or response behavior, but the added context is substantial.

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?

The description is three short sentences, front-loads the core action, and each sentence contributes useful information: purpose, destination/scope, and visibility/formatting behavior. There is no redundant restatement of the name or schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple two-parameter mutation with full schema coverage and annotations covering safety hints, the description is complete enough. It explains visibility, notification behavior, location scope, and text formatting, leaving little an agent needs to infer before calling it.

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 description coverage is 100%, so the baseline is 3. The description adds semantics beyond the schema by explaining that line breaks in the text become paragraphs and that the note applies to all locations, which clarifies formatting behavior and implies there is no location-scoping parameter.

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?

The description states a specific verb and resource: adding a note to a client's profile. It also specifies the destination (Notes tab), scope (all locations), and visibility (team only), so an agent can understand exactly what the tool does without opening the schema.

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?

The description implies this tool is for internal team notes by saying the client is not told and only the team sees it. However, it does not give explicit when-to-use guidance, exclusions, or alternatives for communicating with clients, so usage is only implied.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

cancel_appointmentCancel appointmentA
Destructive
Inspect

Cancel an appointment without a charge, optionally telling the client.

Cancels the appointment as Cancel in its drawer does, with one of the business's cancellation reasons. With notify_client (default true) Fresha sends the client a cancellation message, so this can reach the client; false cancels quietly. whole_series also cancels the later appointments of a repeating series. An appointment with a cancellation fee or a paid deposit is refused: cancel it in Fresha. It cannot be undone here.

ParametersJSON Schema
NameRequiredDescriptionDefault
scopeNothis_appointment (default) or whole_series, for repeating appointments: this and every later one.
reasonNoName of one of the business's cancellation reasons, e.g. Client not available. Default: none.
notify_clientNoSend the client a cancellation message. Default: true.
appointment_idYesAppointment id from list_appointments.

TDQS

A4.1/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description goes well beyond the annotations: it discloses irreversibility ("cannot be undone here"), side effects (the client may be messaged), refusal conditions, and series-wide blast radius. However, some of this overlaps the destructiveHint=true / openWorldHint=true annotations, and it never describes what the call returns, which matters given 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.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the action and its key caveats, and most sentences carry distinct information. There is mild redundancy between the paragraph text and the schema on whole_series/notify_client defaults.

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 destructive mutation with no output schema, it covers safety, side effects, refusal conditions, and scope. The remaining gap is the return value (e.g., which appointments were cancelled) and how to recover after an unexpected series cancellation.

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%, so all four parameters are already documented in the input schema. The description restates the notify_client default and the whole_series meaning without adding format, syntax, or edge-case detail beyond the schema, so the baseline 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?

Specific verb + resource ("Cancel an appointment") plus scope qualifiers (single vs whole series) and an explicit analogy to the in-product Cancel action. It is clearly distinguishable from siblings like reschedule_appointment or get_appointment.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states the precondition that selects the alternative: an appointment with a cancellation fee or paid deposit is refused and must be cancelled in Fresha instead. It also names the quiet-vs-notify choice so the agent knows which mode to pick per situation.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

create_appointmentCreate appointmentA
Destructive
Inspect

Book an appointment for a client: services, team member and start time.

Books the services one after another from start_at with one team member, as New appointment in the calendar does, at each service's catalogue price. Fresha may send the client a booking confirmation by their notification settings (get_client), so this can reach the client. Find free times with find_available_slots first: Fresha books over other appointments and returns its warnings.

ParametersJSON Schema
NameRequiredDescriptionDefault
start_atYesStart, ISO 8601: 2026-11-03T14:30 is wall clock in the business's time zone; with an offset (2026-11-03T14:30:00+01:00) it is converted.
client_idNoClient from list_clients. Without it: a walk-in.
service_idsYesService ids from list_services, done one after another in this order.
team_member_idNoTeam member. Default: the first who takes bookings.

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare destructive=true, openWorld=true and idempotent=false, so the safety profile is covered; the description adds real context beyond that: services are booked sequentially from start_at at catalogue price, and the booking can send a real confirmation to the client. The only thing left vague is what the call returns on success or how the over-booking warning surfaces in this tool's own response.

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?

Two compact sentences, front-loaded with what the tool does before the prerequisites and side effects. Every clause earns its place – the calendar analogue, the sequential booking, the client notification and the double-booking warning all change agent behavior.

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 4-parameter destructive mutation with no output schema, the description covers ordering, pricing, external side effects and the slot-checking prerequisite. The remaining gap is the response shape, which is neither documented here nor in an output schema.

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 every parameter is already documented, including the walk-in default and the team-member default. The description reinforces semantics (services run one after another from start_at with a single team member) but adds no format, ordering or constraint detail the schema does not already carry. Baseline 3 is appropriate.

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 verb and resource ('Book an appointment') plus the key inputs (services, team member, start time), and anchors it to a concrete analogue: 'as New appointment in the calendar does'. An agent can distinguish it from list_appointments, reschedule_appointment and find_available_slots without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives an explicit prerequisite ('Find free times with find_available_slots first') and a concrete consequence of skipping it ('Fresha books over other appointments and returns its warnings'). It also routes to get_client for the notification-settings question, so both when-to-use and which sibling to consult are spelled out.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

find_available_slotsFind available slotsA
Read-onlyIdempotent
Inspect

Free start times for one or more services with a team member, day by day.

Asks the calendar for free start times as New appointment does, for the services done one after another, with one team member, over up to 14 days. Times are wall clock in the business's time zone; closed days have no times. Book a time with create_appointment.

ParametersJSON Schema
NameRequiredDescriptionDefault
dateYesFirst day to search.
daysNoDays to search. Default: 1.
service_idsYesService ids from list_services, done one after another in this order.
team_member_idNoTeam member to book. Default: the first who takes bookings.

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly, idempotent, openWorld, and non-destructive behavior. The description adds useful behavioral context: 'Times are wall clock in the business's time zone; closed days have no times' and sequential service scheduling. No contradictions with 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?

Two sentences, front-loaded with purpose. The second sentence is slightly redundant with 'Asks the calendar for free start times as New appointment does,' but overall the description is efficient and every sentence contributes.

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?

No output schema exists, but the description conveys return structure ('day by day') and key behavioral traits (timezone, closed days). For a read-only tool with full annotations and complete parameter schema, this is sufficiently complete.

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%, so the baseline is 3. The description reiterates 'one or more services' and 'up to 14 days' but adds little meaning beyond what the schema already provides (e.g., service_ids order, days min/max/default are all documented in the schema).

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 verb and resource: 'Free start times for one or more services with a team member, day by day.' It also distinguishes from the booking tool by directing the agent to create_appointment. An agent can readily tell what this tool does versus 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?

Provides a clear next step: 'Book a time with create_appointment.' However, it does not explicitly state when NOT to use this tool or contrast it with other listing tools like list_appointments. Implied usage is clear enough for an agent to select it before booking.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_appointmentGet appointmentA
Read-onlyIdempotent
Inspect

One appointment: client, services, team member, times, status, price and notes.

Reads the appointment as its drawer in the calendar shows it: status, start and end (wall clock in the business's time zone), the client, each booked service with its team member and length, the total and what is left to pay, and the appointment notes.

ParametersJSON Schema
NameRequiredDescriptionDefault
appointment_idYesAppointment id from list_appointments.

TDQS

A3.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly, idempotent, non-destructive and open-world, so the safety profile is covered. The description adds genuinely useful context beyond that: timestamps are wall clock in the business's time zone, the payload includes balance remaining after the total, and appointment notes are returned.

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?

The summary sentence is front-loaded and the second sentence elaborates on the returned fields. There is mild repetition between the two ('client, services, team member' appear in both), but every sentence carries information and nothing is padded.

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 is the only place return values are described, and it does that adequately: status, times with time zone semantics, client, per-service team member and length, totals and balance, and notes. For a single-parameter read tool with full annotation coverage, this is sufficient to call correctly.

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?

There is one parameter and schema description coverage is 100%, with the schema already explaining that the id comes from list_appointments and constraining it to digits. The description adds no further meaning about the identifier, 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?

The description states a specific verb and resource ('One appointment') and enumerates the fields returned (client, services, team member, times, status, price, notes), which distinguishes it clearly from list-oriented siblings. It stops short of naming list_appointments as the companion tool inside the description itself, though the schema covers that linkage.

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: 'One appointment' suggests this is the single-record read rather than a list, and the schema notes the id comes from list_appointments. There is no explicit when-to-use/when-not or named alternative in the description text.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_clientGet clientA
Read-onlyIdempotent
Inspect

One client: contact, notification settings, booking stats, upcoming appointments, notes.

Reads the client profile as the client's page shows it: name, email, mobile, gender, birthday, whether Fresha sends them appointment messages and marketing by email, SMS and WhatsApp, booking and sales totals, the next 10 appointments and the latest 10 notes.

ParametersJSON Schema
NameRequiredDescriptionDefault
client_idYesClient id from list_clients.

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly=true, idempotent=true, destructive=false and openWorld=true, so safety is covered; the description adds genuinely new behavioral detail by stating the result caps ("next 10 appointments", "latest 10 notes") and that output mirrors the client's page. It stops short of noting what happens for a nonexistent client_id or whether data is truncated/paginated.

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 sentences, front-loaded with the one-line summary before the detailed field breakdown. Slight redundancy between the list in sentence one and the restatement in sentence two, but the detail second sentence earns its place by adding caps and field types.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists, so the description must carry the return contract, and it does: exact field families, item limits on appointments and notes, and the "as the client's page shows it" framing. Combined with a fully documented single parameter and read-only annotations, an agent has everything needed to call it correctly.

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 client_id property already documents the pattern and origin ("Client id from list_clients."), so the description adds nothing about parameters. Baseline 3 is appropriate when the schema carries the field-level meaning.

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 opens with a specific verb+resource ("One client: contact, notification settings, booking stats, upcoming appointments, notes") and enumerates the returned fields, so the agent knows exactly what this fetches. It implies the single-record counterpart to list_clients via "One client" but never names that sibling explicitly.

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 pattern that client_id comes "from list_clients" hints at the list-then-fetch flow, but there is no explicit when-to-use, when-not, or named alternative (e.g., list_clients for browsing, get_sales_summary for aggregate numbers).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_sales_summaryGet sales summaryA
Read-onlyIdempotent
Inspect

Sales summary for a period: sales, refunds, discounts, taxes and payments by type.

Reads Reports > Sales summary for the days given: one row per sale type (services, products, memberships, gift cards and so on) with Fresha's own columns (gross and net sales, discounts, refunds, taxes) and a totals row. columns names each key. A period without sales has no rows. Amounts are in the business's currency.

ParametersJSON Schema
NameRequiredDescriptionDefault
toNoLast day. Default: same as from.
fromYesFirst day.

TDQS

A3.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already carry readOnly/idempotent/destructive=false, so the safety profile is covered. The description adds genuine context beyond them: rows are grouped per sale type with a totals row, an empty period returns no rows, and amounts are in the business's currency — all useful for interpreting results.

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 short paragraphs, front-loaded with the purpose then the return shape; every sentence contributes (metrics list, row structure, empty-period behavior, currency). Minor redundancy between the opening list and the parenthetical column list.

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 must describe the return shape, and it does: one row per sale type, Fresha's columns, a totals row, and 'columns names each key.' Only gap is any hint of aggregation granularity limits or currency conversion behavior.

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% and both parameters (from required, to defaulting to from) are fully documented there. The description only restates 'for the days given' without adding format, timezone, or range-limit semantics, so it meets the baseline but no more.

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?

Opens with a specific verb+resource ('Sales summary for a period') and immediately enumerates the metrics covered (sales, refunds, discounts, taxes, payments by type). The second paragraph's 'one row per sale type' shape implicitly separates it from the transaction-level list_sales sibling, though it never names an alternative.

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 grounds the tool in a known UI location ('Reads Reports > Sales summary for the days given'), which tells the agent this is an aggregated report pull. But there is no explicit when-to-use/when-not guidance and no mention of list_sales as the per-transaction alternative, leaving the choice to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_appointmentsList appointmentsA
Read-onlyIdempotent
Inspect

Appointments in a date range, with client, service, team member, price and status.

Lists appointments as Sales > Appointments shows them, latest first: one row per booked service with its appointment id, reference, start (wall clock in the business's time zone), length, client, team member, price, status and channel (online or offline). Cancelled appointments are included with their status. Page with next_cursor. The report itself has no status, team member or client filter, so those three apply to the first 100 rows of the date range: for a busy range, narrow the dates.

ParametersJSON Schema
NameRequiredDescriptionDefault
toNoLast day. Default: same as from.
fromYesFirst day.
limitNoPage size. Default: 50.
cursorNonext_cursor from the previous call.
statusNoOnly this status, as Fresha names it: booked, confirmed, arrived, started, completed, canceled, no-show. Default: all.
client_idNoOnly this client's appointments.
team_member_idNoOnly this team member's appointments.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the read-only/idempotent annotations, it discloses ordering (latest first), row granularity (one row per booked service), inclusion of cancelled appointments, wall-clock timezone handling, and pagination via next_cursor. The filter limitation on the first 100 rows is an important non-obvious behavior.

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?

The description is front-loaded with purpose and ordering, then describes return fields, pagination, and the filter caveat. It is slightly dense and repeats some field-level detail already available in the schema, but every sentence contributes useful behavioral context.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/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 no output schema, it covers return fields, ordering, status inclusion, timezone semantics, pagination, and the important filter-scope limitation. An agent has enough information to call and interpret results correctly.

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 schema already defines each parameter. The description still adds meaningful context by explaining that status/client/team_member filters only cover the first 100 rows and that pagination uses next_cursor, which is not apparent from the schema alone.

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?

The description states a specific verb and resource ('Appointments in a date range') plus the fields returned, and anchors behavior to 'Sales > Appointments' ordering. It is clearly distinguishable from siblings like get_appointment or list_sales.

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?

It gives a concrete usage caveat: status, team member and client filters only apply to the first 100 rows of the date range, so busy ranges should be narrowed. It does not explicitly name sibling alternatives for single-appointment lookup, but the operational guidance is clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_clientsList clientsA
Read-onlyIdempotent
Inspect

Clients of the business, searchable by name, email or phone.

Lists clients as the Client list shows them, newest first by default, with email, mobile, gender, total sales, review count and whether they are blocked. search matches name, email or phone. total is the number of matching clients. Page with next_cursor.

ParametersJSON Schema
NameRequiredDescriptionDefault
sortNoOrder: newest (default), oldest or name.
limitNoPage size, at most 50 (Fresha refuses more). Default: 50.
cursorNonext_cursor from the previous call.
searchNoName, email or phone.

TDQS

A3.8/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly, idempotent, non-destructive and openWorld, so safety is covered. The description adds genuinely new behavioral context beyond that: default ordering (newest first), the field set returned, a total match count, and cursor-based paging via next_cursor.

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?

Dense and front-loaded, with the resource named first and paging last. Minor waste in repeating the searchable fields twice ('searchable by name, email or phone' then 'search matches name, email or phone'), but overall tight.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/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 return-shape burden and does so: it lists the fields returned, the total count, the default sort, and how to page. Four optional parameters are all accounted for, leaving nothing an agent needs 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 every parameter is already documented with defaults and the 50-item cap. The description mostly restates the schema ('search matches name, email or phone', 'newest first by default', 'Page with next_cursor') rather than adding syntax or edge-case meaning, so baseline 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?

Opens with a clear verb+resource statement ('Clients of the business, searchable by name, email or phone') and enumerates the returned fields. It is distinguishable from get_client via the word 'Lists' and the paging/search framing, but never explicitly contrasts itself with the single-client sibling.

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 by the tool's shape: an agent can infer this enumerates clients and supports a search filter. However, there is no explicit guidance on when to prefer list_clients over get_client (e.g., 'use get_client when you already know the id') and no stated exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_reviewsList reviewsA
Read-onlyIdempotent
Inspect

Client reviews of the business with rating, text and replies.

Lists reviews as Online reputation shows them, newest first: star rating, text, author, the client and appointment it is about, source (Fresha or Google) and the replies. Filter by rating, source, words or reviews still without a reply. Page with next_cursor.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoPage size. Default: 50.
cursorNonext_cursor from the previous call.
searchNoWords in the review.
sourceNoOnly Fresha or Google reviews.
ratingsNoOnly these star ratings.
unreplied_onlyNoOnly reviews without a reply. Default: false.

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly, idempotent and non-destructive, so the description spends its words well: it adds the ordering guarantee ('newest first'), the source domain (Fresha or Google), and the pagination mechanics via next_cursor. It doesn't discuss page-size defaults or rate limits, but those are minor given the annotation coverage.

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?

Two sentences, front-loaded with what is returned, then the ordering, then filters, then pagination. No filler and nothing buried at the end.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema exists, and the description compensates by enumerating the fields each review contains plus sort order and cursor paging. Combined with the fully documented schema, an agent has everything needed to call this correctly.

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 every parameter is already documented. The description restates the filter dimensions in prose (rating, source, words, unreplied) and names next_cursor for paging, but adds no syntax, defaults, or edge-case semantics beyond what the schema provides — notably omitting `limit`.

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 verb and resource ('Client reviews of the business') plus the exact payload each item carries (rating, text, author, client, appointment, source, replies). An agent can immediately distinguish this read-only listing from the mutation sibling reply_to_review without opening the 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?

Usage context is concrete: filter by rating, source, words, or reviews still without a reply, and page with next_cursor. The 'still without a reply' filter implicitly routes the agent toward reply_to_review, but no sibling is named and no exclusion (e.g. when to use a different listing tool) is stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_salesList salesA
Read-onlyIdempotent
Inspect

Sales (invoices) in a date range: number, date, client, status and totals.

Lists sales as Sales > Sales list shows them for the days given, one row per sale with Fresha's columns (sale number, date, client, status, gross total and so on; linked records come with an _id). Amounts are in the business's currency. Page with next_cursor.

ParametersJSON Schema
NameRequiredDescriptionDefault
toNoLast day. Default: same as from.
fromYesFirst day.
limitNoPage size. Default: 50.
cursorNonext_cursor from the previous call.

TDQS

A3.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint and destructiveHint=false, so the safety profile is covered. The description adds genuinely useful context beyond that: amounts are in the business's currency, linked records carry an `_id`, and results are paginated. It stops short of saying how the date range is interpreted (inclusive boundaries, timezone) or what happens with very large ranges.

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?

Front-loaded and reasonably tight: the shape of the rows comes first, then the pagination instruction. The two paragraphs partially restate each other (date range and column list appear twice), which costs a little economy but no clarity.

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 does the work of describing the return shape (columns, currency, `_id` on linked records) and pagination. That is enough to call the tool correctly, though the treatment of inclusive date boundaries and default range behavior is left to the schema alone.

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 defaults for `to` and `limit` documented inline, so the baseline is 3. The description only reinforces 'date range' and 'next_cursor', adding no format details or constraint semantics beyond what the schema already provides.

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 states a specific verb and resource ('Sales (invoices) in a date range') and enumerates the columns returned (sale number, date, client, status, gross total). It does not explicitly distinguish itself from the sibling get_sales_summary, so a reader must infer list-vs-aggregate on their own.

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 by the date-range framing; there is no statement of when to call this versus get_sales_summary or how to handle open-ended ranges. The pagination hint ('Page with next_cursor') is the only actionable guidance.

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-onlyIdempotent
Inspect

Services of the business with category, duration and price.

Lists the active services of the business's location as the Catalogue shows them, with their category, duration in minutes, price and whether clients can book them online. A service with several prices (by length or level) lists each as a pricing level; bookings use the first one. Use service_id in find_available_slots and create_appointment.

ParametersJSON Schema
NameRequiredDescriptionDefault
searchNoOnly services whose name contains this.

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is covered. The description adds meaningful behavior beyond annotations: only active services are listed, results mirror the Catalogue, multi-price services appear as pricing levels, and bookings use the first level.

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?

The description is front-loaded and tightly structured: the opening sentence names the resource and fields, and the second explains catalogue semantics and downstream tool usage. Every sentence carries operational value without padding.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/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 compensates by explaining the returned service attributes, active-only scope, multi-price representation, and how service_id is used downstream. No essential calling context is missing for a read-only catalogue list tool.

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 single 'search' parameter is already fully documented in the schema. The description adds no parameter-specific guidance, making the baseline 3 appropriate.

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?

The description states a specific verb and resource ('Lists the active services of the business's location') and enumerates the returned fields: category, duration, price, and online booking availability. It also differentiates itself from adjacent workflows by pointing to find_available_slots and create_appointment for service_id consumption.

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?

It clearly establishes the context: retrieving the catalogue of active services, including multi-price handling and the rule that bookings use the first pricing level. It does not explicitly name competing sibling tools or exclusion conditions, but the downstream usage guidance for service_id is concrete.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_team_membersList team membersA
Read-onlyIdempotent
Inspect

Team members with role, contact, services they do and whether they take bookings.

Lists the team as Team members shows it: name, email, mobile, role (owner, manager, basic), job title, whether they take bookings and online bookings, the services assigned to them and their location. Also lists the business's locations. Use team_member_id in the calendar tools.

ParametersJSON Schema
NameRequiredDescriptionDefault
include_formerNoAlso team members who left. Default: false.

TDQS

A3.5/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint and destructiveHint=false, so the safety profile is covered. The description adds useful context about what is returned (including business locations), but says nothing about ordering, pagination, or authorization needs.

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?

Content is front-loaded with the resource and its fields. The phrasing 'Lists the team as Team members shows it' is slightly awkward and redundant, but overall there is little waste.

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 returns, and it does so by enumerating the member fields and noting locations are included. An agent can call this confidently; only ordering/pagination details are absent.

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 single boolean include_former is fully documented in the schema ('Also team members who left. Default: false'). The description does not touch the parameter at all, so baseline 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 and resource (list team members) and enumerates the fields returned – name, email, role, bookings, services, location. It is clearly distinguishable from siblings like list_clients or list_services, though no sibling is named explicitly.

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?

The closing line 'Use team_member_id in the calendar tools' implies the primary workflow (discover members, then use their IDs for appointments). However, there is no explicit when/when-not guidance or mention of alternatives such as list_services for the service side.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

reply_to_reviewReply to reviewA
Destructive
Inspect

Post a public reply to a client's review.

Posts a reply under the review as Reply in Online reputation does, signed as the business or the team member. The reply is public on the business's Fresha page and the client is told, so this reaches people. It needs a review that exists: take review_id from list_reviews.

ParametersJSON Schema
NameRequiredDescriptionDefault
textYesReply text.
reply_asNoSign the reply as the business (default) or as the team member signed in.
review_idYesReview id from list_reviews.

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare write, destructive, open-world and non-idempotent, and the description adds real consequence: the reply is public on the business's Fresha page and the client is notified, plus who it is signed as. It falls short of explaining the non-idempotent/destructive angle — e.g. whether a second reply replaces the first or stacks — which matters given idempotentHint=false.

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?

Short and front-loaded with the action and its audience. The middle sentence ('as Reply in Online reputation does') is slightly redundant framing that could be cut, but nothing else is wasted.

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 3-parameter write tool with no output schema, the description covers the action, the audience, the prerequisite and the identity option. The only real omission is what the call returns and what happens on a repeat reply.

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%, so all three parameters (text, reply_id, reply_as enum) are already documented in the schema, including the enum meanings and the list_reviews provenance. The description restates signing-as-both rather than adding syntax, limits, or edge cases beyond the schema.

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?

Specific verb+resource ('Post a public reply to a client's review') with the write target and visibility stated up front. It is clearly distinct from list_reviews and the rest of the sibling set, which are read/list or scheduling tools.

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 an explicit prerequisite chain: 'It needs a review that exists: take review_id from list_reviews,' which routes the agent to the sibling that produces the required input. It does not state any when-not-to-use conditions, but no competing reply tool exists.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

reschedule_appointmentReschedule appointmentA
Destructive
Inspect

Move an appointment to a new start time, optionally to another team member.

Moves every service of the appointment by the same amount so the first starts at start_at, as Reschedule in the appointment drawer does; lengths and prices stay. team_member_id moves all services to that team member. With notify_client (default true) Fresha sends the client a reschedule message by their notification settings; false moves it quietly. Cancelled, completed and no-show appointments are refused.

ParametersJSON Schema
NameRequiredDescriptionDefault
start_atYesNew start. ISO 8601: 2026-11-03T14:30 is wall clock in the business's time zone; with an offset (2026-11-03T14:30:00+01:00) it is converted.
notify_clientNoLet Fresha send the client a reschedule message, by their notification settings. Default: true.
appointment_idYesAppointment id from list_appointments.
team_member_idNoNew team member for every service. Default: unchanged.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond destructiveHint/openWorldHint, the description discloses the crucial non-obvious behaviors: all services shift by the same offset with lengths and prices preserved, team_member_id reassigns every service, and notify_client=true (default) sends a client message while false moves it quietly. Refusal on cancelled/completed/no-show is exactly the kind of behavioral constraint annotations cannot express.

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 sentences, front-loaded with purpose, then mechanics, then the notification default, then the refusal conditions. No filler and no repetition of schema text.

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 never indicates what comes back after a reschedule (updated appointment, confirmation, error shape), which is the one remaining gap. Everything an agent needs to decide, prepare inputs, and anticipate side effects is otherwise 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 still adds meaning the schema lacks by explaining that start_at is the first service's start and that all remaining services are shifted relative to it, and that team_member_id applies to every service rather than one. It does not clarify timezone conversion, which is left entirely to the schema.

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 verb and resource ('Move an appointment to a new start time') plus the optional scope ('optionally to another team member'), which cleanly separates it from create_appointment and cancel_appointment in the sibling list. The added sentence about shifting all services makes the operation concrete.

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 when-not guidance: 'Cancelled, completed and no-show appointments are refused,' and equivalences the agent can reason from ('as Reschedule in the appointment drawer does'). It never names a sibling alternative for the refusal cases (e.g. create_appointment for a new booking), so it stops short of full 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. 17 tool updatesv0.1.0
    • First observedadd_blocked_time
    • First observedadd_client
    • First observedadd_client_note
    • First observedcancel_appointment
    • First observedcreate_appointment
    • First observedfind_available_slots
    • First observedget_appointment
    • First observedget_client
    • First observedget_sales_summary
    • First observedlist_appointments
    • First observedlist_clients
    • First observedlist_reviews
    • First observedlist_sales
    • First observedlist_services
    • First observedlist_team_members
    • First observedreply_to_review
    • First observedreschedule_appointment

TDQS

A3.9/5.0

Scored across 17 tools

Disambiguation4/5

Most tools target a distinct resource+action (add_client, get_appointment, cancel_appointment, reply_to_review), and the descriptions draw careful boundaries between calendar writes. The main soft overlap is in reporting: list_appointments, list_sales and get_sales_summary all return revenue-flavoured rows, so an agent wanting 'today's bookings' vs 'today's invoices' must read descriptions carefully.

Naming Consistency5/5

Nearly everything follows a clean verb_noun pattern: add_/list_/get_/create_/cancel_/reschedule_/find_ plus a resource noun. The only slight deviation is reply_to_review (verb_to_noun), but it reads naturally and matches the domain language.

Tool Count4/5

17 tools is slightly on the heavy side but each maps to a real capability across clients, calendar, services, team, sales and reviews. Nothing looks like filler; the count is justified for a multi-surface business-management domain.

Completeness3/5

Reads and the core booking lifecycle (find slots, create, reschedule, cancel) are well covered, but write coverage is uneven: clients can be created, listed and noted but never edited or deleted; blocked time can be added but never listed for removal. Several lifecycle steps (mark complete/no-show, edit appointment services or notes, get a single sale/service) are missing, leaving dead ends.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    C
    maintenance
    Self-hosted MCP server for browser automation with stealth patches, offering 50 tools for navigation, scraping, and session configuration. Runs via Docker and supports remote control from any MCP client.
    -
  • A
    license
    A
    quality
    B
    maintenance
    Enables AI agents and scripts to manage bookings, provider assignment, rescheduling, cancellations, customers, quotes, invoices, and dashboard data through a self-hosted API and MCP interface using your own Chrome session.
    2
    17
    1
    PolyForm Noncommercial 1.0.0