---
title: Connect an agent
description: Give an MCP client access to Hollware with a personal token or with OAuth, and choose what it may do.
section: start
order: 3
---

# Connect an agent

Any MCP client can write to Hollware. It connects to `/mcp` of your Hollware, over HTTP, in one of two ways.

## With a personal token

A personal token is a bearer token that starts with `hw_pat_`. `hollware init` makes the first one; make more with the CLI or in the admin, under Tokens:

```sh
npx hollware token create --label claude-code --scopes content:read,content:write
```

A token carries **scopes**, and never more than the role of the person who made it:

| Scope             | Lets the agent                                     |
| ----------------- | -------------------------------------------------- |
| `content:read`    | read entries, drafts included, and the site        |
| `content:write`   | create and update drafts                           |
| `content:publish` | publish, unpublish, and approve reviews            |
| `schema:admin`    | change the structure of the site, and the admin's own routes |

Give the token to the client as the `Authorization` header:

```sh
claude mcp add --transport http hollware https://cms.example.com/mcp --header "Authorization: Bearer hw_pat_..."
```

`npx hollware mcp-config --url https://cms.example.com` prints that line, and `--client cursor`, `--client vscode` or `--client json` the block of `.mcp.json` for any other client; both name an environment variable, `HOLLWARE_TOKEN`, instead of the token.

::callout{type="tip"}
An agent without `content:publish` can still call `publish`: the entry waits in the review queue of the admin until an editor approves it.
::

## With OAuth

Clients that speak OAuth, such as claude.ai connectors, need no token. Give them the URL of `/mcp`; the first time, Hollware sends you to sign in with your passkey and asks what the client may do. You choose the scopes, and the site when you are a member of several.

A client either has a Client ID Metadata Document, which Hollware fetches over the public internet, or registers itself. Self-registration is off unless your config turns it on:

```ts
export default defineConfig({
  auth: { dynamicClientRegistration: true },
  sites: { ... },
})
```

## What the agent sees

Forty tools, the same for every client, whatever it may do: a tool checks the scopes when it runs, and a call without them gets a 403 that names what is missing. The [tools reference](/reference/mcp-tools/) lists them with their input.

One prompt, `refresh_content`, walks an agent from what readers read to an updated entry: `content_stats`, `get_entry`, `search`, `update_draft` and `publish`, in that order. Pick it from your client's prompt menu. It needs the site's [analytics](/docs/search-and-analytics/) connected to know what readers read.

An agent with `schema:admin` shapes the site too: `get_structure`, `update_site`, `set_collection`, `create_site` and the others of [Configure your content](/docs/configure-your-content/).

An agent that should never publish, whatever its token holds, sends its work to a person with `request_review` instead of `publish`, and comments on a review with `comment_review`: that is how Hollware's own [agents](/docs/agents/) work.

## Without an MCP client

`/mcp` is plain JSON-RPC over HTTP, so `curl` reaches it too. No session is needed: each request stands alone.

```sh
curl http://localhost:5199/mcp \
  -H "Authorization: Bearer hw_pat_..." \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"describe_site","arguments":{}}}'
```

The answer may come as a server-sent event (`event: message`, then `data: {...}`). The tool's output is in `result.structuredContent`, and again as text in `result.content`.

Every write moves the entry's `version` up. `update_draft` and `publish` take the version you last read, and answer with the new one: after `create_draft` returns version 1, `publish` with version 1 answers version 2.

The first call of a good agent is `describe_site`: it returns your collections, their schemas as JSON Schema, their routes, their components with examples, and your style guides.
