@hypothesi/tauri-mcp-server 0.6.4 → 0.7.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.
@@ -41,11 +41,25 @@ export async function manageIPCMonitoring(action, appIdentifier) {
41
41
  }
42
42
  export async function startIPCMonitoring(appIdentifier) {
43
43
  try {
44
+ // Start the Rust-side monitor state
44
45
  const result = await executeIPCCommand({ command: 'plugin:mcp-bridge|start_ipc_monitor', appIdentifier });
45
46
  const parsed = JSON.parse(result);
46
47
  if (!parsed.success) {
47
48
  throw new Error(parsed.error || 'Unknown error');
48
49
  }
50
+ // Start the JS-side IPC interception
51
+ const client = await ensureSessionAndConnect(appIdentifier);
52
+ const jsResponse = await client.sendCommand({
53
+ command: 'execute_js',
54
+ args: {
55
+ script: 'window.__MCP_START_IPC_MONITOR__ && window.__MCP_START_IPC_MONITOR__(); true;',
56
+ windowLabel: 'main',
57
+ },
58
+ }, 5000);
59
+ if (!jsResponse.success) {
60
+ // Log but don't fail - Rust-side monitoring is still active
61
+ console.error('Failed to start JS-side IPC interception:', jsResponse.error);
62
+ }
49
63
  return JSON.stringify(parsed.result);
50
64
  }
51
65
  catch (error) {
@@ -55,6 +69,20 @@ export async function startIPCMonitoring(appIdentifier) {
55
69
  }
56
70
  export async function stopIPCMonitoring(appIdentifier) {
57
71
  try {
72
+ // Stop the JS-side IPC interception first
73
+ const client = await ensureSessionAndConnect(appIdentifier);
74
+ const jsResponse = await client.sendCommand({
75
+ command: 'execute_js',
76
+ args: {
77
+ script: 'window.__MCP_STOP_IPC_MONITOR__ && window.__MCP_STOP_IPC_MONITOR__(); true;',
78
+ windowLabel: 'main',
79
+ },
80
+ }, 5000);
81
+ if (!jsResponse.success) {
82
+ // Log but don't fail - continue to stop Rust-side monitoring
83
+ console.error('Failed to stop JS-side IPC interception:', jsResponse.error);
84
+ }
85
+ // Stop the Rust-side monitor state
58
86
  const result = await executeIPCCommand({ command: 'plugin:mcp-bridge|stop_ipc_monitor', appIdentifier });
59
87
  const parsed = JSON.parse(result);
60
88
  if (!parsed.success) {
@@ -285,11 +285,11 @@ async function prepareHtml2canvasScript(format, quality) {
285
285
  /**
286
286
  * Capture a screenshot of the entire webview.
287
287
  *
288
- * @param options - Screenshot options (format, quality, windowId, appIdentifier)
288
+ * @param options - Screenshot options (format, quality, windowId, appIdentifier, etc.)
289
289
  * @returns Screenshot result with image content
290
290
  */
291
291
  export async function captureScreenshot(options = {}) {
292
- const { format = 'png', quality = 90, windowId, appIdentifier } = options;
292
+ const { format = 'png', quality = 90, windowId, appIdentifier, maxWidth } = options;
293
293
  // Primary implementation: Use native platform-specific APIs
294
294
  // - macOS: WKWebView takeSnapshot
295
295
  // - Windows: WebView2 CapturePreview
@@ -307,6 +307,7 @@ export async function captureScreenshot(options = {}) {
307
307
  format,
308
308
  quality,
309
309
  windowLabel: windowId,
310
+ maxWidth,
310
311
  },
311
312
  }, 15000);
312
313
  if (!response.success || !response.data) {
@@ -36,6 +36,8 @@ export const ScreenshotSchema = WindowTargetSchema.extend({
36
36
  format: z.enum(['png', 'jpeg']).optional().default('png').describe('Image format'),
37
37
  quality: z.number().min(0).max(100).optional().describe('JPEG quality (0-100, only for jpeg format)'),
38
38
  filePath: z.string().optional().describe('File path to save the screenshot to instead of returning as base64'),
39
+ maxWidth: z.number().int().positive().optional().describe('Maximum width in pixels. Images wider than this will be scaled down proportionally. ' +
40
+ 'Can also be set via TAURI_MCP_SCREENSHOT_MAX_WIDTH environment variable.'),
39
41
  });
40
42
  export const KeyboardSchema = WindowTargetSchema.extend({
41
43
  action: z.enum(['type', 'press', 'down', 'up'])
@@ -121,9 +123,9 @@ async function performSwipe(options) {
121
123
  }
122
124
  }
123
125
  export async function screenshot(options = {}) {
124
- const { quality, format = 'png', windowId, filePath, appIdentifier } = options;
126
+ const { quality, format = 'png', windowId, filePath, appIdentifier, maxWidth } = options;
125
127
  // Use the native screenshot function from webview-executor
126
- const result = await captureScreenshot({ format, quality, windowId, appIdentifier });
128
+ const result = await captureScreenshot({ format, quality, windowId, appIdentifier, maxWidth });
127
129
  // If filePath is provided, write to file instead of returning base64
128
130
  if (filePath) {
129
131
  // Find the image content in the result
@@ -1,6 +1,49 @@
1
1
  import { z } from 'zod';
2
2
  import { execa } from 'execa';
3
+ import { existsSync } from 'node:fs';
4
+ import { homedir } from 'node:os';
5
+ import { join } from 'node:path';
3
6
  import { getConsoleLogs } from '../driver/webview-interactions.js';
7
+ /**
8
+ * Find the adb executable path. Checks environment variables first, then common
9
+ * installation locations on macOS, Linux, and Windows. This is necessary because
10
+ * MCP servers often run without ANDROID_HOME set (e.g., global npm installs).
11
+ */
12
+ function findAdbPath() {
13
+ // Check environment variables first
14
+ // eslint-disable-next-line no-process-env
15
+ const androidHome = process.env.ANDROID_HOME || process.env.ANDROID_SDK_ROOT;
16
+ if (androidHome) {
17
+ const envPath = join(androidHome, 'platform-tools', 'adb');
18
+ if (existsSync(envPath)) {
19
+ return envPath;
20
+ }
21
+ }
22
+ // Common installation locations to check
23
+ const home = homedir();
24
+ const commonPaths = [
25
+ // macOS - Android Studio default
26
+ join(home, 'Library', 'Android', 'sdk', 'platform-tools', 'adb'),
27
+ // Linux - Android Studio default
28
+ join(home, 'Android', 'Sdk', 'platform-tools', 'adb'),
29
+ // Linux - alternative location
30
+ join(home, 'android-sdk', 'platform-tools', 'adb'),
31
+ // Windows - Android Studio default
32
+ join(home, 'AppData', 'Local', 'Android', 'Sdk', 'platform-tools', 'adb.exe'),
33
+ // Homebrew on macOS
34
+ '/opt/homebrew/bin/adb',
35
+ '/usr/local/bin/adb',
36
+ // Linux system-wide
37
+ '/usr/bin/adb',
38
+ ];
39
+ for (const adbPath of commonPaths) {
40
+ if (existsSync(adbPath)) {
41
+ return adbPath;
42
+ }
43
+ }
44
+ // Fall back to PATH (will fail if not in PATH, but gives a clear error)
45
+ return 'adb';
46
+ }
4
47
  export const ReadLogsSchema = z.object({
5
48
  source: z.enum(['console', 'android', 'ios', 'system'])
6
49
  .describe('Log source: "console" for webview JS logs, "android" for logcat, "ios" for simulator, "system" for desktop'),
@@ -19,10 +62,7 @@ export async function readLogs(options) {
19
62
  return await getConsoleLogs({ filter, since, windowId, appIdentifier });
20
63
  }
21
64
  if (source === 'android') {
22
- // Find adb - check ANDROID_HOME first, then fall back to PATH
23
- // eslint-disable-next-line no-process-env
24
- const androidHome = process.env.ANDROID_HOME || process.env.ANDROID_SDK_ROOT;
25
- const adbPath = androidHome ? `${androidHome}/platform-tools/adb` : 'adb';
65
+ const adbPath = findAdbPath();
26
66
  const args = ['logcat', '-d'];
27
67
  if (since) {
28
68
  // adb logcat -T expects "MM-DD HH:MM:SS.mmm"
@@ -2,6 +2,7 @@
2
2
  * Single source of truth for all MCP prompt definitions
3
3
  * Prompts are user-controlled templates that appear as slash commands in MCP clients
4
4
  */
5
+ import { PLUGIN_VERSION_CARGO } from './version.js';
5
6
  const FIX_WEBVIEW_ERRORS_PROMPT = `I need help finding and fixing JavaScript errors in my Tauri app's webview.
6
7
 
7
8
  Please follow these steps:
@@ -49,7 +50,7 @@ Examine these files and report what needs to be added or updated:
49
50
  Check \`src-tauri/Cargo.toml\` for \`tauri-plugin-mcp-bridge\`. If missing or outdated, note that it needs:
50
51
  \`\`\`toml
51
52
  [dependencies]
52
- tauri-plugin-mcp-bridge = "0.4"
53
+ tauri-plugin-mcp-bridge = "${PLUGIN_VERSION_CARGO}"
53
54
  \`\`\`
54
55
 
55
56
  ### 2. Plugin Registration
@@ -8,6 +8,7 @@ import { manageDriverSession, ManageDriverSessionSchema, } from './driver/sessio
8
8
  import { readLogs, ReadLogsSchema } from './monitor/logs.js';
9
9
  import { executeIPCCommand, manageIPCMonitoring, getIPCEvents, emitTestEvent, getBackendState, manageWindow, ExecuteIPCCommandSchema, ManageIPCMonitoringSchema, GetIPCEventsSchema, EmitTestEventSchema, GetBackendStateSchema, ManageWindowSchema, } from './driver/plugin-commands.js';
10
10
  import { interact, screenshot, keyboard, waitFor, getStyles, executeJavaScript, findElement, InteractSchema, ScreenshotSchema, KeyboardSchema, WaitForSchema, GetStylesSchema, ExecuteJavaScriptSchema, FindElementSchema, } from './driver/webview-interactions.js';
11
+ import { PLUGIN_VERSION_CARGO } from './version.js';
11
12
  /**
12
13
  * Standard multi-app description for webview tools.
13
14
  */
@@ -50,7 +51,7 @@ Examine these files and report what needs to be added or updated:
50
51
  Check \`src-tauri/Cargo.toml\` for \`tauri-plugin-mcp-bridge\`. If missing or outdated, note that it needs:
51
52
  \`\`\`toml
52
53
  [dependencies]
53
- tauri-plugin-mcp-bridge = "0.4"
54
+ tauri-plugin-mcp-bridge = "${PLUGIN_VERSION_CARGO}"
54
55
  \`\`\`
55
56
 
56
57
  ### 2. Plugin Registration
@@ -248,6 +249,7 @@ export const TOOLS = [
248
249
  windowId: parsed.windowId,
249
250
  filePath: parsed.filePath,
250
251
  appIdentifier: parsed.appIdentifier,
252
+ maxWidth: parsed.maxWidth,
251
253
  });
252
254
  // If saved to file, return text confirmation
253
255
  if ('filePath' in result) {
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Version information for the MCP Bridge plugin.
3
+ *
4
+ * Reads the version from this package's package.json at runtime.
5
+ * Both packages share the same version (monorepo single-version policy).
6
+ */
7
+ import { createRequire } from 'module';
8
+ const require = createRequire(import.meta.url), pkg = require('../package.json'), [major, minor] = pkg.version.split('.');
9
+ /**
10
+ * Full version string (e.g., "0.6.5")
11
+ */
12
+ export const PLUGIN_VERSION_FULL = pkg.version;
13
+ /**
14
+ * Cargo-compatible version string for Cargo.toml dependencies (e.g., "0.6")
15
+ * This is the major.minor version used in Cargo.toml dependency specifications.
16
+ */
17
+ export const PLUGIN_VERSION_CARGO = `${major}.${minor}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hypothesi/tauri-mcp-server",
3
- "version": "0.6.4",
3
+ "version": "0.7.0",
4
4
  "mcpName": "io.github.hypothesi/mcp-server-tauri",
5
5
  "description": "A Model Context Protocol server for use with Tauri v2 applications",
6
6
  "type": "module",