@geometra/mcp 1.19.1 → 1.19.3

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.
@@ -1,6 +1,10 @@
1
+ import { existsSync, mkdirSync, mkdtempSync, rmSync, symlinkSync, writeFileSync } from 'node:fs';
2
+ import { createRequire } from 'node:module';
3
+ import { tmpdir } from 'node:os';
4
+ import path from 'node:path';
1
5
  import { describe, expect, it } from 'vitest';
2
6
  import { formatConnectFailureMessage, normalizeConnectTarget } from '../connect-utils.js';
3
- import { formatProxyStartupFailure, parseProxyReadySignalLine } from '../proxy-spawn.js';
7
+ import { formatProxyStartupFailure, parseProxyReadySignalLine, resolveProxyScriptPath, resolveProxyScriptPathWith, } from '../proxy-spawn.js';
4
8
  describe('normalizeConnectTarget', () => {
5
9
  it('accepts explicit pageUrl for http(s) pages', () => {
6
10
  const result = normalizeConnectTarget({ pageUrl: 'https://example.com/jobs/123' });
@@ -61,6 +65,58 @@ describe('formatConnectFailureMessage', () => {
61
65
  });
62
66
  });
63
67
  describe('proxy ready helpers', () => {
68
+ it('resolves the bundled proxy CLI entry in the source tree', () => {
69
+ const scriptPath = resolveProxyScriptPath();
70
+ expect(existsSync(scriptPath)).toBe(true);
71
+ expect(path.basename(scriptPath)).toBe('index.js');
72
+ expect(scriptPath.includes(`${path.sep}proxy${path.sep}`)).toBe(true);
73
+ });
74
+ it('resolves the bundled proxy CLI entry from a packaged dependency layout', () => {
75
+ const tempRoot = mkdtempSync(path.join(tmpdir(), 'geometra-proxy-resolve-'));
76
+ try {
77
+ const scopeDir = path.join(tempRoot, 'node_modules', '@geometra');
78
+ const packageDir = path.join(scopeDir, 'proxy');
79
+ const probePath = path.join(tempRoot, 'probe.cjs');
80
+ mkdirSync(scopeDir, { recursive: true });
81
+ symlinkSync(path.resolve(process.cwd(), 'packages/proxy'), packageDir, 'dir');
82
+ writeFileSync(probePath, 'module.exports = {}');
83
+ const customRequire = createRequire(probePath);
84
+ const scriptPath = resolveProxyScriptPathWith(customRequire);
85
+ expect(existsSync(scriptPath)).toBe(true);
86
+ expect(path.basename(scriptPath)).toBe('index.js');
87
+ }
88
+ finally {
89
+ rmSync(tempRoot, { recursive: true, force: true });
90
+ }
91
+ });
92
+ it('falls back to the packaged sibling proxy dist when package exports are stale', () => {
93
+ const tempRoot = mkdtempSync(path.join(tmpdir(), 'geometra-proxy-stale-exports-'));
94
+ try {
95
+ const proxyDir = path.join(tempRoot, 'node_modules', '@geometra', 'proxy');
96
+ const mcpDistDir = path.join(tempRoot, 'node_modules', '@geometra', 'mcp', 'dist');
97
+ const proxyDistDir = path.join(proxyDir, 'dist');
98
+ const probePath = path.join(mcpDistDir, 'proxy-spawn.cjs');
99
+ mkdirSync(proxyDistDir, { recursive: true });
100
+ mkdirSync(mcpDistDir, { recursive: true });
101
+ writeFileSync(path.join(proxyDir, 'package.json'), JSON.stringify({
102
+ name: '@geometra/proxy',
103
+ type: 'module',
104
+ exports: {
105
+ '.': {
106
+ import: './dist/index.js',
107
+ },
108
+ },
109
+ }, null, 2));
110
+ writeFileSync(path.join(proxyDistDir, 'index.js'), 'export {};\n');
111
+ writeFileSync(probePath, 'module.exports = {};\n');
112
+ const customRequire = createRequire(probePath);
113
+ const scriptPath = resolveProxyScriptPathWith(customRequire, mcpDistDir);
114
+ expect(scriptPath).toBe(path.join(proxyDistDir, 'index.js'));
115
+ }
116
+ finally {
117
+ rmSync(tempRoot, { recursive: true, force: true });
118
+ }
119
+ });
64
120
  it('parses structured proxy ready JSON', () => {
65
121
  const wsUrl = parseProxyReadySignalLine('{"type":"geometra-proxy-ready","wsUrl":"ws://127.0.0.1:41237","pageUrl":"https://example.com"}');
66
122
  expect(wsUrl).toBe('ws://127.0.0.1:41237');
@@ -1,6 +1,7 @@
1
1
  import { type ChildProcess } from 'node:child_process';
2
2
  /** Resolve bundled @geometra/proxy CLI entry (dist/index.js). */
3
3
  export declare function resolveProxyScriptPath(): string;
4
+ export declare function resolveProxyScriptPathWith(customRequire: NodeRequire, moduleDir?: string): string;
4
5
  export interface SpawnProxyParams {
5
6
  pageUrl: string;
6
7
  port: number;
@@ -1,18 +1,42 @@
1
1
  import { spawn } from 'node:child_process';
2
+ import { existsSync } from 'node:fs';
2
3
  import { createRequire } from 'node:module';
3
4
  import path from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
4
6
  const require = createRequire(import.meta.url);
5
7
  const READY_SIGNAL_TYPE = 'geometra-proxy-ready';
6
8
  const READY_TIMEOUT_MS = 45_000;
9
+ const MODULE_DIR = path.dirname(fileURLToPath(import.meta.url));
7
10
  /** Resolve bundled @geometra/proxy CLI entry (dist/index.js). */
8
11
  export function resolveProxyScriptPath() {
12
+ return resolveProxyScriptPathWith(require);
13
+ }
14
+ export function resolveProxyScriptPathWith(customRequire, moduleDir = MODULE_DIR) {
15
+ const errors = [];
9
16
  try {
10
- const pkgJson = require.resolve('@geometra/proxy/package.json');
17
+ const pkgJson = customRequire.resolve('@geometra/proxy/package.json');
11
18
  return path.join(path.dirname(pkgJson), 'dist/index.js');
12
19
  }
13
- catch {
14
- throw new Error('Could not resolve @geometra/proxy. Install it with the MCP package: npm install @geometra/proxy');
20
+ catch (err) {
21
+ errors.push(err instanceof Error ? err.message : String(err));
22
+ }
23
+ try {
24
+ return customRequire.resolve('@geometra/proxy');
25
+ }
26
+ catch (err) {
27
+ errors.push(err instanceof Error ? err.message : String(err));
28
+ }
29
+ const packagedSiblingDist = path.resolve(moduleDir, '../../proxy/dist/index.js');
30
+ if (existsSync(packagedSiblingDist)) {
31
+ return packagedSiblingDist;
32
+ }
33
+ errors.push(`Packaged sibling fallback not found at ${packagedSiblingDist}`);
34
+ const workspaceDist = path.resolve(moduleDir, '../../packages/proxy/dist/index.js');
35
+ if (existsSync(workspaceDist)) {
36
+ return workspaceDist;
15
37
  }
38
+ errors.push(`Workspace fallback not found at ${workspaceDist}`);
39
+ throw new Error(`Could not resolve @geometra/proxy. Install it with the MCP package: npm install @geometra/proxy. Resolution errors: ${errors.join(' | ')}`);
16
40
  }
17
41
  export function parseProxyReadySignalLine(line) {
18
42
  const trimmed = line.trim();
package/dist/server.js CHANGED
@@ -3,7 +3,7 @@ import { z } from 'zod';
3
3
  import { formatConnectFailureMessage, isHttpUrl, normalizeConnectTarget } from './connect-utils.js';
4
4
  import { connect, connectThroughProxy, disconnect, getSession, sendClick, sendType, sendKey, sendFileUpload, sendListboxPick, sendSelectOption, sendWheel, buildA11yTree, buildCompactUiIndex, buildPageModel, expandPageSection, buildUiDelta, hasUiDelta, nodeIdForPath, summarizeCompactIndex, summarizePageModel, summarizeUiDelta, } from './session.js';
5
5
  export function createServer() {
6
- const server = new McpServer({ name: 'geometra', version: '1.19.1' }, { capabilities: { tools: {} } });
6
+ const server = new McpServer({ name: 'geometra', version: '1.19.3' }, { capabilities: { tools: {} } });
7
7
  // ── connect ──────────────────────────────────────────────────
8
8
  server.tool('geometra_connect', `Connect to a Geometra WebSocket peer, or start \`geometra-proxy\` automatically for a normal web page.
9
9
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geometra/mcp",
3
- "version": "1.19.1",
3
+ "version": "1.19.3",
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",
@@ -30,7 +30,7 @@
30
30
  "ui-testing"
31
31
  ],
32
32
  "dependencies": {
33
- "@geometra/proxy": "1.19.1",
33
+ "@geometra/proxy": "1.19.3",
34
34
  "@modelcontextprotocol/sdk": "^1.12.1",
35
35
  "ws": "^8.18.0",
36
36
  "zod": "^3.23.0"