---
title: Connect over MCP
description: "relate, the embedded Cypher graph database (relatedb.ai): Serve a relate store over MCP to Claude Code, Claude Desktop, Cursor, Codex, Windsurf, Gemini CLI, Cline or OpenCode, every config block opening it --read-only."
type: how-to
surfaces:
  - mcp
  - cli
  - agents
status: stable
verified: 0.1.2
verified_by:
  - cypher
  - cli
canonical_url: https://relatedb.ai/docs/guides/agents/connect-over-mcp/
prerequisites:
  - get-started/install
related:
  - get-started/agent-quickstart
  - guides/serve/mcp
  - reference/server/mcp
  - guides/agents/agent-safety
  - guides/agents/run-in-a-sandbox
  - reference/errors#mcp-read-query-only
  - reference/cli
  - guides/integrations/claude-agent-sdk
  - guides/integrations/pydantic-ai
last_updated: 2026-11-10
---

# Connect over MCP

Serve a relate store over MCP to Claude Code, Claude Desktop, Cursor, Codex, Windsurf, Gemini CLI, Cline or OpenCode, every config block opening it --read-only.

> Verified against relate 0.1.2. If your `relate --version` is newer, read https://relatedb.ai/docs/reference/changelog/#since-0.1.2

This guide shows you how to connect an agent host to a relate store over [MCP](https://relatedb.ai/docs/reference/glossary/#mcp) (the Model Context Protocol), with the store opened [read-only](https://relatedb.ai/docs/reference/glossary/#read-only). Every host on this page starts the same command, `relate serve --mcp stdio --database <store> --read-only`; only the file it lives in differs.

## Prerequisites

- relate on your `PATH`: `relate --version` prints its version ([Install relate](https://relatedb.ai/docs/get-started/install/)).
- A [store](https://relatedb.ai/docs/reference/glossary/#store) that already exists, a `.rl` file or a directory. A read-only open never creates one.
- One of the hosts in [Add the server to your host](#add-the-server-to-your-host).

## Choose a transport

`relate serve --mcp` takes either the keyword `stdio` or a port number. Both serve the same tools.

|                  | `--mcp stdio`                                                            | `--mcp <port>`                                                                                                 |
| ---------------- | ------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------- |
| Who starts it    | The host, as a child process, until it closes stdin                      | You, as a long-running process, until SIGINT or SIGTERM                                                        |
| Authentication   | None: the host spawned the process. `--auth` with stdio is a usage error | One basic-auth credential from `--auth` or `RELATE_AUTH`; without either, a generated token printed at startup |
| Where it listens | stdin and stdout                                                         | `127.0.0.1:<port>` by default (`--host`); plaintext HTTP, no TLS                                               |
| Which hosts      | Every host on this page                                                  | Hosts that connect to a URL                                                                                    |

Opened with `--read-only`, the server lists two tools, `read_cypher` and `get_schema`, and takes no writer lease. `write_cypher` is listed only when the store is writable. A directory store can be served read-only beside a process that writes it; a `.rl` file opens only while no writer holds it. [relate serve flags](https://relatedb.ai/docs/reference/cli/flags/#relate-serve) lists every flag.

## What the agent sees

Once the host has started the server, the agent calls its tools with `tools/call` requests, and each reply carries the result as JSON text. The tryout below sends those calls to an in-browser database on this page that holds the same graph as the `graph.rl` that [Verify](#verify) creates, three people and two projects:

```cypher run name=graph
CREATE (ada:Person {name: 'Ada', role: 'engineer'}),
       (grace:Person {name: 'Grace', role: 'engineer'}),
       (noor:Person {name: 'Noor', role: 'maintainer'}),
       (relate:Project {name: 'relate', language: 'Rust'}),
       (tck:Project {name: 'opencypher-tck', language: 'Gherkin'}),
       (ada)-[:WORKS_ON {since: 2024}]->(relate),
       (grace)-[:WORKS_ON {since: 2023}]->(relate),
       (grace)-[:WORKS_ON {since: 2022}]->(tck),
       (noor)-[:MAINTAINS]->(relate),
       (ada)-[:KNOWS]->(grace)
```

```table
(no rows) · nodes created: 5, relationships created: 5, properties set: 13, labels added: 5
```

```json data=calls
{"calls": [
  {"tool": "get_schema", "arguments": {}},
  {"tool": "read_cypher", "arguments": {"statement": "MATCH (p:Person)-[w:WORKS_ON]->(:Project {name: $project}) RETURN p.name AS name, w.since AS since ORDER BY since", "parameters": {"project": "relate"}}},
  {"tool": "write_cypher", "arguments": {"statement": "CREATE (:Person {name: $name, role: $role})", "parameters": {"name": "Eve", "role": "engineer"}}}
]}
```

These calls ran when the page was recorded, on a database that holds what this page's cells write, through the same mapping the live tryout uses. Timings show as `<ms>`; live, each reply carries the timings of its own run. The server lists `write_cypher`, `read_cypher`, `get_schema`.

Live, the tryout starts as a server started `--read-only`, as every configuration on this page opens the store; with **Serve read-only** off it lists `write_cypher` as well.

**`get_schema`**: the request a host sends, then the reply.

```json
{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_schema","arguments":{}}}
```

```json
{"jsonrpc":"2.0","id":1,"result":{"content":[{"text":"{\"Person\":{\"count\":3,\"properties\":{\"name\":{\"type\":\"String\"},\"role\":{\"type\":\"String\"}},\"relationships\":{\"KNOWS\":{\"direction\":\"out\",\"labels\":[\"Person\"]},\"MAINTAINS\":{\"direction\":\"out\",\"labels\":[\"Project\"]},\"WORKS_ON\":{\"direction\":\"out\",\"labels\":[\"Project\"],\"properties\":{\"since\":{\"type\":\"Integer\"}}}},\"type\":\"node\"},\"Project\":{\"count\":2,\"properties\":{\"language\":{\"type\":\"String\"},\"name\":{\"type\":\"String\"}},\"type\":\"node\"}}","type":"text"}],"isError":false}}
```

| Label   | Nodes | Properties                       | Relationships out                                          |
| ------- | ----- | -------------------------------- | ---------------------------------------------------------- |
| Person  | 3     | name (String), role (String)     | WORKS_ON to Project; KNOWS to Person; MAINTAINS to Project |
| Project | 2     | language (String), name (String) | -                                                          |

**`read_cypher`**: the request a host sends, then the reply.

```json
{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"read_cypher","arguments":{"statement":"MATCH (p:Person)-[w:WORKS_ON]->(:Project {name: $project}) RETURN p.name AS name, w.since AS since ORDER BY since","parameters":{"project":"relate"}}}}
```

```json
{"jsonrpc":"2.0","id":2,"result":{"content":[{"text":"{\"columnTypes\":[\"STRING\",\"INTEGER\"],\"columns\":[\"name\",\"since\"],\"elapsed_ms\":<ms>,\"error\":null,\"execute_ms\":<ms>,\"lex_parse_ms\":<ms>,\"lower_ms\":<ms>,\"notifications\":[{\"category\":\"PERFORMANCE\",\"code\":\"Relate.Notification.Statement.MissingIndex\",\"description\":\"the equality predicate on name filters :Project without a range index on (:Project {name})\",\"gql_status\":\"03C91\",\"operator_id\":1,\"remedy\":\"CREATE INDEX relate_Project__name FOR (n:Project) ON (n.name)\",\"severity\":\"INFORMATION\",\"title\":\"Missing index\"}],\"parse_ms\":<ms>,\"plan\":{\"profiled\":false,\"root\":{\"actual\":null,\"children\":[{\"actual\":null,\"children\":[],\"details\":\"(:Project)<-[w:WORKS_ON]-(p:Person)\",\"estimated_rows\":null,\"identifiers\":[],\"operator\":\"Expand\",\"warnings\":[{\"category\":\"PERFORMANCE\",\"code\":\"Relate.Notification.Statement.MissingIndex\",\"description\":\"the equality predicate on name filters :Project without a range index on (:Project {name})\",\"gql_status\":\"03C91\",\"remedy\":\"CREATE INDEX relate_Project__name FOR (n:Project) ON (n.name)\",\"severity\":\"INFORMATION\",\"title\":\"Missing index\"}]}],\"details\":\"2 item(s), ordered\",\"estimated_rows\":null,\"identifiers\":[],\"operator\":\"ProduceResults\",\"warnings\":[]},\"schema\":\"relate.plan/v1\",\"statement\":\"MATCH (p:Person)-[w:WORKS_ON]->(:Project {name: $project}) RETURN p.name AS name, w.since AS since ORDER BY since\"},\"plan_cache\":\"miss\",\"plan_ms\":<ms>,\"result_generation_ms\":<ms>,\"rewrite_ms\":<ms>,\"rows\":[{\"name\":\"Grace\",\"since\":2023},{\"name\":\"Ada\",\"since\":2024}],\"stats\":{\"constraints_added\":0,\"constraints_removed\":0,\"indexes_added\":0,\"indexes_removed\":0,\"labels_added\":0,\"labels_removed\":0,\"nodes_created\":0,\"nodes_deleted\":0,\"properties_set\":0,\"relationships_created\":0,\"relationships_deleted\":0}}","type":"text"}],"isError":false}}
```

| name  | since |
| ----- | ----- |
| Grace | 2023  |
| Ada   | 2024  |

**`write_cypher`**: the request a host sends, then the reply.

```json
{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"write_cypher","arguments":{"statement":"CREATE (:Person {name: $name, role: $role})","parameters":{"name":"Eve","role":"engineer"}}}}
```

```json
{"jsonrpc":"2.0","id":3,"result":{"content":[{"text":"{\"columnTypes\":[],\"columns\":[],\"elapsed_ms\":<ms>,\"error\":null,\"execute_ms\":<ms>,\"lex_parse_ms\":<ms>,\"lower_ms\":<ms>,\"notifications\":[],\"parse_ms\":<ms>,\"plan\":{\"profiled\":false,\"root\":{\"actual\":null,\"children\":[],\"details\":\"(:Person)\",\"estimated_rows\":null,\"identifiers\":[],\"operator\":\"Create\",\"warnings\":[]},\"schema\":\"relate.plan/v1\",\"statement\":\"CREATE (:Person {name: $name, role: $role})\"},\"plan_cache\":\"miss\",\"plan_ms\":<ms>,\"result_generation_ms\":<ms>,\"rewrite_ms\":<ms>,\"rows\":[],\"stats\":{\"constraints_added\":0,\"constraints_removed\":0,\"indexes_added\":0,\"indexes_removed\":0,\"labels_added\":1,\"labels_removed\":0,\"nodes_created\":1,\"nodes_deleted\":0,\"properties_set\":2,\"relationships_created\":0,\"relationships_deleted\":0}}","type":"text"}],"isError":false}}
```

Counters: `nodes_created` 1, `properties_set` 2, `labels_added` 1; `rows` is empty, as `write_cypher` returns counters.

**`write_cypher` on a server started `--read-only`**: it lists only `read_cypher` and `get_schema`, and answers a `write_cypher` call with a tool error before the engine sees the statement. This run is recorded from relate 0.1.2 (errors.json `mcp-unknown-tool`, replayed against the binary by `docs:cli-check`); the page quotes it as the binary printed it:

```bash
printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"check","version":"0"}}}' '{"jsonrpc":"2.0","method":"notifications/initialized"}' '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"write_cypher","arguments":{"query":"CREATE (:B)"}}}' | relate serve --mcp stdio --database ./graph.rl --read-only
```

```text
{"jsonrpc":"2.0","id":1,"result":{"capabilities":{"tools":{}},"protocolVersion":"2025-06-18","serverInfo":{"name":"relate-mcp","version":"0.1.2"}}}
{"jsonrpc":"2.0","id":2,"result":{"content":[{"text":"unknown tool 'write_cypher'","type":"text"}],"isError":true}}
```

Transport answers (HTTP 401, 403 and 415, the body cap, the header deadline) are not part of the tryout; the [MCP server reference](https://relatedb.ai/docs/reference/server/mcp/#errors-and-refusals) lists them.

Live: each call is a button that sends its `tools/call` request to the page's database in your browser and shows the request and the reply, built from the engine's result the way `relate serve --mcp` builds it, with the statement and parameters editable; "Serve read-only" drops `write_cypher` from the tool list, as `--read-only` does, and shows the engine's own refusal of the write on a read-only database beside the server's recorded answer.

In a browser the tryout starts with **Serve read-only** on, because every block in the next section opens the store read-only: the tool list has no `write_cypher`, and a call to it is refused before the engine sees it. Turned off, `write_cypher` writes to this page's in-browser database and nothing else. The rows and the plan come from the engine; apart from the timings, a host gets the same reply from `relate serve`.

## Add the server to your host

Each block starts relate on stdio against `graph.rl`, read-only. Host configuration formats change between releases. Each host's block follows that host's own documentation as of 2026-11-07.

A relative store path resolves against the directory the host starts the server in, which is not the same for every host. Blocks for a host that starts servers from your project folder use `./graph.rl`; the others use `<absolute-path>/graph.rl`, which works everywhere.

### Claude Code

A person adds the server with `claude mcp add`. An agent working in the repository writes the same server into `.mcp.json` at the project root, a file the person can review and commit.

#### At a terminal

```bash
claude mcp add relate -- relate serve --mcp stdio --database ./graph.rl --read-only
```

To allow writes, remove `--read-only`.

That adds the server for you in the current project (the default `local` scope, kept in `~/.claude.json`). With `--scope project`, Claude Code writes the same entry to `.mcp.json` at the project root instead, so it can be committed.

#### From an agent

```json title=".mcp.json"
{
  "mcpServers": {
    "relate": {
      "command": "relate",
      "args": ["serve", "--mcp", "stdio", "--database", "./graph.rl", "--read-only"]
    }
  }
}
```

To allow writes, remove `"--read-only"` from `args`.

The entry is the one `claude mcp add --scope project` writes. Claude Code asks before it uses a project-scoped server from `.mcp.json`, so the person approves the server the agent added.

`claude mcp list` shows each server with its health status, and `/mcp` inside a session shows its tools.

### Claude Desktop

The file is `claude_desktop_config.json`: `~/Library/Application Support/Claude/` on macOS, `%APPDATA%\Claude\` on Windows, `~/.config/Claude/` on Linux. **Settings**, then **Developer**, then **Edit Config** opens it.

```json title="claude_desktop_config.json"
{
  "mcpServers": {
    "relate": {
      "command": "relate",
      "args": ["serve", "--mcp", "stdio", "--database", "<absolute-path>/graph.rl", "--read-only"]
    }
  }
}
```

To allow writes, remove `"--read-only"` from `args`.

Quit and restart Claude Desktop after saving. The server's stderr, including relate's startup lines, goes to `mcp-server-relate.log` in Claude Desktop's log folder (`~/Library/Logs/Claude` on macOS).

### Cursor

The file is `.cursor/mcp.json` in the project, or `~/.cursor/mcp.json` for every project. With `--read-only` in `args`, Cursor can query the graph and cannot write to it.

```json title="mcp.json"
{
  "mcpServers": {
    "relate": {
      "command": "relate",
      "args": ["serve", "--mcp", "stdio", "--database", "<absolute-path>/graph.rl", "--read-only"]
    }
  }
}
```

To allow writes, remove `"--read-only"` from `args`.

The same server entry as a Cursor install link, generated from the JSON shown with it:

```json
{
  "command": "relate",
  "args": ["serve", "--mcp", "stdio", "--database", "<absolute-path>/graph.rl", "--read-only"]
}
```

Cursor install link for the server `relate`, generated from this JSON: `cursor://anysphere.cursor-deeplink/mcp/install?name=relate&config=eyJjb21tYW5kIjoicmVsYXRlIiwiYXJncyI6WyJzZXJ2ZSIsIi0tbWNwIiwic3RkaW8iLCItLWRhdGFiYXNlIiwiPGFic29sdXRlLXBhdGg%2BL2dyYXBoLnJsIiwiLS1yZWFkLW9ubHkiXX0%3D`

The link carries the path as written, `<absolute-path>` included, so the entry needs the store's real path in `mcp.json` once it is added.

### Codex

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

```toml title="config.toml"
[mcp_servers.relate]
command = "relate"
args = ["serve", "--mcp", "stdio", "--database", "<absolute-path>/graph.rl", "--read-only"]
```

To allow writes, remove `"--read-only"` from `args`.

The CLI writes the same entry:

```bash
codex mcp add relate -- relate serve --mcp stdio --database <absolute-path>/graph.rl --read-only
```

To allow writes, remove `--read-only`. `codex mcp list` and `/mcp` show the configured servers.

### Windsurf

The file is `~/.codeium/windsurf/mcp_config.json`, in the same shape as Claude Desktop's.

```json title="mcp_config.json"
{
  "mcpServers": {
    "relate": {
      "command": "relate",
      "args": ["serve", "--mcp", "stdio", "--database", "<absolute-path>/graph.rl", "--read-only"]
    }
  }
}
```

To allow writes, remove `"--read-only"` from `args`.

As of 2026-11-07, Windsurf's English documentation redirects to Devin Desktop's. This page does not describe Devin Desktop's MCP configuration.

### Gemini CLI

The file is `.gemini/settings.json` in the project, or `~/.gemini/settings.json` for every project.

```json title="settings.json"
{
  "mcpServers": {
    "relate": {
      "command": "relate",
      "args": ["serve", "--mcp", "stdio", "--database", "<absolute-path>/graph.rl", "--read-only"]
    }
  }
}
```

To allow writes, remove `"--read-only"` from `args`.

`/mcp` in a session and `gemini mcp list` show each server and its tools. In a folder Gemini CLI does not trust, stdio servers show as disconnected until you trust it.

### Cline

The file is `cline_mcp_settings.json`. In the IDE extension, the **MCP Servers** icon in the Cline panel, then the **Configure** tab, then **Configure MCP Servers** opens it; the Cline CLI reads `~/.cline/data/settings/cline_mcp_settings.json`.

```json title="cline_mcp_settings.json"
{
  "mcpServers": {
    "relate": {
      "command": "relate",
      "args": ["serve", "--mcp", "stdio", "--database", "<absolute-path>/graph.rl", "--read-only"],
      "disabled": false,
      "autoApprove": []
    }
  }
}
```

To allow writes, remove `"--read-only"` from `args`.

`autoApprove` lists the tools Cline runs without asking; empty, it asks for every call.

### OpenCode

The file is `opencode.json` (or `opencode.jsonc`) in the project, or `~/.config/opencode/opencode.json` for every project. Servers go under `mcp.servers`, and a local server's `command` is one array. OpenCode starts a local server in the project folder by default.

```json title="opencode.json"
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "servers": {
      "relate": {
        "type": "local",
        "command": ["relate", "serve", "--mcp", "stdio", "--database", "./graph.rl", "--read-only"]
      }
    }
  }
}
```

To allow writes, remove `"--read-only"` from `command`. `opencode mcp list` shows each server and its connection state.

## Serve over HTTP

If your host connects to a URL, or several clients share one server, start relate yourself on a port as in [Serve over HTTP](https://relatedb.ai/docs/guides/serve/mcp/#serve-over-http): `relate serve --mcp 8000 --database ./graph.rl --read-only` listens on `127.0.0.1:8000` and checks a credential from `RELATE_AUTH` or `--auth`, or else a token it generates for the user `relate` and saves beside the store as `<store>.auth-token`. The [MCP server reference](https://relatedb.ai/docs/reference/server/mcp/) describes the transport and every answer.

In another terminal, register the URL with your host. For Claude Code, `<credential>` is the base64 of `<user>:<password>` (`printf '%s' '<user>:<password>' | base64` prints it):

```bash
claude mcp add --transport http relate http://127.0.0.1:8000 --header "Authorization: Basic <credential>"
```

The server opened the store read-only, so this entry cannot write.

## Verify

Check the server from a shell before a host is involved. This step creates a small `graph.rl` to check against, the shared example graph of three people and two projects:

```bash verify
relate --database ./graph.rl "CREATE (ada:Person {name: 'Ada', role: 'engineer'}),
       (grace:Person {name: 'Grace', role: 'engineer'}),
       (noor:Person {name: 'Noor', role: 'maintainer'}),
       (relate:Project {name: 'relate', language: 'Rust'}),
       (tck:Project {name: 'opencypher-tck', language: 'Gherkin'}),
       (ada)-[:WORKS_ON {since: 2024}]->(relate),
       (grace)-[:WORKS_ON {since: 2023}]->(relate),
       (grace)-[:WORKS_ON {since: 2022}]->(tck),
       (noor)-[:MAINTAINS]->(relate),
       (ada)-[:KNOWS]->(grace)"
```

Then send three JSON-RPC messages the way a host does, one per line: `initialize`, `tools/list`, and a write sent to `read_cypher`. The `2>/dev/null` drops relate's startup lines on stderr:

```bash verify
printf '%s\n' \
  '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"shell","version":"0"}}}' \
  '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}' \
  '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"read_cypher","arguments":{"statement":"CREATE (:Person {name: \"Eve\"})"}}}' \
  | relate serve --mcp stdio --database ./graph.rl --read-only 2>/dev/null
```

```text
{"jsonrpc":"2.0","id":1,"result":{"capabilities":{"tools":{}},"protocolVersion":"2024-11-05","serverInfo":{"name":"relate-mcp","version":"0.1.2"}}}
{"jsonrpc":"2.0","id":2,"result":{"tools":[{"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true,"title":"Read Cypher"},"description":"Execute one read-only Cypher statement. Returns the result's rows. Write and schema (DDL) statements are rejected.","inputSchema":{"properties":{"parameters":{"default":{},"description":"The statement's parameters; a `rows` array feeds `$rows`.","type":"object"},"statement":{"description":"The Cypher statement.","type":"string"}},"required":["statement"],"type":"object"},"name":"read_cypher"},{"annotations":{"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"readOnlyHint":true,"title":"Get Schema"},"description":"Get the schema of the graph store: node labels with their property keys and inferred types, and the relationship types between them. `sample_size` bounds how many nodes and relationships are examined per label (larger is slower but more accurate; -1 examines all).","inputSchema":{"properties":{"sample_size":{"description":"The sample size used to infer the graph schema. Larger samples are slower, but more accurate. Smaller samples are faster, but might miss information. -1 samples the whole graph.","type":"integer"}},"type":"object"},"name":"get_schema"}]}}
{"jsonrpc":"2.0","id":3,"result":{"content":[{"text":"Only MATCH queries are allowed for read-query","type":"text"}],"isError":true}}
```

The tool list names `read_cypher` and `get_schema` and no `write_cypher`, and the write came back as a tool error with the store unchanged. In the host, the same two tools appear in its server list (`/mcp` in Claude Code, Codex and Gemini CLI).

For the HTTP transport, the same `tools/list` with `curl`:

```bash
curl -s -u <user>:<password> -H 'Content-Type: application/json' -X POST http://127.0.0.1:8000 -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
```

## If it goes wrong

**The host reports the server failed, and its log shows `Error: Failed to open Relate: storage error: database not found: <path>`.** The read-only open never creates a store, and a relative path resolved against a directory you did not expect. Put the store's absolute path in the block, or create the store first.

**The host cannot start `relate` at all.** The host's `PATH` does not include the directory relate is installed in (`~/.local/bin` for `install.sh`), which is common for desktop apps. Put the binary's absolute path in `command`.

**A write fails with `Only MATCH queries are allowed for read-query`, or `unknown tool 'write_cypher'`.** The store is open read-only, as configured. To let the agent write, remove `--read-only`; [Keep an agent safe](https://relatedb.ai/docs/guides/agents/agent-safety/) covers what to put in place first.

**HTTP answers `401 Unauthorized` or `415 Unsupported Media Type`.** A 401 carries `WWW-Authenticate: Basic realm="relate"`: the request has no credential, or the wrong one. A 415 means the `POST` had no `Content-Type`, or a browser-simple one (`text/plain` or a form type).

**`relate serve` exits 2 with an error that begins `Error: serve --mcp stdio skips auth`.** `--auth` applies to the port listeners only. Drop it from a stdio block.

## Related

- [Connect your agent to relate](https://relatedb.ai/docs/get-started/agent-quickstart/): install, rehearse a change, then connect over MCP.
- [Keep an agent safe](https://relatedb.ai/docs/guides/agents/agent-safety/): read-only opens, safe mode, and backups before an agent writes.
- [MCP errors](https://relatedb.ai/docs/reference/errors/#mcp-read-query-only): every MCP refusal and JSON-RPC error code.
- [Run relate in a sandbox](https://relatedb.ai/docs/guides/agents/run-in-a-sandbox/): what to allow when the host runs inside one.
- [CLI reference](https://relatedb.ai/docs/reference/cli/): `relate serve` and its flags.
- [Use relate with the Claude Agent SDK](https://relatedb.ai/docs/guides/integrations/claude-agent-sdk/): the same read-only server, started by the SDK.

## Terms used on this page

- **MCP**: The Model Context Protocol, which agent hosts use to call tools; `relate serve --mcp` exposes a store as `read_cypher`, `get_schema` and `write_cypher`.
- **read-only**: An open mode (`--read-only`) that never writes, checkpoints or migrates the store; writes fail, and a directory store can be read beside its writer.
- **store**: A relate database: a directory, a single `.rl` file, or `:memory:`, opened with `--database`.
