# MCP server for AI agents

Checked against the code on 2026-10-31 (version 0.1.0).

SeeDropHost has an MCP server so an agent (Claude Code, or any MCP client) can create sites, deploy, read the SEO/GEO report, connect domains, read leads, check the plan usage and the subscription, and export a site. It comes in two forms with almost the same tools.

| | Local MCP | Remote MCP |
|---|---|---|
| Transport | stdio | Streamable HTTP, `POST /mcp`, stateless |
| Auth | `SDH_TOKEN` in the environment | `Authorization: Bearer <token>` |
| Which token | an account token (`sdh_…`) or the server token | an account token (`sdh_…`) or the server token |
| Reads your disk | only folders listed in `SDH_MCP_ROOTS` | never — it publishes what the agent sends |
| Tools | 20 | 18 (no `deploy_directory`, `deploy_zip`) |
| Audit actor | `mcp:claude` | `mcp-remoto` |

> **In progress:** OAuth 2.1 sign-in for the remote MCP. Today it uses the server's Bearer token.

## Which token to give an agent

The MCP uses the same Bearer token as the [HTTP API](/docs/api/). With an **account token** (`sdh_…`) the agent sees and changes only the sites of that account; a site of another account answers "not found", through the MCP too. With the server token it sees every account. Give each agent its own account token (`sdh token:criar claude`, see the [CLI](/docs/cli/)) so it can be revoked on its own.

## The rule: agents deploy drafts

Every deploy tool (`deploy_files`, `deploy_directory`, `deploy_zip`) creates a **draft**. Nothing changes for visitors. The tool returns the preview URL, the SEO/GEO score and the main issues, the forms found and the next step. Only `publish_deploy` puts a deploy live — and it is marked destructive, so the MCP client asks a person first. `set_env_var` and `delete_env_var` are destructive too, because a replaced or deleted secret cannot be brought back.

## Connect Claude Code

### Local (stdio)

From the repository folder, with the server running:

```bash
claude mcp add seedrophost \
  -e SDH_TOKEN=dev-token -e SDH_API_URL=http://localhost:8787 -e SDH_MCP_ROOTS=$PWD \
  -- node --disable-warning=ExperimentalWarning apps/mcp/src/main.ts
```

`SDH_MCP_ROOTS` is a `:`-separated list of folders the agent may publish from (default: the current folder).

### Remote (Streamable HTTP)

```bash
claude mcp add --transport http seedrophost https://your-server.example/mcp \
  --header "Authorization: Bearer YOUR-TOKEN"
```

Without a valid token the endpoint answers `401` with `WWW-Authenticate: Bearer realm="seedrophost"`. Only `POST` is accepted (no sessions). The remote `compare_sites` refuses addresses outside the public internet, checked again at connection time.

Then ask, for example: "list my sites", "publish this HTML as a draft on site X", "show this week's leads".

## Tools

| Tool | What it does | Annotation |
|---|---|---|
| `list_sites` | sites with address and live deploy | read-only |
| `get_site` | address, live deploy and domains of one site | read-only |
| `create_site` | creates an empty site | write |
| `deploy_files` | draft deploy from file contents (1–500 files, utf8 or base64); only changed files upload | write |
| `deploy_directory` | draft deploy from a local folder inside `SDH_MCP_ROOTS` (local only) | write |
| `deploy_zip` | draft deploy from a local `.zip` inside `SDH_MCP_ROOTS` (local only) | write |
| `list_deploys` | latest deploys, which one is live, score of each | read-only |
| `get_deploy_report` | SEO/GEO report, forms, redirect rules, changed pages | read-only |
| `publish_deploy` | puts a ready deploy live: approves a draft or rolls back | **Destructive** |
| `list_env_vars` | variables, secret values masked | read-only |
| `set_env_var` | creates or replaces a variable (encrypted); a replaced secret cannot be recovered | **Destructive** |
| `delete_env_var` | removes a variable | **Destructive** |
| `add_domain` | connects a domain and returns the DNS records | write |
| `check_domain` | looks up DNS: verified, routed, next step | write, open world |
| `list_forms` | forms with fields, totals, spam blocked | read-only |
| `compare_sites` | migration check between the current site and the new one; `previa` for a draft preview (detected automatically for `<deploy>--<site>.` addresses); `projeto` (local only) also checks the old addresses in a project's `_redirects` / `netlify.toml` | read-only, open world |
| `list_leads` | form submissions, latest first | read-only |
| `get_usage` | plan of the account, limits, usage of the month (sites, bandwidth, leads), state and next steps; deploys never count, and going over only warns | read-only |
| `get_billing` | subscription of the account (`gratis`, `pendente`, `ativo`, `atrasado` or `cancelado`), plan, paid until, next charge, open invoice link and prices. Subscribing needs a CPF and cancelling stops the charge, so both stay with the person: the agent points to the dashboard ("Mudar de plano") or `sdh assinar` / `sdh cancelar-assinatura` | read-only |
| `export_site` | summary of the "take everything" export of a site (files, leads, variable names; values never leave) and how to download the zip (`GET /v1/sites/{site}/export` or `sdh exportar`); it does not download the zip itself | read-only |

"Destructive" means the tool is registered with `destructiveHint: true`; "read-only" means `readOnlyHint: true`. Every call goes through the HTTP API and is written to the audit log.

## Typical agent flow

1. `create_site` (once; beyond the plan's site count it answers that the plan is full, and nothing live is touched).
2. `deploy_files` → draft + preview URL + score.
3. Fix what `get_deploy_report` lists, deploy again (only changed files upload).
4. For a migration, `compare_sites` between the current site and the preview URL.
5. Show the preview to the person; on their approval, `publish_deploy`.
6. Rolling back is `publish_deploy` with an earlier `deploy_id` from `list_deploys`.
7. `get_usage` any time to see how the month is going; `export_site` before a migration away, to hand the person their files and leads.
