Skip to main content
Glama
memethzmli-ctrl

simpro-claude-connector

README.md
# Simpro → Claude Connector

An MCP server that lets Claude read and act on a [Simpro](https://www.simprogroup.com/)
instance. Ask Claude about your jobs, customers and quotes in plain language and
it queries Simpro directly — no exports, no copy-paste.

```
You:    Which Harborview jobs are still open, and what's holding up the board upgrade?

Claude: [calls search_customers, then list_jobs, then get_job]

        Two open for Harborview Property Group:

        #20841  Annual fixed wire testing        In Progress   £4,820.00   due 4 Sep
        #20871  Distribution board upgrade       Pending       £6,390.00   due 25 Sep

        The board upgrade is waiting on parts — purchasing noted a three week
        lead time on 26 August, with the board due the week of 16 September.
```

**Writes are off by default.** Out of the box Claude can read Simpro and nothing
else. The two tools that change data — adding a note and moving a job's stage —
are only advertised when you explicitly enable them. An assistant that can read
your job list is useful; one that can quietly change it is a liability.

**It runs before you have a token.** Demo mode serves realistic built-in data, so
you can install it, open Claude and see exactly how it behaves before handing
over API credentials.

---

## Tools

| Tool | What Claude uses it for |
| --- | --- |
| `list_jobs` | "What's open for this customer", "what's due next week", "what's awaiting parts" |
| `get_job` | Full record for one job, including its note history |
| `search_customers` | Resolve a customer name to an id before the other calls |
| `get_customer` | Contact details and address for one customer |
| `list_quotes` | Pipeline questions: outstanding, approved, expiring |
| `add_job_note` * | Append a note to a job's history |
| `set_job_stage` * | Move a job to a different stage |

\* Only offered when `SIMPRO_ALLOW_WRITES=true`.

## Install

Requires Python 3.10 or newer.

```bash
git clone https://github.com/memethzmli-ctrl/simpro-claude-connector.git
cd simpro-claude-connector
pip install -e .
```

## Try it without a Simpro account

```bash
simpro-connector demo
```

This runs a scripted set of tool calls against the bundled sample data and prints
exactly what Claude receives:

```
simpro-claude-connector 1.0.0 - demo mode (built-in sample data, no network calls)

search_customers(search='harborview')
[
  {
    "id": 4101,
    "name": "Harborview Property Group",
    "type": "Company",
    "email": "facilities@harborview.example",
    "phone": "+44 1482 555 0117",
    "address": "Unit 7, Prospect Business Park, Hull HU2 8PZ",
    "archived": false
  }
]

list_jobs(stage='Pending')
[
  {
    "id": 20860,
    "name": "Emergency lighting installation - science block",
    "customer_name": "St Chad's Academy Trust",
    "stage": "Pending",
    "status": "Awaiting customer approval",
    "due_date": "2026-10-16",
    "total_ex_tax": 18740.0,
    "currency": "GBP"
  },
  ...
]
```

Two other commands help when something looks wrong:

```bash
simpro-connector check    # print the resolved config and make one real call
simpro-connector tools    # print the tool schemas exactly as Claude sees them
```

## Connect it to Claude Desktop

Add this to `claude_desktop_config.json` and restart Claude Desktop. The full
annotated version is in [`examples/`](examples/claude_desktop_config.json).

```json
{
  "mcpServers": {
    "simpro": {
      "command": "simpro-connector",
      "args": ["serve"],
      "env": { "SIMPRO_MODE": "demo" }
    }
  }
}
```

Start in demo mode. Once Claude is answering from the sample data, switch to
live.

## Going live

| Variable | Required | Meaning |
| --- | --- | --- |
| `SIMPRO_MODE` | – | `demo` (default) or `live` |
| `SIMPRO_BASE_URL` | live | Your instance's API root, e.g. `https://acme.simprosuite.com/api/v1.0` |
| `SIMPRO_ACCESS_TOKEN` | live | Token generated in Simpro under **Setup → Integrations → API** |
| `SIMPRO_COMPANY_ID` | – | Which company within the instance. Default `0` |
| `SIMPRO_ALLOW_WRITES` | – | `true` to enable `add_job_note` and `set_job_stage`. Default off |
| `SIMPRO_PAGE_SIZE` | – | Rows fetched per API page, 1–100. Default 25 |
| `SIMPRO_TIMEOUT_SECONDS` | – | Per-request timeout. Default 30 |

Then confirm the connection before touching Claude:

```bash
SIMPRO_MODE=live \
SIMPRO_BASE_URL=https://acme.simprosuite.com/api/v1.0 \
SIMPRO_ACCESS_TOKEN=... \
simpro-connector check
```

A bad token, an unreachable host or a timeout each produce a plain sentence
saying what to fix, not a stack trace.

## Design notes

**Configuration, not hard-coding.** Simpro is tenant-hosted: every customer has
their own host, company id and credentials. Nothing outside `config.py` knows a
URL, so pointing this at a different instance is environment variables, not a
code change.

**Tolerant field mapping.** Simpro payloads vary slightly between instance
versions, so `client.py` accepts several plausible keys per field and normalises
them into one stable shape. Adapting to a specific customer's Simpro is a change
in one small module rather than a rewrite, and the tool layer never sees a raw
payload.

**Two guards on writes, not one.** Write tools are hidden from Claude when
writes are disabled *and* the dispatcher refuses them if called anyway. Each
write is narrow and validated — there is no generic "update job" accepting
arbitrary fields.

**Errors are answers.** A failed call returns readable text rather than raising,
so Claude can tell the person what went wrong and what to do about it instead of
just failing.

**Demo mode is a real rehearsal.** Both backends implement the same interface, so
a tool that works against the sample data works against a live instance.

## Tests

```bash
pip install -e ".[dev]"
pytest
```

45 tests covering configuration validation, tool schemas, read-only enforcement,
filtering and search, pagination against a stubbed transport, every HTTP error
path, field normalisation — and four end-to-end tests that launch the real MCP
server as a subprocess and drive it with an MCP client, exactly as Claude
Desktop does.

## Adapting it

- `simpro_connector/tools.py` — add or reshape the tools Claude is offered
- `simpro_connector/client.py` — endpoint paths and field mapping for a specific instance
- `simpro_connector/fixtures.py` — sample data for demo mode

## License

MIT