# Remote MCP server

The remote MCP server is Koo's hosted endpoint at `https://mcp.koo.io/mcp`. Any MCP host that speaks remote MCP over HTTP — Claude Code, Claude.ai, Cursor, ChatGPT — connects to it by **URL**, and you authorize it in the browser with **Sign in with Koo**. There is nothing to install: no package to add, no process for your host to launch, and no token to mint, paste, or store — the host gets an access token through OAuth and refreshes it on its own.

It exposes Koo to your agent as a set of `koo_*` tools — deploy a [service](/docs/projects/projects-and-environments), follow the [deployment](/docs/deploy/deployments-and-rollback) timeline, roll back, tail [logs](/docs/observability/logs), read [metrics](/docs/observability/metrics), set variables, check [status](/docs/observability/status). Where there is no browser to authorize in — a CI runner, a remote shell — the same endpoint takes a `kc_…` [API token](/docs/developers/api-tokens) as its bearer instead; see [Headless / CI](#headless-ci).

## Connect

In **Claude Code**, one command adds it:

```text
claude mcp add --transport http koo https://mcp.koo.io/mcp
```

In **Claude.ai**, **Cursor**, **ChatGPT**, or any other host with a remote-connector or custom-integration setting, add a connector and give it the same URL:

```text
https://mcp.koo.io/mcp
```

The first tool call triggers the authorization flow. Your browser opens, you sign in to Koo, and you choose what the client may do — then the host stores the result and you are done.

## What happens when you connect

1. 
2. 
3. 
4. 
5.

You approve again each time a client reconnects — a connection is always a deliberate act, never a silent renewal.

## Tools

Every tool returns structured content and acts on the one account the connection is bound to — there is no account switch, and no account to pass. Reads are marked read-only; writes (`koo_deploy`, `koo_rollback`, `koo_set_variables`) carry a destructive hint, so your host can prompt before one is applied. The two creates are writes too, but marked non-destructive — they only add.

<!-- mcp-tools:begin -->

`koo_get_logs` and `koo_get_metrics` return the window actually queried after it is clamped to your plan's retention — the agent reports that resolved window and does not retry to widen it. Deploying from local source is not a tool: that goes through `koo up` in the [CLI](/docs/developers/cli), and the agent then watches the result with these tools.

## What the connection can do

A connection is deliberately narrower than your own account access:

- 
- 
- 
-

Every action is attributed to you in the account's audit trail, together with the client that made it.

## Guardrails

Koo maintains an agent skill — the Koo deploy flow written once and rendered for each host — that teaches an agent to work this way. The rules that matter hold whichever agent is driving, because the API is what enforces them:

- 
- 
- 
-

## Headless / CI

OAuth needs a browser, and a CI runner does not have one. The same endpoint therefore also accepts a `kc_…` [API token](/docs/developers/api-tokens) as its bearer, with no authorization flow at all — the token brings its own account and role, exactly as it does on the [REST API](/docs/developers/api).

In **Claude Code**, add the connection with a header:

```text
claude mcp add --transport http koo https://mcp.koo.io/mcp \
  --header "Authorization: Bearer ${KOO_TOKEN}"
```

Your shell expands `${KOO_TOKEN}` as that command runs, so the token comes from the environment rather than your shell history. Hosts differ on whether they expand `${VAR}` themselves when reading a config file — one that does not will store the literal text you gave it. Check your host before you paste a real token anywhere.

Any host works the same way, on one condition: it must let you set a custom header on a remote MCP server. A host that accepts only a URL has nowhere to put the bearer, and OAuth in a browser is the only path there.

Token hygiene for an agent that runs unattended:

- 
- 
-

## Revoke a connection

Open **Connections** in the console — it is in your avatar menu, and under **User** in the account sidebar. Each connection shows the client, the account, and the role you granted.

Revoking is immediate for anything new: the client's refresh token dies at once, so it cannot obtain fresh access. An access token it already holds keeps working until it expires, which is **within one hour**. If you need the connection cut off with no residue at all, remove the connection _and_ adjust your membership — the live-role check applies on every single request.

A headless agent holds a `kc_…` token rather than a connection, so it is not listed there — revoke it from the account's **Tokens** page instead, where revocation takes effect at once.

## Troubleshooting

- 
- 
- 
- 
-
