Skip to main content
Glama

TimeZest MCP Server

An MCP server for the TimeZest API, the appointment-scheduling service MSPs use so their customers can book time with technicians from a PSA ticket. It lets an AI agent read agents, teams, appointment types, bookable resources and scheduling requests and, on explicit request, create a scheduling request (optionally linked to a PSA ticket).

  • Transport: MCP Streamable HTTP at POST /mcp, health probe at GET /health

  • Stateless and multi-tenant: the API key arrives on every request as an HTTP header and is never stored; every tool is listed from the first tools/list

  • Python 3.12, uv, FastMCP, httpx

  • License: Apache-2.0, Copyright 2026 MSPbots.ai

Authentication headers

Header

Required

Type

Default

Allowed values

Description

Example

X-Timezest-Api-Token

Yes

string

none

-

TimeZest API key (a leading Bearer is accepted and ignored)

your-api-token

Where to get it:

  • A TimeZest administrator creates an API key on the API Keys page of the TimeZest web app (app.timezest.com -> Settings -> API Keys).

  • A read-only key is enough for every tool except timezest_scheduling_create_request, which needs a read/write key.

  • TimeZest allows 180 requests per minute per account (all keys combined).

How the key is sent to TimeZest: Authorization: Bearer <key> on every call to https://api.timezest.com/v1/....

A request to /mcp without the header gets HTTP 401 naming it.

Related MCP server: Zenoti MCP Server

Tools

All tools return a JSON string. TimeZest returns lists newest first in fixed pages of 20; list tools return {items, count, has_more, next_cursor} and take startingAfter (the previous next_cursor), pageSize (return at most this many of the page) and filter, a TimeZest Query Language expression such as scheduling_request.end_user_email LIKE @example.com. Timestamps are returned as ISO 8601 UTC.

Tool

Purpose

Parameters (required in bold)

timezest_status

Check the connection (the API key works) and list the tool groups

-

timezest_agents_list

List agents (technicians): name, email, role, whether schedulable

pageSize, filter, startingAfter

timezest_agents_get

One agent

agentId

timezest_teams_list

List teams (pools of agents) and their type

pageSize, filter, startingAfter

timezest_teams_get

One team

teamId

timezest_appointment_types_list

List appointment types with default duration

pageSize, filter, startingAfter

timezest_appointment_types_get

One appointment type

appointmentTypeId

timezest_resources_list

List bookable resources (agents and teams); their ids go into resourceIds

pageSize, type (agent, team), filter, startingAfter

timezest_scheduling_list

List scheduling requests: end user, type, status, chosen time, URL

pageSize, status (new, sent, scheduled, cancelled, closed; also pending, booked, completed), filter, startingAfter

timezest_scheduling_get

One scheduling request with resources, booked agents and booking URL

requestId

timezest_scheduling_create_request

Create a scheduling request; TimeZest emails the customer (write)

appointmentTypeId, triggerMode (pod, generate_url), endUser {name, email, company}, timeRange {earliestDate, earliestTime, latestDate, latestTime}, resourceIds, associatedEntities [{type, id, number}], durationMins, guests

timezest_scheduling_cancel

Explain how to cancel a request (the API cannot cancel); returns its status and URL

requestId, reason

associatedEntities[].type is one of autotask/company, autotask/contact, autotask/ticket, connectwise_psa/company, connectwise_psa/contact, connectwise_psa/project_ticket, connectwise_psa/service_ticket, halo_psa/user, halo_psa/ticket, service_now/incident, service_now/problem, service_now/change_request, service_now/sn_customerservice_case, service_now/contact. When a PSA contact or ticket is linked, TimeZest can take the end user's name and email from it.

Errors come back as a JSON envelope instead of an exception:

{"error": {"code": "unauthorized", "message": "TimeZest returned HTTP 401 for agents: Unauthorized. No valid API key provided", "retryable": false}}

code is one of not_configured, unauthorized, not_found, invalid_argument, rate_limited, upstream_error. Reads are retried with backoff on 429, 5xx and network errors; the create call is retried only on 429, so a request is never created twice.

Run locally

uv sync
uv run python -m timezest_mcp          # listens on 0.0.0.0:8080

or with Docker:

docker build --platform linux/amd64 -t timezest-mcp:dev .
docker run --rm -p 8080:8080 timezest-mcp:dev

Configuration (environment variables, all optional): MCP_HTTP_HOST (default 0.0.0.0), MCP_HTTP_PORT (default 8080), LOG_LEVEL (default INFO). The key is never read from the environment.

Testing example

# list tools
curl -s http://localhost:8080/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "X-Timezest-Api-Token: your-api-token" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'

# bookings waiting for the customer to pick a time
curl -s http://localhost:8080/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "X-Timezest-Api-Token: your-api-token" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"timezest_scheduling_list","arguments":{"status":"sent"}}}'

Unit tests (no network access needed):

uv run pytest

Delivery notes

  • Tool count (12). Kept as is because the tool names are an existing contract.

  • Cancelling. The TimeZest API has no cancel operation, so timezest_scheduling_cancel changes nothing: it returns the request's status and scheduling_url (the customer's reschedule / cancel page) and tells the agent to have it cancelled in TimeZest or the PSA.

  • Create request. appointmentTypeId is required (TimeZest requires it; older versions silently picked the first type). resource_ids is always sent as an array. Associated entities use TimeZest's own type names (for example connectwise_psa/service_ticket), times are sent as HH:MM:SS, and fields TimeZest does not accept (notes, end-user phone, time zone) were removed instead of being silently dropped.

  • Lookups by id. TimeZest has no get-by-id for agents, teams or appointment types, so the _get tools walk the list pages (at most 50 pages) to find the id.

  • No interactive prompts. Older versions asked the user to pick an appointment type or confirm a cancel mid-call, which a stateless gateway cannot relay.

License

Apache License 2.0 - see LICENSE and NOTICE.

Related MCP Connectors

Related MCP Servers