Skip to main content
Glama
arnav-chauhan-kgpian

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.