machine-bridge-mcp 0.6.2 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,47 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.7.1 - 2026-07-11
4
+
5
+ ### Fixed
6
+
7
+ - Persist a sanitized absolute-only command `PATH` in launchd and systemd service definitions, always including the stable Node and CLI directories plus platform defaults. This restores Homebrew/npm/git command resolution for background canonical `full` daemons without accepting empty or relative PATH entries.
8
+ - Align `doctor` with the declared sole runtime baseline by requiring Node.js 26 instead of reporting Node.js 22-25 as supported.
9
+
10
+ ### Tests and documentation
11
+
12
+ - Add service-definition regression tests for PATH preservation, duplicate removal, relative-entry rejection, and launchd/systemd emission; document why `machine-mcp service install` should be rerun after PATH layout changes.
13
+
14
+ ## 0.7.0 - 2026-07-11
15
+
16
+ ### Runtime and dependencies
17
+
18
+ - Raise the sole supported runtime baseline to Node.js 26 and npm 12, add exact local version files and strict engine checks, update Node type definitions to 26.1.1, and run the cross-platform CI suite on Node 26, and disable setup-node's automatic package-manager cache, and bootstrap npm 12 outside the repository before strict project engine checks apply.
19
+ - Confirm Wrangler 4.110.0, ws 8.21.0, and TypeScript 7.0.2 are current; retain exact reviewed dependency versions and zero known audit findings.
20
+ - Accept both legacy array and npm 12 keyed-object `npm pack --json` metadata, invoke the active npm CLI through Node on Windows, keep generated CI SBOM files outside the repository privacy/publication surface, and retry only classified transient GitHub network failures with Git forced to HTTP/1.1. Release creation verifies server state after an ambiguous response before proceeding.
21
+
22
+ ### Security and privacy
23
+
24
+ - Replace private environment-derived aliases in public examples with synthetic identifiers and add a repository privacy gate covering tracked and unignored new files, file names, common credential forms, local home paths, SSH host identifiers, and an ignored machine-specific denylist without echoing matched values. Reject publication-surface symbolic links instead of following their targets.
25
+ - Hide local resource and generated-key paths by default; require explicit `--show-paths` or `expose_paths=true`, return only bare SSH fingerprints, and broaden operational-log redaction for paths, email addresses, token forms, key headers, and Unicode display controls.
26
+ - Separate unrestricted filesystem access from absolute-path display, dynamically redact requested external paths from tool errors, harden autostart files/logs against permissive modes and symbolic links, canonicalize OAuth redirect URIs, and remove bidirectional/zero-width controls from authorization-page display text.
27
+
28
+ ### Correctness and durability
29
+
30
+ - Verify staged managed-job hashes during inspection, approval, and runner startup; serialize approve/cancel transitions and reclaim stale transition/recovery locks even after PID reuse; reject direct execution of unapproved staged plans; remove stale runner claims during recovery; and redact registered-resource source-path aliases from retained output.
31
+ - Clear delayed force-kill timers after process exit, enforce the stdio line limit during incremental reads, reject oversized local WebSocket payloads before string conversion, reject ID-less `tools/call` notifications instead of silently executing them, and accept actual collision-suffixed corrupt-config backups during guarded state removal.
32
+ - Make autostart prefer a stable PATH alias that resolves to the active Node executable instead of a versioned package-manager Cellar path, preventing minor Node upgrades from leaving launchd/systemd definitions pointing at removed binaries.
33
+ - Open and trim managed-job runner diagnostic logs through no-follow file descriptors, rejecting symbolic-link targets instead of following them.
34
+
35
+ ### Release governance and diagnostics
36
+
37
+ - Add a release-impact gate requiring a newer package version and matching CHANGELOG section for every tracked or nonignored repository change after the latest version tag. Document that reviewed changes must be pushed to GitHub and followed by a matching npm release.
38
+ - Clarify in `server_info`, runtime diagnostics, and operations documentation that canonical `full` controls the local daemon and relay catalog only. A connector host can expose a smaller subset, and that host-side subset is not observable or overrideable by Machine Bridge.
39
+
40
+ ### Tests and documentation
41
+
42
+ - Add regression coverage for privacy scanning of new files, clean/parseable package manifests and sensitive-artifact exclusion, default path omission and explicit disclosure, hidden unrestricted paths, plan tampering, direct staged-runner invocation, transition locks, source-path redaction, symlink log targets, corrupt-state cleanup, Unicode authorization spoofing, oversized stdio recovery, ID-less tool calls, and comment-free SSH fingerprints.
43
+ - Make release packaging resilient to lifecycle output by using silent JSON mode, and document repository privacy incident response, immutable history/package limitations, explicit path disclosure, plan integrity enforcement, same-user filesystem race residuals, and privacy checks in the release process.
44
+
3
45
  ## 0.6.2 - 2026-07-10
4
46
 
5
47
  ### Fixed
@@ -0,0 +1,23 @@
1
+ # Contributing and release discipline
2
+
3
+ This repository treats every Git-tracked or nonignored repository file as release-relevant, including source code, tests, scripts, examples, documentation, CI configuration, ignore rules, and package metadata.
4
+
5
+ ## Required for every release-relevant change
6
+
7
+ Before a change is merged to `main`:
8
+
9
+ 1. bump `package.json` to a version newer than the latest reachable `v*` tag;
10
+ 2. add the matching dated section to `CHANGELOG.md`;
11
+ 3. run `npm run check`, `npm audit`, `npm audit --omit=dev`, and `npm run worker:dry-run`;
12
+ 4. inspect the complete diff and the npm package manifest;
13
+ 5. push the reviewed commit to GitHub;
14
+ 6. create the matching Git tag and GitHub Release;
15
+ 7. publish the same version to npm.
16
+
17
+ `npm run release-impact:check` enforces the version and changelog parts. It fails when release-relevant files changed after the latest version tag but the package version was not advanced.
18
+
19
+ A privacy or security correction is always release-relevant. Removing a private identifier only from the current branch is insufficient: publish a replacement npm version, update GitHub, and deprecate or unpublish the affected npm version when policy and authentication permit.
20
+
21
+ ## Privacy
22
+
23
+ Use only synthetic names, reserved example domains, and generic paths. Maintain private local identifiers in the ignored `.privacy-denylist` and run `npm run privacy:check` before committing.
package/README.md CHANGED
@@ -45,7 +45,7 @@ This default prioritizes usability, not least privilege. `run_process` and proce
45
45
 
46
46
  ## Install
47
47
 
48
- Node.js 22 or newer is required.
48
+ Node.js 26 or newer and npm 12 or newer are required. The repository pins the active development versions in `.node-version`, `.nvmrc`, and `packageManager`; project installs fail on older Node runtimes.
49
49
 
50
50
  ```sh
51
51
  npm install -g --allow-scripts=esbuild,workerd,sharp machine-bridge-mcp@latest
@@ -132,7 +132,7 @@ Important distinctions:
132
132
  - `--absolute-paths` changes returned path metadata; it does not independently grant additional access.
133
133
  - In isolated-environment profiles, commands receive private HOME, temp, and cache directories plus a small set of platform variables.
134
134
  - The server has no filename blacklist. Under `full`, direct read tools may read any UTF-8 regular file that the local OS user can access, including files outside the workspace and names such as `.env`, `passwords.txt`, or private-key files.
135
- - Maximum local policy does not override operating-system permissions, macOS TCC/SIP, Windows ACLs, container boundaries, or independent safety rules imposed by the MCP host/platform. A host-generated “sensitive file” denial is outside this server's enforcement layer.
135
+ - Maximum local policy does not override operating-system permissions, macOS TCC/SIP, Windows ACLs, container boundaries, or independent safety rules imposed by the MCP host/platform. `full` means the local daemon and relay advertise the complete catalog; a connector may still expose only a subset to a particular session. Machine Bridge cannot observe or override that host-side subset. A host-generated “sensitive file” denial is outside this server's enforcement layer.
136
136
 
137
137
  ## Diagnose host, bridge, and local execution failures
138
138
 
@@ -169,18 +169,19 @@ When the host blocks execution-class tools but still permits state mutation, `st
169
169
  Register credential/key files locally without sending their contents through MCP:
170
170
 
171
171
  ```sh
172
- chmod 600 ~/.ssh/racknerd_ed25519
173
- machine-mcp resource add racknerd-key ~/.ssh/racknerd_ed25519
174
- machine-mcp resource list
172
+ chmod 600 ~/.ssh/example_maintenance_ed25519
173
+ machine-mcp resource add maintenance-key ~/.ssh/example_maintenance_ed25519
174
+ machine-mcp resource list # paths omitted by default
175
+ machine-mcp resource list --show-paths # explicit local-only path disclosure
175
176
  ```
176
177
 
177
178
  Generate an Ed25519 key and register its private file in one operation:
178
179
 
179
180
  ```sh
180
- machine-mcp resource generate-ssh-key racknerd-key ~/.ssh/ai-racknerd-maint-ed25519
181
+ machine-mcp resource generate-ssh-key maintenance-key ~/.ssh/machine-mcp-example-maint-ed25519
181
182
  ```
182
183
 
183
- Under canonical `full`, an authorized MCP host can invoke `generate_ssh_key_resource` with the same semantics. The tool is idempotent, verifies that existing public/private files match, enforces local file modes where supported, and returns only paths, public fingerprint, key type, and registration status—not private key bytes.
184
+ Under canonical `full`, an authorized MCP host can invoke `generate_ssh_key_resource` with the same semantics. The tool is idempotent, verifies that existing public/private files match, enforces local file modes where supported, and returns the public fingerprint, key type, and registration status—not private key bytes or local paths. Pass `expose_paths=true` only when the caller genuinely needs those paths.
184
185
 
185
186
  A job refers to the alias rather than the value:
186
187
 
@@ -192,8 +193,8 @@ A job refers to the alias rather than the value:
192
193
  "argv": [
193
194
  "ssh",
194
195
  "-i",
195
- "{{resource:racknerd-key}}",
196
- "root@example",
196
+ "{{resource:maintenance-key}}",
197
+ "admin@server.example",
197
198
  "sh",
198
199
  "-s"
199
200
  ],
@@ -202,7 +203,7 @@ A job refers to the alias rather than the value:
202
203
  ],
203
204
  "finally_steps": [
204
205
  {
205
- "argv": ["ssh", "-i", "{{resource:racknerd-key}}", "root@example", "rm", "-f", "/tmp/helper"],
206
+ "argv": ["ssh", "-i", "{{resource:maintenance-key}}", "admin@server.example", "rm", "-f", "/tmp/helper"],
206
207
  "allow_failure": true
207
208
  }
208
209
  ]
@@ -258,7 +259,7 @@ Repository-configured external diff, text conversion, and filesystem-monitor hel
258
259
 
259
260
  - `diagnose_runtime` — fixed layered probes; no user-controlled command input
260
261
  - `list_local_resources` — aliases and validation status without paths or values
261
- - `generate_ssh_key_resource` — canonical-full-only Ed25519 generation and private-file resource registration without returning private content
262
+ - `generate_ssh_key_resource` — canonical-full-only Ed25519 generation and private-file registration; private bytes and local paths are omitted by default
262
263
  - `stage_job` — persist a validated plan for later local approval without executing it
263
264
  - `start_job` — detached ordered argv steps, private temporary files, and finally steps
264
265
  - `list_jobs`
@@ -313,7 +314,7 @@ Remote mode supports:
313
314
  - Linux `systemd --user`, with best-effort lingering;
314
315
  - Windows Scheduled Task at logon.
315
316
 
316
- The service definition contains neither credentials nor a duplicate policy. It loads the selected policy from owner-only local state and uses the documented `full` default if policy state is absent. Background services run at log level `warn`: relay, protocol, and service problems are retained, while all per-tool success/failure/cancellation/timing events remain debug-only. Logs are owner-only where supported and bounded by tail trimming.
317
+ The service definition contains neither credentials nor a duplicate policy. It loads the selected policy from owner-only local state and uses the documented `full` default if policy state is absent. launchd/systemd definitions persist a sanitized absolute-only PATH captured during installation, including the stable Node/CLI directories, so background `full` mode does not lose Homebrew or other developer command locations. Background services run at log level `warn`: relay, protocol, and service problems are retained, while all per-tool success/failure/cancellation/timing events remain debug-only. Logs are owner-only where supported and bounded by tail trimming.
317
318
 
318
319
  ## Secret rotation
319
320
 
@@ -347,7 +348,7 @@ npm audit --omit=dev --audit-level=high
347
348
  npm pack --dry-run
348
349
  ```
349
350
 
350
- `npm run check` covers generated Worker types, TypeScript, JavaScript syntax, the shared tool catalog, local path/write/process/state/log/service invariants, Ed25519/RSA generation and key-pair validation, real-machine `full` sandbox acceptance, managed-job detachment/resource redaction/finally/cancellation/recovery, a live stdio MCP flow, and a live local OAuth/Worker/WebSocket/MCP flow. GitHub Actions runs the suite on Linux, macOS, and Windows with supported Node versions.
351
+ `npm run check` covers privacy and release-impact gates, generated Worker types, TypeScript, JavaScript syntax, the shared tool catalog, local path/write/process/state/log/service invariants, Ed25519/RSA generation and key-pair validation, real-machine `full` sandbox acceptance, a clean npm package-manifest/sensitive-artifact check, managed-job detachment/resource redaction/finally/cancellation/recovery, a live stdio MCP flow, and a live local OAuth/Worker/WebSocket/MCP flow. GitHub Actions runs the suite on Linux, macOS, and Windows with the pinned Node 26/npm 12 baseline.
351
352
 
352
353
  See [docs/MANAGED_JOBS.md](docs/MANAGED_JOBS.md), [docs/TESTING.md](docs/TESTING.md), [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md), and [SECURITY.md](SECURITY.md).
353
354
 
@@ -363,3 +364,5 @@ Use `--keep-worker` to retain deployed Workers while removing local state and au
363
364
  ## License
364
365
 
365
366
  MIT
367
+
368
+ See [repository privacy hygiene](docs/PRIVACY.md) and [contribution/release discipline](CONTRIBUTING.md) before committing. Every release-relevant code, test, script, configuration, or documentation change must be pushed to GitHub with a new version and followed by a matching npm release.
package/SECURITY.md CHANGED
@@ -17,6 +17,12 @@ Do not open a public issue for an undisclosed vulnerability. Use GitHub private
17
17
 
18
18
  Do not include live MCP passwords, daemon secrets, OAuth tokens, Cloudflare credentials, private keys, or unrelated local files. Rotate credentials used in a reproduction.
19
19
 
20
+ ## Repository and documentation privacy
21
+
22
+ Tests, examples, documentation, release notes, and package metadata are publication surfaces. Use only synthetic hostnames, resource aliases, usernames, paths, and project names. Run `npm run privacy:check` before committing or publishing, and maintain private local identifiers in the ignored `.privacy-denylist`; the scanner never prints matched values. See [Repository privacy hygiene](docs/PRIVACY.md).
23
+
24
+ Removing a value from the current branch does not remove it from Git history, caches, forks, or an already published npm package. Rotate any exposed credential immediately and coordinate destructive history rewriting separately when its risk is justified.
25
+
20
26
  ## Core trust model
21
27
 
22
28
  Trusted components are:
@@ -53,7 +59,7 @@ The default `full` profile returns absolute paths. Narrower profiles return work
53
59
 
54
60
  The server does not maintain a sensitive-filename blacklist. Under `full`, direct read tools may access any UTF-8 regular file available to the local OS user, including files outside the selected workspace and names such as `.env`, password stores, private keys, credentials, database dumps, and production configuration. Narrower profiles confine direct filesystem tools but do not classify names inside that boundary.
55
61
 
56
- Maximum local policy does not bypass Unix permissions, Windows ACLs, macOS TCC/SIP, container/VM boundaries, endpoint-security controls, shell restrictions, or security decisions made by the MCP host/platform. A host-side refusal is independent of Machine Bridge and cannot be disabled by local policy configuration. `diagnose_runtime` and `machine-mcp doctor` use fixed probes to distinguish requests that reached the daemon from local filesystem/process/shell failures; they cannot inspect a call blocked before delivery.
62
+ Maximum local policy does not bypass Unix permissions, Windows ACLs, macOS TCC/SIP, container/VM boundaries, endpoint-security controls, shell restrictions, or security decisions made by the MCP host/platform. `full` guarantees the complete local daemon and relay-advertised catalog, not the set a connector host chooses to expose to one session. The server cannot observe that host-side subset. A host-side refusal is independent of Machine Bridge and cannot be disabled by local policy configuration. `diagnose_runtime` and `machine-mcp doctor` use fixed probes to distinguish requests that reached the daemon from local filesystem/process/shell failures; they cannot inspect a call blocked before delivery.
57
63
 
58
64
  Processes are not confined by the filesystem-tool resolver. They can access paths, networks, processes, credential stores, and devices available to the local user.
59
65
 
@@ -67,9 +73,7 @@ A canonical `full` profile guarantees that Machine Bridge itself will not reject
67
73
 
68
74
  Writes are bounded, reject symbolic-link/non-regular destinations, use same-directory staging, and commit atomically per file. Create-only commit fails if a concurrent destination appears. Expected hashes and exact edits reduce accidental stale overwrites.
69
75
 
70
- Patch operations prevalidate all paths/content, reject canonical collisions, recheck source hashes and destination absence, serialize bridge mutations, maintain backups, and roll back on ordinary commit errors.
71
-
72
- These controls do not defend against a malicious process running under the same user racing filesystem metadata, nor do they make a multi-directory patch power-loss atomic.
76
+ Patch operations prevalidate all paths/content, reject canonical collisions, recheck source hashes and destination absence, serialize bridge mutations, maintain backups, and roll back on ordinary commit errors. On platforms without descriptor-relative path traversal, a malicious process running as the same local account can still race filesystem or parent-directory replacement between validation and commit. These controls do not claim protection against a hostile same-user namespace, nor do they make a multi-directory patch power-loss atomic.
73
77
 
74
78
  ## Credential exposure
75
79
 
@@ -81,7 +85,7 @@ The default `full` profile passes the complete parent environment. Narrower prof
81
85
 
82
86
  ## Local resources and managed jobs
83
87
 
84
- Local resources are registered through the operator-controlled CLI or, only under canonical `full`, through `generate_ssh_key_resource`. State stores canonical paths and metadata, not file contents. The SSH generator creates or reuses an unencrypted automation key, verifies that the public and private files match, rejects symbolic links/incomplete pairs, applies `0600`/`0644` modes where supported, and returns no private bytes. Unix-like registration rejects group/other-readable private resource files unless explicitly overridden. Portable mode checks do not fully describe Windows ACLs or extended Unix ACLs; the operator remains responsible for platform permissions.
88
+ Local resources are registered through the operator-controlled CLI or, only under canonical `full`, through `generate_ssh_key_resource`. State stores canonical paths, bounded registration-time aliases used only for redaction, and metadatanot file contents. Public status and resource results omit those aliases. The SSH generator creates or reuses an unencrypted automation key, verifies that the public and private files match, rejects symbolic links/incomplete pairs, applies `0600`/`0644` modes where supported, and returns no private bytes. Resource CLI output and `generate_ssh_key_resource` omit local paths by default; path disclosure requires `--show-paths` or `expose_paths=true`. Unix-like registration rejects group/other-readable private resource files unless explicitly overridden. Portable mode checks do not fully describe Windows ACLs or extended Unix ACLs; the operator remains responsible for platform permissions.
85
89
 
86
90
  At job acceptance, referenced resources are bounded and hashed. The detached runner reopens and verifies each hash before copying it to a private `0600` runtime file. Resource copies are removed after the finally phase. A changed or unavailable resource fails closed.
87
91
 
@@ -97,7 +101,7 @@ Managed jobs accept arbitrary argv and therefore retain local-user authority. Th
97
101
 
98
102
  Active plans are owner-only and may temporarily contain argv, non-secret stdin, temporary helper content, environment overrides, and resource source paths for crash recovery. A terminal runner deletes the full plan. Status and bounded results remain for up to seven days/50 jobs. If a runner crashes before terminal commit, the plan remains until recovery or retention cleanup.
99
103
 
100
- Exact resource paths, exact resource bytes interpreted as text, and bounded exact base64/hex forms are redacted from retained output. This cannot detect partial, transformed, encrypted, compressed, or application-specific encodings. It also cannot redact unrelated secrets inherited through the full parent environment. Use `capture_output: "discard"` whenever a process may echo credentials, and never place a secret directly in argv, ordinary env, stdin, temporary-file content, or a JSON plan.
104
+ Exact canonical and registration-time resource path aliases, exact resource bytes interpreted as text, and bounded exact base64/hex forms are redacted from retained output. This cannot detect partial, transformed, encrypted, compressed, or application-specific encodings. It also cannot redact unrelated secrets inherited through the full parent environment. Use `capture_output: "discard"` whenever a process may echo credentials, and never place a secret directly in argv, ordinary env, stdin, temporary-file content, or a JSON plan.
101
105
 
102
106
  `finally_steps` run after ordinary success, failure, timeout, and cancellation. Cancellation uses an owner-only marker rather than signaling the runner process itself, so the coordinator remains alive to execute cleanup consistently across platforms. A dead runner is detected on the next daemon or local job-CLI start; stale private resource copies are removed and cleanup is retried. This is best effort. Power loss, disk failure, permanent loss of credentials/network access, SIGKILL without later recovery, or security software denying the cleanup executable can prevent cleanup. Finally steps must be idempotent and safe to repeat. Automatic recovery is capped at three attempts so persistent endpoint-security or executable-policy denial cannot create an endless launch loop. Uninstall refuses to remove local state while managed jobs are active; operators must inspect or cancel them first.
103
107
 
@@ -157,7 +161,7 @@ machine-mcp --workspace /narrow/project --profile edit --no-print-credentials
157
161
 
158
162
  Also:
159
163
 
160
- - patch the OS and use supported Node.js releases;
164
+ - patch the OS and use the repository-pinned Node.js 26/npm 12 baseline;
161
165
  - enable MFA on Cloudflare, GitHub, and npm accounts;
162
166
  - do not configure broad CORS origins;
163
167
  - select `agent`, `edit`, or `review` instead of the default `full` when broad authority is unnecessary;
@@ -85,7 +85,7 @@ The daemon attachment deliberately omits workspace path/name/hash and process ID
85
85
 
86
86
  ### Autostart layer
87
87
 
88
- The service layer emits launchd, systemd-user, or Windows Scheduled Task definitions. Credentials are not embedded in service definitions; the daemon loads owner-only state. The exact policy is stored in owner-only state; platform service definitions contain only the workspace/state-root selectors and a `warn` log-level setting.
88
+ The service layer emits launchd, systemd-user, or Windows Scheduled Task definitions. Credentials are not embedded in service definitions; the daemon loads owner-only state. The exact policy is stored in owner-only state. launchd/systemd definitions contain the workspace/state-root selectors, a `warn` log-level setting, and a sanitized absolute-only PATH captured at installation so background `full` mode can resolve the same developer tools without accepting relative PATH entries.
89
89
 
90
90
  ## Trust boundaries
91
91
 
@@ -105,7 +105,7 @@ flowchart LR
105
105
  CLI --> S[Autostart provider]
106
106
  ```
107
107
 
108
- Remote OAuth determines which client may call tools. Local stdio access relies on the local process and configuration boundary. Policy determines which tools are advertised. Canonical resolution limits direct filesystem tools. Processes retain local-user authority and can escape workspace constraints through their own code or system calls.
108
+ Remote OAuth determines which client may call tools. Local stdio access relies on the local process and configuration boundary. Policy determines which tools the local daemon and relay advertise. A connector host can independently present a smaller tool subset to a session; this post-relay filtering is outside the protocol state visible to Machine Bridge. Canonical resolution limits direct filesystem tools. Processes retain local-user authority and can escape workspace constraints through their own code or system calls.
109
109
 
110
110
  ## Remote request lifecycle
111
111
 
@@ -131,15 +131,15 @@ Duplicate in-flight JSON-RPC IDs for the same access token are rejected so cance
131
131
  2. The server negotiates one of the supported MCP versions.
132
132
  3. Tool discovery is generated from the same catalog and policy used by remote mode.
133
133
  4. Each call receives an internal random call ID used only for cancellation and process tracking.
134
- 5. Results are emitted as JSON-RPC on stdout; logs remain on stderr.
135
- 6. Duplicate in-flight request IDs are rejected.
134
+ 5. Input is parsed as incrementally bounded newline-delimited JSON-RPC, so an oversized line is discarded before unbounded buffering and the next line can still be processed. Results are emitted as JSON-RPC on stdout; logs remain on stderr.
135
+ 6. Duplicate in-flight request IDs are rejected, and `tools/call` requires a non-null request ID so write or execution calls cannot run as unacknowledged JSON-RPC notifications.
136
136
  7. Closing stdin cancels pending calls, terminates ordinary active processes/process sessions, and removes the transport runtime directory. Previously accepted managed jobs continue in their persistent per-workspace job directories.
137
137
 
138
138
  ## Filesystem resolution and privacy
139
139
 
140
140
  The workspace is canonicalized and compared with targets through consistent platform-native/async `realpath` representations. Existing targets must remain inside the workspace unless the active policy is unrestricted. New targets walk to the nearest existing ancestor, validate its canonical path, and reconstruct the destination below that canonical ancestor.
141
141
 
142
- Path behavior is profile-dependent. The default `full` profile permits unrestricted direct filesystem paths and returns absolute paths. The `agent`, `edit`, and `review` profiles enforce canonical workspace containment and return workspace-relative paths. Error strings redact canonical and common platform-alias forms of workspace, runtime, and home paths whenever absolute path display is disabled.
142
+ Path behavior is profile-dependent. The default `full` profile permits unrestricted direct filesystem paths and returns absolute paths. The `agent`, `edit`, and `review` profiles enforce canonical workspace containment and return workspace-relative paths. Error strings redact canonical and common platform-alias forms of workspace, runtime, and home paths whenever absolute path display is disabled. Access scope and path display are independent: unrestricted access with path display disabled returns relative workspace paths and opaque external-path identifiers.
143
143
 
144
144
  Symbolic-link destinations and non-regular write targets are rejected. Recursive walkers do not follow symbolic-link directories.
145
145
 
@@ -193,7 +193,7 @@ OAuth metadata is pruned on access. Expired codes/tokens, old throttling records
193
193
 
194
194
  ## Observability
195
195
 
196
- Public health exposes only server identity and version. Authenticated `server_info` exposes bounded runtime status, policy origin/revision, managed-job counts, and resource alias names without paths or values. `diagnose_runtime` runs fixed local probes and explicitly reports that its own request reached the daemon.
196
+ Public health exposes only server identity and version. Authenticated `server_info` exposes bounded runtime status, policy origin/revision, managed-job counts, resource alias names without paths or values, and the daemon/relay-advertised tool counts. It explicitly reports that the host-exposed subset is unknown to the server. `diagnose_runtime` runs fixed local probes and explicitly reports that its own request reached the daemon.
197
197
 
198
198
  Foreground logging defaults to `info`; autostart uses `warn`. All per-tool starts, successes, failures, cancellations, durations, and shortened random correlation IDs are debug-only. Normal logs retain deployment, connection, protocol, service, and infrastructure events rather than duplicating MCP tool outcomes. Unexpected local and Worker infrastructure errors are reduced to classes. Messages, strings, arrays, object depth/key counts, and serialized fields are bounded.
199
199
 
package/docs/CLIENTS.md CHANGED
@@ -131,9 +131,9 @@ Before connecting a host, verify the local implementation directly:
131
131
  machine-mcp full-test --workspace /path/to/project
132
132
  ```
133
133
 
134
- A passing result proves that Machine Bridge and the local OS allowed its temporary file/process/shell/key/job probes at that time. It does not prove that a hosted MCP connector will deliver a later request or that a cloud/remote account will authorize it.
134
+ A passing result proves that Machine Bridge and the local OS allowed its temporary file/process/shell/key/job probes at that time. It does not prove that a hosted MCP connector will expose every relay-advertised tool, deliver a later request, or that a cloud/remote account will authorize it.
135
135
 
136
- For SSH automation, prefer `generate_ssh_key_resource` under canonical full, or `machine-mcp resource generate-ssh-key` from the terminal. The private key remains a local resource; only paths and the public fingerprint are returned. Installation of the public key into Google OS Login or a remote `authorized_keys` file remains an explicit external action.
136
+ For SSH automation, prefer `generate_ssh_key_resource` under canonical full, or `machine-mcp resource generate-ssh-key` from the terminal. The private key remains a local resource; private bytes and local paths are omitted by default, while metadata and the bare public fingerprint are returned. Paths require an explicit disclosure option. Installation of the public key into Google OS Login or a remote `authorized_keys` file remains an explicit external action.
137
137
 
138
138
  ## Host-side safety rules
139
139
 
package/docs/LOGGING.md CHANGED
@@ -71,3 +71,7 @@ Each managed job also has owner-only `runner.out.log` and `runner.err.log` files
71
71
  Machine Bridge does not classify filenames as sensitive and does not block `.env`, password, key, or credential-looking names. The active local policy, local OS permissions, and endpoint-security controls determine what the server itself can read or execute.
72
72
 
73
73
  An MCP host, model provider, desktop application, or platform execution layer may independently deny a request involving credentials or sensitive files. Such a denial occurs before or outside Machine Bridge's file resolver and cannot be disabled by selecting the local `full` profile. Use `server_info`, `machine-mcp status`, and `machine-mcp doctor` to distinguish the active local policy from host-side enforcement.
74
+
75
+ ## Privacy filtering
76
+
77
+ Structured fields whose names indicate a local path, workspace, working directory, home, or state root are replaced with `<local-path>`. Free-form log text removes known home-directory prefixes, email addresses, common bearer/cloud/API token forms, private-key headers, control characters, and Unicode bidirectional/zero-width formatting controls. Explicit command output and JSON command results are not operational logs and retain their documented opt-in disclosure semantics.
@@ -46,10 +46,11 @@ A successful diagnostic response proves that particular request reached the loca
46
46
  Secrets and other local-only files should be registered from the user's terminal, not read into the model context:
47
47
 
48
48
  ```sh
49
- chmod 600 ~/.ssh/racknerd_ed25519
50
- machine-mcp resource add racknerd-key ~/.ssh/racknerd_ed25519
51
- machine-mcp resource list
52
- machine-mcp resource check racknerd-key
49
+ chmod 600 ~/.ssh/example_maintenance_ed25519
50
+ machine-mcp resource add maintenance-key ~/.ssh/example_maintenance_ed25519
51
+ machine-mcp resource list # paths omitted by default
52
+ machine-mcp resource list --show-paths # explicit local-only disclosure
53
+ machine-mcp resource check maintenance-key
53
54
  ```
54
55
 
55
56
  Registration stores only canonical path and bounded metadata in owner-only state. It reads the file locally to validate accessibility and size but does not print or send its contents. New jobs see registry changes immediately; the daemon does not need a restart.
@@ -59,7 +60,7 @@ Unix-like systems reject group/other-readable resource files by default. `--allo
59
60
  Remove an alias with:
60
61
 
61
62
  ```sh
62
- machine-mcp resource remove racknerd-key
63
+ machine-mcp resource remove maintenance-key
63
64
  ```
64
65
 
65
66
  Removing an alias affects new jobs. A job already accepted has an owner-only resource snapshot specification and continues independently.
@@ -67,10 +68,10 @@ Removing an alias affects new jobs. A job already accepted has an owner-only res
67
68
  Generate a new Ed25519 resource rather than exposing a private-key creation command through a model-generated shell string:
68
69
 
69
70
  ```sh
70
- machine-mcp resource generate-ssh-key racknerd-key ~/.ssh/ai-racknerd-maint-ed25519
71
+ machine-mcp resource generate-ssh-key maintenance-key ~/.ssh/machine-mcp-example-maint-ed25519
71
72
  ```
72
73
 
73
- Canonical-full MCP clients also receive `generate_ssh_key_resource`. It generates or reuses the pair locally, verifies correspondence, registers the private file, and returns no private bytes. Public-key installation in a cloud or remote account should be a separate reviewed step or managed job.
74
+ Canonical-full MCP clients also receive `generate_ssh_key_resource`. It generates or reuses the pair locally, verifies correspondence, registers the private file, and returns neither private bytes nor local paths by default. Set `expose_paths=true` only for an explicit path-retrieval operation. Public-key installation in a cloud or remote account should be a separate reviewed step or managed job.
74
75
 
75
76
  ## Resource injection modes
76
77
 
@@ -80,7 +81,7 @@ A managed step is argv-based and supports three local resource modes:
80
81
 
81
82
  ```json
82
83
  {
83
- "argv": ["ssh", "-i", "{{resource:racknerd-key}}", "root@example", "true"]
84
+ "argv": ["ssh", "-i", "{{resource:maintenance-key}}", "admin@server.example", "true"]
84
85
  }
85
86
  ```
86
87
 
@@ -152,8 +153,8 @@ For a remote shell program, avoid a remote helper entirely when possible:
152
153
  "argv": [
153
154
  "ssh",
154
155
  "-i",
155
- "{{resource:racknerd-key}}",
156
- "root@example",
156
+ "{{resource:maintenance-key}}",
157
+ "admin@server.example",
157
158
  "sh",
158
159
  "-s"
159
160
  ],
@@ -174,12 +175,12 @@ A job can contain ordered main steps and ordered `finally_steps`:
174
175
  "name": "remote maintenance",
175
176
  "steps": [
176
177
  {
177
- "argv": ["ssh", "root@example", "perform-maintenance"]
178
+ "argv": ["ssh", "admin@server.example", "perform-maintenance"]
178
179
  }
179
180
  ],
180
181
  "finally_steps": [
181
182
  {
182
- "argv": ["ssh", "root@example", "rm", "-f", "/tmp/maintenance-helper"],
183
+ "argv": ["ssh", "admin@server.example", "rm", "-f", "/tmp/maintenance-helper"],
183
184
  "allow_failure": true
184
185
  }
185
186
  ]
@@ -207,7 +208,7 @@ machine-mcp job approve JOB_ID
207
208
  machine-mcp job approve JOB_ID --yes
208
209
  ```
209
210
 
210
- `job inspect` displays the reviewable plan, including argv, ordinary environment overrides, stdin, temporary helper content, and finally steps, while omitting registered resource source paths and per-resource hashes. The overall `plan_sha256` can be compared with the value returned by `stage_job`.
211
+ `job inspect` displays the reviewable plan, including argv, ordinary environment overrides, stdin, temporary helper content, and finally steps, while omitting registered resource source paths and per-resource hashes. The overall `plan_sha256` is displayed for review and is revalidated atomically during approval and again by the runner before execution. A modified staged plan is rejected.
211
212
 
212
213
  Local approval is a new operator authorization. It intentionally does not depend on the current MCP execution profile: a plan staged under a write-capable profile can be reviewed and approved from the terminal even when the connector is not allowed to execute. The plan retains the filesystem scope and environment mode captured when it was staged.
213
214
 
@@ -14,6 +14,7 @@ machine-mcp service status
14
14
 
15
15
  | Result | Interpretation |
16
16
  |---|---|
17
+ | `server_info` reports full and all relay tools, but the current session UI exposes fewer tools | Host/connector post-relay filtering; Machine Bridge cannot enumerate or override that subset |
17
18
  | No structured result because the host rejects the call | Host/connector approval or safety layer, or transport before daemon delivery |
18
19
  | `mcp-host-to-daemon` passes but `local-filesystem` fails | Local state/runtime permissions, disk policy, sandbox, or endpoint security |
19
20
  | Filesystem passes but `local-process-spawn` fails | Local executable policy, endpoint security, OS permissions, or damaged Node runtime |
@@ -21,11 +22,11 @@ machine-mcp service status
21
22
  | `managed-job-storage` fails | Owner-only profile/job directory cannot be used |
22
23
  | Registered resource is unavailable | File moved, permissions changed, size exceeded, or local access denied |
23
24
 
24
- A successful diagnostic result applies only to that probe. An MCP host can still deny a later call based on its own request context.
25
+ A successful diagnostic result applies only to that probe. An MCP host can still deny a later call based on its own request context. This is expected layering, not a defect in the `full` profile: `full` removes Machine Bridge's own denials, while host delivery remains independent.
25
26
 
26
27
  ## Logs
27
28
 
28
- Remote autostart logs are stored under the state root in `logs/daemon.out.log` and `logs/daemon.err.log`. Files are owner-only where supported and tail-trimmed before daemon startup.
29
+ Remote autostart definitions prefer a stable PATH alias that resolves to the currently running Node executable and persist a sanitized absolute-only service `PATH` containing the Node/CLI directories, the installer's absolute PATH entries, and platform defaults. This avoids versioned Homebrew-style paths becoming invalid after upgrades and prevents launchd/systemd from falling back to a minimal system-only PATH. Re-run `machine-mcp service install` after changing Node installation families or PATH layout. Autostart logs are stored under the state root in `logs/daemon.out.log` and `logs/daemon.err.log`. Files are owner-only where supported and tail-trimmed before daemon startup.
29
30
 
30
31
  Logging is level-based:
31
32
 
@@ -58,7 +59,7 @@ Generate and register an operator key locally:
58
59
  machine-mcp resource generate-ssh-key NAME [PRIVATE_KEY_PATH]
59
60
  ```
60
61
 
61
- An authorized canonical-full MCP client can use `generate_ssh_key_resource`. Both paths validate the key pair and return only metadata and a public fingerprint. They do not install the public key in Google, modify `authorized_keys`, or grant remote `sudo`; those remain explicit managed-job/local-operator operations.
62
+ An authorized canonical-full MCP client can use `generate_ssh_key_resource`. Both paths validate the key pair and return only metadata and the bare public fingerprint. Local paths are omitted unless `--show-paths` or `expose_paths=true` is explicitly requested; public-key comments are not included in the returned fingerprint. They do not install the public key in Google, modify `authorized_keys`, or grant remote `sudo`; those remain explicit managed-job/local-operator operations.
62
63
 
63
64
  ## Managed jobs and local recovery
64
65
 
@@ -66,7 +67,8 @@ Register local-only resources from the terminal:
66
67
 
67
68
  ```sh
68
69
  machine-mcp resource add NAME FILE_PATH
69
- machine-mcp resource list
70
+ machine-mcp resource list # paths omitted by default
71
+ machine-mcp resource list --show-paths # explicit local-only disclosure
70
72
  machine-mcp resource check NAME
71
73
  machine-mcp resource remove NAME
72
74
  ```
@@ -102,8 +104,9 @@ Pending calls are bound to the socket that received them. Results from another s
102
104
  Defense-in-depth limits include:
103
105
 
104
106
  - Worker MCP body: 8 MiB by default, hard cap 16 MiB;
107
+ - stdio JSON-RPC line: 8 MiB, enforced incrementally while reading;
105
108
  - OAuth body: 64 KiB;
106
- - daemon WebSocket message: 8 MiB;
109
+ - daemon WebSocket message: 8 MiB, enforced by the local WebSocket parser before string conversion;
107
110
  - text writes and patch envelopes: 5 MiB;
108
111
  - images: 4 MiB before base64 encoding;
109
112
  - shell/argv envelope: 64 KiB;
@@ -128,7 +131,7 @@ Defense-in-depth limits include:
128
131
 
129
132
  Policy revision 3 makes named profiles canonical. A state entry labelled `full` is repaired to writes, direct processes, process sessions, shell execution, unrestricted direct filesystem paths, absolute path output, the complete parent environment, and the complete tool catalog. CLI capability overrides are stored as `custom`. The exact pre-0.4 implicit-default shape is still migrated to the current `full` default; explicit restrictive and identified custom profiles remain preserved.
130
133
 
131
- `full` removes Machine Bridge's own profile/path/environment/shell denials. It does not override operating-system access controls, endpoint security, remote authentication, cloud IAM, `sudo`, or independent MCP-host/platform policy.
134
+ `full` removes Machine Bridge's own profile/path/environment/shell denials and makes the complete catalog available to the relay. It does not force a connector host to expose every relayed tool, and the server cannot see the host's final subset. It also does not override operating-system access controls, endpoint security, remote authentication, cloud IAM, `sudo`, or independent MCP-host/platform policy.
132
135
 
133
136
  Inspect effective policy with:
134
137
 
@@ -0,0 +1,37 @@
1
+ # Repository privacy hygiene
2
+
3
+ Source code, tests, examples, release notes, and documentation are publication surfaces. Examples must use synthetic identifiers such as `maintenance-key`, `admin@server.example`, reserved example domains, and generic filesystem paths. Do not copy a real server alias, username, hostname, account name, workspace path, key filename, customer name, or internal codename into a fixture merely because the value is not itself a credential.
4
+
5
+ ## Automated check
6
+
7
+ Run:
8
+
9
+ ```sh
10
+ npm run privacy:check
11
+ ```
12
+
13
+ The check scans tracked and unignored new UTF-8 files and their relative names for private-key material, common live-token forms, user-home paths, non-example `user@host` identifiers, and locally configured private identifiers. Publication-surface symbolic links are rejected rather than followed. Binary, invalid UTF-8, and files above the bounded scanner limit fail closed and require explicit manual review instead of being silently skipped. It reports only the file, line, and rule; it does not print the matched value.
14
+
15
+ Maintain machine-specific names in an ignored owner-only file:
16
+
17
+ ```sh
18
+ cp .privacy-denylist.example .privacy-denylist
19
+ chmod 600 .privacy-denylist
20
+ ```
21
+
22
+ Add one identifier per line. The denylist is deliberately local and must never be committed. CI still runs the built-in generic checks; a developer's local check adds their private vocabulary.
23
+
24
+ ## Review rules
25
+
26
+ Before committing or publishing:
27
+
28
+ - inspect the complete staged diff, including tests, snapshots, examples, release notes, and generated metadata;
29
+ - use reserved example domains and neutral aliases;
30
+ - run `npm run privacy:check`, `npm run check`, and `npm pack --dry-run`;
31
+ - treat paths, host aliases, usernames, and codenames as private metadata even when they are not authentication secrets.
32
+
33
+ The scanner is heuristic. It cannot identify every personal or organizational name, transformed value, image, archive, binary fixture, or data already present in Git history.
34
+
35
+ ## Incident response
36
+
37
+ For an accidental publication, remove the value from the current tree and release artifacts, determine whether it is merely identifying metadata or an active credential, and rotate/revoke any credential immediately. Public Git and npm history are immutable in ordinary workflows: replacing the current file does not erase old commits or a published package. A coordinated history rewrite, cache invalidation request, or replacement release may be appropriate, but those actions are disruptive and require an explicit repository-owner decision.
package/docs/RELEASING.md CHANGED
@@ -7,6 +7,8 @@ The release invariant is:
7
7
  - A final GitHub Release exists for the tag.
8
8
  - The GitHub Release contains the npm tarball generated from that commit.
9
9
  - `package.json`, `package-lock.json`, and the Worker-reported version agree.
10
+ - Every release-relevant change since the prior version tag has a higher package version and matching CHANGELOG section.
11
+ - The same reviewed change is present on GitHub and in a new npm version.
10
12
 
11
13
  `npm publish` runs `release:check` through `prepublishOnly`, so npm publication is blocked until all GitHub state is synchronized.
12
14
 
@@ -18,8 +20,11 @@ The release invariant is:
18
20
  npm version <version> --no-git-tag-version
19
21
  ```
20
22
 
21
- 2. Add the matching `CHANGELOG.md` section.
22
- 3. Run `npm run check`, review the diff, and commit all release changes to `main`.
23
+ 2. Add the matching dated `CHANGELOG.md` section.
24
+ 3. Run `npm run release-impact:check`, `npm run privacy:check`, `npm run check`, both dependency audits, `npm audit signatures`, and generate a CycloneDX `npm sbom`.
25
+ 4. Inspect the complete diff and `npm pack --dry-run`, then commit and push all release changes to `main`.
26
+
27
+ A privacy/security documentation correction is not “docs only” for release purposes. It requires a replacement npm version and, when appropriate, deprecation or unpublication of the affected version.
23
28
 
24
29
  ## Publish GitHub source and release
25
30
 
@@ -29,7 +34,7 @@ From a clean `main` worktree:
29
34
  npm run release:publish
30
35
  ```
31
36
 
32
- The command validates the project, fast-forwards `origin/main`, creates or verifies the annotated version tag, pushes it, builds the npm tarball, creates or updates the GitHub Release, uploads the tarball, and verifies the resulting state.
37
+ The command validates the project, including repository privacy checks, fast-forwards `origin/main`, creates or verifies the annotated version tag, pushes it, builds the npm tarball, creates or updates the GitHub Release, uploads the tarball, and verifies the resulting state. Read-only GitHub operations, Git pushes, and idempotent release updates use bounded retries only for classified transient network failures; ambiguous Release creation responses are resolved by querying server state before continuing.
33
38
 
34
39
  To verify without changing anything:
35
40
 
@@ -51,7 +56,7 @@ Only after `release:check` succeeds:
51
56
  npm publish --access public
52
57
  ```
53
58
 
54
- The npm lifecycle repeats the full project checks and the GitHub synchronization check before upload.
59
+ The npm lifecycle repeats the full project checks and the GitHub synchronization check before upload. Do not leave a code or documentation fix only on GitHub; the corresponding npm version must be published, and the operator should be explicitly reminded until registry publication is confirmed.
55
60
 
56
61
  ## Authentication requirements
57
62
 
package/docs/TESTING.md CHANGED
@@ -8,8 +8,11 @@ The project treats transport, authorization, local authority, and state removal
8
8
  npm run check
9
9
  ```
10
10
 
11
+ The repository requires Node.js 26 and npm 12. `.node-version`, `.nvmrc`, `packageManager`, `devEngines`, and strict engine checks keep local and CI execution on the same baseline.
12
+
11
13
  The suite includes:
12
14
 
15
+ - release-impact enforcement requiring a new package version and CHANGELOG section for release-relevant changes;
13
16
  - generated Cloudflare Worker types and strict TypeScript checking;
14
17
  - syntax validation for every shipped JavaScript entry point;
15
18
  - shared tool-catalog schema, annotation, and profile-inventory checks;
@@ -44,11 +47,14 @@ The suite includes:
44
47
  npm run worker:dry-run
45
48
  npm audit --audit-level=high
46
49
  npm audit --omit=dev --audit-level=high
50
+ npm audit signatures
51
+ npm sbom --sbom-format cyclonedx
47
52
  npm pack --dry-run
48
53
  npm run version:check
54
+ npm run release-impact:check
49
55
  ```
50
56
 
51
- GitHub Actions executes the main suite on Linux, macOS, and Windows. Node 22 and 24 are covered on Linux; Node 22 is covered on macOS and Windows. A separate package-audit job audits both the complete dependency graph and the production-only graph, then performs a dry-run package build. Dependency and GitHub Actions updates are monitored by Dependabot.
57
+ GitHub Actions executes the main suite on Linux, macOS, and Windows using the pinned Node 26/npm 12 baseline. Because Node 26 currently bundles npm 11, CI explicitly disables setup-node's automatic package-manager cache and upgrades npm from the runner temporary directory before any project-local npm command can trigger strict `devEngines`. Checkout fetches version tags so the release-impact gate can compare the branch with the latest release. A separate package-audit job audits both the complete dependency graph and the production-only graph, verifies registry signatures and attestations, validates a CycloneDX SBOM written under the runner temporary directory, then performs a dry-run package build. Dependency and GitHub Actions updates are monitored by Dependabot.
52
58
 
53
59
  ## Test design rules
54
60
 
@@ -61,3 +67,13 @@ GitHub Actions executes the main suite on Linux, macOS, and Windows. Node 22 and
61
67
  - Secret-bearing resource tests must assert absence of raw, path, base64, and hex forms from MCP-visible results.
62
68
  - Logs and public metadata should be tested for absence of sensitive fields, arguments, outputs, and routine success noise—not only presence of expected fields.
63
69
  - Cross-platform tests must avoid shell syntax, URL-path conversion, and executable-shim assumptions specific to one operating system.
70
+
71
+ ## Privacy hygiene
72
+
73
+ Run `npm run privacy:check` before committing and before packaging. Developers should maintain an ignored owner-only `.privacy-denylist` for machine aliases, usernames, internal codenames, and other private identifiers that a generic scanner cannot know. See [Repository privacy hygiene](PRIVACY.md).
74
+
75
+ ## Package manifest
76
+
77
+ `npm run package:test` executes a real silent `npm pack --dry-run --json`, requires clean parseable JSON, rejects sensitive local artifacts and credential-like file classes, and verifies that privacy guidance, contribution/release discipline, and both privacy/release-impact checkers are present in the published package.
78
+
79
+ The stdio integration test also sends an oversized line, verifies bounded rejection, and confirms that the next valid request is still processed.