#MCP Integration — LLM-Native Access

The VibeCRM MCP integration exposes your pipeline to AI agents through the Model Context Protocol. Once enabled, any MCP-compatible client — Claude Desktop, Cursor, Claude Code, ChatGPT (when MCP-enabled), or a custom agent — can list, create, update, and delete leads on your behalf.

It is the AI-agent equivalent of the Public API: same operations, same project scoping, but designed for tool-using LLMs instead of HTTP scripts.

#How it works

  • Transport: Streamable HTTP, stateless mode. Every request is a single JSON-RPC 2.0 message sent via POST. No SSE stream, no session state to manage on the client side.
  • Authentication: OAuth-style Authorization: Bearer <token>. Each token is bound to one project, so a token unambiguously identifies the workspace the agent is acting on.
  • Protocol version: 2025-06-18.
  • Capabilities: tools only — resources and prompts return empty lists.
  • Rate limit: 100 requests per token per 60 seconds. Exceeding it returns HTTP 429 with Retry-After: 60.

The endpoint is the same for every customer:

endpoint — http
POST https://app.thevibecrm.com/api/mcp

What changes per token is the project that the agent has access to.

#Getting started

#1. Enable the MCP integration

  1. Open your project → Integrations
  2. Click the MCP card
  3. Click Enable MCP Integration

You need to do this once per project. It only requires the Premium plan.

#2. Issue a token

  1. Click + New Token
  2. Give it a descriptive name (e.g. Claude Desktop — laptop, Cursor — work, n8n agent)
  3. Click Create Token

A modal will appear with two values — save them immediately, the token is shown only once:

ValueDescription
MCP URLThe endpoint: https://app.thevibecrm.com/api/mcp
Bearer TokenA vibecrm_mcp_* token sent in the Authorization header. Shown only once.
Important

If you lose a token, use Regenerate Token on the token card. The old token is invalidated immediately.

#3. Wire it into your agent

Claude Desktop / Claude Code / Cursor

Edit your MCP config file (Claude Desktop: ~/Library/Application Support/Claude/claude_desktop_config.json):

claude_desktop_config — json
{
  "mcpServers": {
    "vibecrm": {
      "url": "https://app.thevibecrm.com/api/mcp",
      "headers": {
        "Authorization": "Bearer vibecrm_mcp_<your-token>"
      }
    }
  }
}

Restart the client. The agent will now see the vibecrm server with the tools described below.

Programmatic / SDK

Any client that supports MCP Streamable HTTP works. Example using @modelcontextprotocol/sdk:

sdk — typescript
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";

const transport = new StreamableHTTPClientTransport(
  new URL("https://app.thevibecrm.com/api/mcp"),
  {
    requestInit: {
      headers: { Authorization: "Bearer vibecrm_mcp_<your-token>" },
    },
  }
);

const client = new Client({ name: "my-app", version: "1.0.0" }, { capabilities: {} });
await client.connect(transport);

const { tools } = await client.listTools();
const result = await client.callTool({
  name: "create_lead",
  arguments: { name: "Jane Doe", email: "jane@example.com" },
});

Raw HTTP (debugging)

Every MCP message is just JSON-RPC over POST:

curl — bash
curl -s -X POST https://app.thevibecrm.com/api/mcp \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer vibecrm_mcp_<your-token>" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

#Authentication

Every request must include:

header — http
Authorization: Bearer vibecrm_mcp_<your-token>
FailureHTTPReason
Missing header401 + WWW-Authenticate: BearerNo Authorization header
Wrong token401Token does not exist
Deactivated token401Token toggled off in the UI
Disabled integration401MCP integration was disconnected
Rate-limited429 + Retry-After: 60More than 100 req/min on this token

A token is bound to exactly one project at creation. Rotating it (Regenerate Token) preserves the binding; revoking it (Delete) disconnects every agent using it instantly.

#Tools

The server advertises exactly six tools. They mirror the Public API one-for-one — anything the API can do, the MCP can do, scoped to the project bound to your token.

#list_pipeline_stages

List every kanban column in your project, sorted left-to-right. Use this first so the agent knows what stage IDs to pass to create_lead / update_lead.

  • Input: none
  • Returns: { stages: [{ id, name, color, order, isSold }] }

#list_leads

List leads in your project.

  • Input:
    • stageId (string, optional) — filter by a single stage
    • limit (integer, optional, 1–500, default 100)
  • Returns: { leads: [Lead, …] }

#get_lead

Fetch one lead by ID.

  • Input: { leadId: string }
  • Returns: { lead: Lead }
  • Errors: "Lead not found", "Lead does not belong to this project"

#create_lead

Create a new lead.

  • Input:
    • name (string, required)
    • email (string, required)
    • stageId (string, optional) — defaults to the first stage of the pipeline
    • phone, companyName, companyUrl, source, recurrence (string, optional)
    • value (number, optional, default 0)
  • Returns: { lead: Lead }
  • Defaults: source "MCP", recurrence "One-time".

#update_lead

Patch one or more fields of a lead. Only fields you pass are touched. Pass an empty string to clear phone / companyName / companyUrl.

  • Input:
    • leadId (string, required)
    • stageId (string, optional) — move the lead to another column
    • name, email, phone, companyName, companyUrl, source, recurrence (string, optional)
    • value (number, optional)
  • Returns: { lead: Lead }
  • Errors: "No updatable fields provided", "stageId '…' not found in this project".

#delete_lead

Permanently delete a lead.

  • Input: { leadId: string }
  • Returns: { ok: true, leadId }

#The Lead shape

All lead-returning tools serialize leads the same way:

lead — json
{
  "id": "clyyy5678",
  "projectId": "clppp1111",
  "stageId": "clxxx1234",
  "position": 3,
  "name": "Jane Doe",
  "email": "jane@example.com",
  "phone": "+1 555 0100",
  "companyName": "Acme Corp",
  "companyUrl": "https://acme.com",
  "source": "MCP",
  "value": 5000,
  "recurrence": "Monthly",
  "createdAt": "2026-05-23T10:12:34.000Z",
  "updatedAt": "2026-05-23T10:12:34.000Z"
}

Every tool returns its payload twice on success — once as a JSON string in the content[0].text field (for clients that only read text) and once as structuredContent (for clients that prefer parsed JSON). Tool-level failures (e.g. "lead not found") set isError: true rather than producing a JSON-RPC error, so the agent can read the message and recover.

#JSON-RPC reference

The transport is plain JSON-RPC 2.0. Every method is supported as POST /api/mcp.

#initialize

The first call in any MCP session. Negotiates capabilities.

Request

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

Response

response — json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2025-06-18",
    "capabilities": { "tools": { "listChanged": false } },
    "serverInfo": { "name": "vibecrm-mcp", "version": "1.0.0" },
    "instructions": "VibeCRM MCP server. Use list_pipeline_stages first…"
  }
}

#tools/list

Returns the six tools described above with their JSON Schemas.

curl — bash
curl -s -X POST https://app.thevibecrm.com/api/mcp \
  -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'

#tools/call

request — json
{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "tools/call",
  "params": {
    "name": "create_lead",
    "arguments": { "name": "Jane Doe", "email": "jane@example.com" }
  }
}

#Other methods

MethodBehavior
pingReturns {}
notifications/initializedAcknowledged, no response (notification)
notifications/cancelledAcknowledged, no response (notification)
resources/listReturns { resources: [] } — not supported
prompts/listReturns { prompts: [] } — not supported
GET /api/mcpReturns 405 (server is stateless, no SSE)
DELETE /api/mcpReturns 204 (no session to terminate)

#Best practices

The server is built around the MCP best practices that matter for this use case:

  • Bearer-token auth with WWW-Authenticate challenge on 401 so MCP clients that support OAuth flows can detect the realm.
  • Stateless transport — every request is independent. No session expiry to track, no reconnection logic.
  • Constant-set tool list with conservative names (create_lead, not vibecrm_lead_create) and short, action-oriented descriptions. Verbose tool names waste agent context.
  • Strict JSON Schemas with additionalProperties: false and required arrays, so agents that follow schemas can't misshape requests.
  • Structured + text dual output on every tool result, matching the MCP "rich content" recommendation.
  • Tool errors are not protocol errors. A failed update_lead returns isError: true inside result, not a JSON-RPC error. This keeps the agent in a recoverable state.
  • Per-token rate limiting prevents a runaway agent from saturating the database.
  • Token rotation without losing the binding Regenerate Token keeps the same identity but invalidates the old secret.
  • Token prefix vibecrm_mcp_ makes accidental commits trivial to spot in secret scanners.

#Guidance for agent prompts

If you're embedding the server in a custom agent, the following system-prompt fragment works well:

You have access to the vibecrm MCP server. Before creating or updating leads, call list_pipeline_stages once to learn the valid stage IDs. When the user describes a lead, prefer create_lead. When they ask to "move", "promote", or "close" a lead, use update_lead with a new stageId. Never call delete_lead without explicit confirmation from the user.

#Disabling MCP

  • Deactivate one token: click Deactivate on the token card. The agent immediately gets 401s.
  • Delete one token: permanent, same effect.
  • Disable the entire integration: click Disconnect on the MCP card in Integrations. Every token stops working at once.

Disabling never deletes leads — it only revokes agent access.