---
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`    | everything the admin's own routes do               |

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_..."
```

::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

Twelve 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.

## 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.
