machine-bridge-mcp 0.17.1 → 0.18.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 +27 -0
- package/README.md +12 -13
- package/SECURITY.md +13 -13
- package/browser-extension/manifest.json +2 -2
- package/docs/ARCHITECTURE.md +5 -5
- package/docs/AUDIT.md +3 -3
- package/docs/CLIENTS.md +2 -2
- package/docs/GETTING_STARTED.md +13 -9
- package/docs/LOGGING.md +2 -2
- package/docs/MANAGED_JOBS.md +1 -1
- package/docs/MULTI_ACCOUNT.md +75 -358
- package/docs/OPERATIONS.md +4 -4
- package/docs/POLICY_REFERENCE.md +1 -1
- package/docs/PRIVACY.md +1 -1
- package/docs/PROJECT_STANDARDS.md +1 -1
- package/docs/TESTING.md +4 -4
- package/package.json +4 -3
- package/src/local/account-access.mjs +37 -0
- package/src/local/account-admin.mjs +105 -0
- package/src/local/bounded-output.mjs +50 -0
- package/src/local/call-registry.mjs +10 -0
- package/src/local/cli-account-admin.mjs +79 -0
- package/src/local/cli-options.mjs +9 -4
- package/src/local/cli-policy.mjs +7 -28
- package/src/local/cli.mjs +48 -78
- package/src/local/daemon-process.mjs +3 -2
- package/src/local/errors.mjs +0 -14
- package/src/local/log.mjs +1 -1
- package/src/local/managed-jobs.mjs +1 -3
- package/src/local/process-execution.mjs +90 -60
- package/src/local/relay-connection.mjs +11 -3
- package/src/local/runtime.mjs +27 -2
- package/src/local/service-convergence.mjs +20 -0
- package/src/local/service.mjs +12 -29
- package/src/local/shell.mjs +17 -29
- package/src/local/state-inventory.mjs +2 -2
- package/src/local/state.mjs +30 -85
- package/src/local/tool-executor.mjs +8 -2
- package/src/shared/access-contract.json +23 -0
- package/src/shared/policy-contract.json +30 -7
- package/src/worker/access.ts +46 -0
- package/src/worker/account-admin.ts +103 -0
- package/src/worker/index.ts +75 -48
- package/src/worker/oauth-state.ts +184 -2
- package/src/worker/tool-catalog.ts +13 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.18.1 - 2026-07-14
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- Wait for launchd service state to converge after a successful `bootout` before deciding that stop or restart failed. The bounded poll handles macOS's asynchronous unload window while still failing closed when the service remains active.
|
|
8
|
+
- Add deterministic coverage for delayed launchd inactivity and for the bounded failure path.
|
|
9
|
+
|
|
10
|
+
## 0.18.0 - 2026-07-14
|
|
11
|
+
|
|
12
|
+
### Isolated multi-account authorization
|
|
13
|
+
|
|
14
|
+
- Replace the workspace-wide shared OAuth password with named accounts and four roles: reviewer, editor, operator, and owner. OAuth codes and tokens are bound to one account id, account version, and role; account changes revoke only that account's credentials.
|
|
15
|
+
- Intersect each account role with the connected daemon policy when listing or invoking tools. The Worker rejects unauthorized tools before relay, and every relayed call carries immutable account authorization metadata for a second local enforcement check.
|
|
16
|
+
- Add owner-only account administration for listing, creating, enabling, disabling, changing roles, rotating passwords, and removing accounts. Passwords are generated 256-bit tokens stored as independent salted HMAC-SHA-256 verifiers; arbitrary human-chosen passwords are rejected, plaintext tokens are shown once, and they are not retained in local state.
|
|
17
|
+
- Upgrade the existing Cloudflare Worker and Durable Object in place. A one-time release operation converts the current shared credential into the initial owner account and annotates existing OAuth codes and tokens without changing their keys or the global token version, preserving the existing ChatGPT connector authorization.
|
|
18
|
+
|
|
19
|
+
### Runtime reliability and diagnostics
|
|
20
|
+
|
|
21
|
+
- Cancel all relay-owned local calls immediately when the relay disconnects. Process execution now rejects cancellation before a child emits `close`, while process ownership remains tracked until actual exit, preventing permanently active calls without losing process cleanup.
|
|
22
|
+
- Replace prefix-only command capture with bounded beginning-and-end retention. Long stdout and stderr report exact omitted byte counts and preserve the diagnostic tail where test and compiler failures normally appear.
|
|
23
|
+
- Consume rejected authenticated MCP request bodies before returning 401, preventing workerd request-stream exceptions after per-account token revocation.
|
|
24
|
+
|
|
25
|
+
### Breaking state and maintenance model
|
|
26
|
+
|
|
27
|
+
- Advance local state to schema 6, the state-root marker to schema 2, and policy to revision 5. Final runtime code accepts only the current formats; valid obsolete state is rejected instead of migrated, while syntactically corrupt JSON is isolated and rebuilt as current empty state.
|
|
28
|
+
- Remove shared-password CLI flags, policy migration branches, old daemon-lock interpretation, numeric managed-job PID compatibility, and old log-format archival. The one-time in-place release operation updates live state and deletes obsolete artifacts before the final runtime is installed.
|
|
29
|
+
|
|
3
30
|
## 0.17.1 - 2026-07-14
|
|
4
31
|
|
|
5
32
|
### Installation and first use
|
package/README.md
CHANGED
|
@@ -34,7 +34,7 @@ A newly selected workspace starts with the maximum-permission `full` profile for
|
|
|
34
34
|
- tool results may return absolute paths;
|
|
35
35
|
- child processes inherit the complete parent environment.
|
|
36
36
|
|
|
37
|
-
Policy state records whether it came from the default, an explicit named profile, or custom overrides. Named profiles are canonical contracts: a stored `full` profile
|
|
37
|
+
Policy state records whether it came from the default, an explicit named profile, or custom overrides. Named profiles are canonical contracts: a stored `full` profile always enables writes, shell execution, unrestricted paths, the full parent environment, absolute path output, and the complete tool catalog. Any explicit per-capability narrowing is stored as `custom`. Policy revision 5 is the only accepted persisted policy format and applies compound tool requirements consistently in the local daemon and Worker.
|
|
38
38
|
|
|
39
39
|
| Profile | File edits | Direct argv processes | Shell commands | Filesystem scope | Process environment |
|
|
40
40
|
|---|---:|---:|---:|---|---|
|
|
@@ -51,7 +51,7 @@ For prerequisites, first remote deployment, ChatGPT connection, stdio configurat
|
|
|
51
51
|
|
|
52
52
|
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.
|
|
53
53
|
|
|
54
|
-
Use a new temporary directory for the bootstrap. The existing `npm`/`npx` front-end may inspect nearby project metadata before it launches the requested npm version; starting from an empty directory prevents an unrelated
|
|
54
|
+
Use a new temporary directory for the bootstrap. The existing `npm`/`npx` front-end may inspect nearby project metadata before it launches the requested npm version; starting from an empty directory prevents an unrelated outdated `devEngines` declaration from blocking the bootstrap. The actual installation is then executed by the pinned npm 12 CLI rather than whichever npm happens to be first on `PATH`.
|
|
55
55
|
|
|
56
56
|
macOS/Linux:
|
|
57
57
|
|
|
@@ -81,7 +81,7 @@ npm --version
|
|
|
81
81
|
machine-mcp doctor
|
|
82
82
|
```
|
|
83
83
|
|
|
84
|
-
`Unknown cli config "--allow-scripts"` proves the Machine Bridge install was executed by npm 11 or older rather than the required npm 12. `Invalid property "node"` or `Invalid property "devEngines.node"` means that npm parsed
|
|
84
|
+
`Unknown cli config "--allow-scripts"` proves the Machine Bridge install was executed by npm 11 or older rather than the required npm 12. `Invalid property "node"` or `Invalid property "devEngines.node"` means that npm parsed an outdated `devEngines` object; the npm debug log is required to identify which package supplied it. The empty-directory, pinned-npm procedure avoids relying on that old parser. If `npm --version` still reports an older version after the bootstrap, reopen the terminal and rerun `machine-mcp doctor`.
|
|
85
85
|
|
|
86
86
|
Recent npm releases may otherwise warn that Wrangler's native dependencies (`esbuild`, `workerd`, and `sharp`) have install scripts awaiting approval. The scoped command approves the reviewed native script names that npm 12 evaluates during global resolution while `--omit=optional` keeps optional `fsevents` out of the installed runtime. `fsevents` is used for development-time filesystem watching rather than Machine Bridge runtime or deployment. Omitting `--omit=optional` can therefore produce a harmless blocked-script warning for `fsevents@2.3.3`; use the documented command rather than changing global npm policy. `machine-mcp doctor` remains the authoritative runtime check.
|
|
87
87
|
|
|
@@ -109,7 +109,8 @@ On first remote start, the CLI:
|
|
|
109
109
|
4. deploys a per-workspace Worker;
|
|
110
110
|
5. installs a platform-native login service unless `--no-autostart` is used;
|
|
111
111
|
6. starts an outbound-only daemon connection;
|
|
112
|
-
7.
|
|
112
|
+
7. creates the initial `owner` account when needed and prints its password once;
|
|
113
|
+
8. prints the Remote MCP URL.
|
|
113
114
|
|
|
114
115
|
A normal `machine-mcp` invocation is a foreground start: it remains attached to the terminal and prints `info` logs. Startup and other state-changing operations use an owner-token/process-identity lock and wait up to 30 seconds for an ordinary concurrent startup to finish instead of failing on a brief launchd/systemd race. After a global package upgrade, the CLI unloads the platform service and also checks the workspace lock for a detached/orphan `--daemon-only` process that the service manager no longer tracks. It terminates only a process whose PID, process start time, entrypoint, canonical workspace, canonical state root, and daemon-only arguments all match, waits up to 15 seconds for the PID and lock to disappear, and then starts the installed version in the foreground. A genuine foreground or unverifiable conflict is left untouched and reported with actionable guidance. To run only in the background, use `machine-mcp service start`; inspect its owner-only logs under `~/.local/state/machine-bridge-mcp/logs/`.
|
|
115
116
|
|
|
@@ -121,20 +122,19 @@ machine-mcp --verbose
|
|
|
121
122
|
|
|
122
123
|
The global install replaces files on disk but cannot hot-reload an already running Node process; the foreground command performs the bounded service and orphan-daemon takeover. Keep `--omit=optional` in the installation step to prevent the development-only optional `fsevents` package from producing a blocked-install-script warning. If takeover fails, run `machine-mcp service status` first; it reports the platform service and workspace daemon separately. Then run `machine-mcp service stop` and retry.
|
|
123
124
|
|
|
124
|
-
Use the printed
|
|
125
|
+
Use the printed URL in the MCP client:
|
|
125
126
|
|
|
126
127
|
```text
|
|
127
128
|
MCP Server URL: https://<worker>.<account>.workers.dev/mcp
|
|
128
|
-
MCP connection password: mcp_password_...
|
|
129
129
|
```
|
|
130
130
|
|
|
131
|
-
|
|
131
|
+
During OAuth authorization, enter the name and password of a Machine Bridge account. The first start creates `owner` and prints its generated password once. Additional accounts are managed with `machine-mcp account`. The authorization flow uses PKCE S256, exact redirect/resource binding, expiring hashed access tokens, per-account version checks, and a deployment-wide token version for emergency bulk revocation.
|
|
132
132
|
|
|
133
133
|
### Multiple clients and accounts
|
|
134
134
|
|
|
135
|
-
One Worker
|
|
135
|
+
One Worker supports several named accounts and OAuth clients. Accounts have independent passwords, roles, active state, versions, codes, and tokens. The roles are `reviewer`, `editor`, `operator`, and `owner`; their effective authority is intersected with the connected daemon policy and enforced in both the Worker and local runtime. Role changes, suspension, password rotation, and removal revoke only the affected account.
|
|
136
136
|
|
|
137
|
-
|
|
137
|
+
This is application-level authorization, not kernel or browser-profile isolation. All accounts reach one daemon running as one OS user. Use separate Workers and preferably separate low-privilege OS accounts, containers, or VMs for mutually untrusted users or hard tenant isolation. See [Multi-account authorization and tenancy](docs/MULTI_ACCOUNT.md).
|
|
138
138
|
|
|
139
139
|
## Optional local stdio MCP
|
|
140
140
|
|
|
@@ -218,7 +218,7 @@ Foreground logging defaults to human-readable text. Installed background service
|
|
|
218
218
|
|
|
219
219
|
## Policy controls
|
|
220
220
|
|
|
221
|
-
Policy revision
|
|
221
|
+
Policy revision 5 is defined once in `src/shared/policy-contract.json`. The local runtime, Worker advertisement filter, manager-level defense-in-depth checks, tests, and generated [policy reference](docs/POLICY_REFERENCE.md) consume that same contract. A custom policy is authorized by capabilities rather than its display name; compound classes such as `write+direct-exec` require every capability.
|
|
222
222
|
|
|
223
223
|
The default is `full`. Narrow or customize it with explicit flags:
|
|
224
224
|
|
|
@@ -436,9 +436,9 @@ machine-mcp status
|
|
|
436
436
|
machine-mcp doctor
|
|
437
437
|
machine-mcp rotate-secrets
|
|
438
438
|
machine-mcp resource add|list|check|remove
|
|
439
|
+
machine-mcp account list|add|role|enable|disable|rotate-password|remove
|
|
439
440
|
machine-mcp browser status|setup|pair|path
|
|
440
441
|
machine-mcp job submit|inspect|approve|list|read|cancel
|
|
441
|
-
machine-mcp --print-mcp-credentials
|
|
442
442
|
machine-mcp uninstall [--keep-worker] [--yes]
|
|
443
443
|
```
|
|
444
444
|
|
|
@@ -458,10 +458,9 @@ The service definition contains neither credentials nor a duplicate policy. It l
|
|
|
458
458
|
|
|
459
459
|
```sh
|
|
460
460
|
machine-mcp rotate-secrets
|
|
461
|
-
machine-mcp --print-mcp-credentials
|
|
462
461
|
```
|
|
463
462
|
|
|
464
|
-
Rotation stops the installed service, refuses to proceed while another foreground daemon owns the workspace lock, rotates the
|
|
463
|
+
Rotation stops the installed service, refuses to proceed while another foreground daemon owns the workspace lock, and rotates the account-administration secret, daemon secret, and deployment-wide OAuth token version. It invalidates every account access token and requires all clients to authorize again. Use `machine-mcp account rotate-password NAME` for targeted password rotation without affecting other accounts.
|
|
465
464
|
|
|
466
465
|
## State and observability
|
|
467
466
|
|
package/SECURITY.md
CHANGED
|
@@ -15,7 +15,7 @@ Do not open a public issue for an undisclosed vulnerability. Use GitHub private
|
|
|
15
15
|
- expected and observed impact;
|
|
16
16
|
- whether credentials, filesystem data, process authority, or network access were exposed.
|
|
17
17
|
|
|
18
|
-
Do not include live
|
|
18
|
+
Do not include live account passwords, account-administration secrets, daemon secrets, OAuth tokens, Cloudflare credentials, private keys, or unrelated local files. Rotate credentials used in a reproduction.
|
|
19
19
|
|
|
20
20
|
## Repository and documentation privacy
|
|
21
21
|
|
|
@@ -36,13 +36,13 @@ An authorized client can invoke every tool exposed by the selected profile and r
|
|
|
36
36
|
|
|
37
37
|
The Worker is a remote authentication and relay boundary. The local runtime is the filesystem and process boundary. Stdio bypasses the Worker and relies on local process/configuration trust.
|
|
38
38
|
|
|
39
|
-
###
|
|
39
|
+
### Accounts are authorization boundaries, not OS sandboxes
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
Remote mode supports named accounts with independent passwords, roles, active state, versions, OAuth codes, and access tokens. The roles `reviewer`, `editor`, `operator`, and `owner` map to the local review, edit, agent, and full policy profiles. The Worker intersects the account role with the connected daemon policy, and the local runtime validates the account role again before dispatch. Account suspension, role changes, password rotation, and removal revoke only that account.
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
An OAuth `client_id` still identifies client software and redirect URIs; it is not an account. One account can authorize several clients, and one client can be authorized by several accounts.
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
All accounts ultimately reach one daemon running as one OS user. Application roles cannot isolate direct processes, shells, browser sessions, Accessibility actions, credential stores, or network authority inherited from that user. Mutually untrusted users or hard tenant boundaries require separate bridge instances and external isolation: dedicated low-privilege OS accounts, containers, or VMs, narrow workspaces, independent state roots, and separate Workers. See [Multi-account authorization and tenancy](docs/MULTI_ACCOUNT.md).
|
|
46
46
|
|
|
47
47
|
## Profiles are capability sets, not sandboxes
|
|
48
48
|
|
|
@@ -90,7 +90,7 @@ Text and file resources can be injected locally so their contents do not appear
|
|
|
90
90
|
|
|
91
91
|
## Shared authorization contract
|
|
92
92
|
|
|
93
|
-
Policy revision
|
|
93
|
+
Policy revision 5 is a single source of truth shared by the local daemon and Worker. The catalog availability class controls both advertisement and execution; manager-level checks invoke the same gate as defense in depth. Custom policies are evaluated by capabilities, so a label cannot impersonate `full`. Persistent job start requires both write and direct-execution authority; read-only job/resource inventory does not imply mutation authority.
|
|
94
94
|
|
|
95
95
|
Transport-visible failures use stable error codes and retryability. Unexpected implementation errors are not downgraded to ordinary resource state, and raw internal exceptions are not returned by the Worker. This reduces both authorization drift and accidental disclosure through error strings.
|
|
96
96
|
|
|
@@ -124,11 +124,11 @@ A custom state root is rejected if it overlaps the selected workspace in either
|
|
|
124
124
|
|
|
125
125
|
## Credential exposure
|
|
126
126
|
|
|
127
|
-
Local state contains the
|
|
127
|
+
Local state contains the account-administration secret, daemon secret, and deployment-wide token version. Account passwords are generated 256-bit tokens and are not stored locally; the Worker stores only independent salted HMAC-SHA-256 verifiers. The fixed high-entropy token format is mandatory, so the verifier does not rely on a CPU-intensive human-password KDF inside the Worker request budget. State, lock, temporary secret, runtime, and service-log files use owner-only permissions where supported. State writes are flushed and atomically replaced. A read/type/permission/size/symbolic-link failure is not treated as empty or corrupt state; only successfully read invalid JSON is moved to a bounded corrupt backup.
|
|
128
128
|
|
|
129
129
|
Logs recursively redact known credential fields, private-key headers, npm/GitHub/GitLab/Slack/Google/AWS/live-payment/API token forms, JWT-shaped bearer values, embedded-credential URLs, email addresses, user-home paths, and control characters. These patterns are defense in depth; unknown, transformed, split, encrypted, or application-specific secret forms can still pass through an explicitly requested tool result.
|
|
130
130
|
|
|
131
|
-
|
|
131
|
+
A new deployment prints the generated initial owner password once. Account creation and targeted password rotation also print the generated password once. JSON output includes a generated password only for the command that created it; status, diagnostics, and secret rotation never reveal stored secrets. The account-administration and daemon secrets are never printed. Avoid shared terminal logs, shell recordings, screenshots, CI output, or support tickets.
|
|
132
132
|
|
|
133
133
|
The default `full` profile passes the complete parent environment. Narrower profiles replace HOME, temp, and common cache paths and do not pass arbitrary parent variables. The isolated mode reduces accidental environment-secret leakage; it does not prevent code from explicitly accessing known resources.
|
|
134
134
|
|
|
@@ -160,9 +160,9 @@ Runner diagnostic logs are owner-only and do not receive child stdout/stderr. St
|
|
|
160
160
|
|
|
161
161
|
## OAuth and public endpoints
|
|
162
162
|
|
|
163
|
-
Remote mode uses authorization code flow with PKCE S256, exact redirect/resource/client binding, expiring authorization codes and access tokens, hashed token storage, token-version revocation, and bounded dynamic client registration.
|
|
163
|
+
Remote mode uses authorization code flow with PKCE S256, exact redirect/resource/client binding, expiring authorization codes and access tokens, hashed token storage, per-account version checks, deployment-wide token-version revocation, and bounded dynamic client registration. Authorization codes and tokens are bound to one account ID, account version, and role. Successful consent constructs the registered callback through the URL API and returns `303 See Other`; response parameters are encoded rather than concatenated into an unchecked header string.
|
|
164
164
|
|
|
165
|
-
The authorization page displays the validated client name and redirect URI. Enter
|
|
165
|
+
The authorization page displays the validated client name and redirect URI. Enter an account name and password only after initiating the connection and recognizing both values.
|
|
166
166
|
|
|
167
167
|
Password failures and registrations are limited by deployment-keyed HMAC source identity. Browser requests are same-origin unless an exact origin is listed in `MBM_ALLOWED_ORIGINS`; loopback OAuth redirect permission does not grant browser-origin access.
|
|
168
168
|
|
|
@@ -199,13 +199,13 @@ No logging policy can prevent data from being returned to a client that explicit
|
|
|
199
199
|
For sensitive review:
|
|
200
200
|
|
|
201
201
|
```sh
|
|
202
|
-
machine-mcp --workspace /narrow/project --profile review
|
|
202
|
+
machine-mcp --workspace /narrow/project --profile review
|
|
203
203
|
```
|
|
204
204
|
|
|
205
205
|
For controlled editing without execution:
|
|
206
206
|
|
|
207
207
|
```sh
|
|
208
|
-
machine-mcp --workspace /narrow/project --profile edit
|
|
208
|
+
machine-mcp --workspace /narrow/project --profile edit
|
|
209
209
|
```
|
|
210
210
|
|
|
211
211
|
Also:
|
|
@@ -217,7 +217,7 @@ Also:
|
|
|
217
217
|
- treat an unreadable or malformed live lock as an incident to inspect, not a file to delete blindly;
|
|
218
218
|
- select `agent`, `edit`, or `review` instead of the default `full` when broad authority is unnecessary;
|
|
219
219
|
- inspect client names and OAuth redirect URIs;
|
|
220
|
-
- rotate secrets after
|
|
220
|
+
- rotate one account password after a targeted disclosure, or rotate deployment secrets after a bridge-wide incident;
|
|
221
221
|
- inspect `status`, `doctor`, and service status;
|
|
222
222
|
- register credential files as local resources instead of reading them into a model conversation;
|
|
223
223
|
- use `capture_output: "discard"` for credential-consuming steps and idempotent finally steps for cleanup;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"manifest_version": 3,
|
|
3
3
|
"name": "Machine Bridge Browser",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.18.1",
|
|
5
5
|
"description": "Connects the current Chromium browser profile to the local Machine Bridge runtime for user-authorized automation.",
|
|
6
6
|
"permissions": [
|
|
7
7
|
"tabs",
|
|
@@ -30,5 +30,5 @@
|
|
|
30
30
|
"action": {
|
|
31
31
|
"default_title": "Machine Bridge Browser"
|
|
32
32
|
},
|
|
33
|
-
"version_name": "0.
|
|
33
|
+
"version_name": "0.18.1"
|
|
34
34
|
}
|
package/docs/ARCHITECTURE.md
CHANGED
|
@@ -86,9 +86,9 @@ Local resource registrations remain in owner-only state and are reloaded for eve
|
|
|
86
86
|
|
|
87
87
|
### Canonical policy contracts
|
|
88
88
|
|
|
89
|
-
Policy revision
|
|
89
|
+
Policy revision 5 is loaded from one shared JSON contract by both local and Worker policy evaluators. Tool advertisement and execution authorization use catalog availability classes; managers receive the same authorizer instead of reimplementing profile conditionals. Read-only job/resource inspection is `always`, job cancellation is write-gated, and starting a persistent job requires `write+direct-exec`.
|
|
90
90
|
|
|
91
|
-
Named profiles are normalized to their complete capability sets. In particular, `full` always means write enabled, shell execution, unrestricted paths, complete parent environment, absolute-path display, and every catalog tool. CLI flags that alter an individual capability deliberately change the profile identity to `custom`. Policy revision
|
|
91
|
+
Named profiles are normalized to their complete capability sets. In particular, `full` always means write enabled, shell execution, unrestricted paths, complete parent environment, absolute-path display, and every catalog tool. CLI flags that alter an individual capability deliberately change the profile identity to `custom`. Policy revision 5 defines the only accepted persisted policy shape. Named profiles are normalized to their canonical capability sets, and persisted data from another revision is rejected rather than interpreted. Compound availability requirements come from the shared contract.
|
|
92
92
|
|
|
93
93
|
The full-only `generate_ssh_key_resource` operation is implemented locally. The Worker only filters and relays its shared catalog definition. Local generation uses `ssh-keygen`, verifies public/private correspondence, registers the private file through the same owner-only state transaction as the CLI, and rolls back a newly created pair if state persistence fails.
|
|
94
94
|
|
|
@@ -109,7 +109,7 @@ All requests for a deployed Worker route to one named Durable Object. It owns:
|
|
|
109
109
|
|
|
110
110
|
The Worker verifies OAuth, validates MCP envelopes and optional protocol headers, converts `tools/call` into WebSocket messages, correlates cancellation by access-token hash and JSON-RPC ID, and formats text/structured/image results. It has no local filesystem or process API.
|
|
111
111
|
|
|
112
|
-
The
|
|
112
|
+
The OAuth store separates client registrations from named accounts. A `client_id` identifies an MCP application and redirect URIs; account records identify the authorized human or service identity. Codes and tokens bind client ID, account ID, account version, role, scope, resource, and expiration. The Worker intersects the role with the active daemon policy before advertising or relaying tools, and the local runtime validates the relayed role again. One bridge-specific Durable Object and one local runtime remain the normal topology for a workspace/trust domain; see [MULTI_ACCOUNT.md](MULTI_ACCOUNT.md).
|
|
113
113
|
|
|
114
114
|
The daemon attachment deliberately omits workspace path/name/hash and process ID. Explicit authenticated tools may return workspace metadata according to local path-display policy.
|
|
115
115
|
|
|
@@ -147,7 +147,7 @@ Remote OAuth currently determines which registered client token may call tools;
|
|
|
147
147
|
1. The MCP client discovers protected-resource and authorization-server metadata.
|
|
148
148
|
2. It dynamically registers bounded redirect metadata.
|
|
149
149
|
3. The Worker validates authorization parameters before displaying a password form.
|
|
150
|
-
4. The user verifies client name and redirect URI and enters
|
|
150
|
+
4. The user verifies client name and redirect URI and enters a Machine Bridge account name and password.
|
|
151
151
|
5. The Worker creates a five-minute code bound to client, redirect, resource, scope, and PKCE challenge.
|
|
152
152
|
6. A valid verifier exchanges the one-time code for an expiring bearer token; only its hash is stored.
|
|
153
153
|
7. The MCP client initializes and negotiates a supported protocol version. When the daemon advertises `session_bootstrap`, the Worker requests bounded local instructions and appends them to the initialization result; failure degrades to static instructions.
|
|
@@ -226,7 +226,7 @@ Local state and global config are owner-only, versioned, and size-bounded. Share
|
|
|
226
226
|
|
|
227
227
|
Process locks contain purpose, workspace, ownership token, lock time, and process start time. Stale removal rechecks device/inode/size/mtime and token so an old observer cannot delete a replacement lock. Recent malformed claims receive a grace period. Startup/state operations wait a bounded interval; daemon and runner identity remain process-lifetime locks. Managed-job transition and recovery locks use the same ownership/snapshot principles and support an atomic runner handoff.
|
|
228
228
|
|
|
229
|
-
Only successfully read but syntactically invalid JSON is moved to a bounded `.corrupt-*` backup. Permission, type, symbolic-link, size, encoding, and I/O failures propagate. A state root must be disjoint from its selected workspace. Resource paths are omitted from redacted status output.
|
|
229
|
+
Only successfully read but syntactically invalid JSON is moved to a bounded `.corrupt-*` backup. Permission, type, symbolic-link, size, encoding, and I/O failures propagate. A state root must be disjoint from its selected workspace. Resource paths are omitted from redacted status output. A custom root is initialized only when empty and must contain the current state marker on subsequent use. Valid state from another schema is rejected; syntactically invalid JSON is isolated as a bounded corrupt backup and rebuilt as current empty state.
|
|
230
230
|
|
|
231
231
|
Active managed jobs persist an owner-only plan, status, runner process identity, and bounded runner diagnostics. Terminal jobs delete the full plan and retain only bounded status/redacted results for up to seven days. This balances crash cleanup with minimization of scripts, stdin, argv, environment overrides, and resource source paths.
|
|
232
232
|
|
package/docs/AUDIT.md
CHANGED
|
@@ -7,7 +7,7 @@ This document records the cross-cutting audit initiated for version 0.12.0, the
|
|
|
7
7
|
|
|
8
8
|
This review confirmed that earlier safety controls existed but were distributed across duplicated policy checks, transport-specific pending maps, message-regex errors, and oversized composition files. It reproduced a production-visible Worker defect where a completed client JSON-RPC request key could remain indexed and cause unrelated later calls to fail as duplicate in-flight IDs. Pending calls now use one atomic double-index registry whose terminal `take` operation clears the internal ID, request key, and timer before resolution or rejection; success, daemon error, cancellation, timeout, send failure, and socket loss have behavior coverage.
|
|
9
9
|
|
|
10
|
-
Policy revision
|
|
10
|
+
Policy revision 5 supplies one authorization contract to the local runtime, Worker role intersection, and manager-level checks. The audit found a concrete compound-ACL error: `start_job` was advertised by direct-exec alone even though it creates persistent files. It now requires write plus direct execution; read-only job/resource inspection no longer inherits mutation requirements. Typed errors, shared middleware, explicit runtime lifecycle, process ownership, structured JSON logs, and local/Worker metrics replace ad hoc message parsing and invisible pending state.
|
|
11
11
|
|
|
12
12
|
The composition roots were reduced by extracting filesystem, process, Git, CLI parsing/admin, ranking, managed-job validation, browser protocol/pairing, Worker HTTP, OAuth, policy, errors, pending calls, and observability. Executable architecture limits prevent these responsibilities from returning. During extraction, a missing local ESM binding was initially hidden by a broad catch and surfaced only as `resource_unavailable`; the catch now rethrows unknown faults, and the stdio generated-resource test exercises the complete state reload path.
|
|
13
13
|
|
|
@@ -47,7 +47,7 @@ The review also found three governance gaps not represented by the original fail
|
|
|
47
47
|
- Workflow actions used movable major-version tags. They are now pinned to immutable official commit SHAs, with an executable invariant.
|
|
48
48
|
- Repository privacy checks covered only the current tree. Package audit now scans reachable historical paths, bounded UTF-8 blobs, and commit messages; deleted credential fixtures fail without echoing their values.
|
|
49
49
|
|
|
50
|
-
No generic active credential pattern was found in the current tree or reachable history after excluding standard public automation trailers. The developer-local denylist does match
|
|
50
|
+
No generic active credential pattern was found in the current tree or reachable history after excluding standard public automation trailers. The developer-local denylist does match historical identifiers, and the Git metadata audit found an older non-noreply author/committer identity. These are identity/privacy metadata rather than active credentials. Removing them would require a coordinated history rewrite and force-update of affected refs, which is intentionally not performed as an incidental code fix.
|
|
51
51
|
|
|
52
52
|
## Scope
|
|
53
53
|
|
|
@@ -77,7 +77,7 @@ The runtime now:
|
|
|
77
77
|
- gives a recent malformed lock a grace period rather than deleting a possibly in-progress claim;
|
|
78
78
|
- waits a bounded interval for ordinary startup/state operations instead of failing immediately.
|
|
79
79
|
|
|
80
|
-
Managed-job transition, recovery, and runner identity follow the same
|
|
80
|
+
Managed-job transition, recovery, and runner identity follow the same ownership and process-start-time rules. Numeric-only runner records are rejected.
|
|
81
81
|
|
|
82
82
|
### Service lifecycle
|
|
83
83
|
|
package/docs/CLIENTS.md
CHANGED
|
@@ -122,9 +122,9 @@ Run:
|
|
|
122
122
|
machine-mcp --workspace /path/to/project
|
|
123
123
|
```
|
|
124
124
|
|
|
125
|
-
Enter the printed `/mcp` URL in the remote MCP connector. During OAuth authorization, verify the displayed client name and redirect URI before entering
|
|
125
|
+
Enter the printed `/mcp` URL in the remote MCP connector. During OAuth authorization, verify the displayed client name and redirect URI before entering a Machine Bridge account name and password.
|
|
126
126
|
|
|
127
|
-
Several OAuth clients and
|
|
127
|
+
Several OAuth clients and named accounts can coexist. Accounts have independent passwords, roles, active state, versions, and targeted revocation. Their effective tool sets are intersected with the connected daemon policy. All accounts still share one daemon and OS user, so hard tenant isolation requires separate deployments; see [MULTI_ACCOUNT.md](MULTI_ACCOUNT.md).
|
|
128
128
|
|
|
129
129
|
## Profile guidance
|
|
130
130
|
|
package/docs/GETTING_STARTED.md
CHANGED
|
@@ -163,7 +163,8 @@ The first start performs these operations:
|
|
|
163
163
|
4. deploys a Worker and Durable Object for that workspace;
|
|
164
164
|
5. installs a platform-native login service unless `--no-autostart` is supplied;
|
|
165
165
|
6. starts an outbound authenticated WebSocket from the local daemon to the Worker;
|
|
166
|
-
7.
|
|
166
|
+
7. creates the initial `owner` account when no account exists and prints its generated password once;
|
|
167
|
+
8. prints the remote `/mcp` URL.
|
|
167
168
|
|
|
168
169
|
The foreground command remains attached to the terminal. Keep it running while testing. The remote Worker cannot execute local tools when no authenticated daemon is connected.
|
|
169
170
|
|
|
@@ -182,14 +183,15 @@ machine-mcp --workspace /path/to/project --no-autostart
|
|
|
182
183
|
|
|
183
184
|
## 7. Connect ChatGPT
|
|
184
185
|
|
|
185
|
-
Machine Bridge prints
|
|
186
|
+
Machine Bridge prints the remote endpoint and, only when creating the first account, a one-time owner password:
|
|
186
187
|
|
|
187
188
|
```text
|
|
188
189
|
MCP Server URL: https://<worker>.<account>.workers.dev/mcp
|
|
189
|
-
|
|
190
|
+
Account: owner
|
|
191
|
+
Password: account_password_...
|
|
190
192
|
```
|
|
191
193
|
|
|
192
|
-
|
|
194
|
+
Save the generated password in a password manager. It is not stored locally or shown again. Do not place it in a repository, issue, screenshot, chat message, shell history note, or shared document.
|
|
193
195
|
|
|
194
196
|
Current ChatGPT developer-mode flow, as documented in OpenAI's [Connect from ChatGPT](https://developers.openai.com/apps-sdk/deploy/connect-chatgpt) guide:
|
|
195
197
|
|
|
@@ -199,7 +201,7 @@ Current ChatGPT developer-mode flow, as documented in OpenAI's [Connect from Cha
|
|
|
199
201
|
4. Enter a descriptive name and the exact printed `/mcp` URL.
|
|
200
202
|
5. Start the connection.
|
|
201
203
|
6. On the Machine Bridge authorization page, verify the displayed client name, redirect URI, and resource.
|
|
202
|
-
7. Enter the
|
|
204
|
+
7. Enter the Machine Bridge account name and password only after those values are recognized.
|
|
203
205
|
8. Create a new chat and enable the app for that conversation.
|
|
204
206
|
|
|
205
207
|
ChatGPT navigation labels can change. The invariant is that the client must connect to the public `/mcp` endpoint and complete the OAuth authorization page served by the Worker.
|
|
@@ -273,7 +275,7 @@ machine-mcp doctor
|
|
|
273
275
|
machine-mcp workspace show
|
|
274
276
|
machine-mcp service status
|
|
275
277
|
machine-mcp browser status
|
|
276
|
-
machine-mcp
|
|
278
|
+
machine-mcp account list
|
|
277
279
|
```
|
|
278
280
|
|
|
279
281
|
Useful operational actions:
|
|
@@ -282,11 +284,13 @@ Useful operational actions:
|
|
|
282
284
|
machine-mcp service stop
|
|
283
285
|
machine-mcp service start
|
|
284
286
|
machine-mcp rotate-secrets
|
|
287
|
+
machine-mcp account add alice reviewer
|
|
288
|
+
machine-mcp account rotate-password alice
|
|
285
289
|
machine-mcp resource list
|
|
286
290
|
machine-mcp job list
|
|
287
291
|
```
|
|
288
292
|
|
|
289
|
-
`rotate-secrets` invalidates
|
|
293
|
+
`rotate-secrets` invalidates every account access token and requires all clients to authorize again. For targeted revocation, disable an account, change its role, rotate its password, or remove it.
|
|
290
294
|
|
|
291
295
|
## 12. Work with more than one workspace
|
|
292
296
|
|
|
@@ -315,7 +319,7 @@ rm -rf "$install_dir"
|
|
|
315
319
|
machine-mcp --workspace /path/to/project --verbose
|
|
316
320
|
```
|
|
317
321
|
|
|
318
|
-
The foreground start performs bounded takeover of an
|
|
322
|
+
The foreground start performs bounded takeover of an earlier verified daemon when safe. If it refuses:
|
|
319
323
|
|
|
320
324
|
```sh
|
|
321
325
|
machine-mcp service status
|
|
@@ -397,4 +401,4 @@ Uninstall is fail-closed. If a verified daemon, active managed job, unreadable l
|
|
|
397
401
|
|
|
398
402
|
## 16. Before sharing access
|
|
399
403
|
|
|
400
|
-
The current release supports
|
|
404
|
+
The current release supports named accounts with targeted revocation and four roles: `reviewer`, `editor`, `operator`, and `owner`. Roles are enforced in the Worker and local runtime, but all accounts still share one daemon and OS user. Use separate deployments and external isolation for mutually untrusted users or hard tenant boundaries. Read [MULTI_ACCOUNT.md](MULTI_ACCOUNT.md) before sharing a deployment.
|
package/docs/LOGGING.md
CHANGED
|
@@ -79,7 +79,7 @@ The implementation omits:
|
|
|
79
79
|
- stdin, stdout, and stderr;
|
|
80
80
|
- file, patch, image, and temporary-file content;
|
|
81
81
|
- OAuth request bodies;
|
|
82
|
-
-
|
|
82
|
+
- account passwords, account-administration secrets, daemon secrets, authorization codes, and access tokens;
|
|
83
83
|
- registered resource values and source paths;
|
|
84
84
|
- browser pairing tokens, page URLs/source, DOM metadata, form values, uploaded file bytes, and screenshots;
|
|
85
85
|
- application names, Accessibility trees, selectors, and entered values;
|
|
@@ -118,7 +118,7 @@ logs/daemon.err.log
|
|
|
118
118
|
|
|
119
119
|
Existing files are opened without following symbolic links where supported and tail-trimmed on UTF-8/line boundaries before startup. Background services use `warn`, so ordinary tool traffic and brief relay interruptions do not cause sustained growth.
|
|
120
120
|
|
|
121
|
-
The log format has an explicit schema marker.
|
|
121
|
+
The log format has an explicit schema marker. If the marker differs from the current format, the daemon clears the active files before startup and writes the current marker. Runtime code recognizes only `daemon.out.log` and `daemon.err.log`; it does not parse or archive other log formats.
|
|
122
122
|
|
|
123
123
|
Each managed job has owner-only runner diagnostic logs. Child-step output is retained only in bounded, redacted job results according to `capture_output`; it is not copied into daemon or runner operational logs.
|
|
124
124
|
|
package/docs/MANAGED_JOBS.md
CHANGED
|
@@ -277,7 +277,7 @@ Per-workspace jobs are stored below the owner-only profile directory. Active job
|
|
|
277
277
|
|
|
278
278
|
Retained public job data contains bounded status and redacted results. Up to 50 jobs are retained for up to seven days. Private runtime copies are removed after the finally phase. Runner stdout/stderr log files contain only runner-level diagnostics; step output is not written to those operational logs.
|
|
279
279
|
|
|
280
|
-
The detached runner records
|
|
280
|
+
The detached runner records a structured owner record containing PID and process start time. Recovery rejects a reused PID instead of treating an unrelated process as the active runner. Numeric-only runner records are invalid. Recovery-lock handoff preserves a random ownership token, and the runner removes only a lock whose PID, token, and file snapshot still match. Timeout and cancellation terminate the process group/tree, retain a referenced forced-escalation timer, and clean descendants that ignore graceful termination before the runner exits.
|
|
281
281
|
|
|
282
282
|
Missing job JSON is distinct from unreadable or invalid job JSON. Permission, type, symbolic-link, size, UTF-8, I/O, and parse failures retain the job directory, produce an `unreadable` status for listing, skip automatic recovery/pruning, and block uninstall until an operator inspects the state.
|
|
283
283
|
|