Skip to main content

Local-first remote access, control, and exchange through CLI and MCP

Project description

R.A.C.E. — Remote Access, Control, and Exchange

EN | 中文

CI Python 3.12 | 3.13 | 3.14 License: Apache-2.0

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:

Integration Surfaces

  • Human CLI: race --help and ordinary subcommands.
  • Function Calling CLI: race call <tool> --arguments-json '<JSON object>' --format json.
  • Local MCP client over stdio: launch race stdio explicitly.
  • MCP client over Streamable HTTP: connect to a loopback /mcp endpoint, 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 notes
  • exec: run non-interactive remote commands over SSH
  • exec(background=true) / exec_start: start long-running remote commands in the background and return a stable job_id
  • exec_status / exec_tail / exec_result / exec_cancel: check state, poll logs, collect final output, or cancel a background job
  • sync: upload local workspace contents to the remote workspace with rsync
  • download: pull remote files or directories back to local disk
  • device_* / list_devices: manage and inspect project-local device aliases backed by .ssh/config
  • device_probe_runtime: detect and store the selected device's tmux/screen background exec backend, refreshing the matching background capability snapshot
  • device_health_check: refresh stable online/offline status and last_seen metadata
  • device_probe_capabilities: detect and store tmux/screen/rsync/systemd-user/sudo-broker capability snapshots
  • device_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 server
  • action_request_validate / action_request_preview / action_request_hash: validate, normalize, preview, hash, and draft-archive ActionRequest v1 payloads
  • policy_test_case: test ActionRequest path/resource policy without executing an action
  • audit_export / audit_verify_chain: export sanitized audit JSONL/NDJSON and verify the high-risk audit hash chain
  • state_get / state_set / state_list / state_cleanup: record and query path/file state snapshots
  • backup_create / backup_inspect / rollback_preview / rollback_execute: create local file snapshots and preview or execute approved file rollback
  • runner_broker_check: check runner/broker isolation readiness without server-side install/remove; use CLI-only runner-broker smoke-test for real key-login and transfer probes
  • exec_resume: resume a locally approved pending execution by request_id
  • CLI-only full-access grant|status|history|revoke, approval list|inbox|show|approve|deny|reject|revoke, and ssh-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:

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_start uses a per-device background_tool: tmux or screen
  • tmux is preferred; missing configuration triggers a lazy device_probe_runtime probe with tmux_install_policy="ask"
  • ask mode never installs tmux and returns tmux_install_approval_required when tmux is missing
  • use tmux_install_policy="allow" only when you explicitly permit a non-interactive tmux install attempt; use forbid to fall back to screen when available
  • the remote probe/install script is packaged under src/race_mcp/remote_scripts/ and does not depend on repository-root scripts/

Device registry governance:

  • devices expose stable status values: online, offline, degraded, or unknown
  • last_seen changes only after a successful connectivity or capability probe
  • last_audit_id points at the latest project audit event for a still-registered target device
  • policy_check returns a structured L0-L6 and capability decision for one target tool on one selected device
  • policy_explain returns the same decision plus an operator-readable explanation
  • exec, exec_start, sync, download, device_add, device_update, and device_remove run a pre-execution policy gate and return blocked=true with block_reason="policy_denied" when the required level is outside the runner/broker-derived effective levels
  • runner_user_configured=true plus broker_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 by race full-access grant|status|history|revoke, require exact confirmation text, support duration, uses, or explicit --unlimited, and never write devices.toml
  • full-access status --all reports 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_approval with 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 inbox and approval 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 grants
  • approval approve returns execution_status="running" by default; use approval approve <request-id> --execute or exec 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"; --approver remains 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_export emits sanitized JSONL/NDJSON and audit_verify_chain validates chained event hashes
  • State Recorder stores path/file state snapshots under .race_mcp/state/; backup snapshots live under .race_mcp/backups/ with manifest.json, files/, and metadata/
  • Rollback is file/directory snapshot based, never automatic by default, and rollback_execute always 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 /tmp setup 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 target acl package when setfacl is missing; --remote-ws-path is only an ACL target override; CLI runner-broker check and runner-broker smoke-test use --ssh-config-host directly and do not read or write project/global device registries; CLI-only runner-broker smoke-test runs 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 only runner_broker_check and never direct key creation, setup-script upload, smoke-test, install, or remove
  • device_probe_capabilities records read-only capability snapshots and never executes sudo actions; snapshots now enforce the first execution paths: sync / download require rsync, and exec_start / exec(background=true) require tmux or screen
  • missing, false, or unknown required capabilities return blocked=true with block_reason="missing_device_capability" and suggestion="run device_probe_capabilities"; foreground exec and device_probe_capabilities are 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 include audit_id, and audit_query can filter by audit_id, device, tool, and limit
  • 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, and policy_test_case are public core tools in both CLI and MCP server mode
  • ActionRequest v1 input is normalized, request_id / task_id / session_id are generated when omitted, and supported TTL values are 30s, 300s, 5m, 10m, and 1h
  • resource must be a structured object with type path, service, package, user, network, command, device, or other
  • path resources are normalized and checked against device-level policy.paths.allow / policy.paths.deny lists in devices.toml; deny rules win
  • action_hash is sha256: plus canonical JSON over fixed security fields only; it excludes action_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, and policy_version; L3/L4 also require delegated agent audit metadata, while final execution grants are still signed by race
  • action_request_preview writes 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|remove manages the MCP Streamable HTTP application
  • server mode supports --transport http; --auth none is loopback-only, while --auth reverse-proxy requires a public HTTPS /mcp URL, Host/Origin allowlists, and a fixed absolute config_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/ as server.pid, server.json, stdout.log, and stderr.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_HOST and WS_REMOTE_ROOT
    • this is the fastest path if you only target one machine
  • multi-device mode:
    • define one or more device aliases in .race_mcp/devices.toml under 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 explicit local_ws_path/config_path
    • select devices with the device parameter on exec, sync, and download
    • discover device sources with device_list_ssh_config and device_list_global_config, then manage project devices with list_devices, device_list, device_inspect, device_probe_runtime, device_add, device_update, and device_remove
    • from the CLI, use race device list --ssh-config, race device list --global, and race device add --source global --alias ...
    • use race call ... --format json for process-based Function Calling or race stdio for a local MCP client; for hands-on device management, run CLI commands from inside the initialized project tree

Compatibility rule:

  • legacy single-device mode still uses WS_SSH_HOST and WS_REMOTE_ROOT
  • multi-device mode uses local_ws_path / config_path resolution and ignores legacy device env vars; workspace_path is 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.

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.py
    • uv 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

race_mcp-0.3.0.tar.gz (370.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

race_mcp-0.3.0-py3-none-any.whl (313.9 kB view details)

Uploaded Python 3

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

Hashes for race_mcp-0.3.0.tar.gz
Algorithm Hash digest
SHA256 42277090519bc504dd5b82db1c7b3f5f8651c9e497ef78663f0198820d948bf2
MD5 5125ea01cf7377830249cd9bef83738c
BLAKE2b-256 fd81e17e7ac052b47d632fd4711779d69f6d08953e45005204410ecfb8de032b

See more details on using hashes here.

Provenance

The following attestation bundles were made for race_mcp-0.3.0.tar.gz:

Publisher: publish-python-package.yml on bluewhitep/race-mcp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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

Hashes for race_mcp-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ea852c1192987330b528002147b59110b4b2801c3b9678b147a304c8118680dd
MD5 3966b297e7f0a1cd7a48af766e67a4ef
BLAKE2b-256 2ac5f2f9757a4b1e1c559795a67c7aaa16b31edc4389292b73e3f4ec10ac05d3

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page