machine-bridge-mcp 0.16.2 → 0.17.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 +40 -0
- package/CONTRIBUTING.md +14 -0
- package/README.md +11 -1
- package/SECURITY.md +9 -1
- package/browser-extension/manifest.json +2 -2
- package/browser-extension/service-worker.js +52 -29
- package/docs/ARCHITECTURE.md +4 -2
- package/docs/CLIENTS.md +2 -0
- package/docs/ENGINEERING.md +3 -1
- package/docs/GETTING_STARTED.md +400 -0
- package/docs/MULTI_ACCOUNT.md +406 -0
- package/docs/PROJECT_STANDARDS.md +143 -0
- package/docs/RELEASING.md +12 -0
- package/docs/TESTING.md +7 -5
- package/docs/TOOL_REFERENCE.md +2836 -0
- package/package.json +13 -4
- package/scripts/commit-message-check.mjs +63 -0
- package/scripts/coverage-check.mjs +9 -1
- package/scripts/generate-policy-reference.mjs +1 -4
- package/scripts/generate-tool-reference.mjs +87 -0
- package/scripts/generate-worker-types.mjs +19 -0
- package/scripts/markdown.mjs +9 -0
- package/src/local/agent-context.mjs +8 -15
- package/src/local/cli.mjs +1 -107
- package/src/local/daemon-process.mjs +16 -4
- package/src/local/default-instructions.mjs +2 -45
- package/src/local/git-service.mjs +4 -9
- package/src/local/managed-job-plan.mjs +2 -7
- package/src/local/managed-jobs.mjs +2 -7
- package/src/local/numbers.mjs +9 -0
- package/src/local/process-execution.mjs +4 -9
- package/src/local/process-sessions.mjs +5 -10
- package/src/local/project-metadata.mjs +50 -0
- package/src/local/project-package.mjs +2 -45
- package/src/local/records.mjs +5 -0
- package/src/local/runtime.mjs +5 -12
- package/src/local/state-inventory.mjs +139 -0
- package/src/local/workspace-file-service.mjs +6 -12
- package/src/worker/index.ts +33 -17
- package/tsconfig.json +1 -1
- package/src/worker/worker-configuration.d.ts +0 -14716
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,45 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.17.1 - 2026-07-14
|
|
4
|
+
|
|
5
|
+
### Installation and first use
|
|
6
|
+
|
|
7
|
+
- Add an end-to-end installation and first-use guide covering transport selection, authority profiles, prerequisites, released and source installation, first remote deployment, current ChatGPT developer-mode connection, stdio configuration, existing-profile browser pairing, verification, routine operation, multi-workspace use, upgrades, layered troubleshooting, and fail-closed removal.
|
|
8
|
+
- Link the detailed guide from the README while retaining the compact command reference, and clarify how to distinguish package, Cloudflare, daemon, MCP-host, operating-system, and browser failures.
|
|
9
|
+
|
|
10
|
+
### Multi-client and multi-account boundary
|
|
11
|
+
|
|
12
|
+
- Document that the existing Worker supports multiple OAuth client registrations and access tokens but does not provide isolated human/service accounts: all successful authorizations use one per-workspace connection password and share the same policy and daemon authority.
|
|
13
|
+
- Define a principal-aware evolution path that keeps OAuth clients separate from principals, memberships, and named grants; uses capability intersection and dual Worker/local enforcement; adds targeted revocation and per-principal quotas; and retains one bridge/Durable Object per workspace or trust domain.
|
|
14
|
+
- Make the security and architecture contracts explicit: mutually untrusted users require separate bridge instances and preferably separate low-privilege OS, container, or VM boundaries because application-level roles cannot isolate local process, shell, browser, or credential-store authority.
|
|
15
|
+
|
|
16
|
+
## 0.17.0 - 2026-07-13
|
|
17
|
+
|
|
18
|
+
### Project governance and contribution flow
|
|
19
|
+
|
|
20
|
+
- Define a risk-based project standard covering GitHub Flow, Conventional Commits, architecture boundaries, MCP contract ownership, testing, errors, logging, supply-chain security, documentation, review, and explicit exceptions. Add pull-request and structured issue templates plus area ownership through CODEOWNERS.
|
|
21
|
+
- Add an executable Conventional Commit policy for pull-request and main-branch commit titles. Keep the repository on squash-based GitHub Flow rather than introducing permanent develop/release branches that do not match its single-maintainer, continuously released operating model.
|
|
22
|
+
- Require all repository-host operations to use local `git`, `gh`, and `gh api` through Machine Bridge. Explicitly prohibit hosted GitHub connectors or ChatGPT GitHub plugins so remote mutations, credentials, refs, checks, and recovery remain observable from one local control plane.
|
|
23
|
+
- Make repository automation responsible for closing the source-change lifecycle: after all required checks pass it squash-merges the pull request, verifies `main`, creates and pushes the annotated version tag, and creates or updates the matching GitHub Release. npm publication, Worker deployment, credentials, global installation, and daemon/service replacement remain separately authorized live operations.
|
|
24
|
+
|
|
25
|
+
### Generated contracts and security automation
|
|
26
|
+
|
|
27
|
+
- Generate a complete MCP tool reference from the shared tool catalog and reject stale output in the required suite. The tool catalog remains the single source for names, availability, annotations, and JSON input schemas; REST-specific Swagger documentation is not duplicated for the MCP surface.
|
|
28
|
+
- Add pinned, least-privilege GitHub workflows for CodeQL analysis, pull-request dependency review, OpenSSF Scorecard publication, and governance checks. Preserve exact dependency versions, registry signature/attestation verification, SBOM generation, history privacy scanning, and cross-platform package tests.
|
|
29
|
+
|
|
30
|
+
### Cohesion, reuse, and runtime reliability
|
|
31
|
+
|
|
32
|
+
- Extract optional project-metadata reads, strict integer normalization, plain-record validation, and uninstall/service state inventory into focused shared modules. Remove duplicate numeric clamping, record classification, and no-follow UTF-8 metadata readers while preserving the distinct strict validation semantics used by browser/application commands and Agent Context instruction files. Plain-record validation now rejects class instances instead of treating every non-array object as protocol/configuration data.
|
|
33
|
+
- Reduce the CLI entrypoint from 1,169 to 1,063 lines by moving profile, Worker, active-job, and process-lock inventory behind a dedicated boundary. Add direct failure-path tests and enforce 91% function/73% branch coverage for the new inventory module; raise the CLI branch floor from 5% to 10%.
|
|
34
|
+
- Canonicalize existing state roots before profile enumeration, fixing macOS `/var` versus `/private/var` alias mismatches that could make service removal or lock inspection report inconsistent profile paths. Retry only the final daemon-lock handoff after a verified service stop, and keep daemon fixture subprocesses out of V8 coverage so process teardown does not create platform-timing failures.
|
|
35
|
+
- Generate Wrangler environment declarations through a cross-platform script that creates ignored `.wrangler/` state before invoking Wrangler, instead of writing under `src/worker`; packaging tests reject generated type declarations. This removes clean-runner state dependence and reduces the dry-run package from about 410 KB/1.8 MB unpacked to about 314 KB/1.22 MB while retaining every Worker runtime module.
|
|
36
|
+
- Replace repeated empty WebSocket send/close catches in the Worker and browser extension with small module-local best-effort helpers whose comments preserve the primary failure semantics. Architecture checks reject unexplained empty catches on those protocol boundaries.
|
|
37
|
+
|
|
38
|
+
### Tests and documentation
|
|
39
|
+
|
|
40
|
+
- Extend architecture checks to require generated tool documentation, governance scripts, security workflows, explicit workflow permissions, immutable Action references, and rejection of privileged pull-request triggers or write-all permissions.
|
|
41
|
+
- Document why aggregate 80% coverage is not a sufficient quality target, identify the current CLI orchestration branch-coverage weakness, and retain per-module risk thresholds plus behavior-level cross-platform, concurrency, fault-injection, and protocol tests.
|
|
42
|
+
|
|
3
43
|
## 0.16.2 - 2026-07-13
|
|
4
44
|
|
|
5
45
|
### Fixed
|
package/CONTRIBUTING.md
CHANGED
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
|
|
3
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
4
|
|
|
5
|
+
## Development workflow
|
|
6
|
+
|
|
7
|
+
Read [docs/PROJECT_STANDARDS.md](docs/PROJECT_STANDARDS.md) and the relevant domain documentation before changing behavior. This repository uses GitHub Flow: branch from current `main`, keep the change coherent, open a pull request, satisfy required checks, squash-merge, and delete the branch. Permanent `develop` or generic release integration branches are not used unless an independently maintained release line creates a concrete need. Repository automation performs GitHub operations only through local `git`, `gh`, and `gh api` commands executed by Machine Bridge; hosted GitHub connectors and ChatGPT GitHub plugins are prohibited for this repository.
|
|
8
|
+
|
|
9
|
+
Branch names use a category and purpose such as `feat/browser-downloads`, `fix/relay-timeout`, or `chore/dependency-policy`.
|
|
10
|
+
|
|
11
|
+
Pull-request titles and final commit subjects use Conventional Commits:
|
|
12
|
+
|
|
13
|
+
```text
|
|
14
|
+
<type>[optional scope][optional !]: <imperative description>
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Accepted types are `feat`, `fix`, `docs`, `refactor`, `perf`, `test`, `build`, `ci`, `chore`, `security`, `release`, and `revert`. Explain the causal problem, why the solution is correct, compatibility/security/privacy risk, verification, and release impact in the pull request. Bug fixes require a regression test for the original failure mechanism.
|
|
18
|
+
|
|
5
19
|
## Required for every release-relevant change
|
|
6
20
|
|
|
7
21
|
Before the reviewed code is pushed to `main`:
|
package/README.md
CHANGED
|
@@ -23,6 +23,8 @@ Local clients such as Claude Desktop, Cursor, and Codex CLI
|
|
|
23
23
|
|
|
24
24
|
The remote Worker authenticates and relays calls. It cannot directly read local files or start local processes. File, Git, image, patch, process, diagnostic, and managed-job operations execute in the local runtime.
|
|
25
25
|
|
|
26
|
+
New users should follow the end-to-end [installation and first-use guide](docs/GETTING_STARTED.md). Before sharing a deployment or connecting several accounts, read [multi-client, multi-account, and tenancy architecture](docs/MULTI_ACCOUNT.md).
|
|
27
|
+
|
|
26
28
|
## Default behavior and policy profiles
|
|
27
29
|
|
|
28
30
|
A newly selected workspace starts with the maximum-permission `full` profile for low-friction operation:
|
|
@@ -45,6 +47,8 @@ This default prioritizes usability, not least privilege. `run_process` and proce
|
|
|
45
47
|
|
|
46
48
|
## Install
|
|
47
49
|
|
|
50
|
+
For prerequisites, first remote deployment, ChatGPT connection, stdio configuration, browser pairing, upgrades, troubleshooting, and removal, follow [Installation and first use](docs/GETTING_STARTED.md). The commands below are the compact installation reference.
|
|
51
|
+
|
|
48
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.
|
|
49
53
|
|
|
50
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 legacy `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`.
|
|
@@ -126,6 +130,12 @@ MCP connection password: mcp_password_...
|
|
|
126
130
|
|
|
127
131
|
The remote authorization flow uses an authorization code, PKCE S256, exact redirect/resource binding, expiring access tokens stored as hashes, and a token-version value for bulk revocation. After password approval, the Worker constructs the registered callback with the URL API and returns `303 See Other`, so OAuth response parameters are encoded and the browser performs a GET to the callback.
|
|
128
132
|
|
|
133
|
+
### Multiple clients and accounts
|
|
134
|
+
|
|
135
|
+
One Worker can hold several OAuth client registrations and access tokens, so the same trusted owner or team can connect more than one MCP application or ChatGPT account. This is **multi-client access, not isolated multi-account tenancy**: the current release uses one workspace connection password, one workspace policy, and one active daemon authority. It has no principal records, per-account roles, targeted account revocation, or account-specific audit boundary.
|
|
136
|
+
|
|
137
|
+
Do not share a `full` bridge with mutually untrusted users. Use a separate bridge and preferably a separate low-privilege OS account, container, or VM for each trust domain. See [Multi-client, multi-account, and tenancy architecture](docs/MULTI_ACCOUNT.md) for the current support matrix and the proposed principal/grant design.
|
|
138
|
+
|
|
129
139
|
## Optional local stdio MCP
|
|
130
140
|
|
|
131
141
|
stdio is a local transport, not a model provider. Claude Desktop, Cursor, Codex CLI, ChatGPT Desktop, or another MCP host supplies its own model/session and launches `machine-bridge-mcp` as a subprocess. The MCP server only exposes tools and returns their results; it does not borrow the model running in ChatGPT web.
|
|
@@ -480,7 +490,7 @@ npm pack --dry-run
|
|
|
480
490
|
|
|
481
491
|
`npm run check` covers privacy and release-impact gates, architecture/link invariants, generated Worker types, TypeScript, recursively discovered JavaScript syntax, catalog-to-runtime handler parity, deterministic relay lifecycle and secure-file tests, concurrent lock/atomic-replacement/PID-reuse fixtures, fail-closed service lifecycle tests, descendant process-tree termination, local path/write/state/log/service invariants, Ed25519/RSA generation and key-pair validation, real-machine `full` sandbox acceptance, a clean npm package-manifest/mode/sensitive-artifact check, managed-job integrity/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; macOS and package-audit jobs also exercise the documented isolated global installation.
|
|
482
492
|
|
|
483
|
-
The cross-cutting 0.12.0 review, corrected failure modes, and residual OS-level limits are recorded in [docs/AUDIT.md](docs/AUDIT.md). See also [docs/AGENT_CONTEXT.md](docs/AGENT_CONTEXT.md), [docs/LOCAL_AUTOMATION.md](docs/LOCAL_AUTOMATION.md), [docs/MANAGED_JOBS.md](docs/MANAGED_JOBS.md), [docs/TESTING.md](docs/TESTING.md), [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md), [docs/ENGINEERING.md](docs/ENGINEERING.md), and [SECURITY.md](SECURITY.md).
|
|
493
|
+
The cross-cutting 0.12.0 review, corrected failure modes, and residual OS-level limits are recorded in [docs/AUDIT.md](docs/AUDIT.md). See also [docs/GETTING_STARTED.md](docs/GETTING_STARTED.md), [docs/MULTI_ACCOUNT.md](docs/MULTI_ACCOUNT.md), [docs/AGENT_CONTEXT.md](docs/AGENT_CONTEXT.md), [docs/LOCAL_AUTOMATION.md](docs/LOCAL_AUTOMATION.md), [docs/MANAGED_JOBS.md](docs/MANAGED_JOBS.md), [docs/TESTING.md](docs/TESTING.md), [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md), [docs/ENGINEERING.md](docs/ENGINEERING.md), [docs/PROJECT_STANDARDS.md](docs/PROJECT_STANDARDS.md), the generated [MCP tool reference](docs/TOOL_REFERENCE.md), and [SECURITY.md](SECURITY.md).
|
|
484
494
|
|
|
485
495
|
## Uninstall
|
|
486
496
|
|
package/SECURITY.md
CHANGED
|
@@ -36,6 +36,14 @@ 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
|
+
### Multiple clients are not isolated accounts
|
|
40
|
+
|
|
41
|
+
The current remote design accepts multiple OAuth client registrations and can issue multiple access tokens, but it has one per-workspace connection password and one workspace policy. An OAuth `client_id` identifies client software and redirect URIs; it is not a human or service principal. Different ChatGPT accounts or MCP applications that authorize with the same password therefore enter the same trust domain and receive the same Machine Bridge authority.
|
|
42
|
+
|
|
43
|
+
The current release has no per-account role, suspension, membership expiry, targeted principal revocation, or account-specific audit boundary. Secret rotation invalidates all outstanding access tokens for the workspace. Do not present this behavior as multi-user tenancy.
|
|
44
|
+
|
|
45
|
+
Mutually untrusted users must use separate bridge instances and external isolation appropriate to the authority exposed: a dedicated low-privilege OS account, container, or VM, a narrow workspace, an independent state root and Worker credential set, and the narrowest useful profile. Worker-side account records alone cannot isolate direct processes, shells, browser sessions, Accessibility actions, credential stores, or network authority inherited from the local OS user. See [Multi-client, multi-account, and tenancy architecture](docs/MULTI_ACCOUNT.md).
|
|
46
|
+
|
|
39
47
|
## Profiles are capability sets, not sandboxes
|
|
40
48
|
|
|
41
49
|
The default for newly selected workspaces is `full`, which prioritizes ease of use over least privilege. Named profiles are canonical capability contracts. A stored `full` label is repaired on load to the complete maximum-permission field set and tool catalog; a deliberate per-capability override is represented as `custom`, not as a partially restricted `full`.
|
|
@@ -152,7 +160,7 @@ Runner diagnostic logs are owner-only and do not receive child stdout/stderr. St
|
|
|
152
160
|
|
|
153
161
|
## OAuth and public endpoints
|
|
154
162
|
|
|
155
|
-
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. 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.
|
|
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. Client registrations and tokens may coexist, but all authorizations currently share one workspace credential and authority; there is no principal-aware account model. 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.
|
|
156
164
|
|
|
157
165
|
The authorization page displays the validated client name and redirect URI. Enter the connection password only after initiating the connection and recognizing both values.
|
|
158
166
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"manifest_version": 3,
|
|
3
3
|
"name": "Machine Bridge Browser",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.17.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.17.1"
|
|
34
34
|
}
|
|
@@ -67,12 +67,33 @@ function setConnectionState(state) {
|
|
|
67
67
|
: state === "unconfigured"
|
|
68
68
|
? "Machine Bridge Browser: click to open pairing"
|
|
69
69
|
: "Machine Bridge Browser: disconnected; click to open pairing";
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
ignoreBrowserApiCall(() => chrome.action.setBadgeText({ text: badge }));
|
|
71
|
+
ignoreBrowserApiCall(() => chrome.action.setTitle({ title }));
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
function
|
|
75
|
-
|
|
74
|
+
function ignoreBrowserApiCall(operation) {
|
|
75
|
+
try {
|
|
76
|
+
const value = operation();
|
|
77
|
+
if (value && typeof value.catch === "function") value.catch(() => {});
|
|
78
|
+
} catch {
|
|
79
|
+
// Browser UI decoration is optional and must not disrupt broker connectivity.
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function closeSocketQuietly(ws, code, reason) {
|
|
84
|
+
try {
|
|
85
|
+
ws?.close(code, reason);
|
|
86
|
+
} catch {
|
|
87
|
+
// The socket may already be closed; reconnect state remains authoritative.
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function sendSocketQuietly(ws, payload) {
|
|
92
|
+
try {
|
|
93
|
+
ws.send(payload);
|
|
94
|
+
} catch {
|
|
95
|
+
// A response cannot be recovered after the broker socket closes.
|
|
96
|
+
}
|
|
76
97
|
}
|
|
77
98
|
|
|
78
99
|
async function pairConfiguration(rawEndpoint, rawToken, { replace, senderUrl }) {
|
|
@@ -119,27 +140,29 @@ async function confirmRepairFromTab(tab) {
|
|
|
119
140
|
}),
|
|
120
141
|
});
|
|
121
142
|
const paired = await pairConfiguration(result?.result?.endpoint, result?.result?.token, { replace: true, senderUrl: tab.url });
|
|
122
|
-
await
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
if (status) status.textContent = ok ? "Paired. You may close this tab." : "Pairing failed.";
|
|
127
|
-
},
|
|
128
|
-
args: [paired.ok === true],
|
|
129
|
-
});
|
|
143
|
+
await setPairingPageStatus(
|
|
144
|
+
tab.id,
|
|
145
|
+
paired.ok === true ? "Paired. You may close this tab." : "Pairing failed.",
|
|
146
|
+
);
|
|
130
147
|
} catch {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
const status = document.getElementById("status");
|
|
136
|
-
if (status) status.textContent = "Pairing failed. Reload this page and confirm that the expected extension build is loaded.";
|
|
137
|
-
},
|
|
138
|
-
});
|
|
139
|
-
} catch {}
|
|
148
|
+
ignoreBrowserApiCall(() => setPairingPageStatus(
|
|
149
|
+
tab.id,
|
|
150
|
+
"Pairing failed. Reload this page and confirm that the expected extension build is loaded.",
|
|
151
|
+
));
|
|
140
152
|
}
|
|
141
153
|
}
|
|
142
154
|
|
|
155
|
+
function setPairingPageStatus(tabId, text) {
|
|
156
|
+
return chrome.scripting.executeScript({
|
|
157
|
+
target: { tabId },
|
|
158
|
+
func: (value) => {
|
|
159
|
+
const status = document.getElementById("status");
|
|
160
|
+
if (status) status.textContent = value;
|
|
161
|
+
},
|
|
162
|
+
args: [text],
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
143
166
|
ensureReconnectAlarm();
|
|
144
167
|
void connectFromStorage();
|
|
145
168
|
|
|
@@ -162,7 +185,7 @@ function connect(endpoint, token, { reconnect = true } = {}) {
|
|
|
162
185
|
clearTimeout(reconnectTimer);
|
|
163
186
|
reconnectTimer = null;
|
|
164
187
|
if (socket) {
|
|
165
|
-
|
|
188
|
+
closeSocketQuietly(socket);
|
|
166
189
|
}
|
|
167
190
|
const ws = new WebSocket(endpoint, [`mbm.${token}`]);
|
|
168
191
|
socket = ws;
|
|
@@ -181,12 +204,12 @@ function connect(endpoint, token, { reconnect = true } = {}) {
|
|
|
181
204
|
};
|
|
182
205
|
ws.onopen = () => {
|
|
183
206
|
if (socket !== ws) {
|
|
184
|
-
|
|
207
|
+
closeSocketQuietly(ws);
|
|
185
208
|
settle(new Error("browser connection was superseded"));
|
|
186
209
|
return;
|
|
187
210
|
}
|
|
188
211
|
ws.handshakeTimer = setTimeout(() => {
|
|
189
|
-
|
|
212
|
+
closeSocketQuietly(ws, 1002, "browser broker handshake timed out");
|
|
190
213
|
}, HANDSHAKE_TIMEOUT_MS);
|
|
191
214
|
};
|
|
192
215
|
ws.onmessage = (event) => void handleMessage(ws, event.data, () => settle());
|
|
@@ -214,12 +237,12 @@ function scheduleReconnect(endpoint, token) {
|
|
|
214
237
|
async function handleMessage(ws, raw, onReady = () => {}) {
|
|
215
238
|
let message;
|
|
216
239
|
try { message = JSON.parse(String(raw)); } catch {
|
|
217
|
-
|
|
240
|
+
closeSocketQuietly(ws, 1007, "invalid broker JSON");
|
|
218
241
|
return;
|
|
219
242
|
}
|
|
220
243
|
if (message?.type === "hello") {
|
|
221
244
|
if (ws.serverHelloSeen || message.role !== "extension" || message.protocol !== BROWSER_EXTENSION_PROTOCOL) {
|
|
222
|
-
|
|
245
|
+
closeSocketQuietly(ws, 1002, "browser broker protocol mismatch");
|
|
223
246
|
return;
|
|
224
247
|
}
|
|
225
248
|
ws.serverHelloSeen = true;
|
|
@@ -237,7 +260,7 @@ async function handleMessage(ws, raw, onReady = () => {}) {
|
|
|
237
260
|
}
|
|
238
261
|
if (message?.type === "hello_ack") {
|
|
239
262
|
if (ws.bridgeReady || !ws.serverHelloSeen || message.role !== "extension" || message.protocol !== BROWSER_EXTENSION_PROTOCOL) {
|
|
240
|
-
|
|
263
|
+
closeSocketQuietly(ws, 1002, "invalid browser broker acknowledgement");
|
|
241
264
|
return;
|
|
242
265
|
}
|
|
243
266
|
clearTimeout(ws.handshakeTimer);
|
|
@@ -252,7 +275,7 @@ async function handleMessage(ws, raw, onReady = () => {}) {
|
|
|
252
275
|
return;
|
|
253
276
|
}
|
|
254
277
|
if (!ws.bridgeReady) {
|
|
255
|
-
|
|
278
|
+
closeSocketQuietly(ws, 1002, "browser broker acknowledgement required");
|
|
256
279
|
return;
|
|
257
280
|
}
|
|
258
281
|
if (message?.type === "cancel" && typeof message.id === "string") {
|
|
@@ -291,7 +314,7 @@ function sendResponse(ws, id, ok, result, error = "") {
|
|
|
291
314
|
if (new TextEncoder().encode(payload).byteLength > MAX_RESULT_BYTES) {
|
|
292
315
|
payload = JSON.stringify({ type: "response", id, ok: false, error: "browser result exceeds maximum size" });
|
|
293
316
|
}
|
|
294
|
-
|
|
317
|
+
sendSocketQuietly(ws, payload);
|
|
295
318
|
}
|
|
296
319
|
|
|
297
320
|
|
package/docs/ARCHITECTURE.md
CHANGED
|
@@ -109,6 +109,8 @@ 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 current OAuth store is multi-client but not principal-aware. `client_id` identifies an MCP application/installation; it does not identify a human or service account. Every successful authorization uses the same per-workspace connection password and receives the same workspace policy ceiling. Isolated account support therefore requires explicit principals, memberships, named grants, targeted revocation, and dual Worker/local enforcement rather than treating client registrations as users. The recommended design retains one bridge-specific Durable Object and one local runtime per workspace/trust domain; see [MULTI_ACCOUNT.md](MULTI_ACCOUNT.md).
|
|
113
|
+
|
|
112
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.
|
|
113
115
|
|
|
114
116
|
### Autostart layer
|
|
@@ -138,7 +140,7 @@ flowchart LR
|
|
|
138
140
|
CLI --> S[Autostart provider]
|
|
139
141
|
```
|
|
140
142
|
|
|
141
|
-
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.
|
|
143
|
+
Remote OAuth currently determines which registered client token may call tools; it does not distinguish independently authorized human principals. 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.
|
|
142
144
|
|
|
143
145
|
## Remote request lifecycle
|
|
144
146
|
|
|
@@ -258,4 +260,4 @@ Third-party workflow actions are pinned to immutable commit SHAs. Dependabot pro
|
|
|
258
260
|
- model-level prompt-injection prevention or semantic validation of browser/application actions;
|
|
259
261
|
- universal desktop UI automation beyond the implemented OS Accessibility backend;
|
|
260
262
|
- scripting browser-internal/enterprise-blocked pages or inaccessible cross-origin frames;
|
|
261
|
-
- multi-user tenancy in one Worker deployment.
|
|
263
|
+
- isolated multi-user tenancy or per-principal authorization in one Worker deployment; multiple OAuth client registrations currently share one workspace authority.
|
package/docs/CLIENTS.md
CHANGED
|
@@ -124,6 +124,8 @@ machine-mcp --workspace /path/to/project
|
|
|
124
124
|
|
|
125
125
|
Enter the printed `/mcp` URL in the remote MCP connector. During OAuth authorization, verify the displayed client name and redirect URI before entering the connection password.
|
|
126
126
|
|
|
127
|
+
Several OAuth clients and access tokens can coexist, but the current release does not model separate human/service principals. Every authorization that uses the shared workspace password receives the same workspace authority. Do not treat separate ChatGPT accounts as isolated Machine Bridge accounts; see [MULTI_ACCOUNT.md](MULTI_ACCOUNT.md).
|
|
128
|
+
|
|
127
129
|
## Profile guidance
|
|
128
130
|
|
|
129
131
|
- `full` is the default and prioritizes immediate usability. It is a canonical contract exposing every catalog tool, shell execution, unrestricted direct filesystem paths, absolute path output, and the full parent environment. Any individual narrowing is represented as `custom`.
|
package/docs/ENGINEERING.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Engineering principles and maintenance rules
|
|
2
2
|
|
|
3
|
-
This document records project-wide decisions that must survive individual fixes, releases, and maintainers. It is normative for repository changes. Machine-specific observations belong in the ignored `.project-local/` directory instead.
|
|
3
|
+
This document records project-wide decisions that must survive individual fixes, releases, and maintainers. It is normative for repository changes together with [PROJECT_STANDARDS.md](PROJECT_STANDARDS.md). Machine-specific observations belong in the ignored `.project-local/` directory instead.
|
|
4
4
|
|
|
5
5
|
## Product and security invariants
|
|
6
6
|
|
|
@@ -146,6 +146,8 @@ Cross-platform tests must not depend on shell syntax, case-sensitive Windows pat
|
|
|
146
146
|
- OPERATIONS contains diagnosis and recovery procedures.
|
|
147
147
|
- TESTING records executable coverage and regression expectations.
|
|
148
148
|
- CHANGELOG records externally relevant changes, including documentation and workflow changes.
|
|
149
|
+
- PROJECT_STANDARDS defines collaboration, contract, testing, supply-chain, review, and exception policy.
|
|
150
|
+
- TOOL_REFERENCE is generated from the shared MCP tool catalog and must never be maintained by hand.
|
|
149
151
|
|
|
150
152
|
Documentation that claims a guarantee must identify the code or test enforcing it. Do not document an aspirational behavior as implemented.
|
|
151
153
|
|