# Connect a client

Any MCP client that speaks Streamable HTTP can connect. You need the endpoint and a credential. There is nothing to install and no per-client configuration on Archive’s side.

```http
POST https://app.archive.com/api/v2/mcp
```

## Option 1: Bearer token

This is the simplest option, and the right one for a server-side agent that you run yourself. Create an API token in the Archive app’s **Integration tab** — the same token that works against `/api/v2` — and send it in the `Authorization` header.

```json
{
"mcpServers": {
  "archive": {
    "type": "http",
    "url": "https://app.archive.com/api/v2/mcp",
    "headers": {
      "Authorization": "Bearer <your-token>"
    }
  }
}
}
```

Most clients accept this shape; check yours for the exact key names. If your client can’t send a static header, use OAuth instead.

> **A bearer token is a server-side secret**
>
> The token can read every piece of captured content and every creator contact detail in the workspaces it can access, and it is write-capable. Keep it in a secret store — never in a browser, a mobile bundle, or a desktop client you don’t control.

## Option 2: OAuth 2.1

Use OAuth for a client used by other people, where each person authorizes their own access. Archive is its own authorization server, and the whole flow is discoverable: a compliant client needs only the endpoint URL.

1. The client calls the endpoint without credentials and gets HTTP 401 with a `WWW-Authenticate` challenge naming the protected-resource metadata URL.
2. It fetches that metadata ([RFC 9728](https://www.rfc-editor.org/rfc/rfc9728)), then the authorization-server metadata ([RFC 8414](https://www.rfc-editor.org/rfc/rfc8414)).
3. It registers itself if needed via Dynamic Client Registration ([RFC 7591](https://www.rfc-editor.org/rfc/rfc7591)) at `POST /oauth/register`.
4. It sends the person to `/oauth/authorize`. They log in and consent, choosing whether to grant the optional **write** scope.
5. It exchanges the authorization code at `/oauth/token` for an access token and uses that as the bearer credential.

Tokens are opaque and Archive-issued; there is nothing for the client to decode.

> **Write access is granted at consent time**
>
> Without the write scope, an OAuth connection sees only the read tools. `tools/list` omits the write half entirely rather than advertising tools that would fail. A bearer token is always write-capable.

## Verify the connection

Call `getWorkspaces` first to verify the connection. It doesn’t require a workspace, so it succeeds as soon as the credential is valid, and it returns the workspace IDs that every other tool needs.

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

If it returns HTTP 401, the credential is the problem. If it returns HTTP 200 with `isError: true`, the credential is valid but something about the request is not; read the message.

## What `tools/list` returns

`tools/list` advertises only the tools your credential can actually call. Two things narrow the list:

- **Write capability.** An OAuth connection without the write scope sees read tools only.
- **Alpha gating.** Tools behind an alpha feature are omitted unless the request opts in via the `X-Archive-Alpha-Features` header, and calling one without opting in returns the same response as calling a tool that doesn’t exist. See [Alpha features](/api/v2/docs/guides/alpha-features).

If your `tools/list` output is missing tools that are documented here, your credential isn’t authorized for them.

## Selecting a workspace

Most tools act on one workspace. Pass it explicitly as `workspaceId` on the call — a workspace UUID or the numeric ID from the app — or send a `WORKSPACE-ID` header. If your credential can access exactly one workspace, you can omit both.

```json
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
  "name": "searchItems",
  "arguments": {
    "workspaceId": "6ccefa76-e8ba-5ab0-9c60-e48a9e235a4a",
    "limit": 20
  }
}
}
```

## Protocol version

The server supports the `2025-03-26` and `2025-06-18` Streamable HTTP revisions. Two separate mechanisms carry a protocol version, and they behave differently.

**`initialize` negotiation (the `protocolVersion` parameter).** The server echoes back the version it will speak:

| You send               | Server responds with                                                    |
| ---------------------- | ----------------------------------------------------------------------- |
| A supported version    | That same version                                                       |
| An unsupported version | The newest version it supports (`2025-06-18`) — it does not fail        |
| Nothing                | The oldest supported version (`2025-03-26`), the most compatible choice |

Read the `protocolVersion` in the `initialize` result and speak that version, rather than assuming your request was honored.

**The `MCP-Protocol-Version` HTTP header.** This is recorded but not validated. An unrecognized value is accepted rather than rejected, and a request that omits the header is treated as `2025-03-26` per the transport spec’s backwards-compatibility clause.

> **The header is not validated**
>
> The MCP transport spec says a server should answer an unsupported `MCP-Protocol-Version` with `400 Bad Request`. Archive doesn’t do that today; the header never changes how a request is handled. Negotiate through `initialize` and trust its response; treat the header as advisory.
