> ## Documentation Index
> Fetch the complete documentation index at: https://leonar.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# MCP Server

> Connect Claude Code, Claude Desktop, Cursor, Codex, or any MCP client directly to Leonar using the Model Context Protocol.

Leonar exposes a native [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server that lets AI assistants call Leonar tools and read contextual resources directly.

```
AI Assistant  →  MCP Protocol  →  Leonar MCP Server  →  Leonar CRM data
```

## Quick start

### 1. Choose your setup

* **Claude Desktop / Claude.ai / Claude remote connector (recommended)**: use the hosted MCP endpoint directly. No Leonar API key is required; Claude redirects you to Leonar and you authorize one workspace via OAuth.
* **Claude Code / Codex / Cursor / generic MCP clients that do not support OAuth remote connectors**: use either Direct HTTP with a Bearer API key, or the local `@leonar/mcp` NPX bridge.

### 2. Configure your MCP client

For Claude Desktop, prefer the remote connector tab below. The NPX package is only for local/API-key clients that need a stdio command.

<Tabs>
  <Tab title="Claude remote connector (recommended)">
    In Claude Desktop or Claude.ai, go to **Settings / Customize > Connectors**, choose **Add custom connector**, and enter the Leonar MCP endpoint:

    ```
    https://app.leonar.app/api/mcp
    ```

    When Claude connects without a token, Leonar advertises its OAuth metadata automatically. Claude opens Leonar's sign-in page, you choose the workspace to share, and Leonar returns an OAuth access token scoped to that workspace.

    <Warning>
      For Claude Desktop and Claude.ai, enter exactly `https://app.leonar.app/api/mcp`. Do not use another host, path, or any API key query parameter; Claude handles authorization through OAuth.
    </Warning>

    For Team and Enterprise Claude plans, an organization owner may need to add the custom connector first. Members can then connect and enable it individually.
  </Tab>

  <Tab title="NPX package (local/API-key fallback)">
    Use this only for MCP clients that need a local stdio command and cannot use Claude's remote OAuth connector. Create a `leo_...` API key first in **Settings > API**.

    <CodeGroup>
      ```json Claude Code (.mcp.json) theme={null}
      {
        "mcpServers": {
          "leonar": {
            "command": "npx",
            "args": ["-y", "@leonar/mcp"],
            "env": {
              "LEONAR_API_KEY": "leo_your_api_key"
            }
          }
        }
      }
      ```

      ```json Cursor (.cursor/mcp.json) theme={null}
      {
        "mcpServers": {
          "leonar": {
            "command": "npx",
            "args": ["-y", "@leonar/mcp"],
            "env": {
              "LEONAR_API_KEY": "leo_your_api_key"
            }
          }
        }
      }
      ```
    </CodeGroup>

    Requires Node.js 18+. The package ([`@leonar/mcp`](https://www.npmjs.com/package/@leonar/mcp)) is a lightweight bridge that forwards MCP messages to the Leonar server over Streamable HTTP while preserving stdio request order. It authenticates with a Leonar API key, unlike the Claude remote connector OAuth flow.
  </Tab>

  <Tab title="Direct HTTP">
    If your MCP client supports the `url` transport type, you can connect directly without any package:

    ```
    https://app.leonar.app/api/mcp
    ```

    <CodeGroup>
      ```json Claude Code (.mcp.json) theme={null}
      {
        "mcpServers": {
          "leonar": {
            "type": "url",
            "url": "https://app.leonar.app/api/mcp",
            "headers": {
              "Authorization": "Bearer leo_your_api_key"
            }
          }
        }
      }
      ```

      ```json Codex / Generic MCP client theme={null}
      {
        "mcpServers": {
          "leonar": {
            "type": "url",
            "url": "https://app.leonar.app/api/mcp",
            "headers": {
              "Authorization": "Bearer leo_your_api_key"
            }
          }
        }
      }
      ```
    </CodeGroup>
  </Tab>
</Tabs>

### 3. Start using tools

Once connected, your AI assistant has access to the same safe workflow tools used by Leonar's integrated AI agent, plus 4 contextual resources. Ask it things like:

* *"Search for backend engineers in Paris"*
* *"Show me the context for the Senior PM project"*
* *"Find sourcing candidates for this project"*

### Sourcing with LinkedIn locations

For LinkedIn Sales Navigator or Recruiter location filters, first ask Leonar for selectable location options, then pass the selected option into `sourcing_run_search`:

```json theme={null}
{
  "tool": "sourcing_search_location_options",
  "input": { "query": "Paris", "apiType": "auto" }
}
```

Then use the selected LinkedIn location ID:

```json theme={null}
{
  "tool": "sourcing_run_search",
  "input": {
    "projectName": "VP Sales France",
    "mode": "create",
    "filters": {
      "titles": { "include": ["VP Sales", "Head of Sales"], "scope": "current" },
      "locations": {
        "include": [{
          "label": "Paris, Île-de-France, France",
          "country": "France",
          "linkedin": {
            "id": "90009633",
            "label": "Paris, Île-de-France, France",
            "apiType": "sales_navigator",
            "accountId": "connected-account-id-from-options"
          }
        }]
      },
      "keywordBoolean": { "query": "(SaaS OR B2B) AND \"Enterprise Sales\"" },
      "crm": { "excludeAlreadyInProject": true, "hideAlreadyTreated": true }
    }
  }
}
```

If a LinkedIn search includes a plain-text location without a selected LinkedIn option, `sourcing_run_search` returns `status: "needs_location_selection"` instead of silently running a degraded LinkedIn search.

## Authentication

Leonar supports two authentication modes for MCP:

* **OAuth** for Claude remote connectors. This is the recommended path for Claude Desktop and Claude.ai. Claude discovers Leonar's OAuth metadata automatically from the MCP endpoint, redirects you to Leonar, and receives an access token scoped to one workspace.
* **Bearer API keys** for local/API-key clients such as Claude Code, Codex, Cursor, and generic MCP clients that do not use the OAuth connector flow.

For API-key clients, the MCP server uses the same `leo_` API keys as the REST API. Pass your key as a Bearer token in the `Authorization` header.

```
Authorization: Bearer leo_your_api_key
```

Each tool requires specific scopes. If the API key lacks a required scope, the tool returns an error. See the [scopes reference](/authentication#scopes) for the full list.

<Warning>
  Use the minimum scopes your assistant needs. For read-only exploration, start with `contacts:read`, `projects:read`, and `companies:read`.
</Warning>

<Warning>
  High-impact mutations should be handled carefully by MCP clients. For sourcing, prefer the reviewed flow: run a search, inspect selected `sourcedProfileIds`, then call `sourcing_add_profiles` only for explicit selections.
</Warning>

## Transport

The MCP server uses **Streamable HTTP** transport over a single endpoint (`POST /api/mcp`). It is stateless — no session management is required. All MCP clients that support the `url` transport type can connect directly.

For custom HTTP clients or manual tests, include both accepted response types:

```http theme={null}
Accept: application/json, text/event-stream
Authorization: Bearer leo_your_api_key
Content-Type: application/json
```

The NPX bridge sets these headers automatically.

## Available resources

The server also exposes these read-only resources:

| Resource URI                  | Description                                                  |
| ----------------------------- | ------------------------------------------------------------ |
| `leonar://workspace/context`  | Workspace metadata, billing state, and lightweight counters  |
| `leonar://accounts/connected` | Active connected accounts available for sending and sourcing |
| `leonar://team/members`       | Workspace members and roles                                  |
| `leonar://pipeline/templates` | Pipeline templates with their stages                         |

## Available tools

The MCP server exposes the main CRM API resources as explicit tools. The recommended sourcing workflow is exposed through agent-friendly tools that mirror the unified UI flow without exposing Leonar's internal filter model. Assistant memory tools are not exposed over external MCP.

| Object | Tools | Scopes |
| ------ | ----- | ------ |

\| Recommended sourcing | `sourcing_search_location_options`, `sourcing_run_search`, `sourcing_add_profiles`, `sourcing_reject_profiles` | `projects:read`, `sourcing:read`, `sourcing:write`, plus `contacts:write`/`pipeline:write` for adding |
\| Contacts | `search_contacts`, `get_contact`, `create_contact`, `update_contact`, `delete_contact` | `contacts:read`, `contacts:write`, `contacts:delete` |
\| Companies | `search_companies`, `get_company`, `create_company`, `update_company`, `delete_company` | `companies:read`, `companies:write`, `companies:delete` |
\| Projects | `search_projects`, `get_project`, `create_project`, `update_project`, `delete_project`, `add_contact_to_project` | `projects:read`, `projects:write`, `pipeline:write` |
\| Sequences | `search_sequences`, `get_sequence`, `get_sequence_steps`, `update_sequence_steps`, `list_sequence_enrollments`, `enroll_contacts_in_sequence`, `unenroll_contacts_from_sequence` | `sequences:read`, `sequences:write` |
\| Deals | `search_deals`, `get_deal`, `create_deal`, `update_deal`, `delete_deal` | `deals:read`, `deals:write`, `deals:delete` |
\| Notes | `search_notes`, `create_note`, `update_note`, `delete_note` | `notes:read`, `notes:write` |

Delete tools archive records when the API resource supports soft deletion. Notes are deleted from their note table.

## Tool parameters reference

### Common read parameters

```typescript theme={null}
// get_* and delete_* tools
{
  id: string
}

// search_* tools
{
  search?: string
  limit?: number // max 100
  offset?: number
}
```

### Contacts

```typescript theme={null}
// search_contacts also accepts:
{
  company_id?: string
  location?: string
}

// create_contact / update_contact
{
  first_name: string
  last_name?: string
  title?: string
  current_company?: string
  location?: string
  linkedin_profile?: string
  emails?: { email: string; type?: "work" | "personal" }[]
  phones?: { phone: string; type?: "work" | "personal" }[]
  contact_type?: string[]
  tags?: string[]
  source?: string
  summary?: string
  company_id?: string
  custom_data?: Record<string, unknown>
}
```

### Companies

```typescript theme={null}
// search_companies also accepts:
{
  industry?: string
  owner_id?: string
}

// create_company / update_company
{
  name: string
  domain?: string
  industry?: string
  company_size?: string
  description?: string
  location?: string
  phone?: string
  linkedin_url?: string
  owner_id?: string
  custom_data?: Record<string, unknown>
}
```

### Projects

```typescript theme={null}
// search_projects also accepts:
{
  status?: "active" | "archived" | "all"
}

// create_project / update_project
{
  name: string
  client_name?: string
  client_company_id?: string
  owner_ids?: string[]
  template_id?: string
  location?: string
  description?: string
}

// add_contact_to_project
{
  project_id: string
  contact_id: string
  stage_id?: string // defaults to the first stage
}
```

### Sequences

```typescript theme={null}
// search_sequences also accepts:
{
  status?: "active" | "paused" | "draft" | "archived" | "all"
}

// list_sequence_enrollments
{
  sequence_id: string
  status?: "active" | "paused" | "pending" | "finished" | "replied" | "bounced" | "all"
  search?: string
  limit?: number
  offset?: number
}

// enroll_contacts_in_sequence
{
  sequence_id: string
  contact_ids?: string[]
  contacts?: {
    contact_id: string
    custom_variables?: {
      custom_variable_1?: string | null
      custom_variable_2?: string | null
      custom_variable_3?: string | null
      custom_variable_4?: string | null
      custom_variable_5?: string | null
    }
  }[]
}

// unenroll_contacts_from_sequence
{
  sequence_id: string
  contact_ids: string[]
  reason?: string
}
```

### Deals

```typescript theme={null}
// search_deals also accepts:
{
  status?: "open" | "won" | "lost" | "unqualified" | "all"
  company_id?: string
  owner_id?: string
}

// create_deal / update_deal
{
  title: string
  company_id: string
  pipeline_id?: string
  stage_id?: string
  contact_id?: string
  project_id?: string
  owner_id?: string
  primary_source_id?: string | null
  amount?: number
  currency?: string
  expected_amount?: number
  expected_close_date?: string
  probability?: number
  custom_data?: Record<string, unknown>
}
```

### Notes

```typescript theme={null}
// search_notes
{
  entity_type?: "contact" | "company" | "deal" | "project"
  entity_id?: string
  search?: string
  limit?: number
  offset?: number
}

// create_note
{
  entity_type: "contact" | "company" | "deal" | "project"
  entity_id: string
  content: string
  is_pinned?: boolean
  project_id?: string
}

// update_note
{
  id: string
  entity_type: "contact" | "company" | "deal" | "project"
  content?: string
  is_pinned?: boolean
}
```

## Example use cases

<CardGroup cols={2}>
  <Card title="CRM lookup" icon="magnifying-glass">
    *"Find contacts at Acme and summarize their current roles."*

    The assistant calls `search_contacts` and reads the returned contact records.
  </Card>

  <Card title="Pipeline preparation" icon="chart-bar">
    *"Create a project for our new backend role and attach Acme as the client company."*

    The assistant can use `search_companies` then `create_project`.
  </Card>

  <Card title="Deal update" icon="briefcase">
    *"Update this deal amount and expected close date."*

    Uses `update_deal` with the same API key scopes as the REST API.
  </Card>

  <Card title="Meeting note" icon="note">
    *"Add this call summary to the company record."*

    Uses `create_note` with `entity_type: "company"`.
  </Card>
</CardGroup>

## Rate limits

The MCP server shares the same base rate limit as the REST API: **2000 requests per hour**.

* For API-key clients, the quota is tracked per API key.
* For Claude remote connectors, the quota is tracked per OAuth authorization (`client + workspace + user`). Refreshing an access token does not reset the quota.

Each tool call counts as one request.

## MCP vs REST API

|              | MCP Server                                                                                   | REST API                     |
| ------------ | -------------------------------------------------------------------------------------------- | ---------------------------- |
| **Best for** | AI assistants (Claude, Cursor, Codex)                                                        | Custom integrations, scripts |
| **Protocol** | Model Context Protocol                                                                       | HTTP REST                    |
| **Auth**     | OAuth for Claude remote connectors; `leo_` API keys for local/API-key MCP clients            | Same `leo_` API keys         |
| **Scopes**   | Same scope system                                                                            | Same scope system            |
| **Tools**    | Main CRM object tools, project pipeline entry tools, sequence enrollment tools + 4 resources | 60+ endpoints (full CRUD)    |

Use the MCP server when connecting an AI assistant. Use the REST API when building custom integrations or scripts that need full CRUD access to all resources.
