Skip to main content
Glama
fernandoludvig

RD Station CRM MCP

README.md
# rdstation-crm-mcp

[![CI](https://github.com/fernandoludvig/rdstation-crm-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/fernandoludvig/rdstation-crm-mcp/actions/workflows/ci.yml)
[![npm version](https://img.shields.io/npm/v/rdstation-crm-mcp.svg)](https://www.npmjs.com/package/rdstation-crm-mcp)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

An open-source **[MCP](https://modelcontextprotocol.io) server for [RD Station CRM](https://crm.rdstation.com)** — the leading CRM in Brazil and Latin America. Manage contacts, deals, tasks and notes, and get pipeline health reports, straight from Claude or any MCP-compatible client.

> "How's my sales pipeline this month?" → stage-by-stage totals, win rate, and the deals going stale.

![Demo: connecting to the server and running rdcrm_pipeline_overview against a real RD Station CRM account](docs/demo.gif)

## Why

RD Station CRM is huge in the LatAm market, but had no open-source MCP server. This project connects it to the MCP ecosystem so AI agents can work your pipeline: qualifying leads, moving deals, scheduling follow-ups, and answering questions about your sales data in natural language.

## Quick start

1. Get your **instance token** in RD Station CRM: *Profile → Products and integrations → Instance token*.
2. Add the server to your MCP client.

**Claude Desktop** (`claude_desktop_config.json`):

```json
{
  "mcpServers": {
    "rdstation-crm": {
      "command": "npx",
      "args": ["-y", "rdstation-crm-mcp"],
      "env": {
        "RDSTATION_CRM_TOKEN": "your-instance-token"
      }
    }
  }
}
```

**Claude Code:**

```bash
claude mcp add rdstation-crm -e RDSTATION_CRM_TOKEN=your-instance-token -- npx -y rdstation-crm-mcp
```

That's it. Ask Claude something like *"list my open deals"* or *"give me a pipeline overview"*.

## Tools

| Tool | Description |
| --- | --- |
| `rdcrm_search_contacts` | Search contacts by name, email or phone |
| `rdcrm_get_contact` | Contact details, including linked deals |
| `rdcrm_upsert_contact` | Create a contact, or update it if the email already exists |
| `rdcrm_list_deals` | List deals filtered by status, pipeline, stage, owner, dates |
| `rdcrm_get_deal` | Deal details: stage, value, owner, contacts, products |
| `rdcrm_create_deal` | Create a deal — accepts stage by *name*, resolved automatically |
| `rdcrm_update_deal` | Move stage, change owner, rating, close date, pause/resume |
| `rdcrm_close_deal` | Mark won or lost (lost reasons resolved by name) |
| `rdcrm_list_tasks` | List tasks by deal, assignee, status, type, due date |
| `rdcrm_create_task` | Create a task (call, email, meeting, whatsapp...) on a deal |
| `rdcrm_add_note` | Add a note to a deal's timeline |
| `rdcrm_pipeline_overview` | Pipeline health report: totals per stage, win rate, stalled deals |

### Design notes

These tools are designed for LLMs, not as a 1:1 API wrapper:

- **Names instead of IDs.** Stages, pipelines, users and lost reasons can be passed by name; the server resolves them against the account and lists the valid options when something doesn't match.
- **Compact responses.** List tools return one line per record with the fields that matter, plus explicit pagination hints. Large responses are truncated with guidance instead of flooding the context window.
- **Actionable errors.** A 401 tells you which env var to check; an unknown stage lists every stage in every pipeline.
- **Aggregation where it counts.** `rdcrm_pipeline_overview` answers the questions humans actually ask ("where are deals stuck?") with a single tool call.

## Remote deployments (Streamable HTTP)

The default (`rdstation-crm-mcp`) runs over stdio for a single local user, with the token read once from `RDSTATION_CRM_TOKEN`. For a team-hosted or registry-listed deployment (e.g. Smithery), run the Streamable HTTP variant instead:

```bash
npx -y rdstation-crm-mcp-http
```

This starts an HTTP server (`http://127.0.0.1:8080/mcp` by default) implementing the [MCP Streamable HTTP transport](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports#streamable-http), with proper session lifecycle (`initialize` → `Mcp-Session-Id` → `DELETE` to close).

Because a hosted server can serve more than one user, there's no single implicit token: each session sends its own `Authorization: Bearer <token>` header on `initialize`. A `RDSTATION_CRM_TOKEN` env var still works as a fallback default for a single-tenant self-hosted setup where every caller shares one CRM account.

Env vars:

| Var | Default | Purpose |
| --- | --- | --- |
| `PORT` | `8080` | Port to listen on |
| `HOST` | `127.0.0.1` | Bind address — use `0.0.0.0` for containers/cloud |
| `ALLOWED_HOSTS` | *(unset)* | Comma-separated Host header allow-list (DNS-rebinding guard); recommended when binding to `0.0.0.0` without a reverse proxy in front |
| `RDSTATION_CRM_TOKEN` | *(unset)* | Default token used when a session sends no Authorization header |

```bash
curl http://127.0.0.1:8080/health
# {"status":"ok","server":"rdstation-crm-mcp","sessions":0}
```

## Development

```bash
git clone https://github.com/fernandoludvig/rdstation-crm-mcp.git
cd rdstation-crm-mcp
npm install
npm test              # unit tests (API mocked with msw)
npm run typecheck
npm run build
RDSTATION_CRM_TOKEN=xxx npx @modelcontextprotocol/inspector node dist/index.js
```

The HTTP layer (`src/client/`) is isolated from the tools, with retry and exponential backoff for 429/5xx built in.

## Roadmap

- [ ] Organizations and products tools
- [ ] RD Station CRM API v2 support (OAuth) behind the same tool surface
- [x] Streamable HTTP transport for remote deployments
- [ ] Publish to MCP registries (Glama, PulseMCP, Smithery)

Contributions welcome — open an issue first for anything non-trivial.

## License

[MIT](LICENSE) © Fernando Ludvig

*Not affiliated with or endorsed by RD Station. Uses the public [RD Station CRM API v1](https://developers.rdstation.com/reference/crm-v1-introducao-e-requisitos).*

TDQS

A4.2/5.0

Scored across 12 tools

Disambiguation5/5

Each tool targets a distinct resource-action combination: search/get/upsert for contacts, list/get/create/update/close for deals, list/create for tasks, add for notes, and overview for reporting. There is no overlap—rdcrm_get_contact vs rdcrm_get_deal are clearly separated by resource, and update_deal explicitly defers close operations to close_deal, preventing confusion.

Naming Consistency4/5

The tools follow a highly consistent rdcrm_<resource>_<verb> pattern (rdcrm_search_contacts, rdcrm_get_deal, rdcrm_create_task) throughout. The only minor deviation is rdcrm_pipeline_overview and rdcrm_add_note, which use different verb styles (overview vs get/list, add vs create) rather than strictly following the verb_noun pattern.

Tool Count5/5

12 tools is well within the sweet spot for a CRM server covering contacts, deals, tasks, notes, and pipeline reporting. Each tool serves a clearly identifiable purpose in the sales workflow, and none feel redundant. The count feels right-sized for the domain.

Completeness4/5

The surface covers the full contact lifecycle (search/get/upsert), the deal lifecycle (list/get/create/update/close), plus tasks, notes, and pipeline analytics—strong coverage. Minor gaps exist: there is no tool to delete a contact or task, no tool to update a task (e.g., mark done), and no way to unlink a contact from a deal. These are workable gaps, not dead ends.