Skip to main content
Glama

servicetitan-mcp

A remote Model Context Protocol (MCP) server that exposes the ServiceTitan API as MCP tools to clients like Claude. It runs as a single Cloudflare Worker, speaks MCP over Streamable HTTP at POST /mcp, and talks directly to the ServiceTitan API using your own ServiceTitan app credentials.

Unofficial — not affiliated with or endorsed by ServiceTitan, Inc. This is an independent, community-maintained connector. "ServiceTitan" is a trademark of its respective owner. See TRADEMARK.md.


Features

  • 76 tools spanning CRM, jobs & appointments, pricebook, invoicing, estimates, dispatch, dispatch-pro, marketing, memberships, calls & forms, tasks, payroll, inventory, opportunities, and reporting — plus 6 cross-domain composites and one admin-only raw API gateway.

  • Bring your own credentials. No credentials are bundled. The Worker authenticates to ServiceTitan via OAuth 2.0 client-credentials using your ServiceTitan app, scoped to your tenant.

  • Write safety by default. State-changing tools use a two-phase dryRun → confirm flow gated by an HMAC confirmation token. A single env var (WRITE_GATE=off) disables it; MCP_LOCKDOWN=true forces the server fully read-only.

  • MCP tool annotations (readOnlyHint, destructiveHint, idempotentHint, openWorldHint) are emitted for every tool so clients can reason about effects.

  • Built-in observability. Every call is audited to a Cloudflare D1 database (audit log + error log), with optional Analytics Engine metrics and admin inspection routes.

  • Per-endpoint-family rate limiting via a Durable Object, protecting your ServiceTitan API quota.

  • Inbound auth with a shared X-Sync-Key header or an optional signed JWT.

  • Runs at the edge on Cloudflare Workers with per-request MCP server isolation, built on the Cloudflare Agents SDK (createMcpHandler) and the official @modelcontextprotocol/sdk (McpServer).


Related MCP server: OpenAPI MCP Server

Architecture

  ┌─────────────┐   Streamable HTTP    ┌────────────────────────────┐
  │ MCP client  │  POST /mcp           │   servicetitan-mcp          │
  │ (Claude,    │ ───────────────────► │   (Cloudflare Worker)       │
  │  agents,    │   X-Sync-Key / JWT   │                             │
  │  scripts)   │ ◄─────────────────── │  • createMcpHandler         │
  └─────────────┘                      │  • 76 tools + annotations   │
                                       │  • write-gate (dryRun/HMAC) │
                                       └──────────┬──────────────────┘
                                                  │
                 ┌────────────────────────────────┼────────────────────────────┐
                 ▼                                 ▼                            ▼
        ┌──────────────────┐          ┌──────────────────────┐     ┌────────────────────┐
        │ ServiceTitan API │          │ D1 (your account)    │     │ Durable Object     │
        │ OAuth 2.0        │          │ audit_log / error_log│     │ per-endpoint-family│
        │ client-creds     │          │ + read cache         │     │ rate limiter       │
        └──────────────────┘          └──────────────────────┘     └────────────────────┘

Each MCP request gets an isolated McpServer instance. Read tools hit the ServiceTitan API (with optional caching); write tools route through the write-gate; every invocation is recorded to your own D1 database and, optionally, Analytics Engine.


Prerequisites

  1. A ServiceTitan app. From the ServiceTitan developer portal, create an app and obtain:

    • a Client ID and Client Secret (OAuth 2.0 client-credentials),

    • an App Key,

    • your Tenant ID.

    Scope the app to only the API areas you intend to use (least privilege).

  2. A Cloudflare account with Workers enabled, plus wrangler installed and authenticated.

  3. Node.js 18+ and npm.

You provision your own Cloudflare D1 database and Durable Object bindings — see wrangler.toml for the binding names and replace the placeholder resource IDs with your own.


Quick start

# 1. Clone and install
git clone <your-fork-url> servicetitan-mcp
cd servicetitan-mcp
npm install

# 2. Set your ServiceTitan + inbound-auth secrets (never commit these)
wrangler secret put ST_CLIENT_ID
wrangler secret put ST_CLIENT_SECRET
wrangler secret put ST_APP_KEY
wrangler secret put MCP_SYNC_KEY

# 3. Edit wrangler.toml:
#    - set ST_TENANT_ID under [vars]
#    - replace the placeholder D1 database_id / DO bindings with your own

# 4. Run the test suite and type-check
npm test
npm run typecheck

# 5. Deploy
wrangler deploy

After deploy, confirm the Worker is live:

curl https://<your-worker>.workers.dev/health

Optional secrets — set only if you use the corresponding feature:

wrangler secret put JWT_SECRET          # enable signed-JWT inbound auth
wrangler secret put ST_WEBHOOK_SECRET   # enable HMAC-verified ServiceTitan webhook ingest

Registering with an MCP client

Point any Streamable-HTTP MCP client at https://<your-worker>/mcp and send your sync key in the X-Sync-Key header.

For Claude (in ~/.claude.json):

{
  "mcpServers": {
    "servicetitan": {
      "type": "http",
      "url": "https://<your-worker>.workers.dev/mcp",
      "headers": {
        "X-Sync-Key": "<your MCP_SYNC_KEY value>"
      }
    }
  }
}

If you enabled JWT_SECRET, you may instead send Authorization: Bearer <signed-JWT>.


Tool catalog

76 tools grouped by ServiceTitan domain. Tools marked write mutate state and pass through the write-gate (dryRun → confirm); everything else is read-only. st_call is admin-only.

CRM & customers

Tool

Purpose

Type

find_customer

Search customers by name, phone, or email

read

get_customer

Get a customer by ID

read

st_get_customer

Get a customer by ID (thin wrapper)

read

st_list_customers

List / search customers

read

get_customer_locations

List a customer's service locations

read

list_customer_jobs

List a customer's jobs

read

get_customer_membership

Get a customer's memberships

read

add_customer_note

Append a note to a customer record

write

Jobs & appointments

Tool

Purpose

Type

get_job

Get a job by ID

read

st_list_jobs

List / search jobs

read

list_jobs_today

List jobs scheduled for today

read

get_job_appointments

List appointments for a job

read

st_list_appointments

List / search appointments

read

jobs_hold_reasons_list

List configured job hold reasons

read

book_job

Book a new job

write

reschedule_appointment

Reschedule an appointment

write

hold_appointment

Place an appointment on hold

write

assign_technicians

Assign technicians to an appointment

write

add_job_note

Append a note to a job

write

Pricebook

Tool

Purpose

Type

search_pricebook_all

Search across services, materials, and equipment

read

search_pricebook_services

Search pricebook services

read

search_materials

Search pricebook materials

read

get_service_details

Get full details for a service

read

get_configurable_equipment_children

List child variations of configurable equipment

read

list_service_categories

List pricebook service categories

read

st_get_pricebook

Generic pricebook fetch

read

st_create_service

Create a pricebook service

write

st_patch_service

Update a pricebook service

write

st_create_material

Create a pricebook material

write

st_patch_material

Update a pricebook material

write

Invoicing

Tool

Purpose

Type

get_invoice

Get an invoice with line items and totals

read

list_invoices_job

List invoices for a job

read

get_invoice_balance

Get an invoice's outstanding balance

read

list_unpaid_invoices

List invoices with an outstanding balance

read

Estimates

Tool

Purpose

Type

get_estimate

Get an estimate with line items and status

read

list_estimates_job

List estimates for a job

read

sell_estimate

Mark an estimate sold

write

unsell_estimate

Revert a sold estimate to open

write

dismiss_estimate

Dismiss an estimate

write

Dispatch

Tool

Purpose

Type

get_capacity

Get dispatch capacity for business units over a range

read

st_get_capacity_slots

Discover bookable capacity slots

read

list_technicians_available

List technicians available on a date

read

get_technician_shifts

Get a technician's scheduled shifts

read

list_non_job_events

List non-job dispatch events (time-off, training)

read

Dispatch Pro

Tool

Purpose

Type

dispatch_pro_utilization_list

List technician utilization metrics

read

dispatch_pro_ratio_list

List dispatch ratio metrics

read

dispatch_pro_alerts_list

List dispatch alerts

read

Marketing

Tool

Purpose

Type

list_campaigns

List marketing campaigns

read

get_campaign_performance

Get campaign performance metrics

read

create_call_with_campaign

Create a call record attributed to a campaign

write

Memberships

Tool

Purpose

Type

list_memberships_active

List active memberships

read

list_memberships_expiring

List memberships expiring within N days

read

create_recurring_service

Create a recurring service under a membership

write

Calls & forms

Tool

Purpose

Type

get_call

Get a telecom call record

read

get_form_submission

Get a form submission record

read

Tasks

Tool

Purpose

Type

list_open_tasks

List open (incomplete) tasks

read

create_task

Create a task

write

Payroll

Tool

Purpose

Type

payroll_payrolls_list

List payrolls

read

payroll_job_timesheets_list

List job timesheets

read

payroll_non_job_timesheets_list

List non-job timesheets

read

payroll_location_rates_list

List location pay rates

read

payroll_settings_get

Get payroll settings

read

Inventory

Tool

Purpose

Type

inventory_vendors_list

List inventory vendors

read

inventory_warehouses_list

List warehouses

read

inventory_receipts_list

List inventory receipts

read

inventory_transfers_list

List inventory transfers

read

Opportunities

Tool

Purpose

Type

opportunities_list

List opportunities

read

opportunity_get

Get an opportunity by ID

read

Reporting

Tool

Purpose

Type

st_run_report

Run a ServiceTitan report and return rows

read

Composites (cross-domain)

Tool

Purpose

Type

customer_snapshot

Full customer view: details, locations, jobs, memberships, estimates, invoices in one call

read

margin_audit

Margin analysis across jobs

read

job_cost_actuals

Actual job costs (labor + materials)

read

membership_value_leaderboard

Rank customers / memberships by value

read

dispatch_override_audit

Audit manual dispatch overrides

read

open_opportunities_feed

Feed of open opportunities

read

Admin

Tool

Purpose

Type

st_call

Raw ServiceTitan API gateway (admin-only). GET reads; non-GET passes through the write-gate.

write (admin)


Write safety

State-changing tools never mutate ServiceTitan in a single shot. They follow a two-phase flow:

  1. dryRun (default). The tool validates inputs, builds the exact request it would send, and returns a preview plus a short-lived HMAC confirmation token. Nothing is written.

  2. Confirm. Call the tool again with dryRun: false and the returned token. The server verifies the token (HMAC over the request shape, time-bounded) and only then issues the write.

This makes accidental or hallucinated writes impossible without an explicit, verifiable second step.

  • The write-gate is on by default. Set WRITE_GATE=off (var) to disable the two-phase flow.

  • Set MCP_LOCKDOWN=true (var) to force the server fully read-only — every write tool and the admin gateway are stripped from the catalog regardless of WRITE_GATE.

Every tool also advertises MCP annotations so clients can pre-filter destructive operations:

Annotation

Meaning

readOnlyHint

Tool performs no writes

destructiveHint

Tool may make irreversible changes

idempotentHint

Repeated identical calls have no extra effect

openWorldHint

Tool reaches an external system (always true here — the ServiceTitan API)


Auth & roles

Inbound (client → Worker): every POST /mcp request must present either

  • an X-Sync-Key header matching the MCP_SYNC_KEY secret, or

  • an Authorization: Bearer <JWT> signed with the optional JWT_SECRET.

Requests without valid credentials are rejected before any tool runs.

Roles determine which slice of the catalog a caller sees:

Role

Catalog

default

All tools except admin-only (st_call)

admin

Full catalog including st_call

lockdown

Read-only tools only (forced when MCP_LOCKDOWN=true)

Outbound (Worker → ServiceTitan): OAuth 2.0 client-credentials using your ST_CLIENT_ID / ST_CLIENT_SECRET / ST_APP_KEY against your ST_TENANT_ID. Tokens are obtained and refreshed by the Worker; no ServiceTitan credentials ever leave your infrastructure.


Observability & admin endpoints

All admin routes require the X-Sync-Key header.

Route

Purpose

GET /health

Liveness probe + tool inventory

GET /admin/roles

Effective role / catalog resolution

GET /admin/metrics

Tool-call summary from the audit log

GET /admin/health/audit

Last-activity probe (detect telemetry silence)

GET /admin/endpoints

Inventory of ServiceTitan endpoints each tool maps to

GET /admin/endpoints/coverage

Pass/fail gate on endpoint-descriptor coverage

POST /webhooks/st

Optional HMAC-verified ServiceTitan webhook ingest (requires ST_WEBHOOK_SECRET)

Every tool call is written to your D1 audit_log (and error_log on failure). If you bind an Analytics Engine dataset, per-call metrics are emitted there as well.


Configuration

Secrets (wrangler secret put)

Secret

Required

Purpose

ST_CLIENT_ID

yes

ServiceTitan OAuth client ID

ST_CLIENT_SECRET

yes

ServiceTitan OAuth client secret

ST_APP_KEY

yes

ServiceTitan app key

MCP_SYNC_KEY

yes

Inbound shared key clients send as X-Sync-Key

JWT_SECRET

no

Enables signed-JWT inbound auth

ST_WEBHOOK_SECRET

no

HMAC secret for POST /webhooks/st

Vars (wrangler.toml)

Var

Default

Purpose

ST_TENANT_ID

Your ServiceTitan tenant ID

ST_ENV

production

ServiceTitan environment: production or integration

MCP_SERVICE_VERSION

Version string reported by /health

WRITE_GATE

on

Set to off to disable the two-phase write flow

MCP_LOCKDOWN

false

Set to true to force read-only mode


Security

See SECURITY.md for the threat model, hardening guidance, supported versions, and how to report a vulnerability.

Contributing

Pull requests are welcome. See CONTRIBUTING.md for setup, tests, and how to add a tool.

License

MIT.

Trademark

See TRADEMARK.md. This project is an independent, unofficial connector and is not affiliated with or endorsed by ServiceTitan, Inc.

A
license - permissive license
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/lpeluso-dotcom/servicetitan-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server