service-manager 0.11 writes Disabled: true into every plist carrying KeepAlive, and our RestartPolicy::Always guarantees KeepAlive, so every agent we installed was born disabled. launchctl load honours the key while still exiting 0, so install reported success on an agent that would never start — not then and not at the next login. service::start now removes the Disabled key itself before loading, via a pure enable_plist() that rewrites nothing when the key is absent and preserves every other key, including the EnvironmentVariables PATH snapshot. That makes start self-healing for plists left disabled by an earlier build. The crate's own start() is still not used, since without Disabled it degrades to launchctl start, which fails on an unloaded job. Because launchctl load exits 0 on failure, start also checks a post-condition: it asks launchd whether the job now exists and reports a diagnostic if it does not. stop keeps no such check, since a benign unload of an already-stopped job also prints a failure while exiting 0. status now treats the plist on disk as the definition of installed, as the spec says: a plist that exists but is not loaded reports stopped with its program, PATH and snapshot date intact instead of collapsing to not-installed with every field cleared. That is precisely the state the Disabled bug left users in, so it is the state status most needs to describe. status also gains the log path the spec always listed, and the daemon's own log is renamed xy.log -> daemon.log so a supervised server named xy cannot share a file, and two rotation counters, with the daemon. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EGntTHCW3sEPy1VBRopNNp
xy — HTTP MCP server supervisor
Daemon + CLI that launches and supervises HTTP-based MCP servers.
Build
cargo build --release
Run
target/release/xy daemon # foreground
Drop a server definition into $XDG_CONFIG_HOME/xy/servers/<name>.kdl
(see examples/insikt.kdl) and xy reload.
Commands:
xy list
xy status <name>
xy start <name|--all>
xy stop <name|--all>
xy restart <name|--all>
xy reload
xy logs <name> [--tail N] [--follow]
Exit codes: 0 success, 1 operational error, 2 daemon unreachable, 3 config invalid.
Start on login (macOS)
xy service install # write the LaunchAgent, load it, start the daemon
xy service uninstall # unload and remove the agent
xy service start # load an installed agent
xy service stop # unload until the next login
xy service status # show agent state
xy service install snapshots the current PATH into the agent, because a
launchd agent otherwise inherits only /usr/bin:/bin:/usr/sbin:/sbin and
supervised servers would not find their toolchains. Re-run with --force
after installing a new toolchain to refresh the snapshot.
xy service stop lasts until the next login. To disable start-on-login
permanently, use xy service uninstall.
The daemon writes to $XDG_STATE_HOME/xy/logs/daemon.log. Failures that happen
before the daemon starts logging — a missing binary, a malformed plist — are
visible only to launchd:
launchctl print gui/$UID/se.aceofba.xy