servicetitan-mcp
A read-only MCP server over the ServiceTitan API providing six task-shaped tools to find customers, view their jobs, billing details, and resolve external IDs.
README
servicetitan-mcp
A read-only MCP server over the ServiceTitan API: six task-shaped tools (find a customer, look at their jobs, their money, resolve an external id) instead of a thin wrapper over ServiceTitan's own endpoints. ReadOnlyClient defines only get and get_page — no write path exists.
See docs/DESIGN.md for the reasoning behind these choices.
The credentials rule
The MCP client config carries exactly one setting: ST_ENV_FILE, a path — never a secret directly. Everything else (client id, secret, app key, tenant id) lives in the file it points at, chmod 600, outside the repo and outside any MCP config: MCP configs get pasted into chats, and some (.mcp.json) are designed to be committed.
permission_warning checks the file's mode at startup and warns — doesn't refuse to start — if it's looser than 600. Full reasoning in docs/DESIGN.md.
{
"mcpServers": {
"servicetitan": {
"command": "/absolute/path/to/servicetitan-mcp/.venv/bin/servicetitan-mcp",
"env": { "ST_ENV_FILE": "/home/you/.config/servicetitan-mcp/env" }
}
}
}
command must be an absolute path into this project's .venv — an MCP client launches from an arbitrary directory, so a bare python may resolve to an interpreter without mcp/httpx/st_mcp installed.
The six tools
| Tool | Answers | Reach for it when |
|---|---|---|
find_customer |
Who is this, by name/phone/external id? | You have a human identifier, not a ServiceTitan id. One match returns the full card; several return a short list to disambiguate. |
customer_overview |
Full card for one customer: contacts, locations, 5 recent jobs, external ids. | You already have the numeric customer id — from find_customer or a prior call. |
find_jobs |
Which jobs match these filters, and when's the next visit? | You want a list of jobs by customer, date range, or status. Not for finding a customer — that's find_customer. |
job_detail |
Everything about one job: appointments, technicians. | You have a job id and need its full appointment history. |
customer_money |
Balance, estimates, invoices, payments — for one customer, one call. | Any "what do they owe" or billing-history question. |
find_by_external_id |
Which ServiceTitan customer has this id in another system? | You're crossing over from a CRM synced into ServiceTitan via externalData (requires ST_APP_GUID). |
Job types, business units, and payment types are also exposed as MCP resources (cached client-side) rather than tools, and back the id→name substitution above.
Token savings, measured against a live tenant
chars / 4, on the same four ServiceTitan reads:
| tokens | |
|---|---|
customer_overview, raw JSON pretty-printed |
1516 |
customer_overview, raw JSON minified |
1001 |
customer_overview, this server's output |
69 |
customer_money |
43 |
find_jobs, one customer |
28 |
find_jobs, 20 jobs with next-visit dates |
318 |
22x against pretty-printed JSON, 15x against minified, per call — and customer_overview is one model round trip for four ServiceTitan reads, where an endpoint-shaped tool surface would spend four.
ServiceTitan findings
totalCountisnullunless the request sendsincludeTotal=true.jpm/appointmentshas no batch filter —jobIds,jobId=<csv>, repeatedjobIdare all ignored or wrong; onlyjobId=<single>works.sales/estimatesignorescustomerId; reachable only viajobIdorlocationId.- A 404 on an appointment's assigned-technicians means "nobody assigned yet", not "not found" — the API's own "could not" that actually means "none".
Setup
Requires Python 3.11+.
python -m venv .venv
.venv/bin/pip install -e ".[dev]"
Create the env file ST_ENV_FILE will point at (e.g. ~/.config/servicetitan-mcp/env), chmod 600 it, and fill in:
ST_CLIENT_ID=...
ST_CLIENT_SECRET=...
ST_APP_KEY=...
ST_TENANT_ID=...
# Optional:
ST_AUTH_HOST=auth.servicetitan.io
ST_API_HOST=api.servicetitan.io
ST_APP_GUID=... # required only for find_by_external_id
ST_EXTERNAL_ID_KEY=... # the externalData key find_customer treats as an id
ST_AUTH_HOST/ST_API_HOST default to production; ServiceTitan's sandbox uses different hosts (*-integration.*) and both must match the credentials' environment, or the token request 400s with invalid_client.
Registering it with a client
Both routes need an absolute path to the servicetitan-mcp console script in this project's .venv, and ST_ENV_FILE. Neither carries a secret.
Claude Code:
claude mcp add servicetitan -s user \
-e ST_ENV_FILE=/home/you/.config/servicetitan-mcp/env \
-- /home/you/servicetitan-mcp/.venv/bin/servicetitan-mcp
-s user registers it for every project on the machine — prefer it over -s project, which writes a committable .mcp.json. Verify with claude mcp list (✔ Connected).
Claude Desktop: copy claude_desktop_config_example.json, fix the two paths, and merge it into the client's own config.
Run the tests with .venv/bin/pytest. Nothing in the suite makes a live ServiceTitan call — every test uses the fake clients in tests/conftest.py.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.