Local-first remote access, control, and exchange through CLI and MCP
Project description
R.A.C.E. — Remote Access, Control, and Exchange
R.A.C.E. — Remote Access, Control, and Exchange — provides a local-first remote workspace runtime with shared Core/Runtime modules and thin Human CLI, Function Calling, and MCP adapters.
Canonical names:
- project and distribution:
race-mcp; - Python import:
race_mcp; - preferred CLI command:
race; - full CLI command:
race-mcp; - project/global configuration directory:
.race_mcp.
Current release version:
0.3.0
Read This First
Do not start with the detailed reference pages.
Start with one of these pages:
- User path: User Quickstart
- Developer path: Developer Setup
- Upgrade path: Migration Guide
Integration Surfaces
- Human CLI:
race --helpand ordinary subcommands. - Function Calling CLI:
race call <tool> --arguments-json '<JSON object>' --format json. - Local MCP client over stdio: launch
race stdioexplicitly. - MCP client over Streamable HTTP: connect to a loopback
/mcpendpoint, or to an authenticated TLS reverse proxy that forwards to the loopback application.
Bare race and race-mcp display human CLI help. R.A.C.E. never provides direct non-loopback authentication: service deployments keep the application on loopback and require a separately managed reverse proxy for TLS and authentication.
What This Project Does
help: return tool usage guidance, examples, and discovery notesexec: run non-interactive remote commands over SSHexec(background=true)/exec_start: start long-running remote commands in the background and return a stablejob_idexec_status/exec_tail/exec_result/exec_cancel: check state, poll logs, collect final output, or cancel a background jobsync: upload local workspace contents to the remote workspace withrsyncdownload: pull remote files or directories back to local diskdevice_*/list_devices: manage and inspect project-local device aliases backed by.ssh/configdevice_probe_runtime: detect and store the selected device's tmux/screen background exec backend, refreshing the matching background capability snapshotdevice_health_check: refresh stable online/offline status andlast_seenmetadatadevice_probe_capabilities: detect and store tmux/screen/rsync/systemd-user/sudo-broker capability snapshotsdevice_snapshot: return full device registry governance metadata- CLI-only
doctor/device readiness: summarize local project, device, governance, and server readiness with next-action hints tool_list/tool_inspect/tool_schema_export: inspect the shared core tool contract used by CLI and serveraction_request_validate/action_request_preview/action_request_hash: validate, normalize, preview, hash, and draft-archive ActionRequest v1 payloadspolicy_test_case: test ActionRequest path/resource policy without executing an actionaudit_export/audit_verify_chain: export sanitized audit JSONL/NDJSON and verify the high-risk audit hash chainstate_get/state_set/state_list/state_cleanup: record and query path/file state snapshotsbackup_create/backup_inspect/rollback_preview/rollback_execute: create local file snapshots and preview or execute approved file rollbackrunner_broker_check: check runner/broker isolation readiness without server-side install/remove; use CLI-onlyrunner-broker smoke-testfor real key-login and transfer probesexec_resume: resume a locally approved pending execution byrequest_id- CLI-only
full-access grant|status|history|revoke,approval list|inbox|show|approve|deny|reject|revoke, andssh-key setup: manage device-scoped Full Access grants, local approvals, and ordinary-user SSH key setup
Common MCP discovery requests:
{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}
{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"help","arguments":{"tool":"exec"}}}
{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"tool_inspect","arguments":{"tool":"exec"}}}
Common operator commands:
race help --tool exec
race doctor
race doctor --device gpu-01
race device readiness gpu-01
race tools list
race tools inspect exec
race tools schema-export
race call exec --arguments-json '{"local_ws_path":"/abs/workspace","device":"gpu-01","cmd":"pwd"}' --format json
race stdio
race stdio --global
race server status
race server start --transport http --host 127.0.0.1 --port 8000 --config-path /abs/workspace/.race_mcp/devices.toml --detach
race server render-user-service --transport http --host 127.0.0.1 --port 8000 --config-path /abs/workspace/.race_mcp/devices.toml
cd /abs/workspace && race init
race device list
race device health-check --device gpu-01
race device probe-runtime --device gpu-01 --tmux-install-policy forbid
race device probe-capabilities --device gpu-01
race device snapshot --device gpu-01
race full-access grant --device gpu-01 --duration 1h --confirm "CONFIRM FULL ACCESS gpu-01"
race full-access status --all
race full-access history --device gpu-01
race approval inbox
race approval show <request-id>
race approval approve <request-id> --execute
race approval reject <request-id> --reason "not approved"
race exec resume --request-id <request-id>
race audit query --device gpu-01 --tool exec --limit 20
race audit export --level L3 --format jsonl
race audit verify-chain
race state set --path config.toml
race backup create --path config.toml
race rollback preview --backup-id <backup-id>
race rollback apply --backup-id <backup-id>
race runner-broker create-key --ssh-config-host <ssh-config-host>
race runner-broker setup-script --ssh-config-host <ssh-config-host>
race runner-broker check --ssh-config-host <ssh-config-host>
race runner-broker smoke-test --ssh-config-host <ssh-config-host>
race ssh-key setup --device gpu-01
race sync --device gpu-01 --local-root . --remote-path /abs/remote/workspace
race exec --device gpu-01 --cmd "pwd && ls"
race exec --background --device gpu-01 --cmd "python train.py"
race exec_status --device gpu-01 --job-id 0123456789abcdef0123456789abcdef
race exec_tail --device gpu-01 --job-id 0123456789abcdef0123456789abcdef --stream stderr --lines 50
race exec_result --device gpu-01 --job-id 0123456789abcdef0123456789abcdef
race exec_cancel --device gpu-01 --job-id 0123456789abcdef0123456789abcdef
race download --device gpu-01 --remote-path logs/train.log --local-path ./downloads/train.log
race action-request validate --requester agent --executor runner --device gpu-01 --level L3 --capability service.restart --resource-json '{"type":"service","scope":"system","name":"nginx"}' --reason "restart after config test" --ttl 10m
race action-request preview --requester agent --executor runner --device gpu-01 --level L2 --capability workspace.write --resource-json '{"type":"path","scope":"workspace","path":"report.md"}' --reason "update report" --ttl 5m
Tool contract discovery details live in Tool Contract Discovery.
Usage locations:
- CLI usage: Usage Reference
- runner/broker configuration: Runner/Broker Configuration
- MCP tool arguments: MCP Tool Arguments
- MCP tool discovery: Tool Contract Discovery
- server startup and lifecycle: Deployment / Install Reference
- rename and configuration migration: Migration Guide
Exec tool naming:
- canonical MCP/CLI names use underscores:
exec_start,exec_status,exec_tail,exec_cancel,exec_result - dotted aliases are also accepted for the async exec family:
exec.start,exec.status,exec.tail,exec.cancel,exec.result
Background exec backend:
exec_startuses a per-devicebackground_tool:tmuxorscreentmuxis preferred; missing configuration triggers a lazydevice_probe_runtimeprobe withtmux_install_policy="ask"- ask mode never installs tmux and returns
tmux_install_approval_requiredwhen tmux is missing - use
tmux_install_policy="allow"only when you explicitly permit a non-interactive tmux install attempt; useforbidto fall back toscreenwhen available - the remote probe/install script is packaged under
src/race_mcp/remote_scripts/and does not depend on repository-rootscripts/
Device registry governance:
- devices expose stable
statusvalues:online,offline,degraded, orunknown last_seenchanges only after a successful connectivity or capability probelast_audit_idpoints at the latest project audit event for a still-registered target devicepolicy_checkreturns a structured L0-L6 and capability decision for one target tool on one selected devicepolicy_explainreturns the same decision plus an operator-readable explanationexec,exec_start,sync,download,device_add,device_update, anddevice_removerun a pre-execution policy gate and returnblocked=truewithblock_reason="policy_denied"when the required level is outside the runner/broker-derived effective levelsrunner_user_configured=trueplusbroker_user_configured=true, resolved from the selected device's SSH config Host state, gives the device full base L0-L6 capability; L4-L6 still require a valid device-scoped Full Access grant- Full Access grants live in
<local_ws_path>/.race_mcp/full_access/grants.json, are managed byrace full-access grant|status|history|revoke, require exact confirmation text, supportduration,uses, or explicit--unlimited, and never writedevices.toml full-access status --allreports all registered devices as active, expired, revoked, uses-exhausted, or not granted;full-access history [--device <alias>]is read-only and combines the current grant snapshot with minimal execution records- Full Access execution records live in
.race_mcp/full_access/executions.jsonl; they store policy/action metadata plus stdout/stderr hashes and lengths, not command text or raw output - P6 local approvals use a request-after-execution-boundary model: L0-L2 execute without approval but are audited, L3 defaults to
pending_approvalwith policy exceptions, L4/L5 require approval after the Full Access gate, and L6 remains validate/preview/hash only - Approval events are append-only JSONL at
<local_ws_path>/.race_mcp/approvals/approvals.jsonl; execution events are append-only JSONL at<local_ws_path>/.race_mcp/executions/executions.jsonl - Human approval is CLI-local through
race approval list|inbox|show|approve|deny|reject|revoke; MCP does not expose remote approve/deny/revoke tools approval inboxandapproval show <request-id>are read-only aggregation views over approval records, pending execution events, matching ActionRequest draft metadata when available, device readiness, warnings, and next actions; they never approve, reject, resume, execute, consume approval, or consume Full Access grantsapproval approvereturnsexecution_status="running"by default; useapproval approve <request-id> --executeorexec resume --request-id <request-id>to resume in a one-shot CLI process- Approval events bind the local approver OS user, uid, gid, host, and
approval_source="local-cli";--approverremains an audit label - A local server process starts a single-instance approval watcher for server-created pending approvals and resumes approved work idempotently
- Audit write failures are fail-open with warnings for L0-L2 operations and fail-closed for L3-L5, broker, and L6-related audit events
- High-risk audit events enter a hash chain;
audit_exportemits sanitized JSONL/NDJSON andaudit_verify_chainvalidates chained event hashes - State Recorder stores path/file state snapshots under
.race_mcp/state/; backup snapshots live under.race_mcp/backups/withmanifest.json,files/, andmetadata/ - Rollback is file/directory snapshot based, never automatic by default, and
rollback_executealways creates a rollback ActionRequest and requires local approval - Backup retention keeps the latest 20 snapshots or snapshots from the last 7 days, while preserving snapshots referenced by active pending rollback
- runner/broker bootstrap uses Host-scoped ed25519 keys under
~/.race_mcp/keys/<ssh-config-host>/, Host-scoped readiness state under~/.race_mcp/runner_broker_hosts.json, plus the global execution-grant key at~/.race_mcp/keys/execution_grant_ed25519; setup-script overwrites the target/tmpsetup scripts, validates generated scripts before upload, grants runner/broker access to the SSH login user's home by default, installs the broker root helper and execution-grant public key, and installs the targetaclpackage whensetfaclis missing;--remote-ws-pathis only an ACL target override; CLIrunner-broker checkandrunner-broker smoke-testuse--ssh-config-hostdirectly and do not read or write project/global device registries; CLI-onlyrunner-broker smoke-testruns real runner/broker key, forced-command, signed broker execution, a signed broker sudo no-op probe, and tmux/screen probes, with configured-workspace sync/download checks skipped for host-only targets; server/MCP exposes onlyrunner_broker_checkand never direct key creation, setup-script upload, smoke-test, install, or remove device_probe_capabilitiesrecords read-only capability snapshots and never executes sudo actions; snapshots now enforce the first execution paths:sync/downloadrequirersync, andexec_start/exec(background=true)requiretmuxorscreen- missing, false, or unknown required capabilities return
blocked=truewithblock_reason="missing_device_capability"andsuggestion="run device_probe_capabilities"; foregroundexecanddevice_probe_capabilitiesare not blocked by the background-backend capability gate exec,exec_start,sync,download,backup_create,rollback_execute,device_add,device_update,device_remove, and policy blocked results write project audit events under.race_mcp/audit/audit.jsonl; tool results includeaudit_id, andaudit_querycan filter byaudit_id,device,tool, andlimit- audit events store command hashes, exact commands for governed execution records, redacted command text where available, and stdout/stderr hash plus length only; raw output, approval tokens, execution grant signatures, and private keys are not persisted
ActionRequest contract:
action_request_validate,action_request_preview,action_request_hash, andpolicy_test_caseare public core tools in both CLI and MCP server mode- ActionRequest v1 input is normalized,
request_id/task_id/session_idare generated when omitted, and supported TTL values are30s,300s,5m,10m, and1h resourcemust be a structured object with typepath,service,package,user,network,command,device, orother- path resources are normalized and checked against device-level
policy.paths.allow/policy.paths.denylists indevices.toml; deny rules win action_hashissha256:plus canonical JSON over fixed security fields only; it excludesaction_hash, signatures, execution grants, execution IDs, approval tokens, receipts/status, output streams, and runtime audit results- L3+ ActionRequest payloads bind
exact_command,risk_summary,expected_effect,rollback_plan, andpolicy_version; L3/L4 also require delegated agent audit metadata, while final execution grants are still signed by race action_request_previewwrites a minimal draft record to<local_ws_path>/.race_mcp/action_requests/action_requests.jsonl- L4-L5 policy requires a valid Full Access grant plus local approval before execution; L6 fields are validated, but L6 execution attempts are rejected in this release
Server lifecycle:
race server start|stop|restart|status|logs|removemanages the MCP Streamable HTTP application- server mode supports
--transport http;--auth noneis loopback-only, while--auth reverse-proxyrequires a public HTTPS/mcpURL, Host/Origin allowlists, and a fixed absoluteconfig_path - the reverse-proxy profile still binds R.A.C.E. to loopback; a separately managed reverse proxy terminates TLS and authenticates every public request
- Linux user-level loopback systemd deployment is available through
server render-user-service|install-user-service|remove-user-service - detached server state lives under
~/.race_mcp/server/asserver.pid,server.json,stdout.log, andstderr.log - the default bind is
127.0.0.1:8000;0.0.0.0, LAN IPs, public IPs, and other non-loopback hosts are rejected in this phase
This project is for sync-then-exec workflows. It is not:
- an interactive shell
- a PTY bridge
- a remote editor
- an interactive long-lived remote session manager
Supported Local Host Backends
- Windows + WSL2 using
windows-wsl - Windows native using
windows-native - macOS/Linux using
posix-native
Default behavior:
- Windows defaults to
windows-wsl - macOS/Linux default to
posix-native
CLI Lifecycle From The Project Root
Use this section when installing, updating, verifying, or uninstalling the CLI from this checkout. Run commands from the repository root so the console script entrypoint is created from this checkout:
cd /path/to/race-mcp
Install
With uv
uv tool install -e .
With pip
python3.12 -m pip install --user -e .
With A Local .venv
python3.12 -m venv .venv
. .venv/bin/activate
python -m pip install -e .
Update An Existing Checkout
When the tool was installed from this checkout, update the repository first, then reinstall with the same install method.
With uv
git pull --ff-only
uv tool install -e . --force
With pip
git pull --ff-only
python3.12 -m pip install --user -e .
With A Local .venv
git pull --ff-only
. .venv/bin/activate
python -m pip install -e .
Verify The CLI
Initialize a global registry only when you want global fallback:
race init --global
Use workspace-free CLI commands to verify that the console scripts resolve:
race --help
race-mcp --help
race tools list
race config locate --json
race config locate --global --json
The race-mcp distribution installs the preferred short command race, the full command race-mcp, and a temporary deprecated compatibility command for older installations. Bare canonical commands print help; MCP registrations must use the explicit stdio argument.
Uninstall The CLI
Uninstall the CLI from the same environment that installed it.
With uv
uv tool uninstall race-mcp
With pip
python3.12 -m pip uninstall race-mcp
With A Local .venv
Activate the environment and run:
python -m pip uninstall race-mcp
If the local .venv is only used for this project, removing .venv is also sufficient.
State Not Removed
Uninstalling the Python package does not remove project metadata under .race_mcp/, global device config under ~/.race_mcp/, legacy configuration, .ssh/config, remote files, or MCP client registrations. Review the Migration Guide before deleting state. If a shell still resolves a deprecated command, remove the older distribution from that same environment and refresh the shell command cache or open a new shell.
Installer Scripts Removed
Repository installer scripts under scripts/install/ have been removed. Use uv or pip for installation and upgrades. Run race init in a project or race init --global only for an explicitly global configuration.
Recommended CLI Model
Use a project-local .venv and point Codex to that Python interpreter.
Why this is the default:
- it avoids global Python drift
- it keeps the MCP server tied to the cloned repository
- it is the most reliable path for local updates
Global installation is still possible for special cases, but it is not the recommended default.
Updating After Version Changes
If you pull a new version of this repository:
- reinstall with the same package-management method used for the existing installation
- if you use a project-local editable install, that also refreshes package metadata such as the version number
- after the reinstall, reload VS Code / Codex
Detailed update steps live in Deployment / Install Reference.
Single-Device vs Multi-Device
There are now two supported configuration models:
- single-device legacy mode:
- set
WS_SSH_HOSTandWS_REMOTE_ROOT - this is the fastest path if you only target one machine
- set
- multi-device mode:
- define one or more device aliases in
.race_mcp/devices.tomlunder the local workspace, or in~/.race_mcp/devices.toml - initialize project metadata explicitly with
cd /abs/workspace && race init - start the MCP server without
WS_PATH; metadata-dependent MCP calls must pass explicitlocal_ws_path/config_path - select devices with the
deviceparameter onexec,sync, anddownload - discover device sources with
device_list_ssh_configanddevice_list_global_config, then manage project devices withlist_devices,device_list,device_inspect,device_probe_runtime,device_add,device_update, anddevice_remove - from the CLI, use
race device list --ssh-config,race device list --global, andrace device add --source global --alias ... - use
race call ... --format jsonfor process-based Function Calling orrace stdiofor a local MCP client; for hands-on device management, run CLI commands from inside the initialized project tree
- define one or more device aliases in
Compatibility rule:
- legacy single-device mode still uses
WS_SSH_HOSTandWS_REMOTE_ROOT - multi-device mode uses
local_ws_path/config_pathresolution and ignores legacy device env vars;workspace_pathis no longer accepted in device config or tool requests
Device Source Discovery And Add Flow
Before adding a project device, list the available sources.
SSH config candidates:
race device list --ssh-config
race device list --ssh-config --host SSH_CONFIG_HOST_ALIAS
The SSH config CLI output is an aligned table:
No Status Host HostName
1 <Ready|Unready> <Host> <HostName>
device list --ssh-config reads SSH config text only. Status is Ready when the Host entry has at least one local IdentityFile key file that exists, and Unready when the Host is missing, has no IdentityFile, or points only to missing key files. It does not run ssh -G, open an SSH connection, or prove that login will succeed. In an interactive terminal, Ready is green and Unready is red.
Global config devices:
race device list --global
The global config CLI output is an aligned table:
No Host HostName
1 <Host> <HostName>
Add from SSH config, which is the default source:
race device add \
--source ssh-config \
--alias DEVICE_ALIAS \
--ssh-host SSH_CONFIG_HOST_ALIAS \
--remote-ws-path /absolute/remote/workspace
Copy an existing global config device into the project config:
race device add \
--source global \
--alias DEVICE_ALIAS
source=global copies the matching device section from $HOME/.race_mcp/devices.toml into the project registry. It copies configuration fields such as ssh_config_host, group, remote_ws_path, and policy, but not CLI or audit state such as status, last_seen, last_audit_id, or runner/broker readiness fields.
The same flow is available through MCP tools:
{"name":"device_list_ssh_config","arguments":{}}
{"name":"device_list_global_config","arguments":{}}
{"name":"device_add","arguments":{"local_ws_path":"/abs/workspace","alias":"DEVICE_ALIAS","source":"global"}}
Detailed Reference
Use the quick guides above first. Use the pages below when you need detail or troubleshooting.
- Documentation Home
- Overview
- Architecture
- Deployment / Install Reference
- Migration Guide
- CLI And Function Calling Contract
- MCP Server And Service Deployment
- Configuration Reference
- Syncignore Reference
- Usage Reference
- MCP Tool Arguments
- Tool Contract Discovery
- Testing
- Troubleshooting
- Release Process
- Security Policy
- Contributing
- Changelog
Quick validation commands:
- default non-E2E suite:
uv run pytest -q -m "not e2e"
- local live validation harnesses:
uv run python tests/live_phase1_validation.pyuv run python tests/live_phase2_write_validation.py
- optional command-audit stress suite:
python scripts/test/run_docker_security_escape.py
Functional Docker E2E harnesses were removed from the current validation path because containerized SSH/rsync checks are sensitive to host Docker filesystem, UID/GID, SSH key, and ssh-agent permission differences. Use the live validation harnesses for SSH-backed behavior.
Chinese docs:
License
This project is licensed under the Apache License 2.0. The repository also includes a NOTICE file for attribution.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file race_mcp-0.3.0.tar.gz.
File metadata
- Download URL: race_mcp-0.3.0.tar.gz
- Upload date:
- Size: 370.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
42277090519bc504dd5b82db1c7b3f5f8651c9e497ef78663f0198820d948bf2
|
|
| MD5 |
5125ea01cf7377830249cd9bef83738c
|
|
| BLAKE2b-256 |
fd81e17e7ac052b47d632fd4711779d69f6d08953e45005204410ecfb8de032b
|
Provenance
The following attestation bundles were made for race_mcp-0.3.0.tar.gz:
Publisher:
publish-python-package.yml on bluewhitep/race-mcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
race_mcp-0.3.0.tar.gz -
Subject digest:
42277090519bc504dd5b82db1c7b3f5f8651c9e497ef78663f0198820d948bf2 - Sigstore transparency entry: 2158985019
- Sigstore integration time:
-
Permalink:
bluewhitep/race-mcp@d62923fb1cbe438b218754f82f013db2994a6c6b -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/bluewhitep
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-python-package.yml@d62923fb1cbe438b218754f82f013db2994a6c6b -
Trigger Event:
release
-
Statement type:
File details
Details for the file race_mcp-0.3.0-py3-none-any.whl.
File metadata
- Download URL: race_mcp-0.3.0-py3-none-any.whl
- Upload date:
- Size: 313.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ea852c1192987330b528002147b59110b4b2801c3b9678b147a304c8118680dd
|
|
| MD5 |
3966b297e7f0a1cd7a48af766e67a4ef
|
|
| BLAKE2b-256 |
2ac5f2f9757a4b1e1c559795a67c7aaa16b31edc4389292b73e3f4ec10ac05d3
|
Provenance
The following attestation bundles were made for race_mcp-0.3.0-py3-none-any.whl:
Publisher:
publish-python-package.yml on bluewhitep/race-mcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
race_mcp-0.3.0-py3-none-any.whl -
Subject digest:
ea852c1192987330b528002147b59110b4b2801c3b9678b147a304c8118680dd - Sigstore transparency entry: 2158985104
- Sigstore integration time:
-
Permalink:
bluewhitep/race-mcp@d62923fb1cbe438b218754f82f013db2994a6c6b -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/bluewhitep
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-python-package.yml@d62923fb1cbe438b218754f82f013db2994a6c6b -
Trigger Event:
release
-
Statement type: