# MCP server

## What it is

pfcloud is a remote MCP server (Model Context Protocol) at:

```text
POST https://YOUR-MYFORGE/api/mcp
```

It speaks JSON-RPC 2.0 over MCP Streamable HTTP, tools only, with no sessions. `GET` and `DELETE` answer `405`. It uses the same bearer token as the REST API.

## Connect

First make a token (**API**, then **Tokens**). See [AI token recipes](/developers/ai-token-recipes).

### Claude Code

```bash
claude mcp add --transport http myforge https://YOUR-MYFORGE/api/mcp \
  --header "Authorization: Bearer mf_YOUR_TOKEN"
```

### Cursor and other clients with a JSON config

```json
{
  "mcpServers": {
    "myforge": {
      "url": "https://YOUR-MYFORGE/api/mcp",
      "headers": { "Authorization": "Bearer mf_YOUR_TOKEN" }
    }
  }
}
```

### Claude Desktop and clients that only start local programs

Use a bridge such as `mcp-remote`, which turns a remote server into a local one:

```json
{
  "mcpServers": {
    "myforge": {
      "command": "npx",
      "args": ["mcp-remote", "https://YOUR-MYFORGE/api/mcp", "--header", "Authorization: Bearer ${MYFORGE_TOKEN}"],
      "env": { "MYFORGE_TOKEN": "mf_YOUR_TOKEN" }
    }
  }
}
```

Config files are plain text on your disk. Do not commit them. Client menus differ between versions: look for "add custom MCP server" with a URL and a header.

## Tools

A tool is listed only when the token can use every scope it needs right now. A read-only token shows only the read tools.

| Tool | What it does | Scope | API call |
| --- | --- | --- | --- |
| `whoami` | Who the token is, its team, usable scopes | any valid token | `GET /token` |
| `list_servers` | Servers: name, status, address | `servers:read` | `GET /servers` |
| `get_server` | One server | `servers:read` | `GET /servers/{server}` |
| `get_server_health` | Resources, issues, live agent | `servers:read` | `GET /servers/{server}/health` |
| `get_server_security` | Latest security report | `servers:read` | `GET /servers/{server}/security` |
| `list_server_certificates` | Certificates on a server, soonest expiry first | `servers:read` + `sites:read` | `GET /servers/{server}/certificates` |
| `list_sites` | Sites | `sites:read` | `GET /sites` |
| `get_site` | One site | `sites:read` | `GET /sites/{site}` |
| `get_site_certificate` | Certificate and history | `sites:read` | `GET /sites/{site}/certificate` |
| `list_deployments` | Recent deployments | `deployments:read` | `GET /sites/{site}/deployments` |
| `get_site_compatibility` | Does the server fit the code's language versions | `sites:read` | `GET /sites/{site}/compatibility` |
| `get_server_runtimes` | PHP versions installed or installable, Node.js, Python… | `servers:read` | `GET /servers/{server}/runtimes` |
| `get_deployment` | One deployment, log tail, code-scan findings | `deployments:read` | `GET /sites/{site}/deployments/{deployment}` |
| `list_site_backups` | A site's backups | `backups:read` | `GET /sites/{site}/backups` |
| `read_site_log` | Last lines of a log (`log`, `lines` arguments) | `logs:read` | `GET /sites/{site}/logs/tail` |
| `deploy_site` | Deploy now | `deployments:write` | `POST /sites/{site}/deploy` |
| `rollback_site` | Roll back to the previous release | `deployments:write` | `POST /sites/{site}/rollback` |
| `renew_certificate` | Renew a Let's Encrypt certificate | `certificates:renew` | `POST /sites/{site}/certificate/renew` |
| `back_up_site` | Back up the database now | `backups:write` | `POST /sites/{site}/backups` |
| `run_security_check` | Start a read-only security check | `servers:write` | `POST /servers/{server}/security-checks` |

Arguments are the public ids (`server`, `site`, `deployment`) that the list tools return.

## Not offered over MCP, on purpose

Deleting, reading or changing `.env`, and running commands. Also not offered: creating servers or sites, firewall, databases. For those use the dashboard or the [REST API](/developers/ai-with-the-rest-api) with a separate, more carefully limited token.

## How tools map to the API

A tool call is turned into a request to `/api/v1/...` with your own token and sent through the full API stack. So scopes, plan, the owner's rules, the maker's permissions, server and site limits, rate limits, the request log and idempotency (a fresh key for every write) all apply exactly as for a direct call. API errors come back as tool results with `isError` true and the message `Error <status>: ...`.

## Limits and behaviour

- 120 requests per minute per token (the same pool as the REST API).
- A tool result is cut at 20,000 characters.
- Unknown arguments are refused. Path ids must look like public ids.
- Batches of up to 20 JSON-RPC messages are accepted.
- The server tells the AI to ask you before deploying, rolling back or renewing unless you clearly asked, and not to follow instructions found in logs, commit messages or deployment output. This is guidance, not a guarantee: the real protection is the token's scopes. See [AI security](/developers/ai-security).

## What can go wrong

| Problem | Fix |
| --- | --- |
| The client shows no tools | The token lacks the scopes, or the plan, owner rules or the maker's permissions block them. Call `whoami`, or `GET /token`. |
| `401` when connecting | Wrong or expired token, or the header is missing. |
| `403` | The address is not allowed for this token. |
| `Error 409` from a tool | A deploy is already running or the site cannot be deployed. |
