Skip to content

MCP Server

SuperSpace runs a Model Context Protocol (MCP) server so AI assistants can manage your sites, DNS, domains, and more on your behalf. It is a stateless, OAuth-only, JSON-RPC 2.0 endpoint at POST /mcp on your brand host, exposing a curated subset of the REST API as MCP tools — broad read access plus a small set of safe writes.

Connecting a client

Modern MCP clients connect to SuperSpace directly over remote HTTP — no local bridge or config file required. Point your client at the SuperSpace MCP endpoint and authorize in the browser.

Quick start

Transport Streamable HTTP (remote)
URL https://control.superspace.nl/mcp
Headers / credentials None — authentication happens after setup via the OAuth browser flow

There are no headers, tokens, or environment variables to configure up front. After you add the server, your client prompts you to sign in to SuperSpace and authorize access; the token is obtained and stored for you.

Use your own brand host

Replace control.superspace.nl with your SuperSpace brand hostname. White-label brands each have their own host (for example brand.example.com). The /mcp URL must match the brand you authorize against — access tokens are locked to the brand they were issued under (see Authentication below).

Claude (desktop)

Claude supports SuperSpace as a custom connector — no manual configuration needed. See Anthropic's Get started with custom connectors using remote MCP for full details.

  1. Open Customize → Connectors → Add custom connector.
  2. Give it a Name (for example, SuperSpace).
  3. Set the Remote MCP server URL to https://control.superspace.nl/mcp.
  4. Click Add.

Claude's Add custom connector dialog

Once added, Claude prompts you to authenticate with your SuperSpace account to complete the connection.

OpenAI Codex (desktop)

  1. Open Settings → MCP Servers → Add Server.
  2. Enter the server URL https://control.superspace.nl/mcp. No additional fields are needed beyond the URL.
  3. Save.

Codex's Connect to a custom MCP form

After saving, Codex prompts you to authenticate with your SuperSpace account to complete the connection.

Transport

  • POST /mcp carries the JSON-RPC request. GET, PUT, PATCH, and DELETE return 405 Method Not Allowed.
  • The request body is a single JSON-RPC object. Batch arrays are rejected (-32600); malformed JSON returns -32700 (parse error).
  • A notification (a request with no id, such as notifications/initialized) returns 202 with an empty body.
  • CORS is enabled for /mcp (origins *, methods GET/POST/OPTIONS). A browser Origin, when present, must match the request host or the request is rejected 403 (Origin not allowed); non-browser clients send no Origin, which is allowed.
  • The optional MCP-Protocol-Version header, if sent, must be one of 2025-06-18, 2025-03-26, or 2024-11-05, otherwise 400.
  • Rate limit: 6000 requests / 10 minutes, keyed per OAuth token.

Authentication

The MCP server accepts only OAuth 2.1 access tokens (session and API-key credentials are refused — see OAuth 2.1). Beyond the normal OAuth checks (brand isolation, account membership, trial accounts are blocked), the token must be audience-bound to this MCP resource per RFC 8707: its resource must equal https://<host>/mcp.

A token issued for the REST API (no resource), or for a different brand's /mcp, is rejected with 401:

{ "jsonrpc": "2.0", "id": null, "error": { "code": -32600, "message": "invalid_token: token audience is not valid for this MCP resource" } }

with the header:

WWW-Authenticate: Bearer resource_metadata="https://<host>/.well-known/oauth-protected-resource/mcp"

The audience is fixed when the token is authorized and is inherited across refreshes. (Conversely, an MCP-audience token is rejected at /api — see Authentication.) mcp-remote performs this audience-bound authorization automatically.

Protected-resource metadata (RFC 9728)

GET /.well-known/oauth-protected-resource
GET /.well-known/oauth-protected-resource/mcp
{
  "resource": "https://<host>/mcp",
  "authorization_servers": ["https://<host>"],
  "scopes_supported": ["sites:read","sites:write","domains:read","domains:write","dns:read","dns:write","billing:read"],
  "bearer_methods_supported": ["header"]
}

A client follows authorization_servers to the authorization-server metadata to discover the authorize and token endpoints, then runs the standard PKCE flow.

JSON-RPC methods

Method Result
initialize { "protocolVersion": "2025-06-18", "capabilities": { "tools": { "listChanged": false } }, "serverInfo": { "name": "cloudpress-mcp", "version": "1" } } (echoes a supported requested version)
ping {}
tools/list { "tools": [ ... ] } — filtered to the tools the token's scopes allow
tools/call Executes a tool (see result shape)
notifications/* Acknowledged, no response (202)
anything else -32601 Method not found

JSON-RPC error codes: -32700 parse error · -32600 invalid request / batch / origin / version / auth · -32601 method not found · -32602 invalid params (unknown tool, insufficient_scope with data.required_scope, missing request_id) · -32603 internal error.

Scopes and tool visibility

Each tool requires an OAuth scope from the same vocabulary as the REST API. tools/list returns only the tools your token's scopes cover. Calling a tool you lack scope for returns a JSON-RPC error inside a 200 response (not an HTTP 403):

{ "jsonrpc": "2.0", "id": 1, "error": { "code": -32602, "message": "insufficient_scope", "data": { "required_scope": "sites:write" } } }

Idempotency

Every write tool requires an arguments.request_id (an idempotency key); omitting it returns -32602 (request_id is required for this tool). Calls are de-duplicated per token, tool, and request_id, with a fingerprint of the remaining arguments:

  • Replaying a completed call returns the original stored result (no re-execution).
  • The same request_id still in flight returns a success result with structuredContent.status = "processing".
  • The same request_id with different arguments returns an error result (isError: true) — use a fresh request_id.

Keys are retained for about 24 hours. A few create tools are explicitly non-idempotent because the underlying POST creates a fresh record (a reclaim could duplicate it): create_dns_zone, create_edge_rule, create_waf_custom_rule, create_rate_limit, create_access_list, and activate_shield. Avoid blind retries on those — to change an existing record, use the matching update_* tool. Each tool advertises its behavior in tools/list via annotations (readOnlyHint, destructiveHint, idempotentHint, openWorldHint).

Tool results

A successful tools/call returns both a text block and structured data (the same payload, rendered from the REST API templates so shapes match the documented responses):

{ "content": [ { "type": "text", "text": "<JSON string>" } ], "structuredContent": { }, "isError": false }

Business failures are not JSON-RPC errors — they come back as a normal result with "isError": true and a text message. Secret redaction is applied to both emits: get_site includes site.ssh only if the token also holds sites:write, and get_order always strips SSH data.

Tool catalog

65 tools, all scoped to the authorized account. Reads are broad; writes cover DNS records/zones, site rename and restart, CDN caching and cache purge, edge rules, and the full Shield surface (activate/deactivate, WAF settings and managed/custom rules, rate limits, access lists, bot detection). Below, * marks a required argument and marks a write tool (which requires a request_id).

Sites

Tool Scope Arguments Notes
list_sites sites:read Active sites
get_site sites:read id* Includes SSH credentials only if the token also has sites:write
rename_site sites:write id*, name*, request_id* Name only (no plan change)
restart_site sites:write id*, request_id* Async container restart

DNS

Tool Scope Arguments
list_dns_zones dns:read page, per_page
get_dns_zone dns:read id*
create_dns_zone dns:write name*, request_id*
delete_dns_zone dns:write id*, request_id*
get_dns_metrics dns:read id*, date_from, date_to
list_dns_records dns:read dns_zone_id*, page, per_page
get_dns_record dns:read dns_zone_id*, id*
create_dns_record dns:write dns_zone_id*, record_type* (integer code), value*, request_id*, plus ttl, name, priority, weight, port, flags, record_tag, comment
update_dns_record dns:write dns_zone_id*, id*, request_id*, plus ttl, value, priority, weight, port, flags, record_tag, comment
delete_dns_record dns:write dns_zone_id*, id*, request_id*

Domains and registration

Tool Scope Arguments Notes
list_domains domains:read page, per_page Site hostnames
get_domain domains:read id*
list_domain_registrations domains:read q
get_domain_registration domains:read id*
list_domain_contacts domains:read q
get_domain_contact domains:read id* id is an integer, not a GUID
check_domain_availability domains:read domain* Availability and pricing
search_domains domains:read base_name* Multi-TLD search
suggest_domains domains:read domain* Registrar suggestions

Registrar writes (register/transfer, contact CRUD, glue hosts) are not exposed as tools — use the REST API.

CDN, cache, logs, and metrics

Site-scoped. Reads use sites:read; writes use sites:write. CDN reads and writes need a provisioned pull zone (otherwise cdn_not_active).

Tool Scope Arguments Notes
get_cdn_status sites:read id* Pull-zone status overview
get_cdn_caching sites:read id* Caching settings (smart cache, expirations, vary toggles, stale-while-*)
get_cache_status sites:read id* Cache-layer status (redis/nginx/bunny)
get_cdn_metrics sites:read id*, period or period_start, step
get_cdn_logs sites:read id*, plus filters (from, to, period, status, cache_status, country, url_contains, limit, offset, order) Window of 3 days max
get_cdn_logs_summary sites:read Same filters Aggregated
get_origin_logs sites:read id*, date (MM-DD-YYYY)
get_resource_metrics sites:read id*, kind[], period_start, period_end, step No range returns a current snapshot
update_cdn_caching sites:write id*, request_id*, plus any caching field Merge — sends only the keys you pass; returns the refreshed config
purge_cdn_cache sites:write id*, request_id* Purges the entire pull-zone cache

Edge rules

Site-scoped, CDN active. Reads use sites:read; writes use sites:write. System (CPRESS -) rules are hidden and cannot be created, updated, deleted, or toggled.

Tool Scope Arguments Notes
list_edge_rules sites:read id* Returns each rule's Bunny Guid and readable labels
create_edge_rule sites:write id*, request_id*, ActionType*, plus ActionParameter1/2/3, TriggerMatchingType, Triggers, ExtraActions, Description, Enabled, OrderIndex Non-idempotent (creates a fresh rule). Bunny PascalCase shape
update_edge_rule sites:write id*, guid*, request_id*, plus any create field Merge (send only what changes) — an MCP convenience; the REST update is a full replace
delete_edge_rule sites:write id*, guid*, request_id* Requires the destroy role
toggle_edge_rule sites:write id*, guid*, enabled*, request_id* Enable or disable

Shield

Site-scoped. Reads use sites:read; writes use sites:write. Plan-gated (shield_not_in_plan); reads and writes need a provisioned shield zone (shield_not_active).

Tool Scope Arguments Notes
get_shield_status sites:read id* Config summary (no engine-config)
get_waf_config sites:read id* Full WAF config incl. engine-config (paranoia levels and protocol allow-lists)
list_waf_managed_rules sites:read id* Managed-rule catalogue (rule ids for update_shield)
list_waf_custom_rules sites:read id* Custom rules and their ids
list_rate_limits sites:read id* Rate-limit rules and their ids
list_access_lists sites:read id* Custom allow/block lists and their ids
list_curated_access_lists sites:read id* Curated Bunny threat lists (no REST equivalent)
get_shield_events sites:read id*, date, continue Event log
get_shield_metrics sites:read id*, view (individual or overview) Not plan-gated
activate_shield sites:write id*, request_id* Non-idempotent; cdn_not_active if no pull zone
deactivate_shield sites:write id*, request_id* Requires the destroy role; soft (disables WAF and DDoS)
update_shield sites:write id*, request_id*, plus WAF / sensitivity / protocol / DDoS / plan_type / learning_mode / whitelabel_response_pages fields Merge (all fields optional)
update_bot_detection sites:write id*, request_id*, plus execution_mode / sensitivity / fingerprint fields Premium-only; merge
create_waf_custom_rule sites:write id*, request_id*, rule_name*, action_type*, variable_type*, operator_type*, severity_type*, value*, plus variable_subselector, rule_description Premium-only, non-idempotent
update_waf_custom_rule sites:write id*, rule_id*, request_id*, plus the same rule fields Full replace; not premium-gated
delete_waf_custom_rule sites:write id*, rule_id*, request_id* Requires the destroy role
create_rate_limit sites:write id*, request_id*, rule_name*, action_type*, match_variable*, operator_type*, severity_type*, value*, request_count*, timeframe*, plus block_time, counter_key_type, rule_description Non-idempotent. rule_name and rule_description: letters, numbers, and spaces only
update_rate_limit sites:write id*, rule_id*, request_id*, plus the same fields Full replace
delete_rate_limit sites:write id*, rule_id*, request_id* Requires the destroy role
create_access_list sites:write id*, request_id*, name*, type*, content*, plus description, checksum, action (allow/block) Non-idempotent; also sets the list action
update_access_list sites:write id*, list_id*, request_id*, plus name, content, checksum, action Content full-replace
delete_access_list sites:write id*, list_id*, request_id* Requires the destroy role
update_curated_access_list sites:write id*, configuration_id*, request_id*, plus is_enabled, action (integer) Curated list enable/action (no REST equivalent; sellable plans only)

Orders and subscriptions

Read-only, scope billing:read.

Tool Arguments Notes
list_orders page, per_page
get_order id* SSH data is always stripped
list_subscriptions page, per_page
get_subscription id*

Not available as tools

Site create/delete/resize, backups and restores, SSO, users/roles/accounts/API keys, carts and order writes (including domain orders), registrar/contact/glue-host writes, site-domain and certificate writes, tasks, and all billing writes are intentionally not exposed via MCP. Use the REST API for those — with a session or API-key credential where the operation is OAuth-blocked.

Advanced: manual installation (stdio bridge)

Only needed for older clients without remote MCP support

Most clients now connect directly over remote HTTP (see Connecting a client above). Use the bridge below only with an older client that speaks stdio and cannot talk to the remote /mcp endpoint directly.

The mcp-remote bridge runs locally over stdio and proxies to SuperSpace, handling the OAuth login for you (it opens a browser to authorize, then caches the token).

Edit your client's MCP configuration file (for example, claude_desktop_config.json) and add SuperSpace under the mcpServers object:

"superspace": {
  "command": "npx",
  "args": [
    "-y",
    "mcp-remote",
    "https://control.superspace.nl/mcp"
  ]
}

If npx is not on the client's PATH — common, since GUI apps don't inherit your shell environment — and you have mise installed, use it to provide npx:

"superspace": {
  "command": "mise",
  "args": [
    "x",
    "--",
    "npx",
    "-y",
    "mcp-remote",
    "https://control.superspace.nl/mcp"
  ]
}

Then fully restart the client. The first time it connects, a browser window opens for you to authorize via SuperSpace OAuth; approve the account and the connection completes.