# Connecting AI Clients

> Ready-to-paste setup for Claude Code, Cursor, Claude Desktop and any other MCP client, plus tokens, remote access and verifying an endpoint without an agent.

- Updated: 2026-09-21
- Source: https://contextator.com/en/docs/connecting-ai-clients/
- Language: en-US
- Author: Muhammet Şafak

---
Each project is one URL. Point a client at it and the agent gains three documentation tools — no other
configuration, no API key, no plugin.

```
http://localhost:3444/mcp/<project-name>
```

The dashboard's **Connect an agent** panel prints every snippet below filled in with the real URL, ready
to copy — including the `Authorization` header when the project requires a token. Replace `demo` with
your project name in the examples, and `ctxm_9f3a…` with the token the project page showed you.

---

## Claude Code

A new project requires a token by default, so add the header with your project's token:

```bash
claude mcp add --transport http demo-docs http://localhost:3444/mcp/demo \
  --header "Authorization: Bearer ctxm_9f3a…"
```

If the project's **MCP access** was switched to **open**, the header can be left off:

```bash
claude mcp add --transport http demo-docs http://localhost:3444/mcp/demo
```

Check it worked:

```bash
claude mcp list
```

Then just ask a question about your documentation — Claude Code decides to call `search_docs` on its own,
because the server describes what it holds.

## Cursor

`~/.cursor/mcp.json` for every project, or `.cursor/mcp.json` inside one repository. A new project
requires a token by default:

```json
{
  "mcpServers": {
    "demo-docs": {
      "url": "http://localhost:3444/mcp/demo",
      "headers": { "Authorization": "Bearer ctxm_9f3a…" }
    }
  }
}
```

If the project's **MCP access** was switched to **open**, the `headers` block can be left off:

```json
{
  "mcpServers": {
    "demo-docs": { "url": "http://localhost:3444/mcp/demo" }
  }
}
```

Restart Cursor, then check **Settings → MCP** for a green indicator.

## Claude Desktop

Claude Desktop speaks stdio, so it needs a bridge. A new project requires a token by default, and
`mcp-remote` passes it on with `--header`, in `claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "demo-docs": {
      "command": "npx",
      "args": [
        "-y", "mcp-remote", "http://localhost:3444/mcp/demo",
        "--header", "Authorization: Bearer ctxm_9f3a…"
      ]
    }
  }
}
```

If the project's **MCP access** was switched to **open**, the `--header` argument can be left off:

```json
{
  "mcpServers": {
    "demo-docs": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "http://localhost:3444/mcp/demo"]
    }
  }
}
```

Restart Claude Desktop. The tools appear under the connectors icon.

Config file locations: macOS `~/Library/Application Support/Claude/claude_desktop_config.json`,
Windows `%APPDATA%\Claude\claude_desktop_config.json`.

## Any other MCP client

Give it the URL. Contextator serves **both** MCP transports on the same address and picks by what the
client sends:

- **Streamable HTTP** (current clients): `POST` an `initialize` request; the session id comes back in
  the `mcp-session-id` header.
- **HTTP + SSE** (protocol `2024-11-05`, older clients): `GET` the URL; the server answers with an
  `endpoint` event pointing at `/mcp/demo/messages?sessionId=…`.

No configuration switches between them.

## Projects that require a token

A project whose **MCP access** is **token required** answers every request without a valid token with
`401` and a `www-authenticate: Bearer realm="<project-name>"` header, whichever transport the client
uses. Mint the token on the project page — it is shown once — and send it as an ordinary header:

```
Authorization: Bearer ctxm_9f3a…
```

- The header is checked on **every** `/mcp/*` request. On the legacy SSE transport that means the `GET`
  that opens the stream *and* the `POST`s to `/mcp/demo/messages`, so a client that can set a header on
  only one of the two cannot connect. A browser `EventSource` is the usual case — leave those projects
  open, or put the whole instance behind an authenticating proxy.
- Tokens are per project. A client connected to two token-protected projects needs one for each.
- Revoking a token cuts its client off immediately, mid-session; so does switching a project from
  **open** to **token required**. Reconnecting with a current token is all that is needed.

Where the switch lives and who may flip it: [Projects](/en/docs/projects/).

## Projects that require an account

**account required** is the third mode, and the one where this dashboard's memberships reach `/mcp/*`.
A static `ctxm_…` token names nobody and is refused there; a client has to act as an account that is a
**member** of the project, and that is re-checked on **every** request — removing a membership,
disabling an account or resetting its password cuts the connection off on its next call rather than at
some expiry.

A client gets that credential through **OAuth 2.1**, which is what browser-based MCP connectors already
speak. You configure nothing: point the connector at `http://host:3444/mcp/<project-name>`, and it
discovers this server's authorization endpoints, registers itself, and sends you to a page here to sign
in and approve it. What it gets back acts as *your* account, renews itself quietly, and expires if the
connector goes unused for a month. Changing your password disconnects every connector acting as you.

`MCP_OAUTH=0` removes the flow entirely, and then only static tokens open a closed project — which also
means browser-based connectors cannot connect at all.

## Several projects at once

Add one entry per project. They stay isolated — an agent connected to both simply has two sets of tools,
and a search in one never returns documents from the other.

```json
{
  "mcpServers": {
    "billing-docs": { "url": "http://localhost:3444/mcp/billing" },
    "mobile-docs":  { "url": "http://localhost:3444/mcp/mobile" }
  }
}
```

---

## Connecting from another machine

1. Make sure the server is reachable: `HOST=0.0.0.0` (the default) and the port is open.
2. Use the server's address, not `localhost`: `http://docs.internal:3444/mcp/demo`.
3. Behind a reverse proxy, set `PUBLIC_BASE_URL` so the dashboard prints the right URLs, and disable
   response buffering — see [Installation](/en/docs/installation/).

:::note
**A project can be left open.** While its **MCP access** is **open**, anyone who can reach the port can
read every document indexed in it anonymously — a new project is not, by default, but can be switched
that way from its own page. Require a token or an account on the project page, keep the port on a
private network, or put authentication in front of it — see [Security](/en/docs/security/). A token is
a door of its own, naming nobody; a credential that names an account is checked against that account's
membership in every mode, **open** included.
:::

## Verifying without an agent

A smoke test ships with the repository. From a source checkout:

```bash
npm install
npm run smoke -- http://localhost:3444/mcp/demo "how do I re-index"
npm run smoke -- http://localhost:3444/mcp/demo "kurulum" --sse   # exercise the legacy transport
```

It performs a real MCP handshake, lists the tools and runs a search. It cannot send an `Authorization`
header, so a project that requires a token answers it `401` — check that one with `curl` instead:

```bash
curl -s -i -X POST http://localhost:3444/mcp/demo \
  -H "Authorization: Bearer ctxm_9f3a…" \
  -H 'content-type: application/json' -H 'accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"curl","version":"0"}}}'
```

## If it does not connect

| Symptom | Check |
|---------|-------|
| `Unknown project "…"` | The project name in the URL, exactly as the dashboard shows it |
| The client connects but finds nothing | The project has been indexed — the dashboard shows the document and chunk counts |
| "indexed with another model" | Re-index the project ([Embedding Models](/en/docs/embedding-models/)) |
| Works locally, not from another machine | `HOST`, firewall, and whether you used the machine's address rather than `localhost` |
| A browser-based client is refused | Add its origin to `ALLOWED_ORIGINS` |
| `401 This project requires an MCP token` | The project is in **token required** mode and the client is sending no `Authorization` header |
| `401 This project requires an account-backed credential` | The project is in **account required** mode and the client is sending a static `ctxm_…` token, which names nobody |
| `403 That account is not a member of this project` | The connector signed in as an account that is not a member of the project. This is checked in **every** mode, **open** included |
| A browser-based connector cannot connect at all | `MCP_OAUTH=0` on this instance, so there is no flow for it to use |
| `401 Unknown or revoked MCP token` | The token was revoked, or belongs to another project. Mint a fresh one on the project page |

More in [Troubleshooting](/en/docs/troubleshooting/).
