# MCP (Claude, ChatGPT, Cursor)

XDive runs a hosted [Model Context Protocol](https://modelcontextprotocol.io) server, so AI assistants and agents can search the web, read pages, crawl sites, extract data and research questions with cited sources. Tools call the same API as your own code, so scopes, quotas, caching and the audit log apply exactly as they do to a direct request. Most clients connect with OAuth: you paste one URL, sign in to XDive and approve; no API key is copied anywhere.

`POST https://xdive.dev/api/mcp`

The server URL is `https://xdive.dev/api/mcp` (self-hosted: `https://your-host/api/mcp`). Use it exactly as written, without a trailing slash.

## Overview

The server exposes eight tools, always in this order. Every tool only reads the public web; none changes anything.

| Tool | What it does | Returns |
|---|---|---|
| `search` | Searches the web, news or images; can also read the top results and write a short cited answer. | JSON: `results`, each with `id`, `title`, `url`, `text` and `passages`, and `answer` when asked. `id` is the result's URL, ready for `fetch`. |
| `fetch` | Reads one URL as Markdown. | JSON: `id`, `title`, `text`, `url` and `metadata`; `metadata.next_offset` is set when the page continues. |
| `research` | Searches, reads the best sources and writes an answer in which every claim cites a source. | Text: the answer or a Markdown report, the numbered sources, and a confidence line. |
| `scrape` | Reads one URL in any scrape format. | Markdown text by default; JSON for other formats. |
| `map` | Lists a site's URLs from its sitemaps and links without reading them. | Text: the number of URLs, then one URL per line. |
| `crawl` | Crawls a site from a seed URL. | Text: a summary and an excerpt of each page, or the crawl's id while it runs. |
| `crawl_status` | Shows a crawl or batch scrape by id. | The same view as `crawl`. |
| `extract` | Pulls structured data from up to 10 URLs with a prompt and/or a JSON Schema. | JSON: the [Extract](https://xdive.dev/docs/extract.md) response. |

### Tool arguments

| Tool | Arguments |
|---|---|
| `search` | `query` (required); `sources`: `web`, `news`, `images` (default `web`); `limit`: 1 to 50 (default 10); `scrape_top`: 0 to 5; `include_answer`; `country` (ISO code such as `us`); `freshness`: `pd`, `pw`, `pm`, `py` or a date range |
| `fetch` | `id` (required): the URL; `offset`; `max_chars` |
| `research` | `query` (required); `depth`: `quick` (default) or `deep`; `output`: `answer` or `report`; `max_sources`: 1 to 30; `freshness`; `country`; `include_domains` |
| `scrape` | `url` (required); `formats`: `markdown` (default), `text`, `html`, `rawHtml`, `links`, `images`, `summary`, `branding`, `product`, `menu`; `redact_pii`; `max_age` (milliseconds); `offset`; `max_chars` |
| `map` | `url` (required); `search`; `limit`: 1 to 5,000 |
| `crawl` | `url` (required); `max_depth`: 0 to 10 (default 2); `max_pages`: 1 to 1,000 (default 100); `include_paths` and `exclude_paths` (RE2 patterns); `wait` (default `true`); `max_chars` |
| `crawl_status` | `id` (required): the `crl_…` id; `max_chars` |
| `extract` | `urls` (required): 1 to 10 URLs; `prompt`; `schema` (JSON Schema) |

The server also sends instructions that tell the model which tool fits which need (search then fetch for precise reading, research for a synthesized and cited answer, map before a crawl). Clients that support server instructions add them to the model's context.

Each tool call is metered like the API call behind it: `search` and `research` like [Search](https://xdive.dev/docs/search.md) and [Research](https://xdive.dev/docs/research.md), `fetch` and `scrape` like [Scrape](https://xdive.dev/docs/scrape.md), and so on. `research`, `extract` and `search` with `include_answer` use the language model configured for your organization. See [Usage and billing](https://xdive.dev/docs/usage.md).

## Connect a client

Pick the tab that matches how you want to authenticate. **OAuth** is the default for every client below: the client discovers XDive's authorization server, opens a browser, and you sign in, choose an organization and click **Allow**. **API key** is for headless agents and clients where you prefer a key: create a dedicated key with the `scrape`, `crawl` and `search` scopes under **API Keys**, keep it in an environment variable, and send it as `Authorization: Bearer ck_live_…` (or `X-API-Key`). Never put a key in the URL.

### ChatGPT

Custom MCP servers are added from **Plugins** in ChatGPT on the web; you don't need to turn on developer mode first.

1. Open **Plugins**, select **+**, then **Add custom MCP server**.
2. Name it XDive and paste the server URL under **Connection**.
3. Choose OAuth for authentication, review the risk warning, and select **I understand and want to continue**.
4. Select **Create as a plugin**, sign in to XDive, choose an organization and click **Allow**. ChatGPT then lists the eight tools.
5. In a chat, type `@` and select XDive.

```text
https://xdive.dev/api/mcp
```

Custom MCP servers are available on ChatGPT Business and Enterprise/Edu workspaces (workspace admins control who may add them) and are not available on mobile. Pro accounts can connect servers for read and fetch actions, which covers all of XDive's tools. Deep research can use the server too: `search` and `fetch` return the result and document shapes it expects.

### Claude (claude.ai and Claude Desktop)

Claude connects to the server from Anthropic's cloud, for claude.ai, Claude Desktop and the mobile apps alike, so a self-hosted server must be reachable from the internet.

1. Open **Customize → Connectors**, select **+ Add**, then **Add custom connector**.
2. Name it XDive, paste the server URL, and select **Continue**. Review the detected authentication and continue.
3. Under **OAuth client**, keep the default. XDive accepts Claude's published client identity (a client ID metadata document) and also supports automatic registration.
4. Select **Add**, then **Connect**. Sign in to XDive, choose an organization and click **Allow**.
5. Turn the connector on for a conversation from **+ → Connectors**.

On Team and Enterprise plans an owner adds the connector once under **Organization settings → Connectors → Add → Custom → Web**, and each member then connects it with their own XDive account from **Customize → Connectors**. Free plans allow one custom connector.

The connector form also has **Request headers** for an API key (`Authorization: Bearer ck_live_…`). On Team and Enterprise plans everyone who uses the connector then shares that key, so prefer OAuth.

If you sign in to Claude Code with the same claude.ai account, connectors you added on claude.ai are available there as well.

### Claude Code

**OAuth**

```bash
claude mcp add --transport http --scope user xdive https://xdive.dev/api/mcp
# then, in a Claude Code session: /mcp, select xdive, and sign in in the browser
# or from your shell:
claude mcp login xdive
```

**API key**

```bash
claude mcp add --transport http --scope user xdive https://xdive.dev/api/mcp \
  --header "Authorization: Bearer $XDIVE_API_KEY"
```

`--scope user` makes the server available in every project; leave it out to add it to the current project only. The shell expands `$XDIVE_API_KEY` when you run the command, so the key is stored in your Claude Code configuration. To share a project configuration without the key, commit a `.mcp.json` that reads it from the environment:

```json
{
  "mcpServers": {
    "xdive": {
      "type": "http",
      "url": "https://xdive.dev/api/mcp",
      "headers": { "Authorization": "Bearer ${XDIVE_API_KEY}" }
    }
  }
}
```

`claude -p` and Agent SDK runs cannot open a browser: sign in once in an interactive session (or with `claude mcp login xdive`) first. Claude Code warns when a tool result exceeds 10,000 tokens and stops at 25,000 by default (`MAX_MCP_OUTPUT_TOKENS`); XDive's default page window of 24,000 characters stays well below that.

### Codex

The Codex CLI, the Codex IDE extension and the ChatGPT desktop app share one configuration file, `~/.codex/config.toml` (or `.codex/config.toml` in a trusted project).

**OAuth**

```toml
[mcp_servers.xdive]
url = "https://xdive.dev/api/mcp"
tool_timeout_sec = 120
```

**API key**

```toml
[mcp_servers.xdive]
url = "https://xdive.dev/api/mcp"
bearer_token_env_var = "XDIVE_API_KEY"
tool_timeout_sec = 120
```

With OAuth, sign in once from the CLI; the IDE extension and the desktop app also show an **Authenticate** button next to the server under **MCP servers**:

```bash
codex mcp login xdive
```

You can add the server from the UI instead: in the ChatGPT desktop app open **Settings → MCP servers → Add server** (in the IDE extension, the gear menu → **MCP servers**), choose **Streamable HTTP**, enter the URL, save and restart.

> **Tip: Set tool_timeout_sec**
>
> Codex stops waiting for a tool after 60 seconds by default. XDive answers every call within about 55 seconds (research and crawl return a "still running" result after about 40 seconds rather than fail), so `tool_timeout_sec = 120` leaves room for slow networks. All tools are marked read-only, so `default_tools_approval_mode = "writes"` lets Codex run them without asking each time.

**Codex cloud tasks.** Cloud environments are configured in ChatGPT (repositories, setup scripts, environment variables, internet access) and do not read your local `config.toml`; OpenAI's documentation says local MCP servers may not be available in the cloud and documents no way to attach a custom MCP server to a cloud environment. The documented route to MCP tools across ChatGPT surfaces is a plugin; see [Plugins](#plugins).

### Cursor

Add the server to `~/.cursor/mcp.json` for every project, or to `.cursor/mcp.json` in one project.

**OAuth**

```json
{
  "mcpServers": {
    "xdive": {
      "url": "https://xdive.dev/api/mcp"
    }
  }
}
```

**API key**

```json
{
  "mcpServers": {
    "xdive": {
      "url": "https://xdive.dev/api/mcp",
      "headers": { "Authorization": "Bearer ${env:XDIVE_API_KEY}" }
    }
  }
}
```

With OAuth, Cursor registers itself and asks you to sign in when it first connects; manage the server from **Customize**. Cursor resolves `${env:NAME}` in `url` and `headers`; remote servers do not support `envFile`, so set the variable in your shell profile.

### VS Code (GitHub Copilot)

Run **MCP: Add Server** from the Command Palette, choose **HTTP**, and enter the URL, or write the configuration yourself:

- `.mcp.json` at the workspace root (`mcpServers`): shared with your team and compatible tools.
- `~/.copilot/mcp-config.json` (`mcpServers`): your own servers, in every workspace.
- `.vscode/mcp.json` (`servers`): for VS Code features such as input variables.

**OAuth**

```json
{
  "mcpServers": {
    "xdive": {
      "type": "http",
      "url": "https://xdive.dev/api/mcp"
    }
  }
}
```

**API key**

```json
{
  "inputs": [
    { "type": "promptString", "id": "xdive-api-key", "description": "XDive API key", "password": true }
  ],
  "servers": {
    "xdive": {
      "type": "http",
      "url": "https://xdive.dev/api/mcp",
      "headers": { "Authorization": "Bearer ${input:xdive-api-key}" }
    }
  }
}
```

The OAuth example uses the `mcpServers` format of `.mcp.json` and `~/.copilot/mcp-config.json`; in `.vscode/mcp.json` the key is `servers`. With OAuth, VS Code registers itself with XDive and opens the browser when the server first starts. The API key variant goes in `.vscode/mcp.json`: VS Code asks for the key once and stores it securely. Copilot harness sessions do not receive servers that need an `${input:…}` value.

### Gemini CLI

**OAuth**

```bash
gemini mcp add --transport http --scope user xdive https://xdive.dev/api/mcp
# then, inside Gemini CLI, run: /mcp auth xdive
```

**API key**

```json
{
  "mcpServers": {
    "xdive": {
      "httpUrl": "https://xdive.dev/api/mcp",
      "headers": { "Authorization": "Bearer $XDIVE_API_KEY" }
    }
  }
}
```

`gemini mcp add` writes to `~/.gemini/settings.json` with `--scope user`, or to the project's `.gemini/settings.json` by default. When editing the file yourself, use `httpUrl`: in Gemini CLI, `url` means the older SSE transport. String values in `settings.json` can reference environment variables as `$NAME` or `${NAME}`.

### Windsurf (Devin Desktop)

Windsurf is now Devin Desktop. Its agents read MCP servers from `~/.config/devin/mcp_config.json` (`%APPDATA%\devin\mcp_config.json` on Windows).

**OAuth**

```json
{
  "mcpServers": {
    "xdive": {
      "url": "https://xdive.dev/api/mcp"
    }
  }
}
```

**API key**

```json
{
  "mcpServers": {
    "xdive": {
      "url": "https://xdive.dev/api/mcp",
      "headers": { "Authorization": "Bearer ${env:XDIVE_API_KEY}" }
    }
  }
}
```

With OAuth you are asked to sign in when the server is first used. With the Devin CLI, `devin mcp add -s user xdive https://xdive.dev/api/mcp` writes the same entry and `devin mcp login xdive` signs in.

### Clients that only run local servers

A client that can only start local (stdio) servers can reach XDive through [mcp-remote](https://github.com/geelen/mcp-remote), which runs locally and forwards to the remote server. It handles OAuth itself: the first run opens a browser to sign in.

**OAuth**

```json
{
  "mcpServers": {
    "xdive": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://xdive.dev/api/mcp"]
    }
  }
}
```

**API key**

```json
{
  "mcpServers": {
    "xdive": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://xdive.dev/api/mcp", "--header", "Authorization:${XDIVE_AUTH}"],
      "env": { "XDIVE_AUTH": "Bearer ck_live_…" }
    }
  }
}
```

mcp-remote substitutes `${XDIVE_AUTH}` from `env`. Writing the header without a space after the colon avoids a bug in some clients that do not quote arguments containing spaces.

Self-hosted deployments can also build the repository's stdio server, `crawler-mcp` (`cmd/mcp`), which calls the API with `XDIVE_API_KEY`, `XDIVE_ORG_ID` and, optionally, `XDIVE_API_URL` (default `https://xdive.dev/api`).

Client menus change often. If a step above no longer matches, see the vendor's guide: [ChatGPT](https://help.openai.com/en/articles/12584461-developer-mode-apps-and-full-mcp-connectors-in-chatgpt-beta), [Claude](https://support.claude.com/en/articles/11175166-getting-started-with-custom-connectors-using-remote-mcp), [Claude Code](https://code.claude.com/docs/en/mcp), [Codex](https://learn.chatgpt.com/docs/extend/mcp?surface=cli), [Cursor](https://cursor.com/docs/context/mcp), [VS Code](https://code.visualstudio.com/docs/copilot/customization/mcp-servers), [Gemini CLI](https://github.com/google-gemini/gemini-cli/blob/main/docs/tools/mcp-server.md), [Devin Desktop](https://docs.devin.ai/desktop/cascade/mcp).

## Use it from code

Model APIs that call remote MCP servers on your behalf can use XDive directly. They connect from the provider's infrastructure, so the server must be publicly reachable, and they take a bearer token: pass an API key.

### OpenAI Responses API

**cURL**

```bash
curl https://api.openai.com/v1/responses \
  -H "Authorization: Bearer $OPENAI_API_KEY" -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-6-astra",
    "tools": [{
      "type": "mcp",
      "server_label": "xdive",
      "server_description": "Search the web, read pages and research questions with cited sources.",
      "server_url": "https://xdive.dev/api/mcp",
      "authorization": "'"$XDIVE_API_KEY"'",
      "require_approval": "never"
    }],
    "input": "How does HTTP/3 differ from HTTP/2? Cite your sources."
  }'
```

**Python**

```python
import os
from openai import OpenAI

client = OpenAI()
response = client.responses.create(
    model="gpt-6-astra",
    tools=[{
        "type": "mcp",
        "server_label": "xdive",
        "server_description": "Search the web, read pages and research questions with cited sources.",
        "server_url": "https://xdive.dev/api/mcp",
        "authorization": os.environ["XDIVE_API_KEY"],
        "require_approval": "never",
    }],
    input="How does HTTP/3 differ from HTTP/2? Cite your sources.",
)
print(response.output_text)
```

**JavaScript**

```ts
import OpenAI from "openai";

const client = new OpenAI();
const response = await client.responses.create({
  model: "gpt-6-astra",
  tools: [{
    type: "mcp",
    server_label: "xdive",
    server_description: "Search the web, read pages and research questions with cited sources.",
    server_url: "https://xdive.dev/api/mcp",
    authorization: process.env.XDIVE_API_KEY,
    require_approval: "never",
  }],
  input: "How does HTTP/3 differ from HTTP/2? Cite your sources.",
});
console.log(response.output_text);
```

`authorization` is sent to XDive as a bearer token. `require_approval: "never"` skips OpenAI's per-call approval; remove it to review each call first. `allowed_tools` (for example `["search", "fetch", "research"]`) limits which tools the model sees. In the OpenAI Agents SDK, `HostedMCPTool(tool_config={…})` takes the same object.

### Anthropic Messages API

The MCP connector is a beta feature: send the `anthropic-beta: mcp-client-2025-11-20` header (the SDKs take `betas`). Each server in `mcp_servers` needs a matching `mcp_toolset` entry in `tools`.

**cURL**

```bash
curl https://api.anthropic.com/v1/messages \
  -H "x-api-key: $ANTHROPIC_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "anthropic-beta: mcp-client-2025-11-20" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-opus-5-5",
    "max_tokens": 2000,
    "messages": [{"role": "user", "content": "How does HTTP/3 differ from HTTP/2? Cite your sources."}],
    "mcp_servers": [{
      "type": "url",
      "url": "https://xdive.dev/api/mcp",
      "name": "xdive",
      "authorization_token": "'"$XDIVE_API_KEY"'"
    }],
    "tools": [{"type": "mcp_toolset", "mcp_server_name": "xdive"}]
  }'
```

**Python**

```python
import os
import anthropic

client = anthropic.Anthropic()
response = client.beta.messages.create(
    model="claude-opus-5-5",
    max_tokens=2000,
    messages=[{"role": "user", "content": "How does HTTP/3 differ from HTTP/2? Cite your sources."}],
    mcp_servers=[{
        "type": "url",
        "url": "https://xdive.dev/api/mcp",
        "name": "xdive",
        "authorization_token": os.environ["XDIVE_API_KEY"],
    }],
    tools=[{"type": "mcp_toolset", "mcp_server_name": "xdive"}],
    betas=["mcp-client-2025-11-20"],
)
print(response.content)
```

**JavaScript**

```ts
import Anthropic from "@anthropic-ai/sdk";

const anthropic = new Anthropic();
const response = await anthropic.beta.messages.create({
  model: "claude-opus-5-5",
  max_tokens: 2000,
  messages: [{ role: "user", content: "How does HTTP/3 differ from HTTP/2? Cite your sources." }],
  mcp_servers: [{
    type: "url",
    url: "https://xdive.dev/api/mcp",
    name: "xdive",
    authorization_token: process.env.XDIVE_API_KEY,
  }],
  tools: [{ type: "mcp_toolset", mcp_server_name: "xdive" }],
  betas: ["mcp-client-2025-11-20"],
});
console.log(response.content);
```

### Raw JSON-RPC

Any HTTP client can talk to the server. With the current protocol revision (`2026-07-28`) there is no handshake: each request carries its protocol version, client information and capabilities in `params._meta`, and repeats the version and method in headers. Start with `server/discover`:

```bash
curl https://xdive.dev/api/mcp \
  -H "Authorization: Bearer $XDIVE_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "MCP-Protocol-Version: 2026-07-28" \
  -H "Mcp-Method: server/discover" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "server/discover",
    "params": {
      "_meta": {
        "io.modelcontextprotocol/protocolVersion": "2026-07-28",
        "io.modelcontextprotocol/clientInfo": {"name": "curl", "version": "1.0"},
        "io.modelcontextprotocol/clientCapabilities": {}
      }
    }
  }'
```

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "_meta": {
      "io.modelcontextprotocol/serverInfo": {
        "name": "xdive",
        "title": "XDive",
        "version": "1.6.0",
        "websiteUrl": "https://xdive.dev",
        "icons": [{ "src": "https://xdive.dev/icon-512.png", "mimeType": "image/png", "sizes": ["512x512"] }, { "src": "https://xdive.dev/icon-192.png", "mimeType": "image/png", "sizes": ["192x192"] }]
      }
    },
    "cacheScope": "private",
    "capabilities": { "tools": {} },
    "instructions": "Web access tools. Pick by need: …",
    "resultType": "complete",
    "supportedVersions": ["2026-07-28", "2025-11-25", "2025-06-18", "2025-03-26", "2024-11-05"],
    "ttlMs": 600000
  }
}
```

Call a tool with `tools/call`. A tool call also needs the `Mcp-Name` header, set to the tool's name:

```bash
curl https://xdive.dev/api/mcp \
  -H "Authorization: Bearer $XDIVE_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "MCP-Protocol-Version: 2026-07-28" \
  -H "Mcp-Method: tools/call" \
  -H "Mcp-Name: fetch" \
  -d '{
    "jsonrpc": "2.0",
    "id": 2,
    "method": "tools/call",
    "params": {
      "name": "fetch",
      "arguments": {"id": "https://example.com"},
      "_meta": {
        "io.modelcontextprotocol/protocolVersion": "2026-07-28",
        "io.modelcontextprotocol/clientInfo": {"name": "curl", "version": "1.0"},
        "io.modelcontextprotocol/clientCapabilities": {}
      }
    }
  }'
```

```json
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "_meta": { "io.modelcontextprotocol/serverInfo": { "name": "xdive", "title": "XDive", "version": "1.6.0" } },
    "content": [
      {
        "text": "{\"id\":\"https://example.com\",\"metadata\":{\"offset\":0,\"total_chars\":182},\"text\":\"# Example Domain\\n\\nThis domain is for use in documentation examples…\",\"title\":\"Example Domain\",\"url\":\"https://example.com\"}",
        "type": "text"
      }
    ],
    "isError": false,
    "resultType": "complete"
  }
}
```

The tool's output is the `text` of the single content block (`serverInfo` is shortened here; it is the same object `server/discover` returns). Clients on older revisions open with `initialize` instead; see [Protocol support](#protocol-support).

## Plugins

A plugin package for Codex (ChatGPT desktop app and Codex CLI) and Claude Code bundles this server, signed in with OAuth, with a `web-research` skill that teaches the agent when to use each tool, how to read long pages in parts, how to continue a long research run and how to cite sources.

The package is ready but not yet published: it is not listed in the OpenAI plugin directory, Anthropic's directory or a public marketplace. Until it is, connect the server directly as described above; the plugin adds the skill on top of the same tools. Once it is listed in the OpenAI plugin directory, which ChatGPT and Codex share, installing it there is the documented way to bring the tools to ChatGPT surfaces that do not read `config.toml`.

## Authentication

### OAuth

Clients that support MCP authorization sign in without any configuration beyond the URL:

1. An unauthenticated request gets `401` with `WWW-Authenticate: Bearer resource_metadata="https://xdive.dev/.well-known/oauth-protected-resource/api/mcp"`.
2. That protected-resource metadata (RFC 9728) names the authorization server, whose metadata (RFC 8414) is at `/.well-known/oauth-authorization-server`.
3. The client identifies itself in one of two ways. Clients that publish a **client ID metadata document** use its `https` URL as their `client_id`; XDive fetches and validates the document (at most 5 KB, no redirects, `client_id` must equal the URL, public clients only) when you approve, so nothing is registered in advance. Other clients register at `/api/oauth/register` (dynamic client registration, RFC 7591). Either way clients are public (no secret); redirect URIs must be `https`, or `http` on a loopback address, where any port is accepted (RFC 8252).
4. You sign in on XDive's consent screen at `/oauth/authorize`, which names the app and where it will send you, choose the organization the app may use, and click **Allow** or **Deny**.
5. The client exchanges the code at `/api/oauth/token`. PKCE with `S256` is required; the only scope is `mcp`.

Access tokens last 1 hour and refresh tokens 30 days; refresh tokens rotate on every use, and reusing a spent code or refresh token revokes the whole grant. Tokens are bound to `/api/mcp`: the REST API rejects them. A grant can scrape, crawl and search for the organization you chose, and stops working when you leave the organization, the organization is suspended, or your account loses access.

Members see every app connected to an organization under **API Keys → Connected apps** and can revoke one there; approvals and revocations are recorded in the audit log. A revoked app has to ask you again.

### API keys

Send an organization API key as `Authorization: Bearer ck_live_…` or `X-API-Key: ck_live_…`. The key decides the organization, so no organization id is needed. Each tool needs one scope:

| Scope | Tools |
|---|---|
| `search` | `search`, `research` |
| `scrape` | `fetch`, `scrape` |
| `crawl` | `map`, `crawl`, `crawl_status` |
| `scrape` or `crawl` | `extract` |

New keys get `scrape` and `crawl` by default; add `search` when you create a key for MCP. Key expiry and IP allowlists apply as usual. See [Authentication](https://xdive.dev/docs/authentication.md).

## How results are shaped

Every tool returns one text block, sized to fit client limits on tool output.

- **Page windows.** `fetch` and `scrape` return up to 24,000 characters of a page (about 6,000 tokens). Set `max_chars` between 1,000 and 60,000 to change the window. When the page continues, `fetch` sets `metadata.next_offset` and `scrape` ends with `[Page continues: … Call scrape again with offset=N to read on.]`; call again with that `offset`. Later parts are read from a copy cached for up to 10 minutes, so all parts come from the same fetch.
- **Search.** Each result has `id` (its URL), `title`, `url`, `text` (the search engine's description) and, when available, `passages` that match the query. With `scrape_top`, each read result adds up to 4,000 characters of `content`. `answer` is present with `include_answer`.
- **Research.** The answer cites sources as `[1]`, `[2]`; a `Sources:` list follows, then a line such as `Confidence: high · 6 pages read · 12.4s`. A research call waits about 40 seconds. A run that takes longer keeps going on the server, and the tool answers that it is still running and asks the model to call again with exactly the same arguments in about 15 seconds (30 for `deep`). The repeated call returns the finished answer, which is kept for 10 minutes, instead of starting over.
- **Crawl.** `crawl` waits about 40 seconds. A finished crawl shows a summary and an excerpt of each page, sharing the output budget (at least 1,500 characters per page) and listing pages that did not fit; read any of them with `fetch`. A crawl still running returns its id for `crawl_status`. Set `wait: false` to get the id at once.
- **Map** lists URLs until the output limit and then says how many more there are; narrow it with `search` or `limit`.
- **Size limit.** No tool result exceeds 60,000 characters; anything longer is cut and marked `…[truncated]`.
- **Errors** come back as tool results with `isError: true` and a sentence such as `Error 403 (SITE_RESTRICTED): …` or `Error 402: …`, so the model can react. See [Errors and limits](https://xdive.dev/docs/errors.md).
- **Annotations.** Every tool is marked `readOnlyHint: true`, `destructiveHint: false` and `openWorldHint: true`; all except `crawl` are also `idempotentHint: true`. Clients use these hints to decide when to ask before running a tool. Tools carry titles and XDive's icon.

## Protocol support

- **Transport:** Streamable HTTP. Requests are `POST` with a JSON-RPC body of at most 4 MiB, and responses are plain JSON (`Cache-Control: no-store`); the server never opens an SSE stream.
- **Stateless:** there are no sessions, and any server instance can answer any request. `GET` and `DELETE` on the endpoint return `405` with `Allow: POST`.
- **Revisions:** `2026-07-28`, plus `2025-11-25`, `2025-06-18`, `2025-03-26` and `2024-11-05` through `initialize`. The era is chosen per request: a request whose `params._meta` names `io.modelcontextprotocol/protocolVersion` is served under the current revision; anything else follows the `initialize` handshake, where the server echoes a version it supports or offers `2025-11-25`.
- **Current revision (`2026-07-28`):** the `MCP-Protocol-Version` header must equal the version in `_meta`, `Mcp-Method` must equal the method, and `Mcp-Name` must equal the tool name on `tools/call` (`=?base64?…?=` encoding is accepted). A mismatch returns `400` with error `-32020`; an unsupported version returns `400` with error `-32022` and the list of supported versions; an unknown method returns `404`. Results carry `resultType: "complete"` and the server's identity in `_meta`; `server/discover` and `tools/list` add `ttlMs` (600,000) and `cacheScope: "private"`.
- **Earlier revisions:** `MCP-Protocol-Version`, when sent, must name a supported version. JSON-RPC batches (a `2025-03-26` feature) are answered as an array. Notifications get `202` with no body.
- **Capabilities:** tools only. The tool list does not change at runtime.
- **Timing:** each request is answered within about 55 seconds.

## Troubleshooting

| Symptom | Cause and fix |
|---|---|
| `401` when connecting, or the client asks you to sign in again | The token expired, was revoked under **Connected apps**, or was issued for another server. Sign in again from the client (for example `/mcp` in Claude Code, `codex mcp login xdive`, `/mcp auth xdive` in Gemini CLI). With an API key, `invalid API key` means the key is wrong, expired, revoked or used from an address outside its allowlist. |
| A tool returns `Error 403` about a scope | The API key lacks the tool's scope. Create a key with `scrape`, `crawl` and `search`. |
| `403` with `ACCOUNT_PENDING_APPROVAL` or `ACCOUNT_REJECTED` | The XDive account is waiting for an administrator's approval, or was not approved. The same codes appear when the client exchanges or refreshes a token. |
| `403 organization is suspended` | Contact the organization's owner or the administrator. |
| The consent screen says `unknown client` or `client metadata: …` | For a registered client, connect again so it re-registers (unused registrations are removed after a day). For a metadata-document client, the message names what is wrong with its document. |
| A tool call times out | Raise the client's tool timeout: `tool_timeout_sec = 120` in Codex. If research answers that it is still running, call it again with the same arguments. |
| `405 Method Not Allowed` | The client sent `GET`, for example because it is configured for the SSE transport. Configure Streamable HTTP (`"type": "http"` or `"streamable-http"`, `httpUrl` in Gemini CLI). |
| `404` or failed discovery | Check the URL: `https://xdive.dev/api/mcp`, with `/api` and no trailing slash. |
| The client only starts local servers | Use [mcp-remote](#clients-that-only-run-local-servers). |
| Self-hosted: sign-in fails with `resource does not identify this MCP server` | `APP_URL` must be the public `https` origin clients use; tokens are bound to `APP_URL` followed by `/api/mcp`. See [Self-hosting](https://xdive.dev/docs/self-hosting.md). |

---

Source: https://xdive.dev/docs/mcp · All docs for agents: https://xdive.dev/llms.txt
