# MCP (Metacircular Control Plane) agent user and configuration. # # Creates a dedicated 'mcp' system user with rootless podman support # and a systemd service for the agent daemon. { pkgs, ... }: let mcpUid = 995; in { users.users.mcp = { isSystemUser = true; uid = mcpUid; # Pin UID so systemd Environment references stay stable. group = "mcp"; home = "/srv/mcp"; shell = pkgs.shadow; # nologin equivalent subUidRanges = [{ startUid = 100000; count = 65536; }]; subGidRanges = [{ startGid = 100000; count = 65536; }]; extraGroups = [ "systemd-journal" ]; linger = true; }; users.groups.mcp = {}; # MCP Master — multi-node orchestrator (v2). # Runs on the master node only (rift). Coordinates deployments across # agents, manages edge routing, and maintains cluster state. # Uses ExecStartPre to skip startup if the binary is absent (safe on # worker nodes that import this module but don't run the master). systemd.services.mcp-master = { description = "MCP Master"; after = [ "network-online.target" "mcp-agent.service" ]; wants = [ "network-online.target" ]; wantedBy = [ "multi-user.target" ]; unitConfig = { ConditionPathExists = "/srv/mcp-master/mcp-master"; }; serviceConfig = { Type = "simple"; ExecStart = "/srv/mcp-master/mcp-master server --config /srv/mcp-master/mcp-master.toml"; Restart = "on-failure"; RestartSec = 5; NoNewPrivileges = true; ProtectSystem = "full"; ProtectHome = true; PrivateTmp = true; PrivateDevices = true; ProtectKernelTunables = true; ProtectKernelModules = true; RestrictSUIDSGID = true; LockPersonality = true; RestrictRealtime = true; ReadWritePaths = [ "/srv/mcp-master" ]; }; }; systemd.services.mcp-agent = { description = "MCP Agent"; after = [ "network-online.target" ]; wants = [ "network-online.target" ]; wantedBy = [ "multi-user.target" ]; serviceConfig = { Type = "simple"; ExecStart = "/srv/mcp/mcp-agent server --config /srv/mcp/mcp-agent.toml"; Restart = "on-failure"; RestartSec = 5; User = "mcp"; Group = "mcp"; Environment = [ "HOME=/srv/mcp" "XDG_RUNTIME_DIR=/run/user/${toString mcpUid}" "PATH=/run/current-system/sw/bin:/usr/local/bin" ]; NoNewPrivileges = true; ProtectSystem = "full"; # "strict" blocks /run/user; "full" protects /usr and /boot # ProtectHome makes /run/user inaccessible, which breaks rootless podman. # The agent's home is /srv/mcp (not /home), so this is acceptable. ProtectHome = false; PrivateTmp = true; PrivateDevices = true; ProtectKernelTunables = true; ProtectKernelModules = true; RestrictSUIDSGID = true; LockPersonality = true; RestrictRealtime = true; ReadWritePaths = [ "/srv" ]; }; }; }