@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.
- package/dist/driver/plugin-commands.js +28 -0
- package/dist/driver/webview-executor.js +3 -2
- package/dist/driver/webview-interactions.js +4 -2
- package/dist/monitor/logs.js +44 -4
- package/dist/prompts-registry.js +2 -1
- package/dist/tools-registry.js +3 -1
- package/dist/version.js +17 -0
- package/package.json +1 -1
|
@@ -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
|
package/dist/monitor/logs.js
CHANGED
|
@@ -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
|
-
|
|
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"
|
package/dist/prompts-registry.js
CHANGED
|
@@ -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 = "
|
|
53
|
+
tauri-plugin-mcp-bridge = "${PLUGIN_VERSION_CARGO}"
|
|
53
54
|
\`\`\`
|
|
54
55
|
|
|
55
56
|
### 2. Plugin Registration
|
package/dist/tools-registry.js
CHANGED
|
@@ -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 = "
|
|
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) {
|
package/dist/version.js
ADDED
|
@@ -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