machine-bridge-mcp 0.17.0 → 0.18.0
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 +33 -0
- package/README.md +21 -12
- package/SECURITY.md +17 -9
- package/browser-extension/manifest.json +2 -2
- package/docs/ARCHITECTURE.md +8 -6
- package/docs/AUDIT.md +3 -3
- package/docs/CLIENTS.md +3 -1
- package/docs/GETTING_STARTED.md +404 -0
- package/docs/LOGGING.md +2 -2
- package/docs/MANAGED_JOBS.md +1 -1
- package/docs/MULTI_ACCOUNT.md +123 -0
- 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.mjs +7 -26
- 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
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
# Installation and first-use guide
|
|
2
|
+
|
|
3
|
+
This guide covers a clean installation, the first remote ChatGPT connection, local stdio clients, browser setup, routine operation, upgrades, troubleshooting, and removal.
|
|
4
|
+
|
|
5
|
+
## 1. Decide which connection mode you need
|
|
6
|
+
|
|
7
|
+
Machine Bridge has two transports. Choose one before installing:
|
|
8
|
+
|
|
9
|
+
| Requirement | Use | Cloudflare required | Process that must remain available |
|
|
10
|
+
|---|---|---:|---|
|
|
11
|
+
| ChatGPT web, a hosted agent, or another device must reach this computer | Remote HTTPS/OAuth | Yes | Machine Bridge daemon or installed login service |
|
|
12
|
+
| Claude Desktop, Cursor, Codex, ChatGPT Desktop, or another local host runs on this computer | Local stdio | No | The MCP host launches Machine Bridge as a subprocess |
|
|
13
|
+
| The local coding client already has equivalent file, Git, patch, and terminal tools | Neither | No | None |
|
|
14
|
+
|
|
15
|
+
Remote and stdio modes use the same local runtime and policy model. The remote Worker authenticates and relays calls; it does not read files or execute processes by itself.
|
|
16
|
+
|
|
17
|
+
## 2. Understand the authority you are granting
|
|
18
|
+
|
|
19
|
+
A new workspace uses the `full` profile unless another profile is selected explicitly. `full` exposes the complete tool catalog, shell execution, paths outside the selected workspace, absolute paths, and the complete parent process environment. It is intended for a trusted owner using a trusted MCP host.
|
|
20
|
+
|
|
21
|
+
For a first connection to an unfamiliar host, start with a narrower profile:
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
machine-mcp --workspace /path/to/project --profile review
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Profiles:
|
|
28
|
+
|
|
29
|
+
| Profile | Reads | File changes | Direct processes | Shell | Direct filesystem scope |
|
|
30
|
+
|---|---:|---:|---:|---:|---|
|
|
31
|
+
| `full` | Yes | Yes | Yes | Yes | Unrestricted |
|
|
32
|
+
| `agent` | Yes | Yes | Yes | No | Selected workspace |
|
|
33
|
+
| `edit` | Yes | Yes | No | No | Selected workspace |
|
|
34
|
+
| `review` | Yes | No | No | No | Selected workspace |
|
|
35
|
+
|
|
36
|
+
A profile is a Machine Bridge policy ceiling. The MCP host, operating system, endpoint-security software, container, and cloud platform may impose additional restrictions.
|
|
37
|
+
|
|
38
|
+
## 3. Prerequisites
|
|
39
|
+
|
|
40
|
+
Required for every installation:
|
|
41
|
+
|
|
42
|
+
- Node.js 26 or newer;
|
|
43
|
+
- npm 12 or newer;
|
|
44
|
+
- macOS, Linux, or Windows;
|
|
45
|
+
- a local user account permitted to read or modify the selected workspace.
|
|
46
|
+
|
|
47
|
+
Remote mode additionally requires:
|
|
48
|
+
|
|
49
|
+
- a Cloudflare account permitted to deploy Workers and Durable Objects;
|
|
50
|
+
- a browser available for Wrangler sign-in;
|
|
51
|
+
- outbound HTTPS and WebSocket access from the computer running the daemon.
|
|
52
|
+
|
|
53
|
+
Browser automation additionally requires:
|
|
54
|
+
|
|
55
|
+
- a Chromium-based browser that can load an unpacked Manifest V3 extension;
|
|
56
|
+
- the extension loaded into the browser profile whose tabs and login state should be controlled.
|
|
57
|
+
|
|
58
|
+
Check the installed runtimes:
|
|
59
|
+
|
|
60
|
+
```sh
|
|
61
|
+
node --version
|
|
62
|
+
npm --version
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Do not continue with an older runtime. This repository intentionally rejects unsupported Node/npm versions.
|
|
66
|
+
|
|
67
|
+
## 4. Install the released package
|
|
68
|
+
|
|
69
|
+
Use a temporary package-free directory. An older npm front-end can inspect metadata in the current directory before it launches npm 12; the isolated bootstrap prevents an unrelated project configuration from breaking installation.
|
|
70
|
+
|
|
71
|
+
### macOS and Linux
|
|
72
|
+
|
|
73
|
+
```sh
|
|
74
|
+
install_dir="$(mktemp -d)"
|
|
75
|
+
(
|
|
76
|
+
cd "$install_dir"
|
|
77
|
+
npx --yes npm@12.0.1 install --global npm@12.0.1
|
|
78
|
+
npx --yes npm@12.0.1 install --global --omit=optional --allow-scripts=esbuild,workerd,sharp,fsevents machine-bridge-mcp@latest
|
|
79
|
+
)
|
|
80
|
+
rm -rf "$install_dir"
|
|
81
|
+
|
|
82
|
+
npm --version
|
|
83
|
+
machine-mcp doctor
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Windows Command Prompt
|
|
87
|
+
|
|
88
|
+
```bat
|
|
89
|
+
set "MBM_INSTALL_DIR=%TEMP%\machine-bridge-mcp-install-%RANDOM%-%RANDOM%"
|
|
90
|
+
mkdir "%MBM_INSTALL_DIR%"
|
|
91
|
+
pushd "%MBM_INSTALL_DIR%"
|
|
92
|
+
npx --yes npm@12.0.1 install --global npm@12.0.1
|
|
93
|
+
npx --yes npm@12.0.1 install --global --omit=optional --allow-scripts=esbuild,workerd,sharp,fsevents machine-bridge-mcp@latest
|
|
94
|
+
popd
|
|
95
|
+
rmdir /s /q "%MBM_INSTALL_DIR%"
|
|
96
|
+
|
|
97
|
+
npm --version
|
|
98
|
+
machine-mcp doctor
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Reopen the terminal if `npm --version` still resolves to an older global installation.
|
|
102
|
+
|
|
103
|
+
### Run from a source checkout
|
|
104
|
+
|
|
105
|
+
macOS/Linux:
|
|
106
|
+
|
|
107
|
+
```sh
|
|
108
|
+
git clone https://github.com/YuLeiFuYun/machine-bridge-mcp.git
|
|
109
|
+
cd machine-bridge-mcp
|
|
110
|
+
npm install
|
|
111
|
+
./mbm
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Windows Command Prompt:
|
|
115
|
+
|
|
116
|
+
```bat
|
|
117
|
+
git clone https://github.com/YuLeiFuYun/machine-bridge-mcp.git
|
|
118
|
+
cd machine-bridge-mcp
|
|
119
|
+
npm install
|
|
120
|
+
.\mbm.cmd
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Source installs are for development or review. Released installations should normally use the global package command above.
|
|
124
|
+
|
|
125
|
+
## 5. Interpret the initial doctor result
|
|
126
|
+
|
|
127
|
+
Run:
|
|
128
|
+
|
|
129
|
+
```sh
|
|
130
|
+
machine-mcp doctor
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
The command checks the local runtime, package layout, Wrangler availability, Cloudflare login state, and known Worker health. Before the first remote deployment, a missing Cloudflare login or Worker is expected; local runtime failures are not.
|
|
134
|
+
|
|
135
|
+
Common installation failures:
|
|
136
|
+
|
|
137
|
+
| Message or symptom | Meaning | Corrective action |
|
|
138
|
+
|---|---|---|
|
|
139
|
+
| `Unknown cli config "--allow-scripts"` | npm 11 or older executed the install | Repeat the isolated npm 12 bootstrap |
|
|
140
|
+
| `Invalid property "node"` or `Invalid property "devEngines.node"` | An old npm parser inspected incompatible project metadata | Run the install from a new empty temporary directory |
|
|
141
|
+
| `machine-mcp: command not found` | The global npm binary directory is not on `PATH` | Reopen the terminal, inspect `npm prefix -g`, and add its binary directory to `PATH` |
|
|
142
|
+
| Native package install warning | npm did not approve reviewed native build scripts | Use the documented `--allow-scripts` and `--omit=optional` command exactly |
|
|
143
|
+
|
|
144
|
+
## 6. First remote start
|
|
145
|
+
|
|
146
|
+
Choose the exact workspace to expose. Prefer an explicit path rather than relying on the current directory:
|
|
147
|
+
|
|
148
|
+
```sh
|
|
149
|
+
machine-mcp --workspace /path/to/project
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
For a narrower first run:
|
|
153
|
+
|
|
154
|
+
```sh
|
|
155
|
+
machine-mcp --workspace /path/to/project --profile review
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
The first start performs these operations:
|
|
159
|
+
|
|
160
|
+
1. canonicalizes and remembers the workspace;
|
|
161
|
+
2. creates owner-only per-workspace state and credentials;
|
|
162
|
+
3. opens the Wrangler/Cloudflare sign-in flow when required;
|
|
163
|
+
4. deploys a Worker and Durable Object for that workspace;
|
|
164
|
+
5. installs a platform-native login service unless `--no-autostart` is supplied;
|
|
165
|
+
6. starts an outbound authenticated WebSocket from the local daemon to the Worker;
|
|
166
|
+
7. creates the initial `owner` account when no account exists and prints its generated password once;
|
|
167
|
+
8. prints the remote `/mcp` URL.
|
|
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.
|
|
170
|
+
|
|
171
|
+
To run only in the background after setup:
|
|
172
|
+
|
|
173
|
+
```sh
|
|
174
|
+
machine-mcp service start
|
|
175
|
+
machine-mcp service status
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
To avoid installing autostart during a temporary test:
|
|
179
|
+
|
|
180
|
+
```sh
|
|
181
|
+
machine-mcp --workspace /path/to/project --no-autostart
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## 7. Connect ChatGPT
|
|
185
|
+
|
|
186
|
+
Machine Bridge prints the remote endpoint and, only when creating the first account, a one-time owner password:
|
|
187
|
+
|
|
188
|
+
```text
|
|
189
|
+
MCP Server URL: https://<worker>.<account>.workers.dev/mcp
|
|
190
|
+
Account: owner
|
|
191
|
+
Password: account_password_...
|
|
192
|
+
```
|
|
193
|
+
|
|
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.
|
|
195
|
+
|
|
196
|
+
Current ChatGPT developer-mode flow, as documented in OpenAI's [Connect from ChatGPT](https://developers.openai.com/apps-sdk/deploy/connect-chatgpt) guide:
|
|
197
|
+
|
|
198
|
+
1. Open ChatGPT settings.
|
|
199
|
+
2. Under **Security and login**, enable **Developer mode** if the account or workspace permits it.
|
|
200
|
+
3. Open **Plugins** and create a developer-mode app.
|
|
201
|
+
4. Enter a descriptive name and the exact printed `/mcp` URL.
|
|
202
|
+
5. Start the connection.
|
|
203
|
+
6. On the Machine Bridge authorization page, verify the displayed client name, redirect URI, and resource.
|
|
204
|
+
7. Enter the Machine Bridge account name and password only after those values are recognized.
|
|
205
|
+
8. Create a new chat and enable the app for that conversation.
|
|
206
|
+
|
|
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.
|
|
208
|
+
|
|
209
|
+
## 8. Verify the first connection
|
|
210
|
+
|
|
211
|
+
Ask the MCP host to call these tools in order:
|
|
212
|
+
|
|
213
|
+
1. `server_info` — proves the request reached the Worker and reports whether a daemon is authenticated;
|
|
214
|
+
2. `project_overview` — proves the relay reached the selected local runtime;
|
|
215
|
+
3. `diagnose_runtime` — runs fixed policy, filesystem, process, shell, managed-job, and resource probes permitted by the active profile.
|
|
216
|
+
|
|
217
|
+
For an explicit local acceptance test of the canonical `full` profile:
|
|
218
|
+
|
|
219
|
+
```sh
|
|
220
|
+
machine-mcp full-test --workspace /path/to/project
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
A successful local test does not prove that a hosted MCP client exposes every advertised tool. Hosts can independently hide tools or require approvals.
|
|
224
|
+
|
|
225
|
+
## 9. Configure a local stdio client
|
|
226
|
+
|
|
227
|
+
Generate configurations rather than manually guessing the Node path or package entrypoint:
|
|
228
|
+
|
|
229
|
+
```sh
|
|
230
|
+
machine-mcp client-config --client all --workspace /path/to/project
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Use a narrower policy when appropriate:
|
|
234
|
+
|
|
235
|
+
```sh
|
|
236
|
+
machine-mcp client-config --client all --workspace /path/to/project --profile agent
|
|
237
|
+
machine-mcp client-config --client all --workspace /path/to/project --profile edit
|
|
238
|
+
machine-mcp client-config --client all --workspace /path/to/project --profile review
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
The generated command uses absolute executable paths so GUI applications do not depend on a shell-specific `PATH`.
|
|
242
|
+
|
|
243
|
+
A generic stdio invocation is:
|
|
244
|
+
|
|
245
|
+
```sh
|
|
246
|
+
machine-mcp stdio --workspace /path/to/project --profile full
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
The host owns the model, conversation, tool-selection loop, and approvals. Machine Bridge supplies tools; it is not a model provider.
|
|
250
|
+
|
|
251
|
+
## 10. Enable existing-browser automation
|
|
252
|
+
|
|
253
|
+
Run once after installation:
|
|
254
|
+
|
|
255
|
+
```sh
|
|
256
|
+
machine-mcp browser setup
|
|
257
|
+
machine-mcp browser status
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
Then:
|
|
261
|
+
|
|
262
|
+
1. Open the extensions page in the Chromium profile you actually use.
|
|
263
|
+
2. Enable Developer mode.
|
|
264
|
+
3. Load the unpacked extension directory printed by `browser setup`.
|
|
265
|
+
4. Complete the local pairing page.
|
|
266
|
+
5. Confirm that `machine-mcp browser status` reports the expected packaged version, protocol, and an authenticated connection.
|
|
267
|
+
|
|
268
|
+
Machine Bridge does not launch a separate browser profile. The extension controls the profile into which it was loaded, including its open tabs and logged-in sessions. Reload the unpacked extension after every Machine Bridge upgrade.
|
|
269
|
+
|
|
270
|
+
## 11. Routine commands
|
|
271
|
+
|
|
272
|
+
```sh
|
|
273
|
+
machine-mcp status
|
|
274
|
+
machine-mcp doctor
|
|
275
|
+
machine-mcp workspace show
|
|
276
|
+
machine-mcp service status
|
|
277
|
+
machine-mcp browser status
|
|
278
|
+
machine-mcp account list
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
Useful operational actions:
|
|
282
|
+
|
|
283
|
+
```sh
|
|
284
|
+
machine-mcp service stop
|
|
285
|
+
machine-mcp service start
|
|
286
|
+
machine-mcp rotate-secrets
|
|
287
|
+
machine-mcp account add alice reviewer
|
|
288
|
+
machine-mcp account rotate-password alice
|
|
289
|
+
machine-mcp resource list
|
|
290
|
+
machine-mcp job list
|
|
291
|
+
```
|
|
292
|
+
|
|
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.
|
|
294
|
+
|
|
295
|
+
## 12. Work with more than one workspace
|
|
296
|
+
|
|
297
|
+
Each canonical workspace receives independent state, policy, credentials, Worker name, resource registry, job directory, startup lock, and daemon lock. Select workspaces explicitly:
|
|
298
|
+
|
|
299
|
+
```sh
|
|
300
|
+
machine-mcp --workspace /path/to/project-a
|
|
301
|
+
machine-mcp --workspace /path/to/project-b
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
Do not point two logical trust domains at one broad parent directory merely to reduce configuration. A workspace is an authorization boundary for confined profiles and an operational identity even when `full` permits paths outside it.
|
|
305
|
+
|
|
306
|
+
## 13. Upgrade
|
|
307
|
+
|
|
308
|
+
Repeat the isolated global installation, then start Machine Bridge in the target workspace:
|
|
309
|
+
|
|
310
|
+
```sh
|
|
311
|
+
install_dir="$(mktemp -d)"
|
|
312
|
+
(
|
|
313
|
+
cd "$install_dir"
|
|
314
|
+
npx --yes npm@12.0.1 install --global npm@12.0.1
|
|
315
|
+
npx --yes npm@12.0.1 install --global --omit=optional --allow-scripts=esbuild,workerd,sharp,fsevents machine-bridge-mcp@latest
|
|
316
|
+
)
|
|
317
|
+
rm -rf "$install_dir"
|
|
318
|
+
|
|
319
|
+
machine-mcp --workspace /path/to/project --verbose
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
The foreground start performs bounded takeover of an earlier verified daemon when safe. If it refuses:
|
|
323
|
+
|
|
324
|
+
```sh
|
|
325
|
+
machine-mcp service status
|
|
326
|
+
machine-mcp service stop
|
|
327
|
+
machine-mcp --workspace /path/to/project --verbose
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
After upgrading, reload the unpacked browser extension before relying on browser tools.
|
|
331
|
+
|
|
332
|
+
## 14. Troubleshooting by layer
|
|
333
|
+
|
|
334
|
+
Use the first failing layer rather than changing unrelated settings.
|
|
335
|
+
|
|
336
|
+
### Package or runtime layer
|
|
337
|
+
|
|
338
|
+
```sh
|
|
339
|
+
node --version
|
|
340
|
+
npm --version
|
|
341
|
+
which machine-mcp # macOS/Linux
|
|
342
|
+
where machine-mcp # Windows
|
|
343
|
+
machine-mcp doctor
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
### Cloudflare/deployment layer
|
|
347
|
+
|
|
348
|
+
```sh
|
|
349
|
+
machine-mcp doctor
|
|
350
|
+
machine-mcp status
|
|
351
|
+
machine-mcp --workspace /path/to/project --force-worker --verbose
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
A forced deployment changes cloud state. Use it only when the normal deployment hash/health reconciliation is insufficient.
|
|
355
|
+
|
|
356
|
+
### Local service/daemon layer
|
|
357
|
+
|
|
358
|
+
```sh
|
|
359
|
+
machine-mcp service status
|
|
360
|
+
machine-mcp service stop
|
|
361
|
+
machine-mcp service start
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
A connected Worker with no authenticated daemon can authorize OAuth successfully but cannot execute local tools.
|
|
365
|
+
|
|
366
|
+
### MCP-host layer
|
|
367
|
+
|
|
368
|
+
If `server_info` or `project_overview` never returns a structured Machine Bridge result, the host may not have delivered the call. Check the host's plugin/app enablement, tool permissions, approval UI, and connection status.
|
|
369
|
+
|
|
370
|
+
### Operating-system layer
|
|
371
|
+
|
|
372
|
+
If `diagnose_runtime` reaches the daemon but a probe fails, inspect filesystem permissions, macOS TCC/SIP, Windows ACLs, endpoint-security policy, shell availability, or container restrictions. Changing Machine Bridge to `full` cannot override the operating system.
|
|
373
|
+
|
|
374
|
+
### Browser layer
|
|
375
|
+
|
|
376
|
+
```sh
|
|
377
|
+
machine-mcp browser status
|
|
378
|
+
machine-mcp browser setup
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
Verify that the extension is loaded in the intended profile, its version matches the installed package, and its badge reports authenticated readiness.
|
|
382
|
+
|
|
383
|
+
For detailed recovery procedures, see [OPERATIONS.md](OPERATIONS.md).
|
|
384
|
+
|
|
385
|
+
## 15. Remove Machine Bridge
|
|
386
|
+
|
|
387
|
+
Remove the selected deployment, service, and local state:
|
|
388
|
+
|
|
389
|
+
```sh
|
|
390
|
+
machine-mcp uninstall
|
|
391
|
+
npm uninstall -g machine-bridge-mcp
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
Keep the deployed Worker while removing local state and autostart:
|
|
395
|
+
|
|
396
|
+
```sh
|
|
397
|
+
machine-mcp uninstall --keep-worker
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
Uninstall is fail-closed. If a verified daemon, active managed job, unreadable lock, or service removal cannot be resolved safely, Machine Bridge retains state for diagnosis instead of deleting only part of the installation.
|
|
401
|
+
|
|
402
|
+
## 16. Before sharing access
|
|
403
|
+
|
|
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
|
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# Multi-account authorization and tenancy
|
|
2
|
+
|
|
3
|
+
## What isolation means
|
|
4
|
+
|
|
5
|
+
Machine Bridge remote mode supports several named accounts on one workspace Worker. Each account has an independent password, role, active state, version, OAuth authorization codes, and access tokens. Account changes revoke only that account's outstanding credentials.
|
|
6
|
+
|
|
7
|
+
This is application-level authorization, not operating-system isolation. All accounts ultimately reach one local daemon running as one OS user. Roles limit which Machine Bridge tools can be listed and invoked; they do not create separate filesystems, browser profiles, process namespaces, keychains, network identities, or kernel security boundaries.
|
|
8
|
+
|
|
9
|
+
Use separate OS accounts, containers, VMs, state roots, Workers, and workspaces when users are mutually untrusted or require hard isolation.
|
|
10
|
+
|
|
11
|
+
## Roles
|
|
12
|
+
|
|
13
|
+
| Role | Effective local profile | Typical use |
|
|
14
|
+
|---|---|---|
|
|
15
|
+
| `reviewer` | `review` | Read-only workspace, Git, image, resource, and job inspection |
|
|
16
|
+
| `editor` | `edit` | Reviewer access plus deterministic file mutation |
|
|
17
|
+
| `operator` | `agent` | Editor access plus workspace-confined direct process execution and sessions |
|
|
18
|
+
| `owner` | `full` | Complete bridge authority, including shell, unrestricted paths, browser, applications, resources, jobs, and account administration |
|
|
19
|
+
|
|
20
|
+
The effective tool set is the intersection of:
|
|
21
|
+
|
|
22
|
+
1. the account role;
|
|
23
|
+
2. the policy advertised by the connected local daemon;
|
|
24
|
+
3. the tools actually available from that daemon.
|
|
25
|
+
|
|
26
|
+
The Worker filters `tools/list` and rejects unauthorized calls before relay. Every accepted relay call also carries `account_id`, `account_version`, and `role`; the local runtime validates the role again before dispatch. The shared policy contract remains the single source of capability semantics.
|
|
27
|
+
|
|
28
|
+
## Account lifecycle
|
|
29
|
+
|
|
30
|
+
List accounts:
|
|
31
|
+
|
|
32
|
+
```sh
|
|
33
|
+
machine-mcp account list
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Create an account. The generated password is displayed once and is not stored locally:
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
machine-mcp account add alice reviewer
|
|
40
|
+
machine-mcp account add build-bot operator
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Change role or active state:
|
|
44
|
+
|
|
45
|
+
```sh
|
|
46
|
+
machine-mcp account role alice editor
|
|
47
|
+
machine-mcp account disable build-bot
|
|
48
|
+
machine-mcp account enable build-bot
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Rotate one account's password:
|
|
52
|
+
|
|
53
|
+
```sh
|
|
54
|
+
machine-mcp account rotate-password alice
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Remove an account:
|
|
58
|
+
|
|
59
|
+
```sh
|
|
60
|
+
machine-mcp account remove alice
|
|
61
|
+
machine-mcp account remove alice --yes
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
The final active owner cannot be disabled, demoted, or removed. This prevents an accidental administrative lockout.
|
|
65
|
+
|
|
66
|
+
## OAuth model
|
|
67
|
+
|
|
68
|
+
An OAuth `client_id` identifies client software and its registered redirect URIs. It is not an account. One OAuth client may be authorized by several Machine Bridge accounts, and one account may authorize several OAuth clients.
|
|
69
|
+
|
|
70
|
+
An authorization code records:
|
|
71
|
+
|
|
72
|
+
- OAuth client ID;
|
|
73
|
+
- account ID and account version;
|
|
74
|
+
- role;
|
|
75
|
+
- redirect URI;
|
|
76
|
+
- PKCE S256 challenge;
|
|
77
|
+
- scope and protected resource;
|
|
78
|
+
- expiration.
|
|
79
|
+
|
|
80
|
+
An access-token record contains the same account binding plus the deployment-wide token version. Token values are stored only as SHA-256 lookup keys. Account passwords are CLI-generated 256-bit tokens. The Worker stores independent salted HMAC-SHA-256 verifiers and rejects arbitrary human-chosen passwords; the token entropy, rather than a CPU-intensive dictionary-hardening loop, provides offline-guessing resistance within the Worker CPU budget.
|
|
81
|
+
|
|
82
|
+
At each authenticated request, the Worker verifies that the account still exists, is active, and has the same version and role recorded in the token. A password rotation, role change, suspension, or removal increments or removes that account state and invalidates only its codes and tokens.
|
|
83
|
+
|
|
84
|
+
`machine-mcp rotate-secrets` is intentionally broader. It rotates the account-administration secret, daemon secret, and deployment-wide token version, invalidating every account token and requiring all clients to authorize again.
|
|
85
|
+
|
|
86
|
+
## Administrative boundary
|
|
87
|
+
|
|
88
|
+
Account administration is not exposed as an MCP tool. It uses an owner-only local secret to call private Worker administration endpoints from the CLI. The administration secret is stored only in owner-protected local state and Cloudflare Worker secrets; it is never printed by `status`, sent through MCP, or used as an account password.
|
|
89
|
+
|
|
90
|
+
The first start of a new deployment creates an `owner` account automatically and prints its generated password once. Subsequent starts do not display account passwords.
|
|
91
|
+
|
|
92
|
+
## Concurrency and revocation
|
|
93
|
+
|
|
94
|
+
Pending calls remain bound to the OAuth access token and JSON-RPC request ID. Duplicate in-flight IDs under one token are rejected. Account revocation blocks new requests immediately; calls already relayed remain subject to ordinary cancellation, deadlines, relay disconnect cleanup, and local role validation.
|
|
95
|
+
|
|
96
|
+
Remote relay loss cancels every relay-owned local call and terminates its child process tree. Process promises settle on cancellation even when a child does not emit `close`; process ownership remains tracked until actual exit.
|
|
97
|
+
|
|
98
|
+
## Audit and privacy
|
|
99
|
+
|
|
100
|
+
Operational metrics identify tools and stable error classes, not account passwords, bearer tokens, arguments, command text, file content, or results. `server_info` may return the authenticated account ID, role, and version to that account so the client can verify its authorization context.
|
|
101
|
+
|
|
102
|
+
Account names and display names are operator-selected metadata. Do not use secrets, email addresses, customer identifiers, or other unnecessary personal data in account names.
|
|
103
|
+
|
|
104
|
+
## Deployment topology
|
|
105
|
+
|
|
106
|
+
One workspace normally maps to one Worker name, one Durable Object instance, one local state profile, and one active daemon. Multiple accounts share this topology and its OS trust boundary.
|
|
107
|
+
|
|
108
|
+
Use a separate deployment when any of these differ:
|
|
109
|
+
|
|
110
|
+
- OS user or machine owner;
|
|
111
|
+
- workspace trust domain;
|
|
112
|
+
- browser/profile trust;
|
|
113
|
+
- network or credential-store authority;
|
|
114
|
+
- billing or incident-response boundary;
|
|
115
|
+
- requirement for hard tenant isolation.
|
|
116
|
+
|
|
117
|
+
Do not place several unrelated machines or mutually untrusted teams behind one broad owner deployment merely to reduce administration.
|
|
118
|
+
|
|
119
|
+
## Security limits
|
|
120
|
+
|
|
121
|
+
A `reviewer` cannot invoke mutation or process tools through Machine Bridge, but data readable by the local OS user may still be exposed by a bug, compromised dependency, or incorrectly broad workspace. An `operator` can run interpreters, package managers, compilers, and repository scripts; direct argv execution therefore remains powerful even without a shell. An `owner` has effectively the authority of the local OS user and any browser or Accessibility permissions granted to the runtime.
|
|
122
|
+
|
|
123
|
+
Roles are useful defense in depth and targeted revocation. They are not substitutes for least-privilege OS design, sandboxing, endpoint security, Cloudflare account protection, or careful review of untrusted repositories and instructions.
|
package/docs/OPERATIONS.md
CHANGED
|
@@ -67,7 +67,7 @@ Application UI inspection/actions require Accessibility permission for the Node/
|
|
|
67
67
|
|
|
68
68
|
`machine-mcp` is a foreground command. It remains attached to the terminal, defaults to `info` logging, and stops on `Ctrl+C`. `machine-mcp service start` launches the installed platform service in the background and returns to the shell; that service uses `warn` logging.
|
|
69
69
|
|
|
70
|
-
A global npm install changes the CLI files on disk but does not replace an already running Node process. Startup and other state-changing CLI operations use a token/process-identity lock and wait up to 30 seconds for a normal concurrent startup to finish; a short launchd/systemd overlap is therefore serialized rather than reported immediately as an error. On a normal foreground start, Machine Bridge unloads the platform service and then independently examines the workspace daemon lock. This second path handles a detached/orphan `--daemon-only` process that launchd
|
|
70
|
+
A global npm install changes the CLI files on disk but does not replace an already running Node process. Startup and other state-changing CLI operations use a token/process-identity lock and wait up to 30 seconds for a normal concurrent startup to finish; a short launchd/systemd overlap is therefore serialized rather than reported immediately as an error. On a normal foreground start, Machine Bridge unloads the platform service and then independently examines the workspace daemon lock. This second path handles a detached/orphan `--daemon-only` process that launchd, systemd, or Task Scheduler no longer tracks. Only current lock records containing service mode, version, PID, process start time, entrypoint, workspace, and state root are eligible for takeover. Before sending `SIGTERM`, Machine Bridge verifies PID and process start time plus the live command line, entrypoint, canonical workspace, canonical state root, and daemon-only flag. It waits up to 15 seconds for both the PID and lock to disappear and does not add a later forced-kill escalation. On POSIX, a daemon that handles and ignores `SIGTERM` therefore reaches the bounded timeout and remains alive. Node maps the supported termination signals to immediate process termination on Windows, so the same verified-daemon stop normally completes rather than exercising the POSIX timeout branch. A foreground or unverifiable process is left untouched; stop a foreground instance with `Ctrl+C`.
|
|
71
71
|
|
|
72
72
|
`machine-mcp service status [WORKSPACE]` reports two independent layers: the platform service (`active`) and `workspace_daemon`, plus `effective_active` and `orphaned_workspace_daemon` summary flags. On macOS it is possible for launchd to report inactive while a prior Node process remains alive with parent PID 1; that is an orphan-daemon condition, not proof that the daemon stopped. `service stop` unloads the provider when present and then terminates only a verified service-style workspace daemon. `service uninstall` and full uninstall are ordered fail-closed operations: provider stop → verified daemon stop(s) → definition removal. A failed or ambiguous stop leaves definitions and state intact. If takeover reaches its deadline, run:
|
|
73
73
|
|
|
@@ -91,7 +91,7 @@ npm --version
|
|
|
91
91
|
machine-mcp --verbose
|
|
92
92
|
```
|
|
93
93
|
|
|
94
|
-
`Unknown cli config "--allow-scripts"` proves the package installation ran under npm 11 or older. `Invalid property "node"` or `Invalid property "devEngines.node"` means npm parsed
|
|
94
|
+
`Unknown cli config "--allow-scripts"` proves the package installation ran under npm 11 or older. `Invalid property "node"` or `Invalid property "devEngines.node"` means npm parsed an outdated `devEngines` object; inspect the npm debug log to identify its source rather than assuming it belongs to Machine Bridge. The published package declares both Node.js 26 and npm 12 in `engines`, and `machine-mcp doctor` checks both active versions. Keep `--omit=optional` in the install command. Without it npm may resolve optional `fsevents` and warn that its install script was not included in `allowScripts`; Machine Bridge does not require that development-time watcher at runtime.
|
|
95
95
|
|
|
96
96
|
## State-root safety and removal
|
|
97
97
|
|
|
@@ -108,7 +108,7 @@ Uninstall acquires a state-root `maintenance.lock` that blocks new profile/state
|
|
|
108
108
|
Stable errors include `policy_denied`, `invalid_request`, `timeout`, `cancelled`, `network_error`, `unavailable`, `limit_exceeded`, and `integrity_error`, with retryability metadata. Diagnose by code first; free-form messages are guidance, not an API contract.
|
|
109
109
|
|
|
110
110
|
|
|
111
|
-
Windows Scheduled Task command lines use CRT-compatible quoting, including trailing backslashes and drive-root paths. 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. A service-style `--daemon-only` start that finds the same workspace daemon already running is an idempotent no-op: it exits successfully without repeating warnings or readiness output; explicit policy/secret/change requests still report that changes were not applied. Autostart logs are stored under the state root in `logs/daemon.out.log` and `logs/daemon.err.log`. Installed services pass `--log-level warn --log-format json`, so each active line is a bounded JSON event suitable for ingestion. Files are owner-only where supported and tail-trimmed before daemon startup.
|
|
111
|
+
Windows Scheduled Task command lines use CRT-compatible quoting, including trailing backslashes and drive-root paths. 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. A service-style `--daemon-only` start that finds the same workspace daemon already running is an idempotent no-op: it exits successfully without repeating warnings or readiness output; explicit policy/secret/change requests still report that changes were not applied. Autostart logs are stored under the state root in `logs/daemon.out.log` and `logs/daemon.err.log`. Installed services pass `--log-level warn --log-format json`, so each active line is a bounded JSON event suitable for ingestion. Files are owner-only where supported and tail-trimmed before daemon startup. If the log schema marker does not match the current format, the active files are cleared before startup and the current marker is written. Runtime code reads and maintains only the active filenames.
|
|
112
112
|
|
|
113
113
|
Logging is level-based:
|
|
114
114
|
|
|
@@ -214,7 +214,7 @@ Defense-in-depth limits include:
|
|
|
214
214
|
|
|
215
215
|
## Upgrade behavior
|
|
216
216
|
|
|
217
|
-
Policy revision
|
|
217
|
+
Policy revision 5 makes named profiles canonical and evaluates compound tool requirements from the shared contract. A state entry labelled `full` means 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`. Persisted policies from another revision are rejected rather than interpreted.
|
|
218
218
|
|
|
219
219
|
`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.
|
|
220
220
|
|
package/docs/POLICY_REFERENCE.md
CHANGED
package/docs/PRIVACY.md
CHANGED
|
@@ -13,7 +13,7 @@ npm run privacy:history
|
|
|
13
13
|
|
|
14
14
|
`privacy:check` scans tracked and unignored new UTF-8 files and relative names for generic/encrypted/algorithm-specific private-key headers, AWS/GitHub/GitLab/npm/Slack/Google/live-payment/API token forms, JWT-shaped bearer values, embedded-credential URLs, absolute user-home paths, non-example email/`user@host` identifiers, credential-shaped filenames, and locally configured private identifiers. A tracked `.npmrc` is parsed: non-secret repository settings such as `engine-strict=true` are allowed, while authentication/identity keys, environment interpolation, and embedded credentials fail closed. Publication-surface symbolic links are rejected rather than followed. Binary, invalid UTF-8, and files above the bounded scanner limit require explicit manual review instead of being silently skipped. Findings report only file, line, and rule; the matched value is never printed.
|
|
15
15
|
|
|
16
|
-
`privacy:history` first runs the same current-tree checks, then scans every reachable historical blob path and bounded UTF-8 blob plus every reachable commit message. It catches values that were committed and later deleted. Standard public Dependabot signing trailers are ignored only in that exact commit-message context; the same non-example address remains disallowed in ordinary files. The local `.privacy-denylist` is also applied to history, so a developer may discover
|
|
16
|
+
`privacy:history` first runs the same current-tree checks, then scans every reachable historical blob path and bounded UTF-8 blob plus every reachable commit message. It catches values that were committed and later deleted. Standard public Dependabot signing trailers are ignored only in that exact commit-message context; the same non-example address remains disallowed in ordinary files. The local `.privacy-denylist` is also applied to history, so a developer may discover older identifiers that CI cannot know. Such a finding is real publication history, but ordinary commits cannot erase it.
|
|
17
17
|
|
|
18
18
|
Git author and committer identity headers are canonical Git metadata rather than blob or commit-message content and are not automatically rejected. Audit them separately with `git log`; changing historical identity metadata requires a coordinated history rewrite and force-update of affected refs.
|
|
19
19
|
|
|
@@ -36,7 +36,7 @@ Commit and squash-merge subjects follow Conventional Commits:
|
|
|
36
36
|
<type>[optional scope][optional !]: <imperative description>
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
Allowed types are `feat`, `fix`, `docs`, `refactor`, `perf`, `test`, `build`, `ci`, `chore`, `security`, `release`, and `revert`. `feat` and `fix` carry their normal semantic-version meaning. A breaking change uses `!` and explains
|
|
39
|
+
Allowed types are `feat`, `fix`, `docs`, `refactor`, `perf`, `test`, `build`, `ci`, `chore`, `security`, `release`, and `revert`. `feat` and `fix` carry their normal semantic-version meaning. A breaking change uses `!` and explains upgrade impact in the body or a `BREAKING CHANGE:` footer.
|
|
40
40
|
|
|
41
41
|
A good change explains both **what changed and why**. Commits should be logically coherent, but intermediate branch history may be amended because the final pull request is squash-merged. Pull-request titles must satisfy the same format because they become the `main` commit subject.
|
|
42
42
|
|