machine-bridge-mcp 1.0.4 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.0.5 - 2026-07-14
4
+
5
+ ### Built-in ChatGPT and Grok origins
6
+
7
+ - Allow the exact first-party browser origins used by ChatGPT (`https://chatgpt.com` and legacy `https://chat.openai.com`) and Grok (`https://grok.com` and `https://x.com`) directly in Worker origin validation. Users no longer need to run Wrangler or edit Cloudflare variables to complete OAuth from those clients.
8
+ - Keep `MBM_ALLOWED_ORIGINS` as an additive exact-origin extension point, preserve same-origin and no-Origin requests, reject unrelated and `null` origins, and apply one predicate to preflight and actual requests. Integration tests exercise every built-in origin alongside a configured custom origin.
9
+
3
10
  ## 1.0.4 - 2026-07-14
4
11
 
5
12
  ### Windows first-run workspace
package/README.md CHANGED
@@ -138,6 +138,8 @@ MCP Server URL: https://<worker>.<account>.workers.dev/mcp
138
138
 
139
139
  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.
140
140
 
141
+ The Worker accepts the exact first-party browser origins used by ChatGPT (`https://chatgpt.com` and the legacy `https://chat.openai.com`) and Grok (`https://grok.com` and its X-hosted surface at `https://x.com`). Users do not need to run Wrangler or edit Cloudflare variables. `MBM_ALLOWED_ORIGINS` remains an operator-only, comma-separated extension point for other exact origins; it is additive and does not replace the built-in set. Wildcards and `null` are not accepted.
142
+
141
143
  ### Multiple clients and accounts
142
144
 
143
145
  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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "manifest_version": 3,
3
3
  "name": "Machine Bridge Browser",
4
- "version": "1.0.4",
4
+ "version": "1.0.5",
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": "1.0.4"
33
+ "version_name": "1.0.5"
34
34
  }
@@ -235,6 +235,8 @@ Removal first acquires a state-root maintenance lock that blocks new profile/sta
235
235
 
236
236
  OAuth metadata is pruned on access. Expired codes/tokens, old throttling records, and inactive clients without active credentials are removed. Source identities are deployment-keyed HMAC values, not stored source addresses or reversible unsalted hashes.
237
237
 
238
+ Browser-origin validation accepts requests without an `Origin` header, the Worker's own origin, and a fixed first-party set for ChatGPT (`https://chatgpt.com`, `https://chat.openai.com`) and Grok (`https://grok.com`, `https://x.com`). `MBM_ALLOWED_ORIGINS` contributes optional exact comma-separated additions. It cannot remove the built-in origins, and wildcard or `null` origins are not accepted. Both preflight and actual requests use the same predicate.
239
+
238
240
  ## Observability
239
241
 
240
242
  Public health exposes only server identity and version. Authenticated `server_info` exposes bounded runtime status, policy origin/revision, managed-job counts, resource alias names without paths or values, daemon/relay-advertised tool counts, relay route state without endpoint details, and privacy-preserving capability-routing evidence. It explicitly reports that the host-exposed subset is unknown to the server. `diagnose_runtime` runs fixed local probes and explicitly reports that its own request reached the daemon.
package/docs/CLIENTS.md CHANGED
@@ -114,7 +114,7 @@ args = ["/absolute/path/to/machine-mcp.mjs", "stdio", "--workspace", "/path/to/p
114
114
 
115
115
  Codex CLI, the Codex IDE extension, and supported ChatGPT Desktop Codex hosts can share MCP configuration on the same Codex host. ChatGPT web does not read local Codex configuration files; web use requires a hosted plugin/connector or a reachable remote MCP endpoint.
116
116
 
117
- ## Remote ChatGPT connection
117
+ ## Remote ChatGPT and Grok connection
118
118
 
119
119
  Run:
120
120
 
@@ -122,7 +122,7 @@ 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 a Machine Bridge account name and password.
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. The Worker has exact built-in CORS support for `https://chatgpt.com`, legacy `https://chat.openai.com`, `https://grok.com`, and the X-hosted Grok surface at `https://x.com`; no direct Wrangler command or Cloudflare variable edit is required.
126
126
 
127
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
 
@@ -204,7 +204,7 @@ Current ChatGPT developer-mode flow, as documented in OpenAI's [Connect from Cha
204
204
  7. Enter the Machine Bridge account name and password only after those values are recognized.
205
205
  8. Create a new chat and enable the app for that conversation.
206
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.
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. The same public `/mcp` URL can be entered in Grok where remote MCP configuration is available. Machine Bridge accepts the exact `https://grok.com` and `https://x.com` browser origins as well as ChatGPT's current and legacy origins without requiring a Wrangler command.
208
208
 
209
209
  ## 8. Verify the first connection
210
210
 
package/docs/TESTING.md CHANGED
@@ -53,7 +53,7 @@ The suite includes:
53
53
  - deterministic property tests over hostile browser-protocol byte strings, canonical/custom policy combinations, argv bounds/NULs, and a real direct process proving shell metacharacters remain literal argv;
54
54
  - CLI parsing, policy profiles, and client configuration boundaries;
55
55
  - live stdio MCP initialization with session instructions, capability resolution, discovery, calls, rich content, sessions, cancellation, managed-job acceptance, and a detached job/finally phase that survives stdio shutdown;
56
- - live local Worker OAuth registration, consent, URL-constructed `303` callbacks including the ChatGPT redirect URI and encoded state, PKCE, token replay rejection, throttling, CORS, protocol negotiation, HMAC-bound MCP session issuance, two-session same-id concurrency, sessionless same-id independence, session-scoped cancellation isolation, same-session duplicate rejection, daemon-backed session bootstrap, dynamic tool advertisement, rich content, daemon replacement, cancellation, malformed daemon JSON/non-object rejection, duplicate hello rejection, and unknown-message closure.
56
+ - live local Worker OAuth registration, consent, URL-constructed `303` callbacks including the ChatGPT redirect URI and encoded state, PKCE, token replay rejection, throttling, exact built-in ChatGPT/Grok browser origins, additive custom origins, unrelated/opaque-origin rejection, protocol negotiation, HMAC-bound MCP session issuance, two-session same-id concurrency, sessionless same-id independence, session-scoped cancellation isolation, same-session duplicate rejection, daemon-backed session bootstrap, dynamic tool advertisement, rich content, daemon replacement, cancellation, malformed daemon JSON/non-object rejection, duplicate hello rejection, and unknown-message closure.
57
57
  - local runtime proof that one blocked tool handler does not serialize an independent handler, plus relay fault injection proving an undeliverable terminal result interrupts the ambiguous socket and enters reconnect backoff.
58
58
 
59
59
  ## Opt-in live desktop and browser validation
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "machine-bridge-mcp",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "Cross-client MCP bridge for local agent context, structured browser and application automation, files, Git, processes, resources, and durable jobs over stdio or OAuth relay.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1,5 +1,14 @@
1
1
  const UNSAFE_DISPLAY_CONTROLS = /[\u0000-\u001f\u007f\u200B-\u200F\u202A-\u202E\u2066-\u2069\uFEFF]/g;
2
2
 
3
+ export const BUILT_IN_BROWSER_ORIGINS = Object.freeze([
4
+ "https://chatgpt.com",
5
+ "https://chat.openai.com",
6
+ "https://grok.com",
7
+ "https://x.com",
8
+ ]);
9
+
10
+ const BUILT_IN_BROWSER_ORIGIN_SET = new Set(BUILT_IN_BROWSER_ORIGINS);
11
+
3
12
  export class HttpError extends Error {
4
13
  readonly status: number;
5
14
  readonly code: string;
@@ -233,7 +242,7 @@ function appendVary(headers: Headers, value: string): void {
233
242
  }
234
243
 
235
244
  function isConfiguredOrSameOrigin(origin: string, base: string, configured: string): boolean {
236
- if (isDefaultAllowedOrigin(origin, base)) return true;
245
+ if (isDefaultAllowedOrigin(origin, base) || BUILT_IN_BROWSER_ORIGIN_SET.has(origin)) return true;
237
246
  const allowed = configured.split(",").map((item) => item.trim()).filter((item) => item && item !== "null");
238
247
  return allowed.includes(origin);
239
248
  }
@@ -22,7 +22,7 @@ import {
22
22
  } from "./http";
23
23
 
24
24
  const SERVER_NAME = String(serverMetadata.name);
25
- const SERVER_VERSION = "1.0.4";
25
+ const SERVER_VERSION = "1.0.5";
26
26
  const MCP_PROTOCOL_VERSION = String(serverMetadata.protocolVersion);
27
27
  const MCP_SUPPORTED_PROTOCOL_VERSIONS = serverMetadata.supportedProtocolVersions.map((value) => String(value));
28
28
  const JSONRPC_VERSION = "2.0";
@@ -90,11 +90,11 @@ export class BridgeRoom extends DurableObject<BridgeEnv> {
90
90
 
91
91
  async fetch(request: Request): Promise<Response> {
92
92
  const base = baseUrl(request);
93
- const configuredOrigins = this.env.MBM_ALLOWED_ORIGINS ?? "";
93
+ const extraOrigins = this.env.MBM_ALLOWED_ORIGINS ?? "";
94
94
  let response: Response;
95
- if (!validateOrigin(request, base, configuredOrigins)) response = json({ error: "origin_not_allowed" }, 403);
96
- else if (request.method === "OPTIONS" && request.headers.has("Origin")) response = corsPreflight(request, base, configuredOrigins);
97
- else response = applyCors(await this.handleRequest(request, base), request, base, configuredOrigins);
95
+ if (!validateOrigin(request, base, extraOrigins)) response = json({ error: "origin_not_allowed" }, 403);
96
+ else if (request.method === "OPTIONS" && request.headers.has("Origin")) response = corsPreflight(request, base, extraOrigins);
97
+ else response = applyCors(await this.handleRequest(request, base), request, base, extraOrigins);
98
98
  this.observability.requestFinished(response.status);
99
99
  return response;
100
100
  }
package/wrangler.jsonc CHANGED
@@ -25,6 +25,7 @@
25
25
  },
26
26
  "vars": {
27
27
  "MBM_WORKER_MAX_BODY_BYTES": "8388608",
28
+ // Optional comma-separated additions. ChatGPT and Grok web origins are built into the Worker.
28
29
  "MBM_ALLOWED_ORIGINS": ""
29
30
  }
30
31
  }