# Connect your agent

> Connect an MCP client with OAuth, a script with an API token, or a terminal with ce login.

Checkend has no AI inside. You bring the agent. The agent reads data and records changes through MCP, the `ce` CLI or the REST API. All three give the same numbers.

| Way | For | How |
|---|---|---|
| MCP with OAuth | Interactive MCP clients, for example Claude Code or Cursor | Give the client the URL `<public URL>/mcp`. A person approves the access in the browser. |
| MCP with an API token | Scripts, scheduled agents, CI | Send the header `Authorization: Bearer ce_...`. |
| `ce mcp` | MCP clients that support only stdio | `ce` runs a local stdio MCP server and sends each call to the server. |
| `ce` CLI | Coding agents in a terminal, people, CI | `ce login`, or the variables `CHECKEND_URL` and `CHECKEND_TOKEN`. |

## MCP with OAuth

The MCP server is at `<public URL>/mcp`, for example `https://stats.example.com/mcp`. It uses Streamable HTTP.

1. Give the URL to your MCP client. For Claude Code:

   ```sh
   claude mcp add --transport http checkend https://stats.example.com/mcp
   ```

2. The client opens the consent page of Checkend in your browser.
3. Sign in with your passkey, if you are not signed in.
4. Read the page. It shows the app name, your email address and role, and the host where the browser goes back to.
5. Select the access for the app.
6. Select **Approve**.

The client then gets an access token for one hour and a refresh token. It renews the access token by itself.

### The access

The consent page shows only the access of your role:

| Choice | Scope |
|---|---|
| Read only | `read:*` |
| Read and write | `write:*` |
| Admin | `admin` |

The page selects **Read only** (`read:*`) first, also when the app asks for more. You can select more access, up to the access of your role. An Admin can give an app the `admin` scope, but only with a deliberate choice.

> **Caution**
> Give an agent read-only access, unless it must write. Write access lets it claim findings, record changes and change goals.

> **Caution**
> Approve only a connection that you started. The app gives its name itself, and any program on your computer can listen on a localhost redirect URI.

> **Caution**
> Set `--public-url` on the server to the URL that MCP clients use. The OAuth metadata comes from it, and a client refuses metadata with another issuer.

The access token belongs to you. It shows in your token list with the app name and "(MCP)". It works only at `/mcp`: the REST API refuses it. To end the access, revoke the token in **Settings**, or with `ce tokens revoke <id>`.

## MCP with an API token

Scripts and scheduled agents cannot open a browser. Give them an API token.

1. Make a read-only token:

   ```sh
   ce tokens create --name "weekly agent" --scope 'read:*'
   ```

   Or make the token in **Settings → API tokens**. Checkend shows the secret one time.

2. Give the token to the client as a bearer token. For Claude Code:

   ```sh
   claude mcp add --transport http checkend https://stats.example.com/mcp \
     --header "Authorization: Bearer $CHECKEND_TOKEN"
   ```

An API token works at `/mcp` and at the REST API. For the scopes, see [Roles and tokens](/docs/concepts/roles-and-tokens.md).

## ce mcp: a stdio bridge

Some MCP clients support only stdio. For them, run `ce mcp`. It connects to `<url>/mcp` with the token of the current `ce` context, or with `CHECKEND_URL` and `CHECKEND_TOKEN`. It gives the same tools and prompts as the server. Each call goes to the server, so the scope checks and the audit log are the same.

Example client configuration:

```json
{
  "mcpServers": {
    "checkend": {
      "command": "ce",
      "args": ["mcp"],
      "env": {
        "CHECKEND_URL": "https://stats.example.com",
        "CHECKEND_TOKEN": "ce_..."
      }
    }
  }
}
```

`ce mcp` writes its logs to stderr. It stops at the end of stdin.

## ce login

`ce login` connects the `ce` CLI to a server. It uses the device flow in the browser.

1. Run the command:

   ```sh
   ce login https://stats.example.com
   ```

2. `ce` prints a URL and a code, for example `BCDF-GHJK`, and opens the browser.
3. Sign in with your passkey.
4. Check that the page shows the same code as the terminal.
5. Select the access, then select **Approve**.
6. Go back to the terminal.

The token belongs to you. It has the scopes of your role, or the scopes that you ask for with `--scope`. It never has more than your role. It has no expiry.

| Flag | Meaning |
|---|---|
| `--scope 'read:*'` | Ask for this scope. Repeat the flag for more scopes. |
| `--no-browser` | Do not open the browser. Open the URL yourself. |
| `--device` | Start the device flow without a read of stdin. Use it in an agent. |
| `--name <context>` | The name of the context. The default is the server host. |

On a pipe, `ce` writes the URL and the code as one JSON line on stderr. An agent can show them to a person.

### Paste a token

You can also log in with an existing API token:

```sh
echo "$TOKEN" | ce login https://stats.example.com
```

Or use `--token-stdin` for a hidden prompt on a terminal:

```sh
ce login https://stats.example.com --token-stdin
```

## Contexts

Each `ce login` makes a *context*: a server URL and a token. Use contexts for many servers.

```sh
ce context list          # each context, its URL and its token store
ce context use work      # select the current context
ce logout work           # remove the context and its token
```

`ce` has no default server. Without a context or `CHECKEND_URL`, it exits with code 2 and tells you to run `ce login <url>`.

## Where ce keeps the token

`ce` stores the token in the OS keychain: the macOS Keychain, the Secret Service on Linux, or the Windows Credential Manager.

When no keychain works, for example on a server without a desktop session or in CI, `ce` uses the credentials file `~/.config/checkend/credentials`. With `XDG_CONFIG_HOME` set, the file is under that folder. The file has mode 0600. `ce` tells you which store it used.

To use only the credentials file, set `CHECKEND_KEYRING=file`.

> **Caution**
> Keep the credentials file at mode 0600. It holds the tokens in clear. `ce` refuses to read the file when its mode is wider.

## CI and agents without login

Set two environment variables. `ce` then needs no context and no keychain:

```sh
CHECKEND_URL=https://stats.example.com CHECKEND_TOKEN=ce_... ce brief example.com
```

On a pipe, `ce` prints one JSON value on stdout. An error is one JSON object on stderr, with the fields `error`, `message` and `next`. See [Troubleshooting](/docs/guides/troubleshooting.md) for the exit codes.

## What the agent can do

The MCP server gives tools for each part of the product, for example `get_brief`, `query`, `get_findings`, `update_finding` and `annotate`. It also gives three prompts: `weekly_seo_review`, `investigate_traffic_drop` and `launch_check`. See the [MCP tools reference](/docs/reference/mcp-tools.md).

A good first call is `get_brief`. It gives the top changes, the open findings, the recent changes and the outcomes of earlier changes. See [The closed loop](/docs/concepts/closed-loop.md).

## Prompt for a coding agent

```text
Connect this coding agent to my Checkend server over MCP.
1. Ask me for the URL of the Checkend server, for example https://stats.example.com.
2. Add the MCP server `<url>/mcp` with the HTTP transport to your MCP configuration. In Claude Code: `claude mcp add --transport http checkend <url>/mcp`.
3. Tell me to approve the access in the browser. Ask for read-only access, unless I say otherwise.
4. Call the `list_sites` tool and show me the sites.
If your client supports only stdio, use the command `ce mcp` as the MCP server.
```
