使用说明
remote-exec-mcp
remote-exec-mcp is a remote-first MCP server for running Codex-style local
system tools on configured Linux, macOS, and Windows machines. Agents connect to
one broker, choose an explicit target, and use familiar tools for command
execution, stdin, patching, image reads, file transfer, and TCP/UDP forwarding.
The tool interface is influenced by Codex, but this repository is a separate broker plus daemon implementation.
Read This First
- Start with
configs/broker.example.tomlandconfigs/daemon.example.toml. - Use
crates/remote-exec-daemon-cpp/config/daemon-cpp.example.inifor the standalone C++ daemon. - Use
skills/using-remote-exec-mcp/SKILL.mdfor agent-facing tool guidance. - Treat
docs/as historical planning and audit context unless a task explicitly asks for maintenance there. - The stable external contracts are the MCP tool schemas, operator config
files, this README,
AGENTS.md, and the user-facing skill.
Quick Start
Generate development certificates for Rust TLS targets:
cargo run -p remote-exec-admin -- certs dev-init \
--out-dir ./remote-exec-certs \
--target builder-a
Start a Rust daemon:
cargo run -p remote-exec-daemon -- configs/daemon.example.toml
Start the broker:
cargo run -p remote-exec-broker -- configs/broker.example.toml
List configured targets through the CLI:
cargo run -p remote-exec-broker --bin remote-exec -- \
--broker-config configs/broker.example.toml \
list-targets
Run the C++ daemon when you need a smaller daemon or legacy Windows coverage. It supports optional OpenSSL or LibreSSL mutual TLS, POSIX BoringSSL mutual TLS, and explicit plain HTTP:
make -C crates/remote-exec-daemon-cpp check-posix
crates/remote-exec-daemon-cpp/build/remote-exec-daemon-cpp \
crates/remote-exec-daemon-cpp/config/daemon-cpp.example.ini
Public Surface
Implemented public MCP tools (prefixed with remote_ by default):
| Tool | Purpose |
|---|---|
remote_list_targets |
Report configured targets and cached daemon metadata. |
remote_exec_command |
Start a command on one target. |
remote_write_stdin |
Write to or poll a live command session. |
remote_apply_patch |
Apply a Codex-style patch on one target. |
remote_view_image |
Read an image from one target. |
remote_transfer_files |
Transfer files or directory trees between local and remote endpoints. |
remote_forward_ports |
Open, list, or close TCP/UDP forwards between two sides. |
Default-hidden file tools are available only when explicitly enabled under
[tools.file] in broker config:
remote_readremote_writeremote_edit
Components
| Component | Role |
|---|---|
remote-exec-broker |
Public MCP server over stdio or streamable HTTP. It validates targets, routes calls, owns public session_id and forward_id namespaces, and can expose local as the broker host or as a relay to one configured remote. |
remote-exec |
CLI client built from the broker crate. It can run against a config in-process or a streamable-HTTP broker. |
apply_patch |
Standalone local CLI built by both the Rust host crate and C++ daemon build. It reads a Codex-style patch from standard input. --help prints built-in usage; --help --help-file PATH prints the supplied help file instead. Without --help, --help-file PATH is ignored. |
remote-exec-daemon |
Rust per-machine daemon. It supports mutual TLS by default, optional plain HTTP, exec, patch, image, transfer, sandbox checks, and v4 port-forward tunnels. |
remote-exec-host |
Shared Rust host runtime reused by the Rust daemon and broker-host local behavior. |
remote-exec-daemon-cpp |
Standalone C++11 daemon with optional OpenSSL or LibreSSL mTLS, POSIX BoringSSL mTLS, explicit plain HTTP, and POSIX and legacy Windows build paths. |
remote-exec-proto |
Public MCP schemas, broker-daemon RPC schemas, path and sandbox helpers, and port-forward protocol types. |
remote-exec-admin |
Certificate/bootstrap CLI. |
remote-exec-pki |
Reusable certificate generation, manifest, and private-key write helpers. |
Runtime Model
Agents talk only to the broker. Each configured remote target points at one daemon. The broker performs target validation, identity checks, routing, result formatting, and runtime ID mapping.
Important invariants:
- Target selection is part of the security boundary.
- Configured remote targets may not be named
local. - A session, file operation, or forward opened for one target is not valid for another target.
- Public
session_idandforward_idvalues are broker-owned opaque tokens. They are not daemon process IDs, daemon-local session IDs, tunnel IDs, or stream IDs. remote_list_targetsreports configured targets and cached daemon metadata. It may perform a short bounded status refresh for targets without currently available metadata, but it does not expose stale daemon metadata while a target is unavailable. Each entry includeshealth_status:unknown,healthy,maybe_unhealthy, orunhealthy. The existinghealthyboolean remains the backward-compatible availability indicator.- Public
supports_port_forwardmeans the target reported forwarding support and the broker verified a supported tunnel protocol version. remote_list_targetsalso reportssupports_execandsupports_apply_patch. These are daemon policy capabilities; missing fields from older daemons mean both operations are supported for compatibility.- Temporarily unreachable targets can remain configured. Broker startup may succeed and verify a target before the first forwarded call.
- Broker-daemon RPC uses HTTP/1.1 JSON. Port forwarding uses daemon-private HTTP/1.1 Upgrade tunnels.
- Direct targets and daemon-initiated reverse targets preserve the same public MCP behavior and broker-owned ID namespaces.
remote_forward_portsv4 usesX-Remote-Exec-Port-Tunnel-Version: 4. Frame numbers 20 and 21 are reserved asForwardRecoveringandForwardRecovered; public recovery state is reported through broker-ownedforward_ports listfields.
Live exec sessions and live port forwards are in-memory runtime state. Broker
restart drops public session_id and forward_id mappings. Daemon restart
drops daemon-local command sessions and forwarded sockets.
Configuration
Use the example configs as the canonical shape:
| File | Covers |
|---|---|
configs/broker.example.toml |
MCP transport, targets, TLS client credentials, reverse listener, embedded or relay local, host sandbox, hidden file tools, transfer limits, and forwarding limits. |
configs/daemon.example.toml |
Rust daemon target name, listen/reverse mode, default workdir, TLS or HTTP transport, bearer auth, shell/PTY policy, sandbox, transfer, yield-time, and forwarding limits. |
crates/remote-exec-daemon-cpp/config/daemon-cpp.example.ini |
C++ daemon listen address, direct/reverse TLS or HTTP transport, default workdir, bearer auth, request/session/forwarding limits, yield-time limits, and sandbox. |
Common rules:
default_workdirmust already exist when a broker[local]target or daemon starts.- Rust broker and Rust daemon targets use TLS by default.
- Plain HTTP targets must be configured with
allow_insecure_http = truein the broker. - The C++ daemon defaults to
TLS=auto. POSIX builds compile and link TLS when OpenSSL 1.0.2 or newer, LibreSSL 2.7.1 or newer, or BoringSSL is available; the detected compatible library is used automatically. Windows XP and newer targets enable TLS automatically, while older Windows targets default to TLS off. - Plain C++ daemon targets require
allow_insecure_http = trueand should usually use bearer auth when they are not isolated by another trusted transport. - Reverse mode keeps a bounded adaptive lane pool because transfers and port-forward upgrades can occupy HTTP/1.1 connections for long periods.
- Both daemons support reverse TLS and explicit insecure HTTP. The C++ daemon requires an OpenSSL- or LibreSSL-backed build, or a BoringSSL-backed POSIX build, for TLS.
On macOS, use an existing directory such as /Users/you/work in place of the
examples' /srv/work paths. The Rust broker, Rust daemon, and C++ daemon support
native command execution, PTYs, file operations, transfers, and TCP/UDP forwards.
The system sh, Bash, and zsh load their login profiles when login is omitted
or true; set login: false to skip profile initialization. C++ builds use the
Xcode Command Line Tools' c++ and make through the existing all-posix and
check-posix targets.
TLS And Bootstrap
Rust broker and Rust daemon targets use mutual TLS by default:
- broker feature
broker-tlsis enabled by default - daemon feature
tlsis enabled by default - the daemon presents a server certificate signed by the configured CA
- the broker presents a client certificate signed by the configured CA
- both sides trust the configured CA
If the broker is built without broker-tls, it rejects https:// daemon
targets and https:// broker URLs. If the Rust daemon is built without tls,
it only supports transport = "http".
Generated broker and daemon leaf certificates are usable for both direct and reverse TLS. The broker leaf has client-auth usage for direct daemon requests and server-auth usage for the reverse listener, with a DNS SAN matching the broker common name. Each daemon leaf has server-auth usage for direct mode and client-auth usage for reverse lane registration, with its common name matching the configured target. Plain reverse mode requires the configured bearer token for lane registration and normal RPC authentication.
Development bootstrap:
cargo run -p remote-exec-admin -- certs dev-init \
--out-dir ./remote-exec-certs \
--target builder-a \
--target builder-b
Reuse an existing CA:
cargo run -p remote-exec-admin -- certs dev-init \
--out-dir ./remote-exec-certs-next \
--target builder-c \
--reuse-ca-from-dir ./remote-exec-certs
Add daemon SANs when the broker connects by DNS name or non-localhost IP:
cargo run -p remote-exec-admin -- certs dev-init \
--out-dir ./remote-exec-certs \
--target builder-a \
--san builder-a=dns:builder-a.example.com \
--san builder-a=ip:10.0.0.12
dev-init writes ca.pem, ca.key, broker.pem, broker.key,
daemons/<target>.pem, daemons/<target>.key, reverse-mode certificates under
reverse/, and certs-manifest.json.
Certificate notes:
- If no SAN is provided, generated daemon certs default to
DNS:localhostandIP:127.0.0.1. - Generated private keys are written with restricted permissions: Unix
0600; Windows DACL for current user, local Administrators, and LocalSystem. expected_daemon_nameshould match the daemon's configuredtarget.skip_server_name_verification = truestill validates CA, key usage, and expiry, but skips URL host to certificate SAN matching.pinned_server_cert_pemandtls.pinned_client_cert_pemadd exact leaf certificate pins on top of normal CA validation.- Bearer auth authenticates requests but does not add confidentiality or integrity on plain HTTP.
Running
Start a Rust daemon:
cargo run -p remote-exec-daemon -- configs/daemon.example.toml
Start the broker over stdio:
cargo run -p remote-exec-broker -- configs/broker.example.toml
Expose the broker over streamable HTTP:
[mcp]
transport = "streamable_http"
listen = "127.0.0.1:8787"
path = "/mcp"
MCP tool names are prefixed with remote_ by default. Set
prepend_tool_names = false in the broker config to retain legacy unprefixed
MCP names; this does not change the remote-exec CLI subcommands.
Run the C++ daemon:
make -C crates/remote-exec-daemon-cpp
crates/remote-exec-daemon-cpp/build/remote-exec-daemon-cpp \
crates/remote-exec-daemon-cpp/config/daemon-cpp.example.ini
CLI Client
The remote-exec CLI keeps its existing subcommand names and automatically
uses either prefixed or legacy MCP tool names advertised by an HTTP broker.
Use a broker config in-process:
cargo run -p remote-exec-broker --bin remote-exec -- \
--broker-config configs/broker.example.toml \
list-targets
Use a running streamable-HTTP broker:
cargo run -p remote-exec-broker --bin remote-exec -- \
--broker-url http://127.0.0.1:8787/mcp \
list-targets
Common examples:
cargo run -p remote-exec-broker --bin remote-exec -- \
--broker-config configs/broker.example.toml \
exec --target builder-a --workdir /srv/project 'cargo test'
cargo run -p remote-exec-broker --bin remote-exec -- \
--broker-config configs/broker.example.toml \
transfer-files \
--source local:/tmp/source.txt \
--destination builder-a:/tmp/dest.txt \
--overwrite replace \
--create-parent
cargo run -p remote-exec-broker --bin remote-exec -- \
--broker-url http://127.0.0.1:8787/mcp \
forward-ports open \
--listen-side local \
--connect-side builder-a \
--forward tcp:127.0.0.1:15432=127.0.0.1:5432
Use --json for normalized JSON output. Use apply-patch --input-file - and
write-stdin --chars-file - to read payloads from stdin.
CLI exit codes are:
| Code | Meaning |
|---|---|
0 |
Success. |
2 |
Usage or input error. |
3 |
Broker config load/build error. |
4 |
Streamable-HTTP connection or transport error. |
5 |
MCP tool error returned by the broker. |
--broker-config mode builds broker state for one CLI invocation. Persistent
port forwards require a long-running broker, so prefer --broker-url for
forward-ports open/list/close workflows.
Tool Behavior
remote_exec_command:
- runs one command on one target
- returns
session_idwhen still running - merges stdout/stderr order into one public
outputfield for non-TTY exec - applies daemon or embedded broker-local
yield_time_mspolicy - truncates output by approximate token budget, where one token is about four UTF-8 bytes
remote_write_stdin:
- writes to or polls a broker-owned live session
- can route by
session_idalone - rejects mismatched
targetif supplied - accepts
pty_sizefor live TTY resize before writing or polling - normalizes lost daemon sessions into the usual unknown-process error
remote_apply_patch:
- applies Codex-style patches on one target
- preserves existing
LFversusCRLFstyle for updated files - supports the documented
*** End of Filemarker - accepts Codex parser tolerances for empty envelopes, blank update context,
blank separators after
*** End of File, and Unicode whitespace around patch control lines - accepts
*** Environment ID: <id>as metadata returned by the daemon; it never overrides the explicitly selectedtarget - parses the complete patch before writing; malformed patches make no changes
- executes valid patch actions sequentially and is non-transactional across actions, so a later filesystem, sandbox, decode, or hunk-match failure can leave earlier actions applied
- writes directly to the target for
*** Add Fileand normal in-place*** Update Fileactions, following symlinks; all update hunks are resolved before writing, but an underlying write failure can leave a partially written file - can use experimental target encoding autodetection when enabled in config
Target encoding autodetection covers UTF-8 with or without a byte-order mark, UTF-16LE/BE with or without a byte-order mark, and Shift_JIS, EUC-JP, GB18030 (which also decodes GBK and GB2312), Big5, EUC-KR, and the single-byte code pages Windows-1250 through Windows-1258, ISO-8859-2 through ISO-8859-16, KOI8-R, KOI8-U, Macintosh, and IBM866. Both daemons verify a detected encoding by re-encoding the decoded text and comparing it against the original bytes, so a wrong guess is reported as a decode failure rather than silently rewriting the file. An edit that introduces a character the detected encoding cannot represent fails instead of substituting a replacement character.
The C++ daemon can also be built without this feature (TEXT_ENCODING=off), in
which case the file tools and apply_patch require UTF-8.
Standalone apply_patch executables print the action and underlying filesystem
or patch-engine error to stderr. If a runtime write/remove error occurs after
earlier actions complete, stdout reports Partial success and lists those
completed actions; the process still exits unsuccessfully.
Default-hidden file tools:
remote_readreads one text file and returns text output onlyread.file_path,write.file_path, andedit.file_pathresolve relative to the target default workdir unless they are target-native absolute pathsread.offsetis one-based; omitted or0means line1read.limitdefaults totools.file.default_read_limit_linesremote_writeoverwrites an existing file or creates a new fileremote_editreplacesold_stringwithnew_string; ifold_stringmatches more than once, the call fails unlessreplace_all = true- these tools are not listed or callable unless enabled under
[tools.file]
remote_view_image:
- reads an image from one target
- accepts
detailfor compatibility but does not use it - preserves PNG, JPEG, and WebP bytes without resizing
- Rust daemon transcodes BMP, GIF, ICO, PNM (including PPM), and TGA to PNG; the C++ daemon supports passthrough PNG, JPEG, and WebP only
remote_transfer_files:
- supports
local -> remote,remote -> local,remote -> remote, andlocal -> local - accepts either one
sourceor asourcesarray - requires endpoint-native absolute paths
- defaults to
overwrite = "merge",destination_mode = "auto", andsymlink_mode = "preserve" - supports
overwrite = "fail","merge", and"replace" - supports
destination_mode = "exact"and"into_directory" - supports
symlink_mode = "preserve","follow", and"skip" - supports
excludeglob patterns relative to each source root - skips unsupported special files inside directory trees with warnings
- streams multi-source archives through the broker with bounded buffering rather than staging them on disk
- does not expose a public compression option; compression is broker-internal
- uses Zstandard for eligible remote transfers, but skips it when every source
filename has a known already-compressed/container extension such as
.zipor.mp4 - is not transactional; failed transfers can leave partial destination changes
remote_forward_ports:
- supports
action = "open" | "list" | "close" - supports
tcpandudp - opens listeners on
listen_sideand outbound connections/datagrams onconnect_side - allows either side to be a configured target or
"local" - treats bare endpoint
"8080"as"127.0.0.1:8080" - allows non-loopback listen binds such as
"0.0.0.0:8080" - allows
listen_endpointport0; read the result for the actual bound port - requires nonzero
connect_endpointports - reports
phase, side health, generation, reconnect counters, drop counters, and effective limits - treats
phase = "ready"as readiness; legacystatus = "open"can coexist withphase = "reconnecting" - can recover future listen-side traffic after broker-daemon transport loss when the daemon stays alive, but active TCP streams and UDP per-peer connector state are lost
Local Semantics
local is a logical endpoint with three possible configurations:
- With no local configuration,
localis unavailable for exec, stdin, patch, image, and hidden file tools. Transfer endpoints and forwarding sides namedlocalretain their legacy broker-host filesystem/network behavior. - An embedded
[local]table makeslocalan actual broker-host target for exec, stdin, patch, image, hidden file tools, and the host-side transfer and forwarding compatibility paths.host_sandboxapplies to broker-host filesystem access. - A scalar
local = "builder-a"enables relay mode. Every operation addressed tolocal, including exec, stdin, patch, image, hidden file tools, transfers, and both sides of port forwarding, runs through the selected remote daemon. The broker host's filesystem and network are not reachable through this endpoint. The selected configured name is replaced publicly bylocal, sobuilder-ais not a second bypass target. Remote daemon sandbox and limits apply; broker-host sandbox and host transfer limits do not.
The scalar relay form and [local] table are mutually exclusive. The relay
target must be a configured remote target and cannot itself be named local.
Daemon Operation Policies
Rust and C++ daemons accept two independent, default-enabled policy settings:
allow_exec = falsedisables command execution, including both new exec sessions and stdin/write or poll requests for existing sessions.allow_apply_patch = falsedisables the patch RPC while leaving other daemon operations available. If command execution remains enabled, commands can still modify files; this setting is not a general write prohibition.
The daemon advertises both settings through target capabilities, and the broker rejects known-disabled operations before forwarding them.
Trust Model
Selecting a target grants broad access on that machine unless static sandbox config restricts the relevant path-based operation. There is no per-call approval flow and no sandbox selection flow.
Sandbox rules are static allow/deny lists:
- missing
alloworallow = []means allow all denyentries refine the allowed setremote_exec_commandchecks only the resolved startingcwd- command text is not inspected for arbitrary path references
remote_view_imageandremote_readcheck read pathsremote_write,remote_edit, andremote_apply_patchcheck write pathsremote_transfer_fileschecks source read access and destination write access on their respective endpointsremote_forward_portscan bind non-loopback addresses and connect to arbitrary endpoints reachable from each side, subject to configured forwarding limits
Security is based on explicit target selection plus broker-to-daemon mutual TLS for normal Rust targets. Plain HTTP requires explicit opt-in.
Reliability Notes
- Broker startup probes run concurrently and are bounded by
timeouts.startup_probe_ms. - Broker target health refresh runs periodically in the background. One failed
probe marks a target
maybe_unhealthy; a second consecutive failure marks itunhealthy. Both states use the shorter unhealthy interval, and any successful probe restoreshealthy. - Timed-out broker-daemon requests are never replayed.
- After repeated direct-target timeouts without a successful HTTP response, the
broker replaces the target's HTTP client pool. Reverse targets additionally
discard queued idle lanes so the daemon replenishes them. Connection resets
remain warning-level while the target is healthy or
maybe_unhealthy, but are debug-level once repeated probes have marked itunhealthy; a successful daemon response restores warning-level reset logging. remote_exec_commandandremote_write_stdinuse at leastyield_time_msplus a small slow-host margin for their daemon RPC timeout.- Rust daemon and broker-host live exec sessions are capped by
max_open_sessionsand prune older sessions under pressure, preferring completed sessions. forward_ports openis all-or-nothing for a single tool call.- Explicit
forward_ports closereports an error if daemon-side cleanup cannot be confirmed, leaving listed state available for retry or inspection. - If the broker disappears without closing a forward, daemon-side detached listeners and UDP sockets are reclaimed after the reconnect grace window.
- Rust daemon shutdown cancels pending tunnel work and closes live forwarded sockets before exit.
- C++ daemon forwarding bounds worker count, tunnel I/O, queued bytes, UDP binds, active TCP streams, retained sessions/listeners, and TCP connect time.
- C++ daemon Windows non-PTY commands are detached from the daemon console.
Its configured default shell,
COMSPEC, and per-commandshellmay name any executable; shell names are not restricted to a built-in list. Recognized shell families keep their argument conventions, and other Windows executables receive/Cfollowed by the command as one argument. Windows 9x/Me commands report completion after process exit and a bounded drain of final output, including when redirected pipes do not report EOF. If output completion arrives later than descendant cleanup, exec calls and stdin polls continue waiting within their remainingyield_time_msbudget. Windows stdin writes are bounded bystdin_write_timeout_ms; a timeout terminates and retires the affected session.
C++ Daemon
The C++ daemon intentionally supports a smaller surface than the Rust daemon:
| Area | C++ daemon behavior |
|---|---|
| Transport | Optional OpenSSL or LibreSSL direct/reverse mTLS, BoringSSL direct/reverse mTLS on POSIX, or explicit plain HTTP. TLS builds use https://...; plain targets use http://... and allow_insecure_http = true. |
| Security | Mutual TLS with OpenSSL 1.0.2 or newer, LibreSSL 2.7.1 or newer, or BoringSSL on POSIX, optional bearer auth, certificate pinning, and static path sandboxing. |
| Exec | C++11 implementation for POSIX and legacy Windows hosts. POSIX PTY is supported when the host can allocate one. GNU/MSVC Windows PTY support depends on vendored winpty. |
| Files | remote_apply_patch, remote_view_image passthrough for PNG/JPEG/WebP, transfer import/export, and the default-hidden remote_read / remote_write / remote_edit with the same semantics and wire error codes as the Rust daemon. |
| Text encoding | Optional. With experimental_apply_patch_target_encoding_autodetect, the file tools and apply_patch decode and rewrite a target file's detected encoding instead of requiring UTF-8. Can be omitted from the binary with TEXT_ENCODING=off. |
| Transfers | File, directory, and broker-built multi-source transfers. No transfer compression. |
| Forwarding | v4 TCP/UDP port-forward tunnel support with daemon-local worker and queue limits. |
| Legacy Windows | GNU paths cover NT 3.x Winsock 1.1, NT 4.0 Winsock 1.1/2, Windows 2000, XP, XP x64, x64 NT-family, and ANSI Windows 9x/Me variants. MSVC covers native, x86 v141_xp, and x64 XP-compatible paths. |
The daemon builds as C++11 on every supported build path. In this repository, "Windows XP-compatible" means using a toolchain that can target XP while still compiling the daemon as C++11.
Common C++ checks:
make -C crates/remote-exec-daemon-cpp check-posix
make -C crates/remote-exec-daemon-cpp check-windows-2000
make -C crates/remote-exec-daemon-cpp prepare-openssl-xp OPENSSL_DEPS_DIR=/path/to/deps
make -C crates/remote-exec-daemon-cpp check-windows-xp OPENSSL_ROOT=/path/to/deps/openssl-1.0.2u
make -C crates/remote-exec-daemon-cpp check-windows-x64 OPENSSL_ROOT=/path/to/openssl-mingw64
make -C crates/remote-exec-daemon-cpp check-windows-xp-x64 TLS=off
make -C crates/remote-exec-daemon-cpp check-windows-nt3x-ws1
make -C crates/remote-exec-daemon-cpp check-windows-nt4-ws1
make -C crates/remote-exec-daemon-cpp check-windows-nt4-ws2
bmake -C crates/remote-exec-daemon-cpp check-posix
Build and execution can be split across machines. test-bundle-* targets
compile and stage a relocatable directory containing the daemon, apply_patch,
test binaries, runtime companions, fixtures, and a native test runner, without
launching target binaries:
make -C crates/remote-exec-daemon-cpp test-bundle-posix
make -C crates/remote-exec-daemon-cpp test-bundle-windows-xp TLS=off
Copy the printed directory under build/test-bundles/ to a compatible machine,
preserving executable permissions, then run ./run-tests on POSIX or
run-tests.exe on Windows. Pass --list to inspect the test names or pass names
such as transfer server-streaming to run a subset. Set TEST_BUNDLE_DIR to
stage directly into a fresh artifact output directory. The execution machine
does not need the repository, Make/NMAKE, or a compiler, but it must provide any
dynamically linked libraries selected at build time. The C++ daemon README
documents the GNU, BSD make, and MSVC bundle targets in detail.
For OpenSSL-backed C++ builds, run the matching prepare-openssl or
prepare-openssl-xp target first and pass the resulting OPENSSL_ROOT.
LibreSSL and BoringSSL builds use the existing TLS=openssl compatibility mode
with OPENSSL_CPPFLAGS and OPENSSL_LDLIBS pointing to the selected library's
headers and libraries. The TLS=auto probe recognizes LibreSSL by its
LIBRESSL_VERSION_NUMBER marker, so its OpenSSL-compatible version number is
not misclassified. When no supported library is available and TLS is not
needed, set TLS=off on the build and check commands.
From an x86 Visual Studio developer prompt:
nmake /f crates\remote-exec-daemon-cpp\NMakefile check-msvc-native OPENSSL_ROOT=C:\path\to\openssl
From an x86 Visual Studio developer prompt with a v141_xp-capable C++11
toolset:
nmake /f crates\remote-exec-daemon-cpp\NMakefile check-msvc-xp OPENSSL_ROOT=C:\path\to\openssl-xp
From an x64 Visual Studio developer prompt with the same XP-capable toolset:
vcvarsall.bat x64 -vcvars_ver=14.16
nmake /f crates\remote-exec-daemon-cpp\NMakefile check-msvc-xp-x64 OPENSSL_ROOT=C:\path\to\openssl-xp-x64
More C++ daemon details live in
crates/remote-exec-daemon-cpp/README.md.
Observability
Runtime components log to stderr.
- The broker keeps
stdoutreserved for MCP stdio. - Broker tool errors include
request_id,tool, andtargetwhen known. - Rust components read
REMOTE_EXEC_LOGfirst, thenRUST_LOG. - C++ daemon reads
REMOTE_EXEC_LOGfirst, thenRUST_LOG. - C++ daemon accepts a bare level such as
debug, shared filters such asremote_exec_daemon_cpp=debug, and the oldremote_exec_daemon_xp=<level>alias.
Examples:
REMOTE_EXEC_LOG=debug cargo run -p remote-exec-daemon -- configs/daemon.example.toml
REMOTE_EXEC_LOG=debug cargo run -p remote-exec-broker -- configs/broker.example.toml
REMOTE_EXEC_LOG='warn,remote_exec_broker=debug,remote_exec_daemon=debug,remote_exec_daemon_cpp=debug'
Development
Rust MSRV is 1.85.0, the first stable release with Rust 2024 edition support.
The Rust broker, Rust daemon, and C++ daemon embed build metadata in their
reported version. A build from a Git checkout with git available reports
versions in the form
0.2.0+g<short-commit>.<YYYYMMDD>; builds without Git report
0.2.0+<YYYYMMDD>. The SemVer core remains unchanged for compatibility, and
the date is the UTC build date.
Full quality gate:
cargo test --workspace
cargo fmt --all --check
cargo clippy --workspace --all-targets --all-features -- -D warnings
crates/remote-exec-daemon-cpp/scripts/clang_format.sh check
make -C crates/remote-exec-daemon-cpp check-posix
make -C crates/remote-exec-daemon-cpp check-windows-2000
make -C crates/remote-exec-daemon-cpp check-windows-xp
make -C crates/remote-exec-daemon-cpp check-windows-x64
make -C crates/remote-exec-daemon-cpp check-windows-xp-x64 TLS=off
make -C crates/remote-exec-daemon-cpp check-windows-nt3x-ws1
make -C crates/remote-exec-daemon-cpp check-windows-nt4-ws1
make -C crates/remote-exec-daemon-cpp check-windows-nt4-ws2
Additional platform checks:
make -C crates/remote-exec-daemon-cpp check-windows WINDOWS_TOOLCHAIN=native WINDOWS_WINVER=0x0501 WINDOWS_WINSOCK_VERSION=2
nmake /f crates\remote-exec-daemon-cpp\NMakefile check-msvc-native
nmake /f crates\remote-exec-daemon-cpp\NMakefile check-msvc-xp
nmake /f crates\remote-exec-daemon-cpp\NMakefile check-msvc-xp-x64
Focused commands:
cargo test -p remote-exec-broker --test multi_target -- --nocapture
cargo test -p remote-exec-broker --test mcp_cli
cargo test -p remote-exec-broker --test mcp_transfer -- --nocapture
cargo test -p remote-exec-broker --test mcp_forward_ports -- --nocapture
cargo test -p remote-exec-daemon --test transfer_rpc -- --nocapture
cargo test -p remote-exec-daemon --test port_forward_rpc -- --nocapture
make -C crates/remote-exec-daemon-cpp test-host-transfer
make -C crates/remote-exec-daemon-cpp test-host-server-runtime
make -C crates/remote-exec-daemon-cpp test-host-server-streaming
make -C crates/remote-exec-daemon-cpp test-windows-xp-server-runtime
make -C crates/remote-exec-daemon-cpp test-windows-xp-server-routes-common
C++ daemon sources are formatted with the root .clang-format:
crates/remote-exec-daemon-cpp/scripts/clang_format.sh format
crates/remote-exec-daemon-cpp/scripts/clang_format.sh check
No-default-features checks:
cargo test -p remote-exec-broker --no-default-features --tests
cargo test -p remote-exec-daemon --no-default-features --tests
cargo test -p remote-exec-host --no-default-features --tests
cargo clippy -p remote-exec-broker --no-default-features --all-targets -- -D warnings
cargo clippy -p remote-exec-daemon --no-default-features --all-targets -- -D warnings
cargo clippy -p remote-exec-host --no-default-features --all-targets -- -D warnings
Windows GNU compile-only checks from Linux:
cargo check --workspace --all-targets --all-features --target x86_64-pc-windows-gnu
cargo clippy --workspace --all-targets --all-features --target x86_64-pc-windows-gnu -- -D warnings
cargo build --workspace --all-targets --all-features --target x86_64-pc-windows-gnu
CI covers Rust broker/daemon paths on Linux, macOS, and Windows, standalone C++ daemon jobs on Linux, macOS, and Windows, C++ formatting, selected Wine runs for legacy GNU Windows binaries when available, and periodic/manual BSD coverage using BSD make. Rust broker integration tests consume a prebuilt C++ daemon binary when one is present and skip C++ daemon scenarios when it is absent.
References
AGENTS.md: implementation guidance for coding agentsskills/using-remote-exec-mcp/SKILL.md: tool and CLI usage guide for agentsconfigs/broker.example.toml: broker config shapeconfigs/daemon.example.toml: Rust daemon config shapecrates/remote-exec-daemon-cpp/README.md: C++ daemon build/runtime guidecrates/remote-exec-proto/src/public.rs: public MCP tool schema
