Controller requirements
SZ-MCP calls your controller from a Cloudflare Worker, over the public internet. That imposes three requirements, and the first one is the one that stops most setups.
1. A publicly trusted TLS certificate
Section titled “1. A publicly trusted TLS certificate”Your controller must present a certificate issued by a public CA on the port you expose. SmartZone ships with a self-signed certificate, which will not work.
Cloudflare Workers validate certificates on every outbound fetch and provide
no skip-verify option — there is no setting in SZ-MCP that relaxes this,
because there is no setting in the platform to expose. A controller with a
self-signed certificate is unreachable, not degraded.
How to fix it
Section titled “How to fix it”Install a certificate from a public CA through the SmartZone admin UI. Let’s Encrypt with a DNS-01 challenge is usually the simplest path: it validates your control of the DNS name rather than requiring inbound HTTP, so the controller does not need port 80 open to the internet.
The certificate must be valid for the exact hostname you enter on the dashboard.
A certificate for sz.example.com will not satisfy a connection made to an IP
address.
Save & detect fails even though the credentials are right
Section titled “Save & detect fails even though the credentials are right”This is almost always the certificate. The TLS handshake fails before
SmartZone ever sees your username, so Save & detect reports invalid_host,
a connection-layer error, rather than “wrong password”. It is easy to misread
as a credentials problem. If you are confident the username and password are
right, suspect the certificate first, then the address and port below.
2. A publicly routable address
Section titled “2. A publicly routable address”SZ-MCP refuses to call hosts that are not publicly routable. This is checked when you save credentials and again on every call, and it applies to both hostnames and IP literals.
Refused outright:
| Category | Examples |
|---|---|
| Loopback | 127.0.0.0/8, ::1, localhost |
| Private (RFC 1918) | 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 |
| Link-local | 169.254.0.0/16 (including cloud metadata endpoints), fe80::/10 |
| Carrier-grade NAT | 100.64.0.0/10 |
| Unique local IPv6 | fc00::/7 |
| Multicast and reserved | 224.0.0.0/4 and above, ff00::/8, 0.0.0.0/8 |
| Internal-looking names | any host ending .local, .internal, .localhost; broadcasthost |
Non-canonical IP literals are refused as a class — integer (2130706433), octal
(0177.0.0.1), hexadecimal (0x7f.0.0.1) and short (127.1) forms all expand
to real addresses at resolve time, so anything whose labels are entirely numeric
is rejected rather than normalised. A trailing dot does not help: 127.0.0.1.
is treated as 127.0.0.1.
Attempting to save one of these returns forbidden_host with a message naming
the reason, for example IPv4 10.1.2.3 is in a reserved/private range.
3. A reachable API port
Section titled “3. A reachable API port”The port defaults to 8443, SmartZone’s usual public API port, and accepts anything from 1 to 65535. Whatever you choose must be open to Cloudflare’s egress and serving the certificate from requirement 1.
SZ-MCP always speaks HTTPS to the controller. There is no plaintext option.
What is checked, and when
Section titled “What is checked, and when”| Moment | What is verified |
|---|---|
| Save & detect | Host is publicly routable, TLS handshake succeeds, credentials are accepted, API version detected |
| Test connection | The same checks, re-run against the saved credentials |
Every call from Claude | Host is publicly routable; TLS is validated by the platform on each request |
The host check runs on every call, not only at save time, so a stored credential cannot become a route into a private range later.