@geometra/mcp 1.61.3 → 1.62.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/dist/proxy-spawn.d.ts +3 -1
- package/dist/proxy-spawn.js +11 -17
- package/dist/session.js +21 -13
- package/package.json +3 -3
package/dist/proxy-spawn.d.ts
CHANGED
|
@@ -40,7 +40,9 @@ export declare function startEmbeddedGeometraProxy(opts: SpawnProxyParams): Prom
|
|
|
40
40
|
runtime: EmbeddedProxyRuntime;
|
|
41
41
|
wsUrl: string;
|
|
42
42
|
}>;
|
|
43
|
-
export declare function parseProxyReadySignalLine(line: string
|
|
43
|
+
export declare function parseProxyReadySignalLine(line: string, options?: {
|
|
44
|
+
allowLegacy?: boolean;
|
|
45
|
+
}): string | undefined;
|
|
44
46
|
export declare function formatProxyStartupFailure(message: string, opts: SpawnProxyParams): string;
|
|
45
47
|
/**
|
|
46
48
|
* Spawn geometra-proxy as a child process and resolve when it emits a structured ready signal.
|
package/dist/proxy-spawn.js
CHANGED
|
@@ -7,6 +7,7 @@ const require = createRequire(import.meta.url);
|
|
|
7
7
|
const READY_SIGNAL_TYPE = 'geometra-proxy-ready';
|
|
8
8
|
const READY_TIMEOUT_MS = 45_000;
|
|
9
9
|
const MODULE_DIR = path.dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
const PLAYWRIGHT_INSTALL_HINT = 'Install Chromium with the Playwright version bundled in this package: npm run browsers:install -w @geometra/proxy (repo checkout) or npx --no-install playwright install chromium.';
|
|
10
11
|
/** Resolve bundled @geometra/proxy CLI entry (dist/index.js). */
|
|
11
12
|
export function resolveProxyScriptPath() {
|
|
12
13
|
return resolveProxyScriptPathWith(require);
|
|
@@ -125,17 +126,8 @@ function buildLocalProxyDistIfPossible(packageDir, entryFile, errors) {
|
|
|
125
126
|
}
|
|
126
127
|
return undefined;
|
|
127
128
|
}
|
|
128
|
-
function envRequestsStealth() {
|
|
129
|
-
const explicit = process.env.GEOMETRA_STEALTH;
|
|
130
|
-
if (explicit !== undefined) {
|
|
131
|
-
const v = explicit.toLowerCase();
|
|
132
|
-
return v === '1' || v === 'true' || v === 'yes' || v === 'stealth' || v === 'cloak';
|
|
133
|
-
}
|
|
134
|
-
const browser = (process.env.GEOMETRA_BROWSER ?? '').toLowerCase();
|
|
135
|
-
return browser === 'stealth' || browser === 'cloak' || browser === 'cloakbrowser';
|
|
136
|
-
}
|
|
137
129
|
export function resolveStealthMode(stealth) {
|
|
138
|
-
return stealth ??
|
|
130
|
+
return stealth ?? true;
|
|
139
131
|
}
|
|
140
132
|
export async function startEmbeddedGeometraProxy(opts) {
|
|
141
133
|
const runtimePath = resolveProxyRuntimePath();
|
|
@@ -148,7 +140,7 @@ export async function startEmbeddedGeometraProxy(opts) {
|
|
|
148
140
|
port: opts.port,
|
|
149
141
|
width: opts.width,
|
|
150
142
|
height: opts.height,
|
|
151
|
-
headed: opts.headless
|
|
143
|
+
headed: opts.headless === false,
|
|
152
144
|
slowMo: opts.slowMo,
|
|
153
145
|
...(opts.stealth !== undefined && { stealth: opts.stealth }),
|
|
154
146
|
eagerInitialExtract: opts.eagerInitialExtract,
|
|
@@ -156,7 +148,7 @@ export async function startEmbeddedGeometraProxy(opts) {
|
|
|
156
148
|
});
|
|
157
149
|
return { runtime, wsUrl: runtime.wsUrl };
|
|
158
150
|
}
|
|
159
|
-
export function parseProxyReadySignalLine(line) {
|
|
151
|
+
export function parseProxyReadySignalLine(line, options) {
|
|
160
152
|
const trimmed = line.trim();
|
|
161
153
|
if (!trimmed)
|
|
162
154
|
return undefined;
|
|
@@ -173,13 +165,15 @@ export function parseProxyReadySignalLine(line) {
|
|
|
173
165
|
/* ignore non-JSON lines */
|
|
174
166
|
}
|
|
175
167
|
}
|
|
168
|
+
if (options?.allowLegacy === false)
|
|
169
|
+
return undefined;
|
|
176
170
|
const fallback = trimmed.match(/WebSocket listening on (ws:\/\/127\.0\.0\.1:\d+)/);
|
|
177
171
|
return fallback?.[1];
|
|
178
172
|
}
|
|
179
173
|
export function formatProxyStartupFailure(message, opts) {
|
|
180
174
|
const hints = [];
|
|
181
175
|
if (/Executable doesn't exist|playwright install chromium|browserType\.launch/i.test(message)) {
|
|
182
|
-
hints.push(
|
|
176
|
+
hints.push(PLAYWRIGHT_INSTALL_HINT);
|
|
183
177
|
}
|
|
184
178
|
if (/cloakbrowser|CLOAKBROWSER|ERR_MODULE_NOT_FOUND|Cannot find package/i.test(message)) {
|
|
185
179
|
hints.push('Stealth mode uses CloakBrowser. Install dependencies with npm install, or disable stealth with stealth=false / GEOMETRA_STEALTH=0. To prefetch the patched Chromium binary, run: npx cloakbrowser install');
|
|
@@ -203,10 +197,10 @@ export function spawnGeometraProxy(opts) {
|
|
|
203
197
|
args.push('--height', String(opts.height));
|
|
204
198
|
if (opts.slowMo != null && opts.slowMo > 0)
|
|
205
199
|
args.push('--slow-mo', String(opts.slowMo));
|
|
206
|
-
if (opts.headless ===
|
|
207
|
-
args.push('--headless');
|
|
208
|
-
else if (opts.headless === false)
|
|
200
|
+
if (opts.headless === false)
|
|
209
201
|
args.push('--headed');
|
|
202
|
+
else
|
|
203
|
+
args.push('--headless');
|
|
210
204
|
if (opts.stealth === true)
|
|
211
205
|
args.push('--stealth');
|
|
212
206
|
else if (opts.stealth === false)
|
|
@@ -236,7 +230,7 @@ export function spawnGeometraProxy(opts) {
|
|
|
236
230
|
child.stderr?.removeAllListeners('data');
|
|
237
231
|
};
|
|
238
232
|
const tryResolveReady = (line) => {
|
|
239
|
-
const wsUrl = parseProxyReadySignalLine(line);
|
|
233
|
+
const wsUrl = parseProxyReadySignalLine(line, { allowLegacy: false });
|
|
240
234
|
if (!wsUrl || settled)
|
|
241
235
|
return false;
|
|
242
236
|
settled = true;
|
package/dist/session.js
CHANGED
|
@@ -147,7 +147,7 @@ function setReusableProxy(proxy, wsUrl, opts) {
|
|
|
147
147
|
const existing = reusableProxies.find(entry => sameReusableProxyEntry(entry, proxy));
|
|
148
148
|
if (existing) {
|
|
149
149
|
existing.wsUrl = wsUrl;
|
|
150
|
-
existing.headless = opts.headless
|
|
150
|
+
existing.headless = opts.headless !== false;
|
|
151
151
|
existing.stealth = stealth;
|
|
152
152
|
existing.slowMo = opts.slowMo ?? 0;
|
|
153
153
|
existing.width = opts.width ?? 1280;
|
|
@@ -163,7 +163,7 @@ function setReusableProxy(proxy, wsUrl, opts) {
|
|
|
163
163
|
const entry = {
|
|
164
164
|
child,
|
|
165
165
|
wsUrl,
|
|
166
|
-
headless: opts.headless
|
|
166
|
+
headless: opts.headless !== false,
|
|
167
167
|
stealth,
|
|
168
168
|
slowMo: opts.slowMo ?? 0,
|
|
169
169
|
width: opts.width ?? 1280,
|
|
@@ -190,7 +190,7 @@ function setReusableProxy(proxy, wsUrl, opts) {
|
|
|
190
190
|
reusableProxies.push({
|
|
191
191
|
runtime: proxy.runtime,
|
|
192
192
|
wsUrl,
|
|
193
|
-
headless: opts.headless
|
|
193
|
+
headless: opts.headless !== false,
|
|
194
194
|
stealth,
|
|
195
195
|
slowMo: opts.slowMo ?? 0,
|
|
196
196
|
width: opts.width ?? 1280,
|
|
@@ -324,6 +324,11 @@ function evictOldestSession() {
|
|
|
324
324
|
function formatUnknownError(err) {
|
|
325
325
|
return err instanceof Error ? err.message : String(err);
|
|
326
326
|
}
|
|
327
|
+
function rejectOnRuntimeReadyFailure(runtime) {
|
|
328
|
+
return new Promise((_, reject) => {
|
|
329
|
+
runtime.ready.catch(reject);
|
|
330
|
+
});
|
|
331
|
+
}
|
|
327
332
|
function warnSessionLifecycleError(action, session, err) {
|
|
328
333
|
console.warn(`geometra-mcp: failed to ${action} for session ${session.id}: ${formatUnknownError(err)}`);
|
|
329
334
|
}
|
|
@@ -408,7 +413,7 @@ function stopSessionHeartbeat(session) {
|
|
|
408
413
|
}
|
|
409
414
|
function reusableProxyMatchesOptions(entry, options) {
|
|
410
415
|
return (entry.pageUrl === options.pageUrl &&
|
|
411
|
-
entry.headless === (options.headless
|
|
416
|
+
entry.headless === (options.headless !== false) &&
|
|
412
417
|
entry.stealth === resolveStealthMode(options.stealth) &&
|
|
413
418
|
entry.slowMo === (options.slowMo ?? 0) &&
|
|
414
419
|
entry.width === (options.width ?? 1280) &&
|
|
@@ -426,7 +431,7 @@ function findExactReusableProxy(options) {
|
|
|
426
431
|
}
|
|
427
432
|
function findReusableProxy(options) {
|
|
428
433
|
clearReusableProxiesIfExited();
|
|
429
|
-
const desiredHeadless = options.headless
|
|
434
|
+
const desiredHeadless = options.headless !== false;
|
|
430
435
|
const desiredStealth = resolveStealthMode(options.stealth);
|
|
431
436
|
const desiredSlowMo = options.slowMo ?? 0;
|
|
432
437
|
const desiredWidth = options.width ?? 1280;
|
|
@@ -465,7 +470,7 @@ export async function prewarmProxy(options) {
|
|
|
465
470
|
transport: existing.runtime ? 'embedded' : 'child',
|
|
466
471
|
pageUrl: options.pageUrl,
|
|
467
472
|
wsUrl: existing.wsUrl,
|
|
468
|
-
headless: options.headless
|
|
473
|
+
headless: options.headless !== false,
|
|
469
474
|
stealth: resolveStealthMode(options.stealth),
|
|
470
475
|
width: options.width ?? 1280,
|
|
471
476
|
height: options.height ?? 720,
|
|
@@ -506,7 +511,7 @@ export async function prewarmProxy(options) {
|
|
|
506
511
|
transport: 'embedded',
|
|
507
512
|
pageUrl: options.pageUrl,
|
|
508
513
|
wsUrl,
|
|
509
|
-
headless: options.headless
|
|
514
|
+
headless: options.headless !== false,
|
|
510
515
|
stealth: resolveStealthMode(options.stealth),
|
|
511
516
|
width: options.width ?? 1280,
|
|
512
517
|
height: options.height ?? 720,
|
|
@@ -541,7 +546,7 @@ export async function prewarmProxy(options) {
|
|
|
541
546
|
transport: 'child',
|
|
542
547
|
pageUrl: options.pageUrl,
|
|
543
548
|
wsUrl,
|
|
544
|
-
headless: options.headless
|
|
549
|
+
headless: options.headless !== false,
|
|
545
550
|
stealth: resolveStealthMode(options.stealth),
|
|
546
551
|
width: options.width ?? 1280,
|
|
547
552
|
height: options.height ?? 720,
|
|
@@ -641,11 +646,14 @@ async function startFreshProxySession(options) {
|
|
|
641
646
|
});
|
|
642
647
|
pendingEmbeddedRuntime = runtime;
|
|
643
648
|
const proxyStartMs = performance.now() - proxyStartStartedAt;
|
|
644
|
-
const session = await
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
+
const session = await Promise.race([
|
|
650
|
+
connect(wsUrl, {
|
|
651
|
+
skipInitialResize: true,
|
|
652
|
+
closePreviousProxy: false,
|
|
653
|
+
awaitInitialFrame: options.awaitInitialFrame,
|
|
654
|
+
}),
|
|
655
|
+
rejectOnRuntimeReadyFailure(runtime),
|
|
656
|
+
]);
|
|
649
657
|
// Connect succeeded — the session now owns the runtime, so the
|
|
650
658
|
// catch-block cleanup below must not also close it.
|
|
651
659
|
pendingEmbeddedRuntime = undefined;
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@geometra/mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.62.1",
|
|
4
4
|
"description": "MCP server for Geometra — interact with running Geometra apps via the geometry protocol, no browser needed",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
|
-
"url": "https://github.com/
|
|
9
|
+
"url": "https://github.com/Agent-Pattern-Labs/geometra",
|
|
10
10
|
"directory": "mcp"
|
|
11
11
|
},
|
|
12
12
|
"bin": {
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"ui-testing"
|
|
33
33
|
],
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@geometra/proxy": "^1.
|
|
35
|
+
"@geometra/proxy": "^1.62.1",
|
|
36
36
|
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
37
37
|
"@razroo/parallel-mcp": "^0.1.0",
|
|
38
38
|
"ws": "^8.18.0",
|