Commit Graph

95 Commits

Author SHA1 Message Date
Kyle Isom
98b166fa7b agent: recover down components on startup when no boot sequence
A unikernel VM has no runtime restart policy, so if it exits — including
when an agent restart's cgroup kill takes it down — nothing restarts it,
and it sits in drift. Recover() already handles this (and unikernels, via
runtimeFor), but only ran inside RunBootSequence, which is gated on a
[boot] sequence that worker nodes don't define. Now the agent also runs
Recover once in the background on startup when there is no boot sequence,
so desired=running components (VMs especially) come back after an agent
or host restart without delaying registration.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 12:58:50 -07:00
Kyle Isom
4a55972455 monitor: see unikernel VMs + use canonical container naming
Two drift-reporting bugs:
1. The monitor listed only the podman runtime, so unikernel VMs always
   showed observed=unknown (false drift). It now takes a ContainerLister
   and the agent passes a merged lister (containers + VMs), mirroring
   listAllContainers.
2. The monitor computed the lookup name as service+"-"+component, which
   is wrong when component==service (the name collapses to just the
   service, e.g. "uktest"/"mc-proxy"). It now uses the canonical
   naming.ContainerNameFor — extracted to a shared package so the agent
   and monitor can't disagree.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 12:48:31 -07:00
Kyle Isom
84dd897bcd unikernel: bake volume config into images + per-service user-mode net
Enables migrating real services (config/cert dirs, stateless) to
unikernels. Volume host dirs are copied into a per-VM staging tree
mirroring guest paths; the ops config goes in the staging root with the
top-level dirs in Dirs, so ops bakes them at the right absolute paths.
(Staging is required — an absolute /srv MapDirs source makes ops descend
into the agent's podman overlay storage and fail.) A component may set
network = "user" to use QEMU user-mode NAT instead of the isolated
bridge (Phase-1 networking for first migrations, before a gateway proxy).

Verified: mcat (the MCIAS policy tester) deployed as a Nanos unikernel
via 'mcp deploy', booting with its baked /srv/mcat config+certs, serving
HTTPS verified against the platform CA, configured against MCIAS.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 10:16:30 -07:00
Kyle Isom
d2431f281d docs: note the unikernel runtime in CLAUDE.md
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 01:12:37 -07:00
Kyle Isom
47ec4e60ad unikernel: isolated host-only bridge networking (Phase 2)
When the mcp-br0 bridge exists, the agent runs unikernels on it instead
of QEMU user-mode networking: each VM gets a TAP device on the bridge
and a static 10.99.0.0/24 IP (baked into the Nanos image via ops
RunConfig). With the host firewall dropping off-bridge VM traffic and no
NAT, a VM can reach only the gateway -- making mc-proxy mediation
mandatory by topology rather than convention.

- runtime/qemu.go: bridge mode (createTAP/destroyTAP, IP allocator,
  deterministic MAC, static-IP ops config, VMAddr for proxy backends).
- agent auto-enables bridge mode when /sys/class/net/mcp-br0 exists.

Verified on straylight: uktest unikernel boots on mcp-br0 at 10.99.0.2,
serves via the gateway, TAP enslaved to the bridge; bridge has no uplink
and off-bridge forwarding is dropped.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 01:07:49 -07:00
Kyle Isom
d56f224359 Add unikernel runtime: run services as Nanos VMs under QEMU/KVM
Implements the hypervisor design's Phase 1: a second runtime.Runtime
backend (QEMU) that runs each service component as a Nanos unikernel VM
instead of a podman container, selected per-component via a new
runtime = "unikernel" service-def field.

- internal/runtime/qemu.go: QEMURuntime. Pull extracts the ELF from the
  OCI image; Run does `ops build` + boots qemu-system-x86_64 with KVM,
  user-mode net port-forwards, QMP control socket and serial console log;
  Stop/Remove/Inspect/List/Logs map onto VM lifecycle + state dir.
- proto/registry/servicedef: add runtime, memory_mb, vcpus fields
  (registry migration 5).
- agent: holds both runtimes; runtimeFor() selects per component;
  listAllContainers() merges containers + VMs so drift/status see both.
  Unikernel runtime auto-enables on nodes with /dev/kvm + ops.

Validated end-to-end on straylight: a test service deploys via
`mcp deploy --direct`, boots as a Nanos unikernel, serves HTTP through
the agent port-forward, and reports running via `mcp status`/`mcp logs`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-11 00:54:49 -07:00
3b08caaa0a Add [master] config section to agent for registration
Heartbeat client now reads master connection settings from the agent
config ([master] section) with env var fallback. Includes address,
ca_cert, token_path, and role fields.

Agent's Run() creates and starts the heartbeat client automatically
when [master] is configured.

Tested on all three nodes: rift (master), svc (edge), orion (worker)
all registered with the master and sending heartbeats every 30s.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
v0.11.1
2026-04-04 13:53:15 -07:00
6351b68ef6 Add agent registration, heartbeats, and monitoring (Phase 4)
Master side:
- Register RPC: identity-bound (agent-rift → rift), allowlist check,
  max nodes limit, upserts node in registry, updates agent pool
- Heartbeat RPC: derives node name from MCIAS identity (not request),
  updates container count and last-heartbeat timestamp
- HeartbeatMonitor: background goroutine checks for missed heartbeats
  (90s threshold), probes agents via HealthCheck, marks unhealthy

Agent side:
- HeartbeatClient: connects to master via env vars (MCP_MASTER_ADDRESS,
  MCP_MASTER_CA_CERT, MCP_MASTER_TOKEN_PATH), registers on startup
  with exponential backoff, sends heartbeats every 30s

Proto: added Register and Heartbeat RPCs + messages to master.proto.

Architecture v2 Phase 4.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
v0.11.0
2026-04-04 12:00:31 -07:00
fa4d022bc1 Add boot sequencing to agent
The agent reads [[boot.sequence]] stages from its config and starts
services in dependency order before accepting gRPC connections. Each
stage waits for its services to pass health checks before proceeding:

- tcp: TCP connect to the container's mapped port
- grpc: standard gRPC health check

Foundation stage (stage 0): blocks and retries indefinitely if health
fails — all downstream services depend on it.
Non-foundation stages: log warning and proceed on failure.

Uses the recover logic to start containers from the registry, then
health-checks to verify readiness.

Config example:
  [[boot.sequence]]
  name = "foundation"
  services = ["mcias", "mcns"]
  timeout = "120s"
  health = "tcp"

Architecture v2 Phase 4 feature.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
v0.10.6
2026-04-04 11:53:11 -07:00
9d543998dc Add mcp-agent recover command
Recreates containers from the agent's SQLite registry when podman's
database is lost (UID change, podman reset, reboot). For each service
with desired_state="running" that doesn't have a running container:

- Removes any stale container with the same name
- Recreates the container from the stored spec (image, ports, volumes,
  cmd, network, user, restart policy)
- Allocates route ports and injects PORT env vars
- Re-registers mc-proxy routes
- Provisions TLS certs for L7 routes

Does NOT pull images — assumes local cache.

Root cause action item from the 2026-04-03 UID incident.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
v0.10.5
2026-04-04 11:50:31 -07:00
f9f6f339f4 Add multi-address fallback for node connectivity
NodeConfig and MasterNodeConfig gain an optional addresses[] field
for fallback addresses tried in order after the primary address.
Provides resilience when Tailscale DNS is down or a node is only
reachable via LAN.

- dialAgentMulti: tries each address with a 3s health check, returns
  first success
- forEachNode: uses multi-address dialing
- AgentPool.AddNodeMulti: master tries all addresses when connecting
- AllAddresses(): deduplicates primary + fallback addresses

Config example:
  [[nodes]]
  name = "rift"
  address = "rift.scylla-hammerhead.ts.net:9444"
  addresses = ["100.95.252.120:9444", "192.168.88.181:9444"]

Existing configs without addresses[] work unchanged.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
v0.10.4
2026-04-03 09:45:50 -07:00
5da307cab5 Add Dockerfile and docker-master build target
Two-stage build: golang:1.25-alpine builder, alpine:3.21 runtime.
Produces a minimal container image for mcp-master.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
v0.10.3
2026-04-02 22:52:10 -07:00
22a836812f Add public, tier, node fields to ServiceDef
RouteDef gains Public field (bool) for edge routing. ServiceDef gains
Tier field. Node validation relaxed: defaults to tier=worker when both
node and tier are empty (v2 compatibility).

ToProto/FromProto updated to round-trip all new fields. Without this,
public=true in TOML was silently dropped and edge routing never triggered.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
v0.10.2
2026-04-02 22:42:00 -07:00
9918859705 Resolve node hostname to IP for DNS registration
Node addresses may be Tailscale DNS names (e.g., rift.scylla-hammerhead.ts.net:9444)
but MCNS needs an IPv4 address for A records. The master now resolves
the hostname via net.LookupHost before passing it to the DNS client.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
v0.10.1
2026-04-02 20:58:21 -07:00
da59d60c2d Add master integration to CLI deploy and undeploy
- CLIConfig gains optional [master] section with address field
- dialMaster() creates McpMasterServiceClient (same TLS/token pattern)
- deploy: routes through master when [master] configured, --direct
  flag bypasses master for v1-style agent deployment
- undeploy: same master/direct routing pattern
- Master responses show per-step results (deploy, dns, edge)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
v0.10.0
2026-04-02 15:43:51 -07:00
598ea44e0b Add mcp-master binary and build target
New cmd/mcp-master/ entry point following the agent pattern:
cobra CLI with --config, version, and server commands.

Makefile: add mcp-master target, update all and clean targets.
Example config: deploy/examples/mcp-master.toml with all sections.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 15:41:43 -07:00
6fd81cacf2 Add master core: deploy, undeploy, status, placement, DNS
Master struct with Run() lifecycle following the agent pattern exactly:
open DB → bootstrap nodes → create agent pool → DNS client → TLS →
auth interceptor → gRPC server → signal handler.

RPC handlers:
- Deploy: place service (tier-aware), forward to agent, register DNS
  with Tailnet IP, detect public routes, validate against allowed
  domains, coordinate edge routing via SetupEdgeRoute, record placement
  and edge routes in master DB, return structured per-step results.
- Undeploy: undeploy on worker first, then remove edge routes, DNS,
  and DB records. Best-effort cleanup on failure.
- Status: query agents for service status, aggregate with placements
  and edge route info from master DB.
- ListNodes: return all nodes with placement counts.

Placement algorithm: fewest services, ties broken alphabetically.
DNS client: extracted from agent's DNSRegistrar with explicit nodeAddr
parameter (master registers for different nodes).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 15:39:46 -07:00
20735e4b41 Add agent client and connection pool for master
AgentClient wraps a gRPC connection to a single agent with typed
forwarding methods (Deploy, UndeployService, SetupEdgeRoute, etc.).
AgentPool manages connections to multiple agents keyed by node name.

Follows the same TLS 1.3 + token interceptor pattern as cmd/mcp/dial.go
but runs server-side with the master's own MCIAS service token.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 15:35:16 -07:00
3c0b55f9f8 Add master database with nodes, placements, and edge_routes
New internal/masterdb/ package for mcp-master cluster state. Separate
from the agent's registry because the schemas are fundamentally
different (cluster-wide placement vs node-local containers).

Tables: nodes, placements, edge_routes. Full CRUD with tests.
Follows the same Open/migrate pattern as internal/registry/.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 15:26:04 -07:00
78890ed76a Add master config loader
MasterConfig with TOML loading, env overrides (MCP_MASTER_*), defaults,
and validation. Follows the exact pattern of AgentConfig. Includes:
server, database, MCIAS, edge (allowed_domains), registration
(allowed_agents, max_nodes), timeouts, MCNS, bootstrap [[nodes]], and
master service token path.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 15:23:19 -07:00
c5ff5bb63c Add McpMasterService proto and v2 ServiceSpec fields
- New proto/mcp/v1/master.proto: McpMasterService with Deploy, Undeploy,
  Status, ListNodes RPCs and all message types per architecture v2 spec.
- ServiceSpec gains tier (field 5), node (field 6), snapshot (field 7).
- RouteSpec gains public (field 5) for edge routing.
- New SnapshotConfig message (method + excludes).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 15:22:04 -07:00
ddd6f123ab Merge pull request 'Document v2 multi-node architecture in CLAUDE.md' (#3) from claude/update-claude-md-v2-multinode into master 2026-04-02 22:20:19 +00:00
90445507a3 Document v2 multi-node architecture in CLAUDE.md
Add v2 Development section covering multi-node fleet design (master,
agent self-registration, tier-based placement, edge routing). Update
project structure to reflect new agent subsystems (edge_rpc, dns,
proxy, certs).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 15:14:20 -07:00
68d670b3ed Add edge CLI scaffolding for Phase 2 testing
Temporary CLI commands for testing edge routing RPCs directly
(before the master exists):

  mcp edge list -n svc
  mcp edge setup <hostname> -n svc --backend-hostname ... --backend-port ...
  mcp edge remove <hostname> -n svc

Verified end-to-end on svc: setup provisions route in mc-proxy and
persists in agent registry, remove cleans up both, list shows routes
with cert metadata.

Finding: MCNS registers LAN IPs for .svc.mcp. hostnames, not Tailnet
IPs. The v2 master needs to register Tailnet IPs in deploy flow step 3.

These commands will be removed or replaced when the master is built
(Phase 3).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 15:04:12 -07:00
714320c018 Add edge routing and health check RPCs (Phase 2)
New agent RPCs for v2 multi-node orchestration:

- SetupEdgeRoute: provisions TLS cert from Metacrypt, resolves backend
  hostname to Tailnet IP, validates it's in 100.64.0.0/10, registers
  L7 route in mc-proxy. Rejects backend_tls=false.
- RemoveEdgeRoute: removes mc-proxy route, cleans up TLS cert, removes
  registry entry.
- ListEdgeRoutes: returns all edge routes with cert serial/expiry.
- HealthCheck: returns agent health and container count.

New database table (migration 4): edge_routes stores hostname, backend
info, and cert paths for persistence across agent restarts.

ProxyRouter gains CertPath/KeyPath helpers for consistent cert path
construction.

Security:
- Backend hostname must resolve to a Tailnet IP (100.64.0.0/10)
- backend_tls=false is rejected (no cleartext to backends)
- Cert provisioning failure fails the setup (no route to missing cert)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
v0.9.0
2026-04-02 13:13:10 -07:00
fa8ba6fac1 Move ARCHITECTURE_V2.md to metacircular docs
The v2 architecture doc is platform-wide (covers master, agents,
edge routing, snapshots, migration across all nodes). Moved to
docs/architecture-v2.md in the metacircular workspace repo.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 11:09:09 -07:00
f66758b92b Hardcode version in flake.nix
The git fetcher doesn't provide gitDescribe, so the Nix build was
falling through to shortRev and producing commit-hash versions instead
of tag-based ones.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
v0.8.3
2026-03-30 17:46:12 -07:00
09d0d197c3 Add component-level targeting to start, stop, and restart
Allow start/stop/restart to target a single component via
<service>/<component> syntax, matching deploy/logs/purge. When a
component is specified, start/stop skip toggling the service-level
active flag. Agent-side filtering returns NotFound for unknown
components.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 17:26:05 -07:00
52914d50b0 Pass mode, backend-tls, and tls cert/key through route add
The --mode flag was defined but never wired through to the RPC.
Add tls_cert and tls_key fields to AddProxyRouteRequest so L7
routes can be created via mcp route add.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
v0.8.2
2026-03-29 20:44:44 -07:00
bb4bee51ba Add mono-repo consideration to ARCHITECTURE_V2.md open questions
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 20:40:32 -07:00
4ac8a6d60b Add ARCHITECTURE_V2.md for multi-node master/agent topology
Documents the planned v2 architecture: mcp-master on straylight
coordinates deployments across worker (rift) and edge (svc) nodes.
Includes edge routing flow, agent RPCs, migration plan, and
operational issues from v1 that motivate the redesign.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 20:37:24 -07:00
d8f45ca520 Merge explicit ports with route-allocated ports during deploy
Previously, explicit port mappings from the service definition were
ignored when routes were present. Now both are included, allowing
services to have stable external port bindings alongside dynamic
route-allocated ports.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
v0.8.1
2026-03-29 19:28:40 -07:00
95f86157b4 Add mcp route command for managing mc-proxy routes
New top-level command with list, add, remove subcommands. Supports
-n/--node to target a specific node. Adds AddProxyRoute and
RemoveProxyRoute RPCs to the agent. Moves route listing from
mcp node routes to mcp route list.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
v0.8.0
2026-03-29 19:10:11 -07:00
93e26d3789 Add mcp dns and mcp node routes commands
mcp dns queries MCNS via an agent to list all zones and DNS records.
mcp node routes queries mc-proxy on each node for listener/route status,
matching the mcproxyctl status output format.

New agent RPCs: ListDNSRecords, ListProxyRoutes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
v0.7.10
2026-03-29 18:51:53 -07:00
3d2edb7c26 Fall back to podman logs when journalctl is inaccessible
Probe journalctl with -n 0 before committing to it. When the journal
is not readable (e.g. rootless podman without user journal storage),
fall back to podman logs instead of streaming the permission error.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
v0.7.9
2026-03-29 17:54:14 -07:00
bf02935716 Add agent version to mcp node list
Thread the linker-injected version string into the Agent struct and
return it in the NodeStatus RPC. The CLI now dials each node and
displays the agent version alongside name and address.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
v0.7.8
2026-03-29 17:49:49 -07:00
c4f0d7be8e Fix mcp logs permission error for rootless podman journald driver
Rootless podman writes container logs to the user journal, but
journalctl without --user only reads the system journal. Add --user
when the agent is running as a non-root user.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
v0.7.7
2026-03-29 16:46:01 -07:00
4d900eafd1 Derive flake version from git rev instead of hardcoding
Eliminates the manual version bump in flake.nix on each release.
Uses self.shortRev (or dirtyShortRev) since self.gitDescribe is not
yet available in this Nix version. Makefile builds still get the full
git describe output via ldflags.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
v0.7.6
2026-03-28 22:48:44 -07:00
38f9070c24 Add top-level mcp edit command
Shortcut for mcp service edit — opens the service definition in $EDITOR.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 22:44:19 -07:00
67d0ab1d9d Bump flake.nix version to 0.7.5
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 19:40:29 -07:00
7383b370f0 Fix mcp ps showing registry version instead of runtime, error on unknown component
mcp ps now uses the actual container image and version from the runtime
instead of the registry, which could be stale after a failed deploy.

Deploy now returns an error when the component filter matches nothing
instead of silently succeeding with zero results.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
v0.7.5
2026-03-28 19:13:02 -07:00
4c847e6de9 Fix extraneous blank lines in mcp logs output
Skip empty lines from the scanner that result from double newlines
(application slog trailing newline + container runtime newline).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
v0.7.4
2026-03-28 18:22:38 -07:00
14b978861f Add mcp logs command for streaming container logs
New server-streaming Logs RPC streams container output to the CLI.
Supports --tail/-n, --follow/-f, --timestamps/-t, --since.

Detects journald log driver and falls back to journalctl (podman logs
can't read journald outside the originating user session). New containers
default to k8s-file via mcp user's containers.conf.

Also adds stream auth interceptor for the agent gRPC server (required
for streaming RPCs).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
v0.7.3
2026-03-28 17:54:48 -07:00
18365cc0a8 Document system account auth model in ARCHITECTURE.md
Replaces the "admin required for all operations" model with the new
three-tier identity model: human operators for CLI, mcp-agent system
account for infrastructure automation, admin reserved for MCIAS-level
administration. Documents agent-to-service token paths and per-service
authorization policies.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 16:11:08 -07:00
86d516acf6 Drop admin requirement from agent interceptor, reject guests
The agent now accepts any authenticated user or system account, except
those with the guest role. Admin is reserved for MCIAS account management
and policy changes, not routine deploy/stop/start operations.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
v0.7.2
2026-03-28 16:07:17 -07:00
dd167b8e0b Auto-login to MCR before image push using CLI token
mcp build and mcp deploy (auto-build path) now authenticate to the
container registry using the CLI's stored MCIAS token before pushing.
MCR accepts JWTs as passwords, so this works with both human and
service account tokens. Falls back silently to existing podman auth.

Eliminates the need for a separate interactive `podman login` step.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
v0.7.1
2026-03-28 15:13:35 -07:00
41437e3730 Use mcdsl/terminal.ReadPassword for secure password input
Replaces raw bufio.Scanner password reading (which echoed to terminal)
with the new mcdsl terminal package that suppresses echo via x/term.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
v0.7.0
2026-03-28 11:11:35 -07:00
cedba9bf83 Fix mcp ps uptime: parse StartedAt from podman ps JSON
List() was not extracting the StartedAt field from podman's JSON
output, so LiveCheck always returned zero timestamps and the CLI
showed "-" for every container's uptime.

podman ps --format json includes StartedAt as a Unix timestamp
(int64). Parse it into ContainerInfo.Started so the existing
LiveCheck → CLI uptime display chain works.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 22:56:39 -07:00
f06ab9aeb6 Bump flake version to 0.6.0
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 21:46:23 -07:00
f932dd64cc Add undeploy command: full inverse of deploy
Implements `mcp undeploy <service>` which tears down all infrastructure
for a service: removes mc-proxy routes, DNS records, TLS certificates,
stops and removes containers, releases allocated ports, and marks the
service inactive.

This fills the gap between `stop` (temporary pause) and `purge` (registry
cleanup). Undeploy is the complete teardown that returns the node to the
state before the service was deployed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
v0.6.0
2026-03-27 21:45:42 -07:00