Salesmate MCP Server
README.md
# Salesmate MCP Server
A production-ready [Model Context Protocol](https://modelcontextprotocol.io) (MCP)
server that exposes the [Salesmate CRM](https://www.salesmate.io) to Claude
Desktop (and any other MCP client). Built with **FastMCP**, **HTTPX**,
**Pydantic**, and **python-dotenv**.
It lets Claude search contacts, inspect and update deals, create tasks and
notes, and review recent activity — all through clean, typed, validated tools.
---
## Get started
There are two ways to install. Pick one.
### Option A - One-click install (`.mcpb`, no terminal)
The cleanest end-user experience. Anyone can install with no clone, no
virtualenv, no JSON editing - just a click and a form.
1. Download the `.mcpb` bundle for your platform from the project's
[GitHub Releases](https://github.com/arnav-chauhan-kgpian/salesmate-mcp/releases)
page (or build it yourself - see below).
2. In Claude Desktop, go to **Settings -> Extensions -> Install Extension...**
and pick the `.mcpb` file.
3. When prompted, enter:
- **Salesmate Session Key** (the field is masked; stored in your OS keychain).
- **Salesmate Workspace URL**, e.g. `https://yourcompany.salesmate.io`.
4. Done. No restart needed - the `salesmate` tools appear in the tool picker.
> **Use the Session Key.** Salesmate shows three keys - Access Key, Secret Key,
> and **Session Key** (Setup -> Integrations -> API & Webhooks). The v4 API
> used here authenticates with the **Session Key**; the other two return
> `AuthorizationFailed`.
#### Build the bundle yourself
The `.mcpb` is platform-specific (Python wheels contain compiled binaries), so
build it on the OS you'll install it on:
```bash
git clone https://github.com/arnav-chauhan-kgpian/salesmate-mcp.git
cd salesmate-mcp
python -m venv .venv
# Windows: .\.venv\Scripts\activate macOS/Linux: source .venv/bin/activate
pip install -e .
python build_mcpb.py
# Output: dist/salesmate-mcp-<platform>-py<ver>.mcpb
```
Then install the resulting `.mcpb` as in step 2 above.
---
### Option B - Clone & connect (manual)
A new user with **no copy of the code** connects in four steps:
```bash
# 1. Clone the repo
git clone https://github.com/arnav-chauhan-kgpian/salesmate-mcp.git
cd salesmate-mcp
# 2. Create a virtualenv and install
python -m venv .venv
# Windows: .\.venv\Scripts\activate macOS/Linux: source .venv/bin/activate
pip install -e .
# 3. Connect to Claude Desktop (writes .env + Claude config, verifies live)
python setup_salesmate.py --verify
# 4. Fully quit and reopen Claude Desktop
```
### You must provide your own secrets
This repository ships **no credentials**. Every user supplies **their own**
Salesmate keys once. The `setup_salesmate.py` script will prompt for them and
write them into a local **`.env`** file (which is git-ignored and never
committed):
```dotenv
SALESMATE_API_KEY=<your Salesmate SESSION KEY>
SALESMATE_BASE_URL=https://yourcompany.salesmate.io
```
You can also create this `.env` by hand (copy `.env.example` to `.env` and fill
it in) instead of letting the script prompt you — then run
`python setup_salesmate.py --no-input --verify`.
> **Use the Session Key.** Salesmate shows three keys — Access Key, Secret Key,
> and **Session Key** (Setup → Integrations → API & Webhooks). The v4 API used
> here authenticates with the **Session Key**; the other two return
> `AuthorizationFailed`.
The setup script:
1. Collects your Session Key + workspace URL (or reuses an existing `.env`).
2. Writes them to `.env`.
3. Registers the `salesmate` server in your Claude Desktop config — preserving
any servers you already have, with a `.bak` backup. **No secrets are written
into the Claude config**; the server reads them from your `.env`.
4. With `--verify`, runs a live read-only check so you know it works before
opening Claude.
Non-interactive form (e.g. for scripted installs):
```bash
python setup_salesmate.py --api-key <SESSION_KEY> --base-url https://yourcompany.salesmate.io --verify
```
---
## Features
- 🔌 **8 MCP tools** covering contacts, deals, tasks, notes and activities.
- 🧱 **Modular architecture** — config, client, models and exceptions are
cleanly separated; each tool group lives in its own module.
- 🔁 **Resilient HTTP client** — async HTTPX with a 30s timeout, automatic
retries and exponential backoff (honouring `Retry-After`) for transient
`429`/`5xx`/network failures.
- 🧪 **Typed Pydantic models** for every resource; structured JSON is always
returned — never raw HTTP responses.
- 🛡️ **Robust error handling** — every failure is mapped to a structured error
object (`SalesmateAuthError`, `SalesmateNotFoundError`, ...).
- 🪵 **Structured logging** to stderr (stdout is reserved for the MCP transport).
- ✅ **Full unit-test suite** covering every tool and the HTTP client.
---
## Tools
| Tool | Signature | Description |
| --- | --- | --- |
| `search_contacts` | `(query: str)` | Search contacts by name, email or company. |
| `get_contact` | `(contact_id: int)` | Fetch a contact's full details. |
| `list_deals` | `(contact_id: int \| None)` | List deals, optionally for one contact. |
| `get_deal` | `(deal_id: int)` | Fetch a deal's full details. |
| `update_deal_stage` | `(deal_id: int, stage: str)` | Move a deal to a new stage. |
| `create_task` | `(title: str, due_date: str, contact_id: int \| None)` | Create a task. |
| `create_note` | `(contact_id: int, note: str)` | Attach a note to a contact. |
| `get_recent_activities` | `(contact_id: int)` | Recent activities for a contact. |
Every tool returns a JSON object. On success the payload contains `"ok": true`
plus the requested data; on failure it contains `"error": true` with a `type`
and `message` (and `status_code` for API errors).
---
## Project structure
```
salesmate-mcp/
├── server.py # FastMCP entrypoint
├── salesmate/
│ ├── __init__.py
│ ├── config.py # env loading + validation
│ ├── client.py # async HTTPX client (retries, errors)
│ ├── models.py # Pydantic response models
│ └── exceptions.py # exception hierarchy
├── tools/
│ ├── __init__.py # registration + error mapping
│ ├── contacts.py
│ ├── deals.py
│ ├── tasks.py
│ ├── notes.py
│ └── activities.py
├── tests/ # pytest suite (tools + client + config)
├── .env.example
├── pyproject.toml
├── README.md
└── claude_desktop_config_example.json
```
---
## Installation
### 1. Prerequisites
- Python **3.12+**
- A Salesmate account with an API **Session Key**
(*Setup → Integrations → API & Webhooks*). Salesmate shows three keys —
Access Key, Secret Key and Session Key — and the v4 API used here
authenticates with the **Session Key**.
### 2. Get the code
```bash
cd salesmate-mcp
```
### 3. Create and activate a virtual environment
**macOS / Linux:**
```bash
python3.12 -m venv .venv
source .venv/bin/activate
```
**Windows (PowerShell):**
```powershell
py -3.12 -m venv .venv
.\.venv\Scripts\Activate.ps1
```
### 4. Install dependencies
```bash
# runtime only
pip install -e .
# runtime + dev/test tools
pip install -e ".[dev]"
```
> Prefer not to install the project as a package? You can instead run:
> `pip install mcp httpx pydantic python-dotenv`
### 5. Configure environment variables
Copy the example file and fill in your credentials:
**macOS / Linux:**
```bash
cp .env.example .env
```
**Windows (PowerShell):**
```powershell
Copy-Item .env.example .env
```
Then edit `.env`:
```dotenv
SALESMATE_API_KEY=your-salesmate-access-token
SALESMATE_BASE_URL=https://yourcompany.salesmate.io
```
All other variables are optional — see `.env.example` for the full list.
### 6. Run the server
```bash
python server.py
```
The server communicates over **stdio**. When launched manually it will simply
wait for an MCP client to connect; logs are printed to stderr. Use the Claude
Desktop integration below for normal use.
---
## Claude Desktop integration
1. Locate your Claude Desktop config file:
- **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
2. Add the Salesmate server (see `claude_desktop_config_example.json`):
```json
{
"mcpServers": {
"salesmate": {
"command": "python",
"args": ["C:\\absolute\\path\\to\\salesmate-mcp\\server.py"],
"env": {
"SALESMATE_API_KEY": "your-salesmate-access-token",
"SALESMATE_BASE_URL": "https://yourcompany.salesmate.io"
}
}
}
}
```
Notes:
- Use the **absolute path** to `server.py`.
- If you use a virtual environment, point `command` at that env's Python
(e.g. `C:\\path\\to\\salesmate-mcp\\.venv\\Scripts\\python.exe` on Windows
or `/path/to/salesmate-mcp/.venv/bin/python` on macOS/Linux).
- Credentials can be supplied either via the `env` block above **or** via a
`.env` file next to `server.py`.
3. Restart Claude Desktop. The Salesmate tools will appear in the tool picker.
---
## Usage examples (in Claude)
- *"Search Salesmate for contacts at Acme."*
- *"Show me deals for contact 1024."*
- *"Move deal 555 to the Negotiation stage."*
- *"Create a task to follow up with contact 1024 due 2026-07-01."*
- *"Add a note to contact 1024: spoke with procurement, decision by Q3."*
- *"What are the recent activities for contact 1024?"*
---
## Configuration reference
| Variable | Required | Default | Description |
| --- | --- | --- | --- |
| `SALESMATE_API_KEY` | ✅ | — | Salesmate **Session Key** (not the Access/Secret key). |
| `SALESMATE_BASE_URL` | ✅ | — | Workspace base URL (`https://...`). |
| `SALESMATE_AUTH_HEADER` | | `accessToken` | Auth header name. |
| `SALESMATE_LINKNAME` | | derived from `base_url` | Value for the required `x-linkname` header. |
| `SALESMATE_TIMEOUT` | | `30` | Per-request timeout (seconds). |
| `SALESMATE_MAX_RETRIES` | | `3` | Retry attempts for transient errors. |
| `SALESMATE_BACKOFF_FACTOR` | | `0.5` | Base backoff delay (seconds). |
| `SALESMATE_LOG_LEVEL` | | `INFO` | Logging verbosity. |
---
## Running the tests
```bash
pip install -e ".[dev]"
pytest
```
The suite uses `pytest-asyncio` and an in-memory `httpx.MockTransport`, so it
runs fully offline and never touches the real Salesmate API.
---
## Adapting to your Salesmate API version
Salesmate exposes several API versions and the exact endpoint paths and search
payloads can differ between workspaces. All endpoint paths are centralised in
`salesmate/client.py` in the `ENDPOINTS` dictionary, and the request bodies for
search operations are small and self-contained — adjust them there if your
workspace expects a different shape. The auth header name can be changed without
code edits via `SALESMATE_AUTH_HEADER`.
---
## License
MIT
TDQS
A3.6/5.0
Scored across 8 tools
Disambiguation5/5
Each tool targets a distinct operation (create note, create task, get contact, get deal, get activities, list deals, search contacts, update deal stage) with no overlap.
Naming Consistency5/5
All tool names follow a consistent verb_noun snake_case pattern (e.g., create_note, get_contact, update_deal_stage), making it predictable.
Tool Count5/5
8 tools is well within the 3-15 range, covering core CRM entities (contacts, deals, tasks, notes) without being excessive.
Completeness2/5
Missing fundamental CRUD operations: no create or update for contacts, no create deal, no delete functionality. Users cannot create new contacts or deals, only attach notes/tasks to existing ones.