# Securely Connect AI Agents to Webship’s MCP Server
An MCP connection to a web server is not a chat widget. It is an operations interface that can inspect production state, change routing and security policy, reload certificates, activate static releases, coordinate fleet changes, and install a signed Webship update.
Treat it accordingly: as a privileged administrative API. The safest Webship setup keeps the MCP listener off the public data plane, binds it to loopback, protects it with TLS 1.3 and a strong bearer token, and reaches it through an authenticated SSH tunnel.
This guide builds that setup, explains why each boundary exists, and gives you a checklist for operating it without turning convenience into exposure.
Start with the trust boundary
Webship’s public traffic and MCP traffic use separate listeners. The MCP control plane is disabled by default and never shares the normal HTTP, HTTP/2, HTTP/3, or WebTransport listener. When enabled, it serves MCP over a dedicated TLS 1.3 HTTP/1.1 endpoint.
A secure deployment has four independent controls:
- Network reachability: the MCP listener binds to
127.0.0.1, not a public or private-LAN address. - Transport identity: the client verifies a certificate issued by a CA it trusts.
- Application authentication: every request carries one strong bearer token.
- Administrative access: operators reach the loopback listener through an authenticated SSH account and tunnel.
None of these controls replaces another. TLS without a private network path still exposes an authentication surface. A tunnel without certificate verification makes endpoint identity ambiguous. A bearer token inside a world-readable file is not a secret.
Prepare the certificate and token
Issue a dedicated MCP certificate from your internal CA. For the tunnel shown below, include localhost and 127.0.0.1 in the certificate’s subject alternative names, then install the issuing CA in the MCP client machine’s trust store. Do not solve a trust error with an insecure-TLS option.
Create a unique token with at least 32 printable ASCII bytes and no whitespace. A 32-byte random value encoded as hexadecimal gives you 64 safe characters:
umask 077
openssl rand -hex 32Webship currently reads the MCP token directly from the protected TOML configuration; token_file is not supported. Store the result in a configuration file readable only by the Webship service account and its administrative group. Do not place the token in a systemd unit, shell history, ticket, chat message, or prompt sent to an AI model.
On a typical Debian host:
sudo chown root:webship /etc/webship/production.toml
sudo chmod 0640 /etc/webship/production.toml
sudo chown root:webship /etc/webship/mcp-cert.pem /etc/webship/mcp-key.pem
sudo chmod 0644 /etc/webship/mcp-cert.pem
sudo chmod 0640 /etc/webship/mcp-key.pemAdapt the service user and group to your installation. The private key and configuration must be readable by Webship, but not by unrelated accounts.
Enable the isolated listener
Add this section to the active Webship configuration:
[security.mcp]
enabled = true
listen = "127.0.0.1:9443"
token = "replace-with-your-generated-64-character-token"
allowed_ips = []
expose_remote = false
[security.mcp.tls]
cert = "/etc/webship/mcp-cert.pem"
key = "/etc/webship/mcp-key.pem"An empty allowed_ips list does not open the endpoint. Loopback clients remain permitted by default. expose_remote = false makes the intended boundary explicit: if someone later changes listen to a non-loopback address, Webship rejects the configuration instead of silently publishing the control plane.
Webship also rejects an enabled MCP listener without TLS, without a token, with a short or whitespace-containing token, or with empty certificate paths. Public placeholder tokens are rejected before remote exposure.
Validate before restart
MCP listener, TLS identity, and token changes rebuild the control plane, so they require a process restart. Validate the complete configuration first:
/usr/local/bin/webship --check-config --config /etc/webship/production.toml
sudo systemctl restart webship
sudo systemctl status webship --no-pagerConfirm that the listener exists only on loopback:
ss -ltn | grep '127.0.0.1:9443'Do not add port 9443 to the host’s public firewall rules. The next step reaches it through SSH.
Create the private tunnel
From the administrator workstation, forward a local port to Webship’s loopback listener:
ssh -N \
-L 127.0.0.1:19443:127.0.0.1:9443 \
webship-admin@edge.example.comThe MCP client now connects to https://localhost:19443/mcp. TCP reaches the SSH server, SSH carries the connection to the host, and the host opens the final connection to Webship on loopback. Closing the SSH session removes that path immediately.
Use key-based SSH authentication, restrict which administrators can open the tunnel, and apply your normal host-access controls. If a jump host is required, keep the MCP listener on the Webship host’s loopback interface and extend the SSH path rather than widening the listener.
Configure the MCP client
Client configuration formats differ, but a typical HTTP MCP entry looks like this:
{
"mcpServers": {
"webship-production": {
"url": "https://localhost:19443/mcp",
"headers": {
"Authorization": "Bearer <your-token>"
}
}
}
}Use the client’s protected secret mechanism when it has one. Otherwise, restrict the client configuration to the current operating-system account. The HTTP client—not the model—should attach the authorization header. Never paste the live token into a conversation.
Keep certificate verification enabled. If the client rejects the certificate, repair the certificate’s subject alternative names or install the correct internal CA. Do not add a permanent bypass.
Make the first session read-only
After the tunnel and client are connected, begin with discovery and inspection:
- Ask for
tools/list; its response is the authoritative argument schema for the running release. - Call
webship.get_configand record the current configuration version. - Inspect
webship.reverse_proxy.get_status,webship.security.get_status,webship.ddos.get_status, andwebship.tls.get_statusas applicable. - Use
webship.policy.explainorwebship.security.simulatebefore changing a policy. - Confirm that the returned configuration redacts bearer tokens.
Only then test a mutation in a non-production environment. Webship’s configuration mutations require the current version ID. A stale write is rejected instead of overwriting a newer change. Candidate policy can be checked with shadow verification and traffic-lab scenarios before activation.
Webship also refuses selected live security downgrades. An MCP request cannot turn off an active WAF, DDoS layer, API Shield, bot challenge, edge-auth policy, or response-header layer. Process-bound listener, protocol, worker, runtime, and MCP-authentication changes require a deliberate restart.
Those guards reduce mistakes; they do not make every authorized action harmless. The token grants a powerful control surface, including update and release operations. Review proposed tool calls exactly as you would review an administrator’s shell command.
If remote binding is unavoidable
Loopback plus SSH is the recommended design. If your environment requires a private-network listener, make the exception explicit:
[security.mcp]
enabled = true
listen = "10.20.0.15:9443"
expose_remote = true
allowed_ips = ["10.20.10.0/24"]
token = "replace-with-your-generated-64-character-token"Keep the TLS block from the earlier example, use a certificate matching the private DNS name, and enforce the same source range at the host and network firewalls. Never use 0.0.0.0/0 or ::/0 as a convenience allowlist. Remember that an application allowlist sees the source address that actually reaches Webship; verify behavior when a load balancer, NAT gateway, or service mesh sits in front of it.
Remote exposure increases the value of centralized access logs, short operational windows, and fast rotation. It is not required merely because the MCP client runs on another machine; that is exactly what the SSH tunnel solves.
Operate the control plane deliberately
Use this checklist for production:
- Keep MCP disabled where no agent or operator needs it.
- Bind to loopback and use an SSH tunnel by default.
- Use a dedicated TLS identity and keep certificate verification enabled.
- Generate a unique bearer token for each Webship environment.
- Protect the TOML, client configuration, TLS key, and SSH keys with filesystem permissions.
- Separate development, testing, and production credentials.
- Start sessions with status and policy-simulation tools before mutations.
- Preserve and review Webship’s security audit events.
- Rotate the token and restart Webship after suspected exposure.
- Close tunnels when the administrative session ends.
For incident response, close active tunnels, restrict the SSH account, replace the MCP token in the protected TOML, restart Webship, and review recent security audit and configuration-version records. If the TLS private key may be exposed, issue a new certificate and key as part of the same restart. Test the old token afterward and confirm that it is rejected.
A control plane should remain a control plane
MCP is useful because an agent can inspect real state and apply validated changes without routing those operations through the public request path. That advantage disappears if the control listener becomes another internet endpoint.
Keep the boundary simple: a separate listener, loopback reachability, verified TLS, one protected bearer credential, an authenticated tunnel, version-checked changes, and a human review process for powerful operations. Webship provides the protocol and safety guards; the operator decides who can reach them.
This guide is based on the Webship 1.3.1 operator documentation, shipped configuration examples, MCP validation and transport code, runtime configuration guards, and tool catalog. Review the current Webship documentation and the running server’s tools/list response before applying it to another release.