Metadata-Version: 2.5
Name: spm-mcp
Version: 0.4.0
Summary: Model Context Protocol server for Secure Proxy Manager — manage the proxy + WAF + DNS stack from an AI assistant/agent.
Project-URL: Homepage, https://github.com/fabriziosalmi/secure-proxy-manager
Project-URL: Repository, https://github.com/fabriziosalmi/secure-proxy-manager
Author: Fabrizio Salmi
License: MIT
Keywords: mcp,model-context-protocol,proxy,secure-web-gateway,self-hosted,waf
Requires-Python: >=3.11
Requires-Dist: httpx<1.0.0,>=0.27
Requires-Dist: mcp<3.0.0,>=2.0.0
Description-Content-Type: text/markdown

# spm-mcp: MCP server for Secure Proxy Manager

A [Model Context Protocol](https://modelcontextprotocol.io) server that exposes
part of the [Secure Proxy Manager](https://github.com/fabriziosalmi/secure-proxy-manager)
management API as tools, so an assistant or agent can query traffic and
analytics, read the WAF categories and the domain blacklist, and, when you
allow it, change them. It speaks MCP over the stdio transport and
authenticates to the backend API with an SPM API token.

## Tools

| Tool | API call | Registered |
|---|---|---|
| `spm_status` | `GET /api/status` | always |
| `spm_dashboard` | `GET /api/dashboard/summary` | always |
| `spm_top_domains` | `GET /api/analytics/top-domains` | always |
| `spm_shadow_it` | `GET /api/analytics/shadow-it` | always |
| `spm_user_agents` | `GET /api/analytics/user-agents` | always |
| `spm_recent_logs` | `GET /api/logs?limit=<n>` (default 50) | always |
| `spm_waf_categories` | `GET /api/waf/categories` | always |
| `spm_list_domain_blocklist` | `GET /api/domain-blacklist` | always |
| `spm_block_domain` | `POST /api/domain-blacklist` | only with `SPM_MCP_READONLY=false` |
| `spm_unblock_domain` | `DELETE /api/domain-blacklist/{id}` | only with `SPM_MCP_READONLY=false` |
| `spm_toggle_waf_category` | `POST /api/waf/categories/toggle` | only with `SPM_MCP_READONLY=false` |
| `spm_allow_egress` | `POST /api/egress-allowlist` | only with `SPM_MCP_READONLY=false` |
| `spm_reload_config` | `POST /api/maintenance/reload-config` | only with `SPM_MCP_READONLY=false` |

**The server is read-only by default.** The read tools return traffic data
that anyone whose requests cross the proxy can shape (URLs, domains, user
agents), so text in a log row can try to instruct the model; with the mutating
tools available, an auto-approved call could disable a WAF category or open
egress. The output of `spm_dashboard`, `spm_top_domains`, `spm_shadow_it`,
`spm_user_agents` and `spm_recent_logs` is wrapped in
`{"untrusted_data_notice": ..., "data": ...}`, and every tool carries MCP
annotations (`readOnlyHint`, `destructiveHint`) for the client's approval
prompt. If you enable the mutating tools, do not auto-approve them.

## Authenticate with a token

`SPM_TOKEN` needs spm-mcp 0.4.0 or later and Secure Proxy Manager 3.28.0
or later; with older versions, use `SPM_USERNAME` and `SPM_PASSWORD`.

Create a token in the dashboard under **Settings > Admin and backup > API
tokens** (or `POST /api/tokens`) and give it to the server as `SPM_TOKEN`.
A `read` token is enough for the default read-only server. The mutating tools
need both `SPM_MCP_READONLY=false` and a `write` token: with a token, the
server asks `GET /api/session` for its scope at start and registers them only
when the answer is `write`. A read token, or an answer it cannot read,
registers none and says so on stderr.

A token is limited to its scope, never reaches the token, password, backup
or database export routes, can be revoked alone, and the audit log records
its changes as `token:<name>`. See the
[authentication API](https://github.com/fabriziosalmi/secure-proxy-manager/blob/main/docs/api/authentication.md#api-tokens).

`SPM_USERNAME` and `SPM_PASSWORD` still work when `SPM_TOKEN` is not set, with
a warning on stderr. They are deprecated and will be removed in the next
release.

## Configure

| Env | Default | Meaning |
|---|---|---|
| `SPM_URL` | `http://localhost:5001` | SPM backend API base URL |
| `SPM_TOKEN` | empty | SPM API token, sent as `Authorization: Bearer` |
| `SPM_USERNAME` | `admin` | Deprecated: admin user (Basic auth), used only without `SPM_TOKEN` |
| `SPM_PASSWORD` | empty | Deprecated: admin password, used only without `SPM_TOKEN` |
| `SPM_VERIFY` | `true` | `false` to skip TLS verification for a self-signed HTTPS URL |
| `SPM_MCP_READONLY` | `true` | `false`, `0` or `no` to also register the mutating tools |

`http://localhost:5001` is the backend's host-only port, so the default works
on the machine that runs the stack. From elsewhere, use
`https://<host>:8443` with `SPM_VERIFY=false` (or a trusted certificate).

## Run

With [uv](https://docs.astral.sh/uv/), from PyPI:

```bash
SPM_URL=http://localhost:5001 SPM_TOKEN=spm_... uvx spm-mcp
```

From this directory of a clone:

```bash
SPM_URL=http://localhost:5001 SPM_TOKEN=spm_... uvx --from . spm-mcp
```

In an MCP client configuration (for example Claude Desktop):

```json
{
  "mcpServers": {
    "secure-proxy-manager": {
      "command": "uvx",
      "args": ["spm-mcp"],
      "env": {
        "SPM_URL": "http://localhost:5001",
        "SPM_TOKEN": "spm_..."
      }
    }
  }
}
```

The `Dockerfile` here builds an image that runs the server over stdio as a
non-root user; the shipped compose files do not include it.

Requires Python 3.11 or later. MIT-licensed, part of Secure Proxy Manager.
