mcp-servicefusion
# mcp-servicefusion
A [Model Context Protocol](https://modelcontextprotocol.io) (MCP) server exposing the [Service Fusion](https://www.servicefusion.com) REST API to AI agents. Enables AI-assisted field service management: job lookup, customer management, dispatch, invoicing, equipment tracking, and more.
> **Disclaimer:** This is an unofficial, community-built integration. Not affiliated with or endorsed by Service Fusion.
## Features
**Read tools:**
- `get_todays_jobs` — today's scheduled jobs with assigned techs
- `search_jobs` — flexible search with filters (status, customer, date range, etc.)
- `get_job_details` — full job record with expanded relations
- `get_customer_jobs` — all jobs for a given customer
- `search_customers` — by name, phone, email, or address
- `get_equipment` — customer equipment with custom fields
- `get_open_invoices` — outstanding invoices
- `get_techs` — technician list
- `get_job_statuses`, `get_job_categories`, `get_sources` — reference data
- `get_me` — current authenticated user
**Create tools:**
- `create_job`, `create_customer`, `create_estimate`
**API documentation:**
- `get_api_docs` — look up the Service Fusion API reference directly from the MCP connection. Sections: `index`, `jobs`, `customers`, `estimates`, `invoices`, `techs`, `data-types`, `authentication`, `known-issues`, `full`
## Prerequisites
- Node.js ≥ 18
- Service Fusion API credentials (My Office → Developer Settings → API Credentials)
## Setup (local / stdio transport)
```bash
git clone https://github.com/commair-tools/mcp-servicefusion-public.git mcp-servicefusion
cd mcp-servicefusion
npm install
npm run build
cp .env.example .env
# Edit .env and add SF_CLIENT_ID and SF_CLIENT_SECRET
```
### Claude Desktop
Add to your `claude_desktop_config.json` (see `claude_desktop_config.example.json`):
```json
{
"mcpServers": {
"service-fusion": {
"command": "node",
"args": ["/absolute/path/to/mcp-servicefusion/build/index.js"],
"env": {
"SF_CLIENT_ID": "your_client_id_here",
"SF_CLIENT_SECRET": "your_client_secret_here"
}
}
}
}
```
### Claude Code CLI
```bash
claude mcp add service-fusion node /absolute/path/to/mcp-servicefusion/build/index.js \
-e SF_CLIENT_ID=your_client_id -e SF_CLIENT_SECRET=your_client_secret
```
## Setup (remote / HTTP transport)
The server also supports Streamable HTTP transport for hosted deployments (Railway, Fly.io, Cloud Run, etc.) with OAuth 2.1 authentication.
### Environment variables
| Variable | Required | Description |
|---|---|---|
| `SF_CLIENT_ID` | Yes | Service Fusion OAuth client ID |
| `SF_CLIENT_SECRET` | Yes | Service Fusion OAuth client secret |
| `TRANSPORT` | Yes (for HTTP) | Set to `http` to enable HTTP transport |
| `PORT` | No | HTTP port (default: `3000`) |
| `BASE_URL` | Yes (for HTTP) | Public URL of your server, e.g. `https://mcp.example.com` — required for OAuth discovery |
| `MCP_OAUTH_PIN` | Recommended | PIN for browser-based OAuth approval (required by Claude.ai web) |
| `MCP_AUTH_TOKEN` | Optional | Static Bearer token for non-OAuth clients (e.g., Claude Code CLI) |
| `SF_API_BASE_URL` | No | Defaults to `https://api.servicefusion.com/v1` |
| `SF_TOKEN_URL` | No | Defaults to `https://api.servicefusion.com/oauth/access_token` |
### Deploying to Railway
1. Fork or import this repo on [Railway](https://railway.app)
2. Set the environment variables listed above
3. Railway auto-builds via `railway.toml` and exposes a public URL
4. Use that URL as your `BASE_URL`
### Authentication
**Claude.ai web** (OAuth flow): add the server URL (without trailing slash, e.g., `https://mcp.example.com/mcp`) as a remote MCP connector in Settings. Leave OAuth client ID/secret fields blank — the server advertises discovery metadata so Claude.ai handles the full OAuth handshake automatically. On first connect, you'll be redirected to a browser page to enter your `MCP_OAUTH_PIN`. After that, tokens auto-refresh for 30 days.
**Claude Code / CLI clients**: use the static token via the `Authorization: Bearer <MCP_AUTH_TOKEN>` header.
**No authentication**: if neither `MCP_OAUTH_PIN` nor `MCP_AUTH_TOKEN` is set, the server runs unauthenticated (not recommended for public-facing deployments).
## API Reference
The repo includes a complete Service Fusion API reference in [`service-fusion-api-reference.md`](./service-fusion-api-reference.md), auto-generated from the official RAML spec at [docs.servicefusion.com](https://docs.servicefusion.com). Agents can access it through the `get_api_docs` tool at runtime.
To regenerate it after Service Fusion updates their spec:
```bash
node scripts/update-api-docs.mjs
```
## Known Issues
### `/jobs` endpoint hangs without `sort` parameter
As of 2026-04-09, Service Fusion's `/jobs` list endpoint hangs indefinitely when queried without a `sort` parameter. This server works around it by defaulting all `/jobs` list queries to `sort=-start_date` in [src/client.ts](./src/client.ts). If you see hangs on other endpoints in the future, check whether they require a sort param too.
### Equipment is a nested resource
There is no top-level `/equipment` endpoint. Equipment must be fetched via `GET /customers/{customer-id}/equipment`. The `get_equipment` tool handles this by resolving `customer_name` to `customer_id` internally.
## API Limitations
Confirmed by Service Fusion support:
- No PUT, PATCH, or DELETE on any endpoint (read and create only)
- No native webhook/callback support
- No sandbox/test environment
- Rate limit: 60 requests/minute (server enforces backoff automatically)
## Tech Stack
- TypeScript + Node.js
- [`@modelcontextprotocol/sdk`](https://github.com/modelcontextprotocol/typescript-sdk) for MCP protocol
- Express for HTTP transport
- OAuth 2.1 with PKCE, Dynamic Client Registration, and resource indicators
## License
Business Source License 1.1 — see [LICENSE](./LICENSE)
**TL;DR:** Free to use, modify, and redistribute (including internally at HVAC businesses to manage your own operations). You may **not** resell it or offer it as a paid hosted service to third parties. On April 10, 2036 it automatically converts to the Apache License 2.0 (fully permissive).
TDQS
Scored across 16 tools
Each tool targets a distinct resource or action (customer, job, estimate, invoice, equipment, tech, etc.) with no overlap in functionality. The create, get, and search prefixes clearly separate intents.
All tools follow a consistent verb_noun pattern (e.g., create_customer, get_job_details, search_customers). Naming is uniform and predictable across the entire set.
16 tools is appropriate for a field service management API covering customer, job, estimate, invoice, equipment, and lookup functions. Each tool serves a necessary purpose without bloat.
The tool set covers creation and retrieval for core entities but lacks update and delete operations for customers, jobs, estimates, and invoices. This is a notable gap for full lifecycle management.