MCP SERVERBusiness plan

The CRM MCP server that lets an AI assistant run your pipeline

Connect Claude, Cursor, VS Code, Windsurf or any Model Context Protocol client to CRM Solid and your assistant stops describing your CRM and starts using it. 62 tools, 21 resources and 15 prompts over one authenticated endpoint, with every call limited by the scopes on the key you minted.

Free forever plan · No credit card required · Cancel anytime

62
Tools
Every one declares its required scope
21
Resources
Pre-loaded context reads by URI
15
Prompts
Named workflows a person picks
2025-06-18
Protocol revision
JSON-RPC 2.0, Streamable HTTP
Definition

The Model Context Protocol (MCP) is an open standard that lets an AI assistant call another piece of software through a described set of tools, resources and prompts, instead of guessing at it from pasted text.

A CRM MCP server is that standard placed in front of a CRM: it publishes contacts, conversations, deals, tasks, invoices and campaigns as operations an assistant can call, so the assistant can read your pipeline and change it inside the permissions you granted.

CRM Solid runs one at https://api.crmsolid.com/mcp. It speaks protocol revision 2025-06-18 over JSON-RPC 2.0, authenticates with a bearer API key you mint yourself, and covers twelve capability areas across twelve messaging channels.

Twelve capability areas, one endpoint

The 62 tools are not a random pile of endpoints. They cluster into twelve areas that mirror how a revenue team actually works, and each area maps onto its own read and write scopes.

Contacts

Search, open and enrich a person record: crm_search_contacts, crm_get_contact, crm_get_contact_activity, plus writes such as crm_tag_contact and crm_set_lead_score.

Conversations

Read the thread before answering it. crm_list_recent_conversations surfaces who is waiting, crm_get_conversation pages through history, crm_send_telegram_message queues the reply.

Inbox and email

crm_search_email_threads and crm_get_email_thread read the shared mailbox. crm_set_email_thread_status and crm_assign_email_thread route the work without sending mail.

Deals

crm_list_deals and crm_get_deal answer what is in the pipeline. crm_create_deal and crm_update_deal_stage move opportunities, with the Won transition deliberately reserved for the panel.

Tasks

crm_list_tasks answers what is due and what is overdue. crm_create_task books the follow-up, crm_complete_task closes it and stamps the completion time.

Pipelines

crm_list_pipelines and crm_get_pipeline expose every board with its ordered stages and live per-stage counts, so an assistant learns the shape of your funnel before touching it.

Finance

crm_finance_summary, crm_list_transactions, crm_list_invoices and crm_revenue_sources_summary report on the ledger. All four are reporting only: nothing here moves money.

Sequences

crm_list_sequences and crm_get_sequence_status report campaign progress. crm_pause_sequence and crm_resume_sequence are the two controls an assistant is trusted with.

Social DMs

crm_social_inbox_summary opens triage in one call. crm_list_social_conversations and crm_get_social_conversation load the thread, crm_send_social_message answers it.

Social posts

crm_list_social_posts shows the calendar, crm_schedule_social_post books content across accounts, crm_update_social_post and crm_cancel_social_post fix what has not gone out yet.

Webhooks

crm_list_webhooks and crm_list_webhook_deliveries answer why an endpoint is not firing. crm_create_webhook registers one and returns its signing secret exactly once.

Agents and jobs

crm_list_agents reports what is automating replies, crm_run_agent test-drives one without delivering anything, crm_list_jobs and crm_get_job show whether a send actually left.

What is the Model Context Protocol?

The Model Context Protocol is an open standard for connecting an AI assistant to external software through a self-describing interface. A server publishes what it can do, a client asks for that list, and the model chooses from it. Nothing about the pairing is hard-coded on either side, which is the entire point: the assistant learns your CRM at runtime rather than shipping with a built-in idea of what a CRM is.

Before a standard existed, every combination of assistant and business tool needed its own bespoke integration. Ten assistants and ten tools meant a hundred adapters, each maintained by somebody who cared about only one side of it. MCP inverts the arithmetic. The CRM describes itself once, and every compliant client can drive it. The same argument won for the Language Server Protocol in code editors: one server, many editors, nobody writing the same completion engine ten times.

The protocol has three primitives, and the difference between them is about who is in control:

  • Tools are actions the model decides to call. Each one carries a name, a description and a JSON Schema for its input, so the model knows what arguments are valid before it tries. In CRM Solid, crm_search_contacts and crm_create_task are tools.
  • Resources are readable context addressed by a URI, which the client attaches to the conversation. They exist so an assistant can start a conversation already knowing something, rather than burning a tool call on a question it will ask every single time. CRM Solid exposes 21 of them, including crm://social/inbox and crm://deals/pipeline.
  • Prompts are named, parameterised workflows that a person picks deliberately. They are not something the model invokes on a whim. CRM Solid ships 15, including daily-briefing, pipeline-review and social-inbox-triage.

That three-way split matters more in a CRM than almost anywhere else, because a CRM is a system of record. Tools are the model acting. Resources are the client deciding what background to load. Prompts are a human saying: run this specific play, now, on this specific record. Any product that collapses all three into one undifferentiated pile of functions has made it harder for you to reason about what your assistant is allowed to do on its own.

MCP is transport agnostic. A server that runs as a local process communicates over standard input and output. A server that lives on the internet, like a hosted CRM, uses HTTP. CRM Solid is the second kind, so everything below describes the remote path.

Why MCP matters for a CRM specifically

A CRM is the system where an assistant that cannot act is least useful, because almost every worthwhile CRM question ends in a change. Who should I reply to first ends in a reply. Which deals are stalling ends in a task. What did we agree with this customer ends in a note that somebody has to write down. An assistant that can only talk about your pipeline leaves the last and most tedious step to you, every single time.

The gap is easiest to see in the copy-paste loop most teams are living in today. You export a view to CSV or screenshot a board, paste it into a chat window, get a genuinely good analysis, then retype the outcome back into the CRM by hand. Three problems compound. The data was stale the moment it left the system. The analysis is detached from the records it describes, so nothing links back. And the write-back is manual, which means on a busy day it does not happen at all and your CRM quietly rots.

An MCP connection removes all three. The read is live, because the tool call hits the database at the moment of the question. The result carries record identifiers, so the follow-up action targets the right row. And the write is one more tool call, which is the difference between an insight and a change.

What MCP replaces

Copy-paste and screenshots. The most common CRM and AI workflow in 2026 is still a human acting as a data bus between two browser tabs. MCP deletes that role. You stop being the integration.

Tab switching. A rep answering a DM checks the contact record, the last email thread, the open deal and the overdue task, in four places. With MCP the assistant assembles that picture in one turn, because crm_get_contact already returns the last ten messages and crm_get_contact_activity returns the timeline behind them.

Brittle no-code automations. A zap encodes a decision at build time: when this trigger fires, always do that. It works beautifully for deterministic plumbing and badly for judgement. An assistant with MCP access decides at call time, with the actual thread in front of it. The two are complements rather than rivals, and we work through exactly where each one wins on the MCP versus REST API versus automation tools comparison.

There is one more reason a CRM is the right place to attach an assistant. It is where multi-channel context already lives. CRM Solid unifies Telegram, WhatsApp, Instagram, Facebook, X, LinkedIn, TikTok, YouTube, Threads, Pinterest, Reddit and Bluesky DMs alongside email and live chat in one unified inbox. An assistant plugged into that inbox can answer a question like which customer has been waiting longest across every channel, which no single-channel tool can answer at all.

How the CRM Solid MCP server is built

The server is a remote Model Context Protocol endpoint at https://api.crmsolid.com/mcp, speaking JSON-RPC 2.0 over the Streamable HTTP transport at protocol revision 2025-06-18, and authenticated with a bearer API key. Every element of that sentence has a practical consequence, so here is each one in plain language followed by the exact wire detail.

JSON-RPC 2.0 is the message format

In plain language: every message is a small JSON envelope with a method name, some parameters and an id, and every response comes back matched to that id. It is a boring, forty-year-old idea and that is a feature. There is no bespoke framing to learn and no ambiguity about which reply belongs to which request.

On the wire: a request body looks like {"jsonrpc":"2.0","id":1,"method":"tools/list"}. Errors are returned as a JSON-RPC error object rather than an HTTP status where the protocol calls for it, which is why a missing scope shows up as error code -32002 in the body rather than an HTTP 403.

Streamable HTTP is the transport

In plain language: one URL handles everything, and the connection upgrades to a stream only when there is something to stream. You do not run a long-lived socket just to ask a question.

On the wire, the three verbs each have a job:

  • POST sends a JSON-RPC request or notification. This is how initialize, tools/list, tools/call, resources/read and prompts/get all travel. The client should send Accept: application/json, text/event-stream so the server can answer with either a single JSON body or an event stream.
  • GET opens the server-sent events stream, which is how the server pushes messages the client did not ask for. A client that only makes request and response calls never needs to open it.
  • DELETE ends a session explicitly. It is the polite way to hang up, and it releases the session immediately instead of waiting for a timeout.

Sessions, and why stateless still works

In plain language: the server can remember you across calls, but it does not have to. That matters for anyone running the assistant inside a serverless function or a CI job, where the same process may never handle two requests in a row.

On the wire: the response to initialize carries an Mcp-Session-Id header. A client that keeps a session echoes that value back on later requests and tears it down with a DELETE. A client that sends no session header still gets answers, because stateless calls are supported: authentication comes from the key on every single request, not from the session. The session is an optimisation, never the security boundary.

Bearer authentication and the discovery document

In plain language: you mint a key in the panel, the client sends it on every request, and there is no login dance. A discovery document tells standards-aware clients how the endpoint expects to be authenticated.

On the wire: pass Authorization: Bearer csk_live_... with every request. Keys are created in the panel at Settings, then Developers, then API keys, and the full token is shown once. The endpoint publishes an RFC 9728 protected resource document at GET /.well-known/oauth-protected-resource, which advertises bearer API-key authentication. Its authorization_servers array is currently empty, and that single detail explains a whole class of connection failures: clients that will only connect through an authorization server flow, rather than a static header, cannot use a key directly. That is why Claude Desktop connectors and ChatGPT custom connectors need a different setup path than Claude Code or Cursor, which we walk through on the connect Claude to your CRM page.

camelCase output

In plain language: if you parse MCP tool results in your own code, expect contactId and not ContactId.

On the wire: MCP responses are camelCase throughout, while the REST v1 API returns PascalCase properties. The two surfaces sit on the same data and the same permissions model, but they were shaped for different consumers, and mixing up the casing is the most common cause of a null field when a developer moves a script from one to the other. Within MCP the convention is consistent across all 62 tools, so you learn it once.

Wire summary. Endpoint https://api.crmsolid.com/mcp. Transport Streamable HTTP. Protocol 2025-06-18. Format JSON-RPC 2.0. Auth Authorization: Bearer csk_live_.... Session header Mcp-Session-Id, optional. Scope failure -32002. Rate limit 60 requests per minute by default, 300 ceiling on Business. Discovery /.well-known/oauth-protected-resource.

What the 62 tools, 21 resources and 15 prompts cover

The surface covers twelve capability areas: contacts, conversations, inbox and email, deals, tasks, pipelines, finance, sequences, social DMs, social posts, webhooks, and agents and jobs. Cutting across all of them are three analytics tools, crm_dashboard_summary, crm_messaging_stats and crm_top_contacts, which answer the how-am-I-doing questions without belonging to any one area. What follows is a paragraph per area with representative tool names. The complete reference, with every tool, its required scope and whether it reads or writes, is on the MCP tools reference.

Contacts

Eight read tools and seven write tools, the largest area by some distance. crm_search_contacts finds a person by name, username or phone and returns up to 25 results ordered by most recently contacted. crm_get_contact opens one record and includes the last ten messages exchanged, which is usually enough context for a reply without a second call. On the write side, crm_tag_contact, crm_set_lead_score and crm_assign_contact each log an entry to the activity timeline, so the change is attributable afterwards. One honest caveat worth knowing before you let an assistant loose: crm_add_contact_note appends to a 500-character field, and once it is full the oldest text is dropped from the front to make room.

Conversations

crm_list_recent_conversations is the tool most assistants reach for first, because it answers who needs a reply with a last-message preview per contact. crm_get_conversation pages back through a thread fifty messages at a time. Sending is deliberately split by channel and by scope: crm_send_telegram_message requires telegram:send and queues asynchronously, while crm_send_twitter_dm requires twitter:send and goes out through the connected X session. crm_list_accounts is the call that tells the assistant which account id it is allowed to send from, and skipping it is the usual reason a send fails on the first try.

Inbox and email

Two read tools and two write tools, and the important detail is what the write tools deliberately do not do. crm_search_email_threads and crm_get_email_thread read the shared mailbox, the second returning plain-text messages oldest-first along with any AI summary and lead score. crm_set_email_thread_status and crm_assign_email_thread move a thread through open, pending and closed, or hand it to a colleague. Neither sends mail. An assistant with email:read and email:write can run your triage without ever being able to email a customer, which is exactly the shape most support teams want first.

Deals

crm_list_deals returns the pipeline ordered by stage then value, with open-task counts attached, so a forecast question needs one call. crm_get_deal opens one with its linked tasks and resolved contact name. crm_create_deal and crm_update_deal_stage handle the writes, and both stop short of the same line: a deal can move between lead, qualified, proposal, negotiation and lost, but it cannot be moved to won over MCP, because won books an income entry in the ledger. Closing a deal stays a human action in the panel.

Tasks

crm_list_tasks sorts by due date then priority, which makes what is overdue and what is due today a single call. crm_create_task books a follow-up and can link it to a contact and a deal at the same time, so the reminder carries its own context. crm_complete_task marks one done and stamps the completion time, or reopens it by passing an explicit status. This is the smallest area on the server and, in practice, the one that changes daily behaviour fastest, because it is where an assistant turns a conclusion into an obligation.

Pipelines

crm_list_pipelines and crm_get_pipeline are read-only and exist to teach an assistant the shape of your CRM before it edits anything. They return each board with its ordered stage columns and a live contact count per stage. A well-behaved assistant calls one of them before it tries to move a contact, because stage names are yours, not ours, and guessing them is how an assistant produces a confident, wrong answer.

Finance

Four tools, all read-only, all reporting. crm_finance_summary returns realised income, expense and net per currency over a window, plus outstanding totals and the top expense categories. crm_list_transactions lists ledger entries newest-first. crm_list_invoices summarises what is still owed per currency. crm_revenue_sources_summary reports the connected revenue feeds with their last sync status and never returns the credentials behind them. None of these four can create, edit, refund, settle or pay anything. A finance assistant on this server can tell you the number and cannot change it.

Sequences

crm_list_sequences answers what campaigns are running, with status and target progress. crm_get_sequence_status goes deeper on one, returning processed, successful and failed counts along with the message steps and recent job activity. The write side is intentionally two controls rather than a full editor: crm_pause_sequence and crm_resume_sequence, both idempotent. An assistant can stop a campaign that is misfiring at three in the morning. It cannot rewrite your outreach copy while you sleep. Building the campaign itself stays in the sequence builder.

Social DMs

Five read tools and two write tools spanning every connected network. crm_social_inbox_summary is the opening move for triage: one call returns conversation and unread totals overall and per network, plus the threads still waiting on a reply, oldest first. crm_list_social_messages pages through a thread and carries transcripts for voice notes and both wordings for translated messages. crm_send_social_message is the one that reaches a real person: it delivers through the account that owns the thread, pauses AI auto-reply for that contact so two robots do not answer at once, and records the send on the CRM timeline. Platform windows still apply, and WhatsApp only allows free-form replies within 24 hours of the customer's last message. The full social workflow has its own page: social media management over MCP.

Social posts

Three read tools and three write tools. crm_list_social_posts shows what is scheduled and what published, including any failure reason. crm_schedule_social_post books content on one or more connected accounts, creating one post per target account, and enforces per-platform rules at call time: TikTok and YouTube need a video, Instagram needs media, X caps at 280 characters. crm_update_social_post and crm_cancel_social_post only touch posts that are still pending. Anything already published, in flight, failed or cancelled is rejected, which means an assistant cannot quietly rewrite history.

Webhooks

crm_list_webhooks and crm_list_webhook_deliveries exist mostly to answer one question: why is my endpoint not firing. The delivery tool returns recent attempts with status, attempt count, last response code and last error, newest first, which is usually enough to diagnose it without opening the panel. Signing secrets are never returned by the list tool, only a short preview. crm_create_webhook registers an HTTPS endpoint and returns its signing secret exactly once, so store it immediately. crm_delete_webhook is the single hard delete on the entire server and is annotated as destructive.

Agents and jobs

crm_list_agents reports the AI agents currently automating replies, with status, channels, response mode, model and a 24-hour run count. crm_run_agent is a playground: it runs an agent against a sample inbound message and returns the reply it would have sent, without delivering anything and without creating, changing or deleting a single CRM record. It is flagged as a non-read-only tool purely because each run calls an external model provider and spends AI credits. crm_list_jobs and crm_get_job close the loop on outbound sending, showing whether a queued message actually left and, if it did not, the exact error.

Resources and prompts

Alongside the tools, 21 resources give a client something to load before the first question is asked. crm://me carries identity and plan. crm://social/inbox carries unread totals per network and the twenty most recently active DM threads. crm://tasks/overdue carries only tasks whose due date has already passed, which is a different list from crm://tasks/today and worth keeping separate. The 15 prompts are the workflows a person triggers on purpose: daily-briefing, triage-inbox, pipeline-review, weekly-finance-report, lost-deal-postmortem, dm-reply-draft and nine more.

Five-minute setup

Three steps: mint a scoped key, add the server to your client, verify with a question that has a checkable answer. The per-client detail differs more than you would expect, because every vendor invented its own configuration file shape, so the exact form for Claude Code, Claude Desktop, Cursor, VS Code and Windsurf lives on the connect Claude to your CRM page. What follows is the summary plus two correct snippets.

Step 1: mint a scoped key

In the panel, open Settings, then Developers, then API keys, and create a key. Choose only the scopes this assistant needs. A reporting assistant is fine with contacts:read, deals:read, pipelines:read and analytics:read. The full token starts with csk_live_ and is shown once, so copy it into an environment variable straight away and never into a repository.

Step 2: add the server

In Claude Code, one command does it. The -s flag chooses where the entry is stored: local for just you in this project, project for a checked-in .mcp.json, user for every project on your machine.

claude mcp add --transport http crmsolid https://api.crmsolid.com/mcp \
  --header "Authorization: Bearer csk_live_YOUR_KEY" \
  -s user

If you prefer a file that lives with the repository, this is the correct .mcp.json shape. The type field is not optional: a url entry without "type": "http" is parsed as a local stdio command and the connection fails with an empty tool list rather than a useful error.

{
  "mcpServers": {
    "crmsolid": {
      "type": "http",
      "url": "https://api.crmsolid.com/mcp",
      "headers": {
        "Authorization": "Bearer csk_live_YOUR_KEY"
      }
    }
  }
}

To see the raw wire before trusting a client, ask the server what it can do with a single POST. The Accept header carries both content types because a Streamable HTTP server may answer with either.

curl -X POST https://api.crmsolid.com/mcp \
  -H "Authorization: Bearer csk_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

A full handshake starts with initialize, which is where the protocol revision is negotiated and where the response carries the Mcp-Session-Id header if you want to keep a session:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "initialize",
  "params": {
    "protocolVersion": "2025-06-18",
    "capabilities": {},
    "clientInfo": { "name": "my-client", "version": "1.0.0" }
  }
}

Step 3: verify with a real question

Do not verify by asking whether the connection works. Ask something only your CRM can answer and then check it. Good first questions: which social conversations are still waiting on a reply, how many deals sit in each pipeline stage, what tasks are overdue right now. The assistant should call crm_social_inbox_summary, crm_list_deals or crm_list_tasks, and the numbers should match the panel. If the answer is vague or hedged, the tool list is probably empty and the assistant is improvising.

The security model, in depth

The security model rests on five things: a per-key scope list checked on every tool call, a write surface that deliberately stops short of irreversible actions, a per-key rate limit, key rotation you control, and tenant isolation enforced at the query level rather than in the model prompt. None of it depends on the assistant behaving well, which is the only sane way to design permissions for a system where the caller is a language model.

Scopes: the exact strings

Every tool declares the one scope it requires. These are the scope strings a key can carry, and the count is the number of tools each one unlocks in the current build:

  • Contacts and conversations: contacts:read (8 tools), contacts:write (7), telegram:read, telegram:send (1), twitter:send (1).
  • Social: social:read (5), social:write (2), posts:read (3), posts:write (3).
  • Sales: deals:read (2), deals:write (2), tasks:read (1), tasks:write (2), pipelines:read (2).
  • Inbox: email:read (2), email:write (2).
  • Operations: sequences:read (2), sequences:write (2), jobs:read (2), webhooks:read (2), webhooks:write (2), agents:read (1), agents:run (1).
  • Reporting: analytics:read (3), finance:read (4).
  • Advanced, offered but unchecked by default: finance:write, email:send, keys:manage. If you find yourself reaching for one of these for a chat assistant, stop and ask what you are actually trying to automate.

Note the punctuation, because it is a common source of a failed first call: the resource comes first and the verb second. It is contacts:read, never read:contacts. When a key is missing a scope, the call fails with JSON-RPC error -32002 and a data object carrying requiredScope and granted, so the assistant can tell you precisely which permission to add instead of reporting a generic failure.

Three least-privilege recipes

Scope sprawl happens when one key is minted for everything and then reused. The alternative is one key per assistant persona. These three cover most teams:

  1. The reporting analyst. Scopes: contacts:read, deals:read, pipelines:read, tasks:read, analytics:read, finance:read. It answers forecast, workload and revenue questions and cannot change a single record. This is the key you share most widely, and the one whose leak costs you the least.
  2. The inbox copilot. Scopes: contacts:read, contacts:write, social:read, email:read, email:write, tasks:read, tasks:write, agents:read, agents:run. It triages, tags, scores, assigns, drafts and books follow-ups. Because neither email:write nor social:read can deliver a message, this persona can run your whole triage loop without ever reaching a customer. Every change it makes is reversible and lands on the activity timeline.
  3. The outreach operator. Everything the copilot has, plus social:write, telegram:send, twitter:send, posts:read, posts:write, sequences:read, sequences:write, jobs:read. This is the only persona that can reach a real person, so it should be the one with a named owner, the shortest rotation interval and the tightest review.

The safe-write boundary

The write tools deliberately stop short of irreversible money and identity actions. This is a design decision, not an oversight, and it is worth spelling out exactly where the line sits:

  • No ledger writes. All four finance tools are reporting only. Nothing on the MCP surface creates a transaction, edits one, issues a refund or settles anything.
  • No invoice payment. crm_list_invoices reports what is outstanding and returns no payment link. There is no tool that sends, voids or pays an invoice.
  • No forcing a deal to won. crm_update_deal_stage accepts lead, qualified, proposal, negotiation and lost, and rejects won, because won books income. That transition stays a human decision in the panel.
  • Agent runs never deliver. crm_run_agent returns the reply an agent would have sent. The reply is never delivered to any contact and no CRM record is created, changed or deleted by the run.
  • One hard delete, clearly labelled. crm_delete_webhook permanently removes an endpoint you registered. It is the only destructive operation on the server and carries the destructive annotation so a client can require confirmation.
  • Secrets never come back out. crm_list_webhooks returns a short preview of a signing secret, never the secret. crm_create_webhook returns the secret once at creation. crm_revenue_sources_summary never returns the credentials for a connected revenue feed.

Two write tools do reach the outside world and deserve deliberate thought before you grant them. crm_send_social_message delivers to a real person immediately. crm_schedule_social_post publishes to a real audience straight away when publishNow is set. Everything else on the write surface changes a record you can change back.

Rate limits

The default limit is 60 requests per minute per key, and a Business workspace can raise a key to a ceiling of 300 per minute. Going over returns HTTP 429 with a Retry-After header giving the number of seconds to wait. The limit is applied per key rather than per workspace, which is the important part: an assistant stuck in a retry loop throttles only itself and cannot starve your reporting dashboard or your webhook processor. If you are running several assistants, give each its own key for this reason alone, independent of the scope argument.

Rotation and revocation

The key is validated on every single request rather than exchanged for a session token, so revocation takes effect on the next call. There is no grace period in which an already-connected client keeps working, and no cached session to expire. That makes the rotation procedure simple and zero-downtime if you do it in this order: mint the replacement key with the same scopes, update the client configuration and confirm it lists tools, then revoke the old key. Both keys are valid during the overlap, so nothing fails mid-cutover.

Rotate on a schedule for any key carrying a sending scope, and rotate immediately whenever a key has been pasted into a chat window, a ticket, a screenshot or a repository. Because keys are per-assistant in the recipe above, rotating one never disturbs the others.

What the audit trail looks like

The audit trail is the CRM's own activity timeline, which is a better place for it than a separate log nobody opens. Write tools record what they did on the record they touched: crm_tag_contact logs a TagAdded entry, crm_untag_contact logs TagRemoved, crm_set_lead_score logs ScoreChanged and marks the score as a manual override rather than an AI one, crm_assign_contact logs Assigned or Unassigned, crm_add_contact_note appends a timestamped note, and crm_send_social_message records the send on the timeline. Read it back with crm_get_contact_activity, newest first, or open the contact in the panel and see the same entries. On the delivery side, crm_list_jobs and crm_get_job show every outbound send with its status and its last error.

Tenant isolation

An API key identifies exactly one workspace user, and every tool resolves its query against that authenticated user id before it touches the database. There is no tool parameter that names a different account, workspace or tenant, so there is nothing for a model to fill in wrongly and nothing for a prompt injection to aim at. This matters specifically in an MCP context: the caller is a language model that can be influenced by content it reads, so the isolation cannot live in an instruction telling the model to stay in its lane. It lives in the query.

The same reasoning applies to the scope check. It runs on the server before the tool body executes, not in the tool description the model reads. A model that has been talked into wanting to send a message still cannot send one with a key that lacks social:write.

Four worked use cases, before and after

1. Sales rep morning triage

Before. Open the CRM, open the social inbox, open email, scan three lists for anything unanswered, guess at priority from whatever is visible on the first screen, and start typing. Twenty minutes, most of it spent deciding rather than doing, and the oldest unanswered thread is frequently the one nobody scrolled to.

After. Ask: who is waiting on a reply across every channel, ranked by how long they have waited and how valuable the relationship is, and tell me what each one wants. The assistant calls crm_social_inbox_summary for the waiting threads oldest first, crm_list_recent_conversations for the direct channels, crm_search_email_threads for the mailbox, and crm_get_contact on the top few for context. You get a ranked list with a one-line reason each. Follow up with: draft a reply to the first three and book me a task to call the second one tomorrow. That is crm_get_social_conversation for thread history and crm_create_task for the reminder.

2. Support handover

Before. A colleague goes on leave and their open threads get reassigned by dragging rows in a list, with no shared understanding of what any of them is actually about. The receiving agent reads each thread from scratch and the customer repeats themselves.

After. Ask: summarise every open email thread assigned to this person, tell me which are blocked on us, and reassign those to me. The assistant calls crm_search_email_threads to pull the open threads, crm_get_email_thread on each one to read the messages and any AI summary, then crm_assign_email_thread to move the blocked ones. It can add crm_add_contact_note so the handover context lives on the contact rather than in a chat log that disappears. The whole loop needs email:read, email:write and contacts:write, and cannot send a single email.

3. Finance review

Before. Export the ledger, build a pivot, reconcile currencies by hand, and produce a number you half trust two hours later.

After. Ask: how did the business do over the last 30 days by currency, what is still outstanding, and which expense categories moved most. The assistant calls crm_finance_summary for realised income, expense and net per currency, crm_list_invoices for what is owed, and crm_list_transactions to look at the entries behind an anomaly. The weekly-finance-report prompt packages the same thing as a repeatable weekly workflow. This runs on finance:read alone, which means the assistant that produces your finance review cannot touch your ledger even if it is asked to. Pair it with the CRM finance module for the panel view.

4. Weekly pipeline hygiene

Before. A recurring calendar block called pipeline review that gets skipped, followed by a quarter-end scramble to work out which deals were real.

After. Ask: show me open deals by stage with value and probability, flag anything with no activity in two weeks, and book me a task for each one. The assistant calls crm_list_deals and crm_list_pipelines to get the board shape, crm_get_contact_activity to check for recent movement, then crm_create_task per stalled deal and crm_update_deal_stage where a deal has genuinely slipped backwards. The pipeline-review prompt does the analysis half as a one-click workflow, and lost-deal-postmortem handles the ones that did not make it. Remember that moving a deal to won is not available here by design: the assistant can clean the board, and you close the business.

Plans and cost

MCP access is part of the Business plan. A key minted on a Free or Pro workspace authenticates correctly and still answers HTTP 402 on every MCP request, because entitlement is checked separately from authentication. That separation is deliberate and has a useful side effect: a 402 tells you the key itself is fine, so you are looking at a plan question rather than a credential question.

MCP comes with the plan rather than as a metered add-on, and the rate limit is the fair-use boundary: 60 requests per minute per key by default, up to a 300 per minute ceiling on Business. Because the entitlement check runs on every request rather than at connection time, upgrading takes effect on the key you already have: no re-mint, no client reconfiguration. Current plan details are on the pricing page.

One cost that is worth naming because it is easy to miss: crm_run_agent calls an external model provider on every run and spends AI credits from your workspace. It is the only tool on the server that does, which is exactly why it is annotated as a write tool despite changing nothing.

Troubleshooting

Nearly every failed first connection is one of six things. The response itself usually tells you which:

What you seeWhat it meansWhat to do
HTTP 401The key is invalid, revoked, or never arrived intact.Confirm the token starts with csk_live_ and that the header is exactly Authorization: Bearer <token>. If the key works in curl but not in your client, suspect a truncated header, below.
HTTP 402The key is valid but the workspace is on Free or Pro. MCP is a Business-plan capability.Upgrade the workspace. The same key starts working immediately, with no re-mint and no client change.
JSON-RPC error -32002The key does not carry the scope this tool requires. The error data object names it.Read data.requiredScope and compare it with data.granted. Add the scope, or mint a second key for that persona rather than widening the first one.
HTTP 429 with Retry-AfterMore than 60 requests in a minute on this key, or more than the 300 ceiling if it has been raised.Wait the number of seconds in Retry-After. If it happens repeatedly, the assistant is probably looping: give it its own key so it throttles only itself.
Empty tool list after connectingThe client parsed the entry as a local stdio command, or the configuration used the wrong key name for that client.In a .mcp.json, add "type": "http". Client shapes differ: the per-client forms are on the Claude setup page.
Silent 401 from one client onlyThe client did not escape the space inside Authorization: Bearer ... when it was passed as a single argument, so the header arrived truncated.Split it. Pass --header "Authorization:${AUTH_HEADER}" with the full Bearer csk_live_... value in an environment variable.

One more diagnostic worth knowing: if a tool call returns data but the fields you expected are all null, check the casing. MCP results are camelCase and the REST v1 API is PascalCase, and a script moved from one to the other will parse cleanly and silently find nothing.

Honest limits

Things this server does not do, stated plainly so you do not discover them at the wrong moment:

  • It is Business plan only. Free and Pro get HTTP 402 even with a perfectly valid key.
  • Static keys, not an authorization server flow. The protected resource document advertises bearer API-key authentication and its authorization_servers list is currently empty. Clients whose only connector path requires an authorization server cannot use a static key directly and need a bridge process instead.
  • Finance is read-only here. Reporting works well; the server will not move money, settle an invoice or book revenue for you.
  • Deals cannot be closed won over MCP. That is on purpose, and it will keep being on purpose.
  • Telegram sends are asynchronous. crm_send_telegram_message queues a job. Confirm delivery with crm_list_jobs or crm_get_job rather than assuming a successful tool call means a delivered message.
  • Platform rules still apply. WhatsApp only allows free-form replies within 24 hours of the customer's last message, X caps a post at 280 characters, TikTok and YouTube require video. The server enforces these at call time, which means the assistant will be told no rather than silently producing a broken post.
  • The contact note field is 500 characters. Once it is full, crm_add_contact_note drops the oldest text from the front to make room, so it can remove earlier note text. Use it for durable facts, not for a running transcript.
  • Sequences can be paused, not authored. Building a campaign stays a panel job.

If you need something on this list, the REST v1 API covers a wider surface for code you write yourself, and the API and MCP integration guide walks through webhooks, signature verification and the parts of the platform that are better driven by a service than by an assistant.

“The most useful thing an assistant can do with a CRM is not summarize it. It is to change one record correctly, refuse the change it should not make, and leave a trail you can read afterwards.”
CRM Solid engineering
On the design of the MCP write tools

Three assistant personas, three keys, three blast radii

The single most valuable security decision is not which tools exist. It is which scopes each assistant's key carries. Start with the leftmost recipe and widen only when a specific job needs it.

CapabilityReporting analystRecommendedInbox copilotOutreach operator
Reading the CRM
Search contacts and read threads
contacts:read
Read the social inbox
social:read
Read deals, pipelines and tasks
deals:read, pipelines:read, tasks:read
Read the ledger and invoices
finance:read
Changing the CRM
Write notes, tags and lead scores
contacts:write
Create and complete tasks
tasks:write
Route email threads without sending mail
email:write
Move a deal between open stages
deals:write
Reaching a real person
Answer a social DM
social:write
Queue a Telegram message
telegram:send
Publish or schedule a post
posts:write
Pause or resume a campaign
sequences:write
Blast radius if the key leaks
Could contact a customer
Yes
Could change a record
Reversible
Reversible
Could move money

No persona can move money: all four finance tools are reporting only and finance:write is an advanced scope that is unchecked by default. Reversible means the change lands on the contact activity timeline and can be undone from the panel.

Design principles

Six rules the server follows

An AI assistant is a caller that can be argued with. Permissions have to live somewhere it cannot reach.

The scope check runs before the tool body

Not in the tool description the model reads. A model that has been persuaded it should send a message still cannot, if the key lacks social:write.

Isolation lives in the query, not the prompt

Every tool filters by the authenticated user id from the key. No tool takes a workspace or tenant parameter, so there is nothing for an injected instruction to aim at.

Money actions stay human

No transaction creation, no invoice payment, no forcing a deal to won. The server reports on the ledger and refuses to change it.

Limits are per key, not per workspace

60 requests per minute by default and a 300 ceiling on Business, so one looping assistant throttles itself instead of starving your dashboards.

Every write leaves a timeline entry

Tags, scores, assignments, notes and sends all record activity on the contact, readable back through crm_get_contact_activity or in the panel.

One endpoint, no local install

A remote Streamable HTTP server means nothing to install, nothing to keep updated, and one URL plus one header to configure.

Your first hour, in order

Do these in sequence and you will never debug two problems at once.

  • Confirm the workspace is on the Business plan, because a Free or Pro key answers 402 no matter what else is right.
  • Mint a read-only key first: contacts:read, deals:read, pipelines:read, analytics:read.
  • Prove the endpoint with a single curl to tools/list before you touch any client configuration.
  • Add the server to one client only, with the correct transport type for that client.
  • Ask a question whose answer you can check in the panel, such as the count of deals per stage.
  • Mint a second key with write scopes only once the read path is proven, and give it a named owner.
  • Store both tokens in environment variables and confirm neither is in a repository.
  • Note which scope each key carries somewhere your team can find it at rotation time.

CRM MCP server FAQ

The questions teams ask in the first hour, answered with the real numbers.

A CRM MCP server is an implementation of the Model Context Protocol that sits in front of a CRM and publishes its records as callable operations. Instead of pasting a contact list into a chat window, an AI assistant calls a named tool such as crm_search_contacts, gets structured JSON back, and can call a write tool to record the outcome. CRM Solid runs one at https://api.crmsolid.com/mcp with 62 tools, 21 resources and 15 prompts.
Protocol revision 2025-06-18, carried over JSON-RPC 2.0 on the Streamable HTTP transport. Clients POST JSON-RPC requests to the endpoint, open a GET for the server-sent events stream when they want server-initiated messages, and DELETE to end a session. Any client that speaks that revision can connect without a vendor-specific adapter.
No. The server is remote and speaks Streamable HTTP, so a client that supports remote MCP servers connects with a URL and an Authorization header. Nothing runs on your machine and there is nothing to keep updated. Clients whose configuration file only understands local stdio processes need the mcp-remote bridge to translate, which is the one case where a local process is involved.
The MCP server is available on the Business plan. A key minted on Free or Pro authenticates but every MCP request answers HTTP 402, because entitlement is checked separately from authentication. Upgrading the workspace enables the same key immediately: you do not need to mint a new one after changing plan.
Each tool declares the single scope it requires, for example contacts:read for crm_search_contacts or social:write for crm_send_social_message. If the calling key does not carry that scope, the call fails with JSON-RPC error -32002 and a data object containing requiredScope and granted. The assistant sees exactly which permission is missing, which turns a silent failure into an actionable message.
The write tools stop short of destructive operations. There is no tool that deletes a contact, a deal, a task, a message or a ledger entry. The single hard delete in the whole surface is crm_delete_webhook, which removes an endpoint you registered yourself and is annotated as destructive so a client can prompt before running it.
Only if you grant a sending scope. crm_send_social_message needs social:write, crm_send_telegram_message needs telegram:send and crm_send_twitter_dm needs twitter:send. A key without those scopes can read every thread and draft replies in chat, but cannot deliver anything. Most teams start with a read-only key and add sending scopes to a second key later.
The default is 60 requests per minute per key, and a Business workspace can raise a key to a ceiling of 300 per minute. Exceeding the limit returns HTTP 429 with a Retry-After header giving the seconds to wait. The limit is per key rather than per workspace, so a runaway assistant throttles itself without starving your other integrations.
No. MCP tool results are camelCase, while the REST v1 API returns PascalCase properties. That difference matters if you are parsing tool output in your own code rather than letting a model read it. Within MCP the casing is consistent across all 62 tools, so a client only has to learn it once.
The API key identifies exactly one workspace user, and every tool resolves its query against that authenticated user id before touching the database. There is no tool parameter that lets a caller name a different account, so a valid key for one workspace cannot read or write another workspace regardless of what the model asks for.
Revocation takes effect on the next request. The key is validated on every call rather than exchanged for a session token, so there is no window in which an already-connected client keeps working. The client will report a 401 and stop listing tools. Rotate by minting the replacement first, updating the client configuration, then revoking the old key.
Yes, in the CRM itself. Write tools log to the contact activity timeline: crm_tag_contact records a TagAdded entry, crm_set_lead_score records ScoreChanged, crm_assign_contact records Assigned, and crm_send_social_message records the send. You can read that history back with crm_get_contact_activity or open the contact in the panel and see the same entries.
Yes. crm_schedule_social_post creates one post per target account and enforces the per-platform rules at call time: TikTok and YouTube require a video, Instagram requires media, X caps text at 280 characters. crm_update_social_post and crm_cancel_social_post can change or stop anything still pending, though a post that has already published cannot be withdrawn through MCP.
Mint a key carrying only read scopes such as contacts:read, deals:read and analytics:read, connect it, and ask the assistant a question with a verifiable answer, for example how many deals sit in each stage. Compare the answer with the panel. Once the read path is proven, mint a second key with the write scopes that specific assistant needs.
Ready to ship

Give your assistant a real CRM to work in

62 tools, 21 resources and 15 prompts behind one authenticated endpoint. Mint a read-only key, connect a client, and ask it something only your CRM can answer.

Free forever plan · GDPR-ready · No credit card required

We value your privacy

We use cookies to improve our site, analyze traffic, and personalize ads. You can accept all, reject non-essential, or customize your choices. Read our Cookie Policy.