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

# Connect an AI agent

> Let Claude Code, Claude Desktop, Cursor, Codex, or another MCP client set up Observer for you. You approve one link; the agent receives a scoped API key and connects to the MCP server.

An AI agent can connect itself to Observer. The agent asks for a connection,
you open one link to sign in and approve it, and the agent receives an API key
for the [MCP server](/docs/mcp/index). From there it can create status pages,
services, metrics, and SLOs, create the Observer Agent that runs your checks
and give you the command to install it, and read the status of everything it
set up.

You never paste a password into the agent, and the agent never sees your
login. The only credential it receives is a scoped `obs_pub_` key that you can
revoke at any time.

## One-prompt setup

Paste this into Claude Code, Cursor, Codex, or any agent that can make HTTP
requests:

```text theme={null}
Set up Observer for me. Instructions: https://use.observer/llms.txt
```

The agent reads the setup section of `llms.txt` and then:

<Steps>
  <Step title="Starts a connect request">
    The agent calls `POST https://use.observer/api/connect/device` and shows you a
    short code such as `WDJB-MJHT` and a link to `https://use.observer/connect`.
  </Step>

  <Step title="You approve in the browser">
    Open the link. If you have no account, you sign up first; if you have no
    organization, one is created for you (from your company email domain, or from
    a name you confirm). Check that the request code on the page matches the code
    the agent showed you, then select **Approve**.
  </Step>

  <Step title="The agent receives its key">
    The agent, which has been waiting in the background, receives the API key and
    adds the Observer MCP server to its configuration. You can return to the agent
    and tell it what to set up.
  </Step>
</Steps>

A connect request lasts 10 minutes and works once. If it expires, ask the
agent to start again; it gets a new code and link.

## What the agent does next

Once connected, the agent sets Observer up in this order:

1. **Checks what the key allows.** It calls `getMe`, which returns the key's
   scopes, your plan (and when a Starter trial ends), how many agents,
   metrics, services, SLOs, and status pages the plan allows and how many are
   used, and the API rate limits.
2. **Creates the Observer Agent, if your checks need one.** Metrics other than
   heartbeats and manual metrics run on an [Observer Agent](/agent/overview)
   inside your network. The agent looks for an existing one by name first and
   reuses it. Otherwise it creates one with `createAgent`, which returns the
   agent key once, together with install commands that already contain it
   (`docker run`, Docker Compose, Kubernetes, systemd, and binary) and the
   environment variables. The agent shows you the command for your
   environment for you to run. Observer stores only a hash of the key, so if
   the command is lost, the agent rotates the key to get a new one.
3. **Waits for the Observer Agent to come online.** It polls `getAgent`
   until the status changes from `never_connected` to `online`, which takes
   about a minute after the install starts.
4. **Plans, then applies the configuration.** It builds a config document
   whose metrics name the Observer Agent, runs `applyConfig` as a dry run,
   reads the diff, and then applies it. Apply rejects a metric that names an
   agent that does not exist.
5. **Shares the result and checks it.** It reads `public_url` from
   `listPages` and gives you the address of your status page. For a metric
   that has no data, it reads `reason`, `reason_label`, and `reason_hint`
   from `getMetric`, which usually point at an environment variable or a
   network setting to fix on the host where the Observer Agent runs.

To remove something it created, the agent deletes that one object by its
config key (`deleteMetric`, `deleteService`, `deleteSlo`, or `deletePage`).

## What you approve

The approval page shows:

* **Organization**: the organization the key belongs to. If you are a member
  of several, you choose one first, and you can change it before approving.
* **Requested by**: the client the agent declared (Claude Code, Claude Desktop,
  Cursor, Codex, or AI agent).
* **Request code**: the code to compare with the one the agent shows. Only
  approve when they match.
* **Access**: the scopes the key receives (see below).
* **Plan**: your current plan, or the trial that approval starts.

Only an **owner** of the organization can approve, because approving creates
an API key. A member who is not an owner sees a page asking them to send the
link to an owner.

Select **Decline** to refuse the request. The agent is told the request was
declined and receives nothing.

## Access preset

Every key created through this flow has the same fixed set of scopes,
labelled **Set up and manage your status pages**:

| Scope | Grants |
| - | - |
| `read:config` | Export your configuration and read your status pages. |
| `write:config` | Create, update, and delete status pages, services, metrics, and SLOs. |
| `read:agents` | Read Observer Agents and whether they are online. |
| `write:agents` | Create Observer Agents, issue new agent keys, and delete agents. |
| `read:services` | Read services. |
| `read:metrics` | Read metrics and their status. |
| `read:slos` | Read SLOs and error budgets. |
| `read:incidents` | Read incidents. |

`write:agents` lets the agent create Observer Agent keys. An agent key lets a
host send data for your organization, so the agent hands it to you in the
install command and does not keep it.

The preset does not include incident or maintenance writes, manual metric
status writes, change events, or SLA statements. Those act on your public
page or your customers, so they are left out on purpose. If you want an
agent to open incidents or schedule maintenance, create a separate key with
those scopes under **Settings** > **API keys**. See
[Authentication](/api/getting-started/auth) for the full scope list.

The key is named after the client, for example `Claude Code (agent connect)`,
so you can find it later in the key list.

## Starter trial

The MCP server runs on the public API, which is included from the Starter
plan. When an organization on Free approves an agent connection, approval
starts a **14-day Starter trial**:

* One trial per organization, ever.
* No card is needed.
* When the trial ends, the organization is back on Free. Nothing is deleted:
  your pages, metrics, and settings stay. API keys stop working until you
  upgrade, and new resources over the Free limits cannot be created.

If the organization has already used its trial and is on Free, the approval
page asks you to upgrade instead. Organizations on a paid plan connect without
a trial.

## Manual setup

If your agent cannot make HTTP requests, or you prefer to paste the key
yourself, open `/connect` directly with your client in the query string:

```text theme={null}
https://use.observer/connect?client=claude-code
```

Accepted `client` values are `claude-code`, `claude-desktop`, `cursor`,
`codex`, and `other`. Sign in, choose the organization, and approve. The page
shows the key **once**, together with a ready-made MCP configuration for that
client:

<Tabs>
  <Tab title="Claude Code">
    ```bash theme={null}
    claude mcp add --transport http observer https://mcp.use.observer/mcp \
      --header "Authorization: Bearer obs_pub_YOUR_KEY"
    ```
  </Tab>

  <Tab title="Claude Desktop">
    Add to `claude_desktop_config.json`, then restart Claude Desktop:

    ```json theme={null}
    {
      "mcpServers": {
        "observer": {
          "command": "npx",
          "args": ["mcp-remote", "https://mcp.use.observer/mcp", "--header", "Authorization: Bearer obs_pub_YOUR_KEY"]
        }
      }
    }
    ```
  </Tab>

  <Tab title="Cursor">
    Add to `~/.cursor/mcp.json`, or `.cursor/mcp.json` in a project:

    ```json theme={null}
    {
      "mcpServers": {
        "observer": {
          "url": "https://mcp.use.observer/mcp",
          "headers": { "Authorization": "Bearer obs_pub_YOUR_KEY" }
        }
      }
    }
    ```
  </Tab>

  <Tab title="Codex">
    Add to `~/.codex/config.toml`:

    ```toml theme={null}
    [mcp_servers.observer]
    url = "https://mcp.use.observer/mcp"
    bearer_token = "obs_pub_YOUR_KEY"
    ```
  </Tab>
</Tabs>

Copy the key before you leave the page. Observer stores only a hash of it and
cannot show it again. When you approve a request that came from an agent, the
same page also shows the key and configuration, in case you want to set up
another client by hand.

## Device flow API

This section is for authors of agents and tools that want to implement the
connect flow. It follows the shape of the OAuth 2.0 Device Authorization Grant
([RFC 8628](https://www.rfc-editor.org/rfc/rfc8628)), without client
registration. Neither endpoint needs authentication.

### Start a request

```bash theme={null}
curl -X POST https://use.observer/api/connect/device \
  -H "Content-Type: application/json" \
  -d '{"client": "claude-code"}'
```

The body is optional. `client` is one of `claude-code`, `claude-desktop`,
`cursor`, `codex`, or `other`; any other value is treated as `other`. It sets
the client name shown on the approval page and the MCP configuration offered
there.

```json theme={null}
{
  "device_code": "obs_dc_...",
  "user_code": "WDJB-MJHT",
  "verification_uri": "https://use.observer/connect?code=WDJB-MJHT&client=claude-code",
  "verification_uri_complete": "https://use.observer/connect?code=WDJB-MJHT&client=claude-code",
  "expires_in": 600,
  "interval": 5
}
```

| Field | Meaning |
| - | - |
| `device_code` | Secret that identifies the request. Keep it in the agent; never show it to the person or log it. |
| `user_code` | Code the person compares on the approval page. Show it to them. |
| `verification_uri` | Link the person opens. It already carries the code. |
| `verification_uri_complete` | Same link as `verification_uri`. |
| `expires_in` | Seconds until the request expires (600). |
| `interval` | Minimum seconds between token polls (5). |

Starting requests is rate limited per IP address (10 per 10 minutes). Over the
limit, the endpoint answers `429` with a `Retry-After` header.

### Poll for the key

Show the person `user_code` and `verification_uri_complete` (or open the link
in their browser), then poll the token endpoint every `interval` seconds:

```bash theme={null}
curl -X POST https://use.observer/api/connect/device/token \
  -H "Content-Type: application/json" \
  -d '{"device_code": "obs_dc_..."}'
```

The endpoint also accepts `application/x-www-form-urlencoded` with a
`device_code` field.

While the request is not finished, the answer is HTTP `400` with an `error`
and an `error_description`:

| `error` | Meaning | What to do |
| - | - | - |
| `authorization_pending` | The person has not approved yet. | Wait `interval` seconds and poll again. |
| `slow_down` | You polled sooner than the interval allows. The response includes a new `interval`. | Use the returned `interval` (5 seconds longer each time, up to 60) for every later poll. |
| `access_denied` | The person declined. | Stop polling. |
| `expired_token` | The request expired, was already delivered, or the device code is unknown. | Stop polling. Start a new request if the person still wants to connect. |

When the person approves, the next poll returns HTTP `200`:

```json theme={null}
{
  "api_key": "obs_pub_...",
  "token_type": "Bearer",
  "org": "acme",
  "mcp_url": "https://mcp.use.observer/mcp",
  "scopes": ["read:config", "write:config", "read:agents", "write:agents", "read:services", "read:metrics", "read:slos", "read:incidents"]
}
```

The key is delivered **exactly once**. Observer removes its copy in the same
step, so any later poll with the same `device_code` returns `expired_token`.
Store the key before doing anything else.

Polling is also rate limited per IP address (120 per minute), which leaves
room for several agents behind one address.

### Configure the MCP server

Add the server at `mcp_url` with the header
`Authorization: Bearer <api_key>`. The configurations under
[Manual setup](#manual-setup) show the shape for each client. Then confirm
the connection by calling `getMe` (`GET /api/v1/me`), which needs no scope
and returns the key's scopes, plan, quotas, and rate limits.

Follow the order in [What the agent does next](#what-the-agent-does-next).
The public [skills repository](https://github.com/useobserver/skills)
describes the same setup loop in more detail.

### Example polling loop

```bash theme={null}
START=$(curl -s -X POST https://use.observer/api/connect/device \
  -H "Content-Type: application/json" -d '{"client": "other"}')
DEVICE_CODE=$(echo "$START" | jq -r .device_code)
INTERVAL=$(echo "$START" | jq -r .interval)
echo "Open $(echo "$START" | jq -r .verification_uri_complete)"
echo "Code: $(echo "$START" | jq -r .user_code)"

while true; do
  sleep "$INTERVAL"
  RES=$(curl -s -X POST https://use.observer/api/connect/device/token \
    -H "Content-Type: application/json" -d "{\"device_code\": \"$DEVICE_CODE\"}")
  ERR=$(echo "$RES" | jq -r '.error // empty')
  case "$ERR" in
    "") echo "$RES" | jq -r .api_key; break ;;
    authorization_pending) ;;
    slow_down) INTERVAL=$(echo "$RES" | jq -r .interval) ;;
    *) echo "Stopped: $ERR"; exit 1 ;;
  esac
done
```

## Revoke the key

Open **Settings** > **API keys** in the console, find the key named after the
client (for example `Claude Code (agent connect)`), and revoke it. The agent's
next call through the MCP server fails, and the key cannot be restored. To
connect again, run the connect flow again; it creates a new key.

## Troubleshooting

* **"This request has expired"**: the link is older than 10 minutes or was
  already used. Ask the agent to start again.
* **"Ask an owner to connect"**: you are a member but not an owner of the
  organization. Send the link to an owner, or ask an owner to create a key for
  you.
* **"API access needs Starter"**: the organization is on Free and has already
  used its trial. Upgrade the plan to connect.
* **A tool call fails with a scope message**: the tool needs a scope outside
  the preset. Create a key with that scope under **Settings** > **API keys**.
  Keys created before the preset included `read:agents` and `write:agents`
  cannot manage Observer Agents; run the connect flow again for a new key.
* **Creating an Observer Agent fails with a plan limit**: the organization
  already has as many agents as the plan allows. Reuse an existing agent,
  delete one you no longer need, or upgrade. The error carries the upgrade
  link.
* **The Observer Agent stays `never_connected`**: the install command has not
  run, or the host cannot reach Observer over HTTPS. Read the agent's logs
  with the command shown next to the install snippet.


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