Systemd¶
Because MCP is stdio-only, kartoza-mcp itself doesn't need systemd.
What does is your bridge — the process that hands long-lived MCP
sessions out to the network.
Pattern: bridge + on-demand server¶
The bridge listens on websocket/HTTP and spawns one kartoza-mcp child
process per session.
/etc/systemd/system/kartoza-mcp-bridge.service¶
# SPDX-FileCopyrightText: 2026 Kartoza.com <info@kartoza.com>
# SPDX-License-Identifier: MIT
[Unit]
Description=Kartoza MCP bridge (websocket → stdio)
After=network.target
[Service]
Type=simple
User=kartoza-mcp
Group=kartoza-mcp
ExecStart=/usr/local/bin/mcp-bridge \
--listen 127.0.0.1:8765 \
--child /usr/local/bin/spatial-cluster
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal
# Hardening
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
PrivateDevices=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
RestrictRealtime=true
RestrictNamespaces=true
LockPersonality=true
MemoryDenyWriteExecute=true
SystemCallArchitectures=native
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now kartoza-mcp-bridge.service
sudo journalctl -u kartoza-mcp-bridge.service -f
Why not a socket-activated server?¶
You can do it — Type=notify plus Sockets= — but the MCP child
spawn pattern is a better fit for per-session isolation. The bridge
gives you that for free.
Resource limits¶
Spatial workloads can spike. Set defensive limits in the unit:
These apply to the bridge and its child MCP processes (via cgroup inheritance), which is what you want.