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

# MCP server

> Connect agents without a shell, such as chat apps, agent frameworks and automation platforms, to your content with a project API key.

Nohead has an [MCP](https://modelcontextprotocol.io) server for agents that can't run the CLI: chat apps, agent frameworks in your own product, and automation platforms. It offers the content work as tools, and it is another client of the same API. Every tool call is one API request made with your key, so scopes, rate limits, usage and history work exactly as they do over HTTP.

Coding agents and CI jobs with a shell are usually better served by the `nohead` CLI. Its `--json` output and exit codes cost an agent less context than a list of tools.

## Connect

The server speaks Streamable HTTP at `https://mcp.nohead.io/mcp`. Authenticate with a project API key as the bearer token. Give the agent a key of its own, with only the scopes it needs, so its changes are attributed to it in history. New keys are published-only by default: an agent that changes content needs a key with **Published records only** off and `schema:read`, `records:read` and `records:write`, plus `search:read` to search, and `assets:read` and `assets:write` for images and files. The server offers only the tools a key's scopes allow, and an agent starts by reading the schema.

Codex and Cursor read the key from the `NOHEAD_API_KEY` environment variable, and VS Code asks for it once and stores it, so none of their config files holds the key itself, and a project's `.cursor/mcp.json` or `.vscode/mcp.json` can be committed. Claude Code saves the key in its own settings, outside the project, when you run its command: run it with `NOHEAD_API_KEY` set.

```bash Claude Code theme={null}
claude mcp add --transport http nohead https://mcp.nohead.io/mcp \
  --header "Authorization: Bearer $NOHEAD_API_KEY"
```

```toml Codex theme={null}
[mcp_servers.nohead]
url = "https://mcp.nohead.io/mcp"
bearer_token_env_var = "NOHEAD_API_KEY"
```

```json Cursor theme={null}
{
  "mcpServers": {
    "nohead": {
      "url": "https://mcp.nohead.io/mcp",
      "headers": { "Authorization": "Bearer ${env:NOHEAD_API_KEY}" }
    }
  }
}
```

```json Copilot theme={null}
{
  "inputs": [
    {
      "id": "nohead-key",
      "type": "promptString",
      "description": "Nohead API key",
      "password": true
    }
  ],
  "servers": {
    "nohead": {
      "type": "http",
      "url": "https://mcp.nohead.io/mcp",
      "headers": { "Authorization": "Bearer ${input:nohead-key}" }
    }
  }
}
```

Codex reads `~/.codex/config.toml`. Cursor reads `.cursor/mcp.json` in the project, or `~/.cursor/mcp.json` for every project; it doesn't load an env file for remote servers, so set `NOHEAD_API_KEY` in your shell profile. Copilot in VS Code reads `.vscode/mcp.json` in the workspace.

Other clients name these fields differently (some want `"type": "http"`, some take the header as a separate setting): check your client's documentation for remote servers, and send the key as `Authorization: Bearer <key>`.

Chat apps that only connect through a sign-in (OAuth), such as Claude.ai connectors, aren't supported.

## Tools

| Tool | What it does | Scope |
| - | - | - |
| `list_collections` | The project's collections | `schema:read` |
| `get_schema` | A collection's fields, types and validation | `schema:read` |
| `search` | Full-text search across the project | `search:read` |
| `search_collection` | Search one collection, with filters and sorting | `search:read` |
| `list_records` | A collection's records, with filters, sorting and pages | `records:read` |
| `get_record` | One record, with its current revision | `records:read` |
| `create_record` | A new record, unpublished | `records:write` |
| `update_record` | Change some of a record's field values | `records:write` |
| `list_drafts` | A collection's drafts: changes waiting for review | `records:read` |
| `get_draft` | A draft: the record as it reads once merged, and the fields it changes | `records:read` |
| `create_draft` | Propose changes to a record, for a person to merge | `records:write` |
| `update_draft` | Change some of a draft's values | `records:write` |
| `discard_draft` | Discard a draft; the record is unchanged | `records:write` |
| `publish_record` | Publish a record's current revision | `records:write` |
| `unpublish_record` | Take a record off sites and apps | `records:write` |
| `schedule_record` | Publish or unpublish a record at a set time | `records:write` |
| `get_schedule` | When a record publishes or unpublishes on its own | `records:read` |
| `unschedule_record` | Cancel a record's schedule | `records:write` |
| `list_revisions` | A record's history | `records:read` |
| `diff_record` | What changed between two revisions | `records:read` |
| `revert_record` | Make an earlier revision current again (with `dry_run`) | `records:write` |
| `restore_record` | Bring back a deleted record | `records:write` |
| `list_assets` | The project's images and files, with search and filters | `assets:read` |
| `get_asset` | One asset, with its URLs | `assets:read` |
| `update_asset` | Set an asset's alt text or filename | `assets:write` |
| `delete_asset` | Delete an asset, restorable for 30 days | `assets:write` |
| `start_upload` | Step 1 of an upload: where to send the file | `assets:write` |
| `complete_upload` | Step 2 of an upload: make the asset ready | `assets:write` |

An agent sees only the tools its key's scopes allow, and a published-only key reads published records only: its `list_revisions` and `diff_record` calls are refused (`403`), since history can hold unpublished content, and so are its `get_schedule` calls. Each tool's arguments carry the API reference's own descriptions. Schema changes aren't tools: make those as reviewed schema files with the CLI (`nohead schema pull`, `diff` and `push`).

`schedule_record` ([Schedule publishing](https://docs.nohead.io/guides/publishing.md#schedule-publishing)) takes `publish_at`, `unpublish_at` or both, as ISO 8601 times with a zone such as `2026-11-06T09:00:00Z`, and replaces the whole schedule: a time left out is cleared, so an agent adding an unpublish time passes the publish time again. A publish time needs an unpublished record, and an unpublish time a published one or a publish time before it. The change is made within a minute of its time, as its own revision; one that can't be made then (the record is live with a pending draft, say) is dropped, and `get_schedule` gives the reason in `last_error`. Scheduling makes no revision, so these tools take no `note` or `expected_revision`, and a schedule change can't be reverted: the last write wins, so read the schedule with `get_schedule` just before replacing it. Schedule changes are in the [activity log](https://docs.nohead.io/guides/history.md#activity-log).

Agents read and write rich text as Markdown: tools that return records, `diff_record` and `revert_record` (its changes too, with `dry_run`) give rich text fields as Markdown unless the agent asks for `rich_text: "html"` or `"document"`, and `create_record`, `update_record`, `create_draft` and `update_draft` take Markdown ([Rich text](https://docs.nohead.io/guides/content-modelling.md#rich-text)).

## Images and files

With `assets:read` and `assets:write`, an agent can find a project's [assets](https://docs.nohead.io/guides/assets.md), fix missing alt text, and upload an image to put on a record. Asset tools take no `note` or `expected_revision`, since assets have no history.

An upload takes [the same three requests as over HTTP](https://docs.nohead.io/guides/assets.md#over-http): two tools, with the agent sending the file itself in between.

1. `start_upload` with the file's `filename`, `content_type` and exact `byte_size`. It returns the pending asset and its `upload`: a `method`, `url` and `headers`, and when it `expires_at`. A file larger than your plan allows, or on Free one that would go over the organization's storage, is refused with `402 plan_limit_exceeded`.
2. The agent sends the file's bytes to `upload.url` with `upload.method` and every header in `upload.headers`, before `upload.expires_at`: for example `curl -X PUT "$UPLOAD_URL" -H "Content-Type: image/png" --data-binary @cover.png`. The bytes go straight to storage, not through the MCP server.
3. `complete_upload` checks the file and marks the asset `ready`.

The second step needs an agent that can make HTTP requests, such as a coding agent with a shell: an agent with only the MCP server's tools can't upload this way.

A ready asset's `id` (`ast_…`) is then the value of an asset field, set with `update_record` (`"data": {"cover": "ast_…"}`, or a list of IDs with **multiple** on), or an image in rich text, `![alt](ast_…)`. `get_schema` shows which fields are asset fields and the types they accept.

## Guardrails

The tools add guardrails for agents:

* **A note on every change to a record.** Each one takes a required `note` saying why, up to 500 characters. It is stored in the record's history next to the key's name and the client, **MCP**.
* **No overwriting.** Changes to an existing record take the `expected_revision` the agent read, and the server's instructions ask agents to pass it. If someone changed the record since, the change is refused with `precondition_failed`, and the agent should read it again. Without it, the last write wins.
* **Safe retries.** Every write takes an optional `idempotency_key`. Retrying with the same key never applies a change twice.
* **Review before it goes live.** A change to a published record shows on your sites at once, so the server's instructions ask agents to propose it as a draft instead, unless you asked for a direct edit. The draft waits until a person merges it in the editor (**Publish changes**) or with `nohead drafts merge`: no tool merges or schedules a draft. A record has at most one draft, and `create_draft` on a record that has one is refused with `draft_exists` and its `draft_id`, so the agent changes that one with `update_draft`, passing the draft's `revision` as `expected_revision`.
* **Nothing irreversible.** Every record change is a revision you can revert, and `revert_record` previews with `dry_run: true`. New records start unpublished.

Errors come back as tool errors with the API's error envelope, so an agent sees the same `type`, `message` and `details` (each with its `code`) the [API reference](https://docs.nohead.io/api-reference/overview.md) documents.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.