servicetitan-mcp

servicetitan-mcp

A remote MCP server that exposes the ServiceTitan API as tools, enabling Claude and other clients to manage customers, jobs, pricebook, invoicing, and more with write safety and built-in observability.

Category
访问服务器

README

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

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.

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选