fleet-mcp

module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 18, 2026 License: MIT

README

Three connected sandboxes

fleet

Let your coding agent choose which machine it runs on.

An MCP server plus a small cross-platform daemon that give an agent CLI a fleet of execution targets — exec, file ops, and process supervision that work like the tools it already has, except they run on a machine you designate instead of your laptop.

[!WARNING] fleet-agent is a remote code execution service. That is its purpose, not a caveat. Read docs/security.md before installing it anywhere.

[!NOTE] AI;DR: This software was entirely developed using LLMs. Please use IP-based allow-listing to prevent unauthorized parties from gaining remote code execution on the machine running the sandbox agent.

What it is

Four binaries, one Go module:

  • fleet-mcp — runs on your workstation. The MCP server your agent talks to. Owns the registry of known sandboxes and the current selection.
  • fleet-agent — runs on every sandbox host. Listens over gRPC, runs commands, and supervises background processes.
  • fleetctl — runs on your workstation. Sets up the CA, mints enrollment tokens, inspects the fleet, and opens an interactive shell on a host with fleetctl shell.
  • fleet-tui — runs on your workstation, and you never type its name. fleetctl tui hands the terminal to it. It is a separate binary so that fleetctl itself does not link a terminal UI; see the note below.

The agent CLI (Claude Code, Cursor, etc.) calls fleet_select to pick a host, then uses the same exec/file/process tools it already knows — they just execute wherever you pointed them.

Install

1. Get the workstation tools:

go install github.com/axelmierczuk/fleet-mcp/cmd/fleet-mcp@latest
go install github.com/axelmierczuk/fleet-mcp/cmd/fleetctl@latest
go install github.com/axelmierczuk/fleet-mcp/cmd/fleet-tui@latest   # for `fleetctl tui`

2. Put the agent on the sandbox host, and give it a config:

curl -fsSL https://raw.githubusercontent.com/axelmierczuk/fleet-mcp/main/install.sh | sh

That downloads the release binary for the platform, checks it against the published checksum, and installs it. Nothing else — no CA, no certificate, no service. Windows uses install.ps1 the same way.

sudo tee /etc/fleet/agent.yaml >/dev/null <<'YAML'
name: "build-box"
listen: "100.83.4.17:8722"    # this host's own address on your private network
tls:
  enabled: false
YAML

That path is Linux's. macOS reads /Library/Application Support/fleet/agent.yaml and Windows %ProgramData%\fleet\agent.yaml; everything else is the same.

Name the interface you mean. With tls.enabled: false the agent refuses to serve on an address that is neither loopback nor private, because on any other address there would be nothing between the port and a shell on the host. Loopback, RFC 1918, unique-local, link-local and CGNAT space — 100.64.0.0/10, where every Tailscale node lives — are permitted. A wildcard bind, a public address, and a hostname it would have to resolve are refused. serve --allow-unauthenticated-public is the only way past that, and the default listen is 0.0.0.0:8722, so a config that omits the line does not start.

Leaving tls.enabled out is not the same as writing false. Unset means "on if this config names a certificate", so a host that enrolled keeps authenticating across an upgrade, and one written like the above never starts asking for a CA.

3. Start it:

sudo fleet-agent service install
sudo fleet-agent service start

On Windows that registers a logon-triggered Scheduled Task in your own session rather than a Windows service. A service runs in session 0 with no operator profile, so it sees none of nvm, rustup, pyenv, cargo, scoop or npm globals — most of PATH on a developer machine, and an agent whose job is running the commands you would type cannot run them. The task stops when you log off; --mechanism service --user <account> is the answer for a machine nobody signs into. See docs/service.md.

4. Point your agent at the MCP server:

{
  "mcpServers": {
    "fleet": {
      "command": "fleet-mcp",
      "args": ["serve"]
    }
  }
}

5. Register the sandbox. There is no CA, so there is no enrollment: nothing is issued and nothing is proved. What is left is giving the host a name, which your agent does with one tool call:

fleet_add(name="build-box", address="100.83.4.17:8722", insecure=true)

insecure has to be said because it cannot be discovered — an agent serving plaintext and one refusing a handshake look identical to a dialer that has not been told. Get it wrong and the connection fails; it never quietly downgrades. The call writes an entry to ~/.config/fleet/registry.yaml, which you can write yourself instead:

version: 1
sandboxes:
  - name: build-box
    address: 100.83.4.17:8722
    insecure: true
    enrolled_at: 2026-08-18T00:00:00Z

That entry is a name this workstation assigned to an address, and the host never proves it. If something else answers there, the fleet will call it build-box and record its commands under that name. On a network that decides who can answer, that is the whole of what a name means.

fleetctl list          # AUTH reads none, and a line under the table says what that means
fleetctl tui           # or watch the whole fleet, its processes and their logs

Done. fleet_list should show build-box.

What the default assumes

Without mTLS the agent's authentication is whatever the network provides, and nothing else. It runs arbitrary commands on its host by design, so on a port something unauthorized can reach, that is unauthenticated remote code execution — and the failure is silent, because an agent that skipped the CA works immediately and looks exactly like a secured one. The precondition is that the network authenticates its peers: a tailnet, a WireGuard mesh, a VPC whose security groups admit only the control plane. On those, the identity check has already been made by something that also encrypts the traffic, and a second identity system buys nothing. If that is not true of your network, use mTLS. docs/security.md → Running without mTLS is the full account.

Setting up mTLS instead

Both ends present certificates issued by a CA you run, and the handshake — not the network — is the boundary. On your workstation:

fleetctl ca init                       # prints the CA fingerprint — keep it
fleetctl ca sign --profile control     # this workstation's own identity
fleetctl serve &                       # enrollment endpoint, :9443 — stop it after
fleetctl enroll mint --name build-box --address build-box.internal:8722

enroll mint prints the command to run on the host, with the token, control address and CA fingerprint already filled in. Paste it there:

curl -fsSL https://raw.githubusercontent.com/axelmierczuk/fleet-mcp/main/install.sh \
  | sh -s -- --token sbx_ey... \
      --control your-workstation:9443 \
      --ca-fingerprint 9F:2C:8A:1E:... \
      --listen 0.0.0.0:8722

It verifies the release checksum, enrolls the host — the private key is generated there and never leaves it — writes tls.enabled: true into the config, and registers a system service when run as root. Windows gets the PowerShell form, printed alongside.

Enrollment registers the sandbox for you, so there is no fleet_add step, and 0.0.0.0 is an ordinary listen address here: the listen guard applies only when the agent authenticates nobody.

Then stop fleetctl serve, and check the fleet:

fleetctl list          # AUTH reads mtls

The long form, including rotating the CA and adding more hosts, is docs/quickstart.md.

Why fleet-tui is its own binary

fleetctl tui is one command, and it stays one command — this is only about what gets linked into what.

The view is built on bubbletea, whose package init asks the terminal for its background colour and reads for up to five seconds waiting for the answer. A package init runs in every process that links the package, whatever subcommand was typed, so linking the view into fleetctl made fleetctl version cost five seconds on any terminal that does not answer — a bare pty, a CI log, a serial console — and swallow whatever was typed while it waited. Nothing inside the process can opt out; every escape hatch the library has is read during that init, before any of our code runs.

So the view lives in fleet-tui, and fleetctl tui hands it the terminal with its command line unchanged. There is nothing extra to configure: fleet-tui is fleetctl's own command tree with the view linked in, reading the same config directory, the same CA and the same registry.

Tools

Twenty tools across five groups — see docs/tools.md for full schemas.

  • Fleetfleet_list, fleet_select, fleet_add, fleet_remove, fleet_info
  • Executefleet_exec
  • Background processesfleet_process_start, fleet_process_list, fleet_process_logs, fleet_process_signal, fleet_process_restart
  • Filesfleet_read, fleet_write, fleet_edit, fleet_ls, fleet_glob, fleet_grep
  • Bridgefleet_transfer, fleet_forward, fleet_socks

fleet_select sets a sticky default sandbox (persisted per client), and every targeted tool can override it with an optional sandbox argument. Every result echoes back which sandbox actually served it, so the agent never silently acts on the wrong host.

Security

  • Transport authentication is a decision you make. fleet-agent enroll writes tls.enabled: true, and both ends then present certificates from the fleet CA. A config with no certificates in it serves plaintext instead, for a network that already authenticates its peers — and then the agent refuses any address that is neither loopback nor private, says so at every start, shows as auth none in fleetctl list, and records every command against the address it came from rather than a verified identity.
  • Keys never move. Enrollment is a CSR exchange against a single-use token.
  • No shell by default. Commands take an argv, not a string.
  • Caps and audit. Wall-clock timeouts, output limits, append-only JSONL log of every exec and write.

fleet does not sandbox — it's remote execution against a host you designate. Isolation is whatever that host already provides (VM, container, dedicated machine). Full threat model in docs/security.md.

Development

make tools        # pinned buf, protoc plugins, golangci-lint into .tools/
make proto        # regenerate Go from proto/
make build        # every binary
make check        # the gate: proto, vet and lint per GOOS, tests under -race
make test-norace  # the unit tests without -race, as CI and the release gate run them

Go 1.25, modelcontextprotocol/go-sdk, gRPC/protobuf, buf for proto tooling, GoReleaser for release builds.

Status

Early. Protocol schema and build pipeline are in place; implementation is tracked in #29. See docs/architecture.md for the full design.

License

MIT. See LICENSE.

Directories

Path Synopsis
cmd
fleet-agent command
Command fleet-agent is the daemon that runs on each sandbox host.
Command fleet-agent is the daemon that runs on each sandbox host.
fleet-mcp command
Command fleet-mcp is the MCP server that agent CLIs launch over stdio.
Command fleet-mcp is the MCP server that agent CLIs launch over stdio.
fleet-tui command
Command fleet-tui draws `fleetctl tui`.
Command fleet-tui draws `fleetctl tui`.
fleetctl command
Command fleetctl is the operator CLI for the fleet control plane.
Command fleetctl is the operator CLI for the fleet control plane.
gen
internal
agent
Package agent hosts the fleet-agent daemon: configuration, the gRPC server — mutually authenticated unless the operator has deliberately said otherwise, see TLSConfig.Enabled — and the lifecycle every M1 service plugs into.
Package agent hosts the fleet-agent daemon: configuration, the gRPC server — mutually authenticated unless the operator has deliberately said otherwise, see TLSConfig.Enabled — and the lifecycle every M1 service plugs into.
agent/exec
Package exec implements ExecService: one-shot command execution with streaming output, wall-clock timeouts, and output caps.
Package exec implements ExecService: one-shot command execution with streaming output, wall-clock timeouts, and output caps.
agent/forward
Package forward implements sandboxd.v1.ForwardService: the sandbox half of `ssh -L`.
Package forward implements sandboxd.v1.ForwardService: the sandbox half of `ssh -L`.
agent/fs
Package fs implements FileService: read, write, edit, list, stat, glob, grep, and the three path-management RPCs — make directory, remove and move.
Package fs implements FileService: read, write, edit, list, stat, glob, grep, and the three path-management RPCs — make directory, remove and move.
agent/host
Package host implements HostService: platform and resource introspection, toolchain detection, and health reporting.
Package host implements HostService: platform and resource introspection, toolchain detection, and health reporting.
agent/process
Package process implements ProcessService: the supervisor for long-running background processes.
Package process implements ProcessService: the supervisor for long-running background processes.
agent/shell
Package shell implements sandboxd.v1.ShellService: one interactive pseudo-terminal session per stream.
Package shell implements sandboxd.v1.ShellService: one interactive pseudo-terminal session per stream.
cli
Package cli holds the output plumbing shared by the fleet binaries.
Package cli holds the output plumbing shared by the fleet binaries.
cli/fleetagent
Package fleetagent implements the fleet-agent CLI: enrollment, the daemon itself, and registration with the platform's service manager.
Package fleetagent implements the fleet-agent CLI: enrollment, the daemon itself, and registration with the platform's service manager.
cli/fleetctl
Package fleetctl implements the operator CLI for the fleet control plane: certificate authority management, enrollment token minting, the enrollment listener, and the operator's view of the fleet.
Package fleetctl implements the operator CLI for the fleet control plane: certificate authority management, enrollment token minting, the enrollment listener, and the operator's view of the fleet.
cli/fleetmcp
Package fleetmcp implements the fleet-mcp CLI: the MCP server an agent CLI launches over stdio.
Package fleetmcp implements the fleet-mcp CLI: the MCP server an agent CLI launches over stdio.
client
Package client dials fleet-agent instances over gRPC — mutually authenticated unless a sandbox is registered as insecure — pooling connections and tracking health so fleet_list can report status without a round trip per call.
Package client dials fleet-agent instances over gRPC — mutually authenticated unless a sandbox is registered as insecure — pooling connections and tracking health so fleet_list can report status without a round trip per call.
fsutil
Package fsutil holds the small filesystem primitives fleet's on-disk state depends on: writing a file atomically, and taking an advisory lock across processes.
Package fsutil holds the small filesystem primitives fleet's on-disk state depends on: writing a file atomically, and taking an advisory lock across processes.
legacypath
Package legacypath resolves the environment variables and directories that the sandboxd → fleet rebrand renamed, preferring the new name and falling back to the old one when only the old one is actually there.
Package legacypath resolves the environment variables and directories that the sandboxd → fleet rebrand renamed, preferring the new name and falling back to the old one when only the old one is actually there.
mcpserver
Package mcpserver hosts the MCP server: transport setup, tool registration, and the wiring that connects the fleet registry and the gRPC client pool to the tool handlers.
Package mcpserver hosts the MCP server: transport setup, tool registration, and the wiring that connects the fleet registry and the gRPC client pool to the tool handlers.
mcpserver/mcperr
Package mcperr turns the errors a sandbox agent returns into messages a model can act on.
Package mcperr turns the errors a sandbox agent returns into messages a model can act on.
mcpserver/selection
Package selection resolves which sandbox a tool call targets.
Package selection resolves which sandbox a tool call targets.
mcpserver/tools
Package tools implements the MCP tool handlers.
Package tools implements the MCP tool handlers.
platform
Package platform isolates the OS-specific behaviour the agent depends on: process groups versus Windows job objects, PTY allocation, signal translation, process introspection, path normalisation, and resource reporting.
Package platform isolates the OS-specific behaviour the agent depends on: process groups versus Windows job objects, PTY allocation, signal translation, process introspection, path normalisation, and resource reporting.
registry
Package registry persists the sandbox inventory and the sticky selection to the user config directory.
Package registry persists the sandbox inventory and the sticky selection to the user config directory.
security/ca
Package ca implements the local certificate authority: key generation, CSR signing, and rotation.
Package ca implements the local certificate authority: key generation, CSR signing, and rotation.
security/enroll
Package enroll implements the enrollment protocol: minting single-use tokens and serving EnrollmentService.
Package enroll implements the enrollment protocol: minting single-use tokens and serving EnrollmentService.
security/jail
Package jail confines filesystem access to a sandbox's allowed roots.
Package jail confines filesystem access to a sandbox's allowed roots.
security/policy
Package policy evaluates per-sandbox execution rules: command allow and deny lists, resource caps, and the audit trail.
Package policy evaluates per-sandbox execution rules: command allow and deny lists, resource caps, and the audit trail.
socks
Package socks implements the SOCKS5 server half of `fleetctl socks` and fleet_socks.
Package socks implements the SOCKS5 server half of `fleetctl socks` and fleet_socks.
tui
Package tui is the full-screen operator view of the fleet behind `fleetctl tui`: four panes — fleet, processes, logs, detail — over the same data every other view of the fleet reports.
Package tui is the full-screen operator view of the fleet behind `fleetctl tui`: four panes — fleet, processes, logs, detail — over the same data every other view of the fleet reports.
tunnel
Package tunnel carries one local TCP connection over one sandboxd.v1.ForwardService stream.
Package tunnel carries one local TCP connection over one sandboxd.v1.ForwardService stream.
version
Package version carries build metadata stamped in at link time.
Package version carries build metadata stamped in at link time.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL