<!-- source: https://docs.redpine.ai/docs/mcp -->
# MCP

> Connect Claude, Cursor, ChatGPT, or any MCP client directly, no code required.

<Callout title="In a hurry?">
  Skip to [Connect your client](#connect-your-client), pick yours, paste the one line it gives you. Most clients need no key. Your browser opens once to approve access, and you're done.
</Callout>

## What this is

[MCP](https://modelcontextprotocol.io) (Model Context Protocol) is the standard AI agents use to connect directly to external tools. If your agent or IDE speaks MCP, it can talk to Redpine Connect the moment you add one server: no API integration to write, no request shapes to learn.

Once connected, your agent can search Redpine's collections and reach every integration (news mentions, aviation data, and more) on its own: it discovers what's available and figures out how to call it. You don't write any code, and neither does it.

If you're building your own integration instead of using an existing client, see [Get started](/). Everything below is for connecting an agent.

## The short version

```
https://api.redpine.ai/mcp
```

That's the whole server. Every client below just needs this URL. Most clients open your browser once to approve access. No key to copy.

## Connect your client

Pick yours: each links straight to its instructions below.

<Cards>
  <Card title="Claude Code" href="#claude-code" icon="<img src=&#x22;/icons/mcp/claude.svg&#x22; alt=&#x22;&#x22; width={16} height={16} />" />

  <Card title="Codex" href="#codex" icon="<><img src=&#x22;/icons/mcp/codex.svg&#x22; alt=&#x22;&#x22; width={16} height={16} className=&#x22;dark:hidden&#x22; /><img src=&#x22;/icons/mcp/codex-inverse.svg&#x22; alt=&#x22;&#x22; width={16} height={16} className=&#x22;hidden dark:inline-block&#x22; /></>" />

  <Card title="Cursor" href="#cursor" icon="<img src=&#x22;/icons/mcp/cursor.svg&#x22; alt=&#x22;&#x22; width={16} height={16} />" />

  <Card title="Redpine CLI" href="#redpine-cli" icon="<><img src=&#x22;/icons/mcp/redpine-cli.svg&#x22; alt=&#x22;&#x22; width={16} height={16} className=&#x22;dark:hidden&#x22; /><img src=&#x22;/icons/mcp/redpine-cli-inverse.svg&#x22; alt=&#x22;&#x22; width={16} height={16} className=&#x22;hidden dark:inline-block&#x22; /></>" />

  <Card title="Claude Desktop" href="#claude-desktop" icon="<img src=&#x22;/icons/mcp/claude.svg&#x22; alt=&#x22;&#x22; width={16} height={16} />" />

  <Card title="ChatGPT" href="#chatgpt" icon="<img src=&#x22;/icons/mcp/chatgpt.svg&#x22; alt=&#x22;&#x22; width={16} height={16} />" />

  <Card title="Windsurf" href="#windsurf" icon="<><img src=&#x22;/icons/mcp/windsurf.svg&#x22; alt=&#x22;&#x22; width={16} height={16} className=&#x22;dark:hidden&#x22; /><img src=&#x22;/icons/mcp/windsurf-inverse.svg&#x22; alt=&#x22;&#x22; width={16} height={16} className=&#x22;hidden dark:inline-block&#x22; /></>" />

  <Card title="Lovable" href="#lovable" icon="<img src=&#x22;/icons/mcp/lovable.svg&#x22; alt=&#x22;&#x22; width={16} height={16} />" />

  <Card title="Antigravity" href="#antigravity" icon="<img src=&#x22;/icons/mcp/antigravity.svg&#x22; alt=&#x22;&#x22; width={16} height={16} />" />
</Cards>

### Claude Code

Run this in your terminal, then approve Redpine in the browser it opens:

```bash
claude mcp add --transport http redpine https://api.redpine.ai/mcp
```

### Codex

Register the server, then authorize it: the second command opens your browser:

```bash
codex mcp add redpine --url https://api.redpine.ai/mcp
codex mcp login redpine
```

### Cursor

Open `~/.cursor/mcp.json` (or `.cursor/mcp.json` in your project), add this, and save. Then click **Login** on the Redpine server in Cursor's MCP settings:

```json
{
  "mcpServers": {
    "redpine": {
      "url": "https://api.redpine.ai/mcp"
    }
  }
}
```

Prefer a static key over the browser login? Create one from your [API Keys](https://app.redpine.ai/api-keys?utm_source=docs\&utm_medium=referral) page and use this instead:

```json
{
  "mcpServers": {
    "redpine": {
      "url": "https://api.redpine.ai/mcp",
      "headers": {
        "X-API-Key": "YOUR_API_KEY"
      }
    }
  }
}
```

### Redpine CLI

```bash
brew install redpine-ai/tap/connect-cli
redpine auth login
```

### Claude Desktop

1. Open Claude Desktop → **Settings** → **Connectors**
2. Click **Add custom connector** at the bottom-left
3. Set the name to "Redpine" and paste this URL:
   ```
   https://api.redpine.ai/mcp
   ```
4. Click **Add**, then click **Connect**

### ChatGPT

1. Open ChatGPT → **Settings** → **Apps/Connectors**
2. Enable Developer Mode in advanced settings
3. Click **Create App**
4. Set the name to "Redpine" and paste this URL:
   ```
   https://api.redpine.ai/mcp
   ```
5. Select **OAuth** as the authentication method
6. Click **Connect**

### Windsurf

Open Windsurf → **Settings** → **MCP**, and add a new server with this URL:

```
https://api.redpine.ai/mcp
```

### Lovable

1. Go to **Connectors** → **All**, then scroll to **Custom MCP**
2. Name it "Redpine" and add this URL:
   ```
   https://api.redpine.ai/mcp
   ```
3. Click **OAuth**, press **Add & Continue**, then choose your organization

### Antigravity

Antigravity doesn't support the browser login, so this one needs a key. Create one from your [API Keys](https://app.redpine.ai/api-keys?utm_source=docs\&utm_medium=referral) page first.

1. Open Antigravity
2. In the Agent panel, click the "more options" menu → **MCP Servers** → **Manage MCP Servers**
3. Click **View raw config**
4. Paste this and save:
   ```json
   {
     "mcpServers": {
       "redpine": {
         "serverUrl": "https://api.redpine.ai/mcp",
         "headers": {
           "X-API-Key": "YOUR_API_KEY"
         }
       }
     }
   }
   ```

### Something else

Any MCP client that supports a remote HTTP server works, even if it's not listed above: this is a standard [Streamable HTTP](https://modelcontextprotocol.io/specification) endpoint. Give it the URL:

```
https://api.redpine.ai/mcp
```

If your client asks how to authenticate, it almost certainly supports OAuth discovery and will figure it out on its own from that URL alone. If it needs manual configuration, see [Authenticating without OAuth](#authenticating-without-oauth) below.

## What your agent can do once connected

You don't need to tell your agent which tool to use. Just ask a question, like "find me recent news mentions of Nvidia" or "search my documents for adverse event reports," and it works out which integration and tool applies, then calls it.

Under the hood, this happens through three tools every client sees: `find-tools` looks up what's available by keyword, `inspect-tool` gets the exact parameters for one, and `call-tool` runs it. Your agent chains these on its own; you never call them directly unless you're scripting against MCP yourself.

Browse everything your organization has access to (full tool list, parameters, and pricing) on the [Integrations](/docs/integrations) page.

## Search over MCP

Search maps onto the same three REST behaviours as everywhere else, but `preview` and `confirm` are their own top-level tools while `search` itself isn't: it's reached the same way any integration tool is, through `find-tools` then `call-tool`, not as a separate named tool most clients see directly.

| MCP tool  | How your agent reaches it                        | REST equivalent               | What it does                                                             |
| --------- | ------------------------------------------------ | ----------------------------- | ------------------------------------------------------------------------ |
| `search`  | Discovered via `find-tools`, run via `call-tool` | `POST /api/v1/search/query`   | Runs a search and returns full results, billed                           |
| `preview` | Directly, top-level                              | `POST /api/v1/search/preview` | Runs the same search for free, returns teaser rows and an estimated cost |
| `confirm` | Directly, top-level                              | `POST /api/v1/search/unlock`  | Pays for and returns some or all of a `preview` call's results in full   |

Your agent picks between these the same way it picks any tool: given a task, not a command. Ask it to search, and it finds and calls `search`; ask it to check what something would cost first, and it reaches for `preview` then `confirm` directly. Search parameters and filters match their REST counterparts. See [Search](/docs/search), [Filtering](/docs/filtering) and [Preview and unlock](/docs/preview-unlock). Responses use the MCP shape below. `/search/assisted`'s agentic loop isn't exposed as a fourth MCP tool: an MCP-connected agent already plans its own multi-step searches using `search`, so there's no separate tool for it. To search a specific collection by name, your agent finds it the same way it finds any other detail: by calling `list_collections`, discovered the same way `search` is. `list_journals`, reached the same way, lists the journals in a collection ranked by h-index, or by topic, with the ISSNs to filter on; it is free, like [its REST counterpart](/docs/collections#list-journals-in-a-collection).

A question about the catalogue itself, such as "which journals do I have on cardiology", sent without filters is answered from the catalogue for free instead of being searched. See [Catalogue questions](/docs/collections#catalogue-questions).

### Search results over MCP

`search`, `preview` and `confirm` return one JSON shape. Read `structuredContent`: the text content carries the same JSON, but may have a balance or trial status line around it. A direct `search` bills immediately and reports what it cost:

```json
{
  "tool": "search",
  "collection": "my-collection",
  "workflow": "complete",
  "billing_status": "paid",
  "cost_charged": "0.214000",
  "tokens_charged": 214,
  "balance_remaining": "9.786000",
  "result_count": 1,
  "results": [
    {
      "id": "abc123",
      "title": "Diabetes Overview",
      "publisher": "Example Publishing",
      "year": "2021",
      "journal": "Example Medical Journal",
      "locked": false,
      "publication_date": "2021-03-15",
      "doi": "10.1234/example",
      "chunks": [{ "text": "Type 2 diabetes symptoms include increased thirst, frequent urination..." }]
    }
  ],
  "filtersApplied": { "publication_date": { "gte": "2020-01-01" } }
}
```

| Field                               | Returned by                                                                                        | Description                                                                                                                                                                                                                                                                                                                                                                                                    |
| ----------------------------------- | -------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `queryId`                           | `preview`, `confirm`                                                                               | Pass to `confirm`. A direct `search` has none                                                                                                                                                                                                                                                                                                                                                                  |
| `workflow`                          | `search`, `preview`                                                                                | `complete` when the full results are included; `requires_confirm` when a preview is locked until `confirm`                                                                                                                                                                                                                                                                                                     |
| `billing_status`                    | `search`, `confirm`, locked `preview`                                                              | How the call is billed, for example `paid`, `trial`, `exempt` or `sandbox`                                                                                                                                                                                                                                                                                                                                     |
| `cost_charged`, `balance_remaining` | `search`, `confirm`                                                                                | What this call charged, and the balance after it. `balance_remaining` is `null` when the API key hides the balance                                                                                                                                                                                                                                                                                             |
| `tokens_charged`                    | `search`                                                                                           | Tokens billed. `0` when nothing was charged                                                                                                                                                                                                                                                                                                                                                                    |
| `cost_to_unlock`                    | locked `preview` (paid)                                                                            | What unlocking every result would cost. Each row also carries its own `cost_to_unlock`                                                                                                                                                                                                                                                                                                                         |
| `cost_to_unlock_remaining`          | `confirm` (paid)                                                                                   | What the still-locked results would cost                                                                                                                                                                                                                                                                                                                                                                       |
| `results`                           | all three                                                                                          | Rows with `id`, `title`, `publisher`, `year`, `journal`, `locked` and `chunks`, plus identifiers (`doi`, `pmid`, `pmcid`, `url`) and other metadata when present. A chunk holds `text`, or `snippet` while the row is locked. `figure_count` appears on rows with figures, and `chunk_index` (the chunk's position in its document) on unlocked rows                                                           |
| `filterWarnings`                    | all three                                                                                          | Advisory filter warnings; omitted when there are none                                                                                                                                                                                                                                                                                                                                                          |
| `filtersApplied`                    | `search`, `preview`                                                                                | The filters that were applied; omitted when none were sent                                                                                                                                                                                                                                                                                                                                                     |
| `figures`                           | `search`, `confirm`, and a `complete` (free) `preview`, with `include_figures`                     | `images_attached`, `unavailable` and `omitted_over_limit`, which add up to the `figure_count` of the delivered rows                                                                                                                                                                                                                                                                                            |
| `message`                           | `search`                                                                                           | What to try next when there are no results                                                                                                                                                                                                                                                                                                                                                                     |
| `filterDiagnosis`                   | `search`, `preview`, when a filtered search returns nothing; optional                              | Whether any document matches your filters at all (`filtersMatchDocuments`), which single condition, if removed, brings documents back (`probes`), and a `hint`. Tells an agent whether to relax the filter or rephrase the query. Free. Left out for sandbox keys, for filters on identifiers only, when a pinned DOI is already reported by `doi_not_in_collection`, and when the check cannot finish in time |
| `filterSuggestions`                 | `search`, `preview`, when a search filtering on `journal` or `publisher` returns nothing; optional | One entry per unmatched value: the closest `suggestions` your key can search and a `hint` with a ready-to-use retry. A journal suggestion carries its `issn` when one is known; a publisher suggestion carries only the `publisher` name. `journal` and `publisher` stay exact-match filters                                                                                                                   |

A row also carries `relevance`: how well the passage answers the query, from 0 to 1. A row with no score leaves the field out (the REST API returns `null` instead).

With `include_audio`, podcast clips arrive as `resource_link` blocks instead, valid for 7 days. See [Podcast audio clips](/docs/audio-clips#over-mcp).

Images arrive as image blocks after the JSON, at most 10 per response, each captioned with `[result <id>]` so it can be matched to its row.

A filter that cannot be applied is an error naming the field, for example `'journall' is not a filterable field. Indexed fields: ...`. Fix the filter rather than retrying. See [Filtering](/docs/filtering#rejected-filters).

## Sandbox keys and MCP

A [sandbox key](/docs/sandbox) works over MCP for search (`search`, `preview`, and `confirm` all return fixture results, same as the REST API). It does **not** work for integration tools reached through `call-tool`: those reach real third-party services, so a sandbox key gets `403 SANDBOX_UNSUPPORTED_ENDPOINT` instead. Use a live key to try aviation, media, or any other integration tool.

## Authenticating without OAuth

Most clients above use OAuth: your browser opens once, you approve Redpine for your organization, and the client is done. No key ever touches its config file. This is what "Connect" or "Login" buttons trigger.

If your client doesn't support that flow, or you're scripting against MCP directly, send an API key instead:

```
X-API-Key: sk_live_YOUR_API_KEY
```

Everything else about the request is identical either way. Create a key from your [API Keys](https://app.redpine.ai/api-keys?utm_source=docs\&utm_medium=referral) page. See [Authentication](/docs/authentication) for the two kinds and what each does.

## Managing connections

See and revoke connected clients from your organization's **Connections** page in the [dashboard](https://app.redpine.ai/?utm_source=docs\&utm_medium=referral). Revoking there ends that client's access immediately. No restart needed on your end.

## Troubleshooting

| Symptom                                                                                                                         | What's happening                                                                                                                                                                                                                                        |
| ------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Nothing happens after clicking Connect/Login                                                                                    | Check for a blocked pop-up: the OAuth approval opens in a new browser window.                                                                                                                                                                           |
| `403 SANDBOX_UNSUPPORTED_ENDPOINT` on a tool call                                                                               | You're on a sandbox key calling an integration tool. Switch to a live key. See [Sandbox keys and MCP](#sandbox-keys-and-mcp) above.                                                                                                                     |
| `401` immediately after connecting                                                                                              | The connection was revoked, or the OAuth approval didn't complete. Reconnect from your client.                                                                                                                                                          |
| Error ending `[error_code: insufficient_credits]`, `[error_code: billing_suspended]` or `[error_code: api_key_budget_exceeded]` | The balance, the organization's billing or the key's spending cap refused a paid call. Nothing was charged; the same call works once credits are added, billing is resolved or the cap is raised. `preview` and free tools keep working at zero balance |
| Error ending `[error_code: upstream_rejected]`                                                                                  | The search was refused and will be refused the same way again. Don't retry; contact support with the query and collection name. `upstream_timeout`, `upstream_unavailable` and `upstream_error` are worth one retry                                     |
| Agent can't find the right tool                                                                                                 | Ask it to call `find-tools` with a more specific query, or browse [Integrations](/docs/integrations) directly to confirm the tool exists and your organization has access.                                                                              |

Anything else, see [Errors](/docs/errors) for the full status code reference.