Add mcp build command and deploy auto-build

Extends MCP to own the full build-push-deploy lifecycle. When deploying,
the CLI checks whether each component's image tag exists in the registry
and builds/pushes automatically if missing and build config is present.

- Add Build, Push, ImageExists to runtime.Runtime interface (podman impl)
- Add mcp build <service>[/<image>] command
- Add [build] section to CLI config (workspace path)
- Add path and [build.images] to service definitions
- Wire auto-build into mcp deploy before agent RPC
- Update ARCHITECTURE.md with runtime interface and deploy auto-build docs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-27 01:34:25 -07:00
parent d7f18a5d90
commit 8b1c89fdc9
10 changed files with 284 additions and 1 deletions

View File

@@ -299,6 +299,12 @@ chain:
If neither exists (first deploy, no file), the deploy fails with an error
telling the operator to create a service definition.
Before pushing to the agent, the CLI checks that each component's image
tag exists in the registry. If a tag is missing and a `[build]` section
is configured, the CLI builds and pushes the image automatically (same
logic as `mcp sync` auto-build, described below). This makes `mcp deploy`
a single command for the bump-build-push-deploy workflow.
The CLI pushes the resolved spec to the agent. The agent records it in its
registry and executes the deploy. The service definition file on disk is
**not** modified -- it represents the operator's declared intent, not the
@@ -656,6 +662,29 @@ The agent runs as a dedicated `mcp` system user. Podman runs rootless under
this user. All containers are owned by `mcp`. The NixOS configuration
provisions the `mcp` user with podman access.
#### Runtime Interface
The `runtime.Runtime` interface abstracts the container runtime. The agent
(and the CLI, for build operations) use it for all container operations.
| Method | Used by | Purpose |
|--------|---------|---------|
| `Pull(image)` | Agent | `podman pull <image>` |
| `Run(spec)` | Agent | `podman run -d ...` |
| `Stop(name)` | Agent | `podman stop <name>` |
| `Remove(name)` | Agent | `podman rm <name>` |
| `Inspect(name)` | Agent | `podman inspect <name>` |
| `List()` | Agent | `podman ps -a` |
| `Build(image, contextDir, dockerfile)` | CLI | `podman build -t <image> -f <dockerfile> <contextDir>` |
| `Push(image)` | CLI | `podman push <image>` |
| `ImageExists(image)` | CLI | `podman manifest inspect docker://<image>` (checks remote registry) |
The first six methods are used by the agent during deploy and monitoring.
The last three are used by the CLI during `mcp build` and `mcp deploy`
auto-build. They are on the same interface because the CLI uses the local
podman installation directly -- no gRPC RPC needed, since builds happen
on the operator's workstation, not on the deployment node.
#### Deploy Flow
When the agent receives a `Deploy` RPC:
@@ -1223,6 +1252,7 @@ mcp/
│ ├── mcp/ CLI
│ │ ├── main.go
│ │ ├── login.go
│ │ ├── build.go build and push images
│ │ ├── deploy.go
│ │ ├── lifecycle.go stop, start, restart
│ │ ├── status.go list, ps, status