@hypothesi/tauri-mcp-server 0.12.0 → 0.13.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/driver/app-discovery.d.ts +4 -2
- package/dist/driver/app-discovery.js +23 -3
- package/dist/driver/plugin-client.d.ts +23 -1
- package/dist/driver/plugin-client.js +127 -2
- package/dist/driver/plugin-commands.d.ts +8 -4
- package/dist/driver/plugin-commands.js +71 -16
- package/dist/driver/scripts/find-element.js +129 -16
- package/dist/driver/scripts/focus.js +31 -4
- package/dist/driver/scripts/html2canvas-loader.js +20 -2
- package/dist/driver/scripts/index.d.ts +2 -4
- package/dist/driver/scripts/index.js +40 -11
- package/dist/driver/scripts/interact.js +66 -5
- package/dist/driver/scripts/resolve-ref.js +101 -50
- package/dist/driver/session-manager.d.ts +1 -0
- package/dist/driver/session-manager.js +53 -6
- package/dist/driver/webview-executor.d.ts +20 -8
- package/dist/driver/webview-executor.js +159 -58
- package/dist/driver/webview-interactions.d.ts +56 -41
- package/dist/driver/webview-interactions.js +62 -40
- package/dist/monitor/logs.d.ts +14 -2
- package/dist/monitor/logs.js +37 -5
- package/dist/tools-registry.js +35 -33
- package/dist/version.d.ts +5 -0
- package/dist/version.js +16 -0
- package/package.json +1 -1
- package/dist/driver/scripts/get-styles.js +0 -47
- package/dist/driver/scripts/keyboard.js +0 -76
package/dist/tools-registry.js
CHANGED
|
@@ -7,7 +7,7 @@ import { listDevices, ListDevicesSchema } from './manager/mobile.js';
|
|
|
7
7
|
import { manageDriverSession, ManageDriverSessionSchema, } from './driver/session-manager.js';
|
|
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
|
-
import { interact, screenshot, keyboard, waitFor,
|
|
10
|
+
import { interact, screenshot, keyboard, waitFor, executeJavaScript, findElement, domSnapshot, InteractSchema, ScreenshotSchema, KeyboardSchema, WaitForSchema, ExecuteJavaScriptSchema, FindElementSchema, DomSnapshotSchema, } from './driver/webview-interactions.js';
|
|
11
11
|
import { selectElement, getPointedElement, SelectElementSchema, GetPointedElementSchema, } from './driver/element-picker.js';
|
|
12
12
|
import { SETUP_INSTRUCTIONS } from './constants.js';
|
|
13
13
|
/**
|
|
@@ -99,10 +99,16 @@ export const TOOLS = [
|
|
|
99
99
|
},
|
|
100
100
|
{
|
|
101
101
|
name: 'webview_find_element',
|
|
102
|
-
description: '[Tauri Apps Only] Find
|
|
102
|
+
description: '[Tauri Apps Only] Find elements in a running Tauri app\'s webview and return their geometry, text, ' +
|
|
103
|
+
'accessible name, attributes, visibility, and optionally their computed styles. ' +
|
|
103
104
|
'Supports CSS selectors (default), XPath expressions, and text content matching via the strategy parameter. ' +
|
|
104
|
-
'The "text" strategy
|
|
105
|
-
'
|
|
105
|
+
'The "text" strategy searches element text content (not just direct text nodes), prefers exact matches over ' +
|
|
106
|
+
'substring matches, prefers innermost elements, and prefers interactive ancestors. ' +
|
|
107
|
+
'Returns structured JSON with totalMatches, returned count, and array of matches each containing: ' +
|
|
108
|
+
'nth index, ref ID, tag, trimmed text, accessible name, attributes, bounding rect, visibility, interactability, ' +
|
|
109
|
+
'optional computed styles, and optional truncated outerHTML. ' +
|
|
110
|
+
'Use this instead of webview_execute_js for querySelector, getBoundingClientRect, textContent, ' +
|
|
111
|
+
'and getComputedStyle reads. ' +
|
|
106
112
|
'Requires active driver_session. ' +
|
|
107
113
|
MULTI_APP_DESC + ' ' +
|
|
108
114
|
'For browser pages or documentation sites, use Chrome DevTools MCP instead.',
|
|
@@ -118,6 +124,11 @@ export const TOOLS = [
|
|
|
118
124
|
return await findElement({
|
|
119
125
|
selector: parsed.selector,
|
|
120
126
|
strategy: parsed.strategy,
|
|
127
|
+
nth: parsed.nth,
|
|
128
|
+
limit: parsed.limit,
|
|
129
|
+
properties: parsed.properties,
|
|
130
|
+
visibleOnly: parsed.visibleOnly,
|
|
131
|
+
includeHtml: parsed.includeHtml,
|
|
121
132
|
windowId: parsed.windowId,
|
|
122
133
|
appIdentifier: parsed.appIdentifier,
|
|
123
134
|
});
|
|
@@ -144,9 +155,11 @@ export const TOOLS = [
|
|
|
144
155
|
// WebView Interaction Tools
|
|
145
156
|
{
|
|
146
157
|
name: 'webview_interact',
|
|
147
|
-
description: '[Tauri Apps Only] Click, scroll, swipe, focus, or perform gestures in a Tauri app webview. ' +
|
|
148
|
-
'Supported actions: click, double-click, long-press, scroll, swipe, focus. ' +
|
|
158
|
+
description: '[Tauri Apps Only] Click, hover, right-click, scroll, swipe, focus, or perform gestures in a Tauri app webview. ' +
|
|
159
|
+
'Supported actions: click, double-click, long-press, scroll, swipe, focus, hover, right-click. ' +
|
|
149
160
|
'Supports CSS selectors (default), XPath, and text content matching via the strategy parameter. ' +
|
|
161
|
+
'When using a text selector that matches multiple visible elements, you must provide the nth parameter ' +
|
|
162
|
+
'to disambiguate, or the tool will throw an error listing the candidates. ' +
|
|
150
163
|
'Requires active driver_session. ' +
|
|
151
164
|
'For browser interaction, use Chrome DevTools MCP instead.',
|
|
152
165
|
category: TOOL_CATEGORIES.UI_AUTOMATION,
|
|
@@ -185,6 +198,7 @@ export const TOOLS = [
|
|
|
185
198
|
filePath: parsed.filePath,
|
|
186
199
|
appIdentifier: parsed.appIdentifier,
|
|
187
200
|
maxWidth: parsed.maxWidth,
|
|
201
|
+
allowScreenCapture: parsed.allowScreenCapture,
|
|
188
202
|
});
|
|
189
203
|
// If saved to file, return text confirmation
|
|
190
204
|
if ('filePath' in result) {
|
|
@@ -217,6 +231,7 @@ export const TOOLS = [
|
|
|
217
231
|
action: parsed.action,
|
|
218
232
|
selectorOrKey: parsed.selector,
|
|
219
233
|
strategy: parsed.strategy,
|
|
234
|
+
nth: parsed.nth,
|
|
220
235
|
textOrModifiers: parsed.text,
|
|
221
236
|
windowId: parsed.windowId,
|
|
222
237
|
appIdentifier: parsed.appIdentifier,
|
|
@@ -257,38 +272,14 @@ export const TOOLS = [
|
|
|
257
272
|
});
|
|
258
273
|
},
|
|
259
274
|
},
|
|
260
|
-
{
|
|
261
|
-
name: 'webview_get_styles',
|
|
262
|
-
description: '[Tauri Apps Only] Get computed CSS styles from elements in a Tauri app. ' +
|
|
263
|
-
'Supports CSS selectors (default), XPath, and text content matching via the strategy parameter. ' +
|
|
264
|
-
'Requires active driver_session. ' +
|
|
265
|
-
MULTI_APP_DESC + ' ' +
|
|
266
|
-
'For browser style inspection, use Chrome DevTools MCP instead.',
|
|
267
|
-
category: TOOL_CATEGORIES.UI_AUTOMATION,
|
|
268
|
-
schema: GetStylesSchema,
|
|
269
|
-
annotations: {
|
|
270
|
-
title: 'Get Styles in Tauri Webview',
|
|
271
|
-
readOnlyHint: true,
|
|
272
|
-
openWorldHint: false,
|
|
273
|
-
},
|
|
274
|
-
handler: async (args) => {
|
|
275
|
-
const parsed = GetStylesSchema.parse(args);
|
|
276
|
-
return await getStyles({
|
|
277
|
-
selector: parsed.selector,
|
|
278
|
-
strategy: parsed.strategy,
|
|
279
|
-
properties: parsed.properties,
|
|
280
|
-
multiple: parsed.multiple,
|
|
281
|
-
windowId: parsed.windowId,
|
|
282
|
-
appIdentifier: parsed.appIdentifier,
|
|
283
|
-
});
|
|
284
|
-
},
|
|
285
|
-
},
|
|
286
275
|
{
|
|
287
276
|
name: 'webview_execute_js',
|
|
288
277
|
description: '[Tauri Apps Only] Execute JavaScript in a Tauri app\'s webview context. ' +
|
|
289
278
|
'Requires active driver_session. Has access to window.__TAURI__. ' +
|
|
290
279
|
'If you need a return value, it must be JSON-serializable. ' +
|
|
291
280
|
'For functions that return values, use an IIFE: "(() => { return 5; })()" not "() => { return 5; }". ' +
|
|
281
|
+
'Accepts an optional timeout parameter (milliseconds) for long-running scripts. ' +
|
|
282
|
+
'Timeout errors will identify which layer timed out (transport, script self-race, or Rust eval). ' +
|
|
292
283
|
MULTI_APP_DESC + ' ' +
|
|
293
284
|
'For browser JS execution, use Chrome DevTools MCP instead.',
|
|
294
285
|
category: TOOL_CATEGORIES.UI_AUTOMATION,
|
|
@@ -304,6 +295,7 @@ export const TOOLS = [
|
|
|
304
295
|
return await executeJavaScript({
|
|
305
296
|
script: parsed.script,
|
|
306
297
|
args: parsed.args,
|
|
298
|
+
timeout: parsed.timeout,
|
|
307
299
|
windowId: parsed.windowId,
|
|
308
300
|
appIdentifier: parsed.appIdentifier,
|
|
309
301
|
});
|
|
@@ -396,6 +388,9 @@ export const TOOLS = [
|
|
|
396
388
|
name: 'ipc_execute_command',
|
|
397
389
|
description: '[Tauri Apps Only] Execute Tauri IPC commands (invoke Rust backend functions). ' +
|
|
398
390
|
'Requires active driver_session. This is Tauri-specific IPC, not browser APIs. ' +
|
|
391
|
+
'Plugin commands (plugin:mcp-bridge|*) are routed through the bridge; all other commands ' +
|
|
392
|
+
'are executed via the webview using window.__TAURI_INTERNALS__.invoke, which keeps ' +
|
|
393
|
+
'the application\'s Tauri capability rules in force. ' +
|
|
399
394
|
'For Electron IPC or browser APIs, use appropriate tools for those frameworks.',
|
|
400
395
|
category: TOOL_CATEGORIES.IPC_PLUGIN,
|
|
401
396
|
schema: ExecuteIPCCommandSchema,
|
|
@@ -410,6 +405,7 @@ export const TOOLS = [
|
|
|
410
405
|
return await executeIPCCommand({
|
|
411
406
|
command: parsed.command,
|
|
412
407
|
args: parsed.args,
|
|
408
|
+
windowId: parsed.windowId,
|
|
413
409
|
appIdentifier: parsed.appIdentifier,
|
|
414
410
|
});
|
|
415
411
|
},
|
|
@@ -417,7 +413,8 @@ export const TOOLS = [
|
|
|
417
413
|
{
|
|
418
414
|
name: 'ipc_monitor',
|
|
419
415
|
description: '[Tauri Apps Only] Monitor Tauri IPC calls between frontend and Rust backend. ' +
|
|
420
|
-
'Requires active driver_session. Captures invoke() calls
|
|
416
|
+
'Requires active driver_session. Captures invoke() calls made through window.__TAURI__.core. ' +
|
|
417
|
+
'Bridge-internal commands (plugin:mcp-bridge|*) are excluded from capture. ' +
|
|
421
418
|
'This is Tauri-specific; for browser network monitoring, use Chrome DevTools MCP.',
|
|
422
419
|
category: TOOL_CATEGORIES.IPC_PLUGIN,
|
|
423
420
|
schema: ManageIPCMonitoringSchema,
|
|
@@ -492,6 +489,11 @@ export const TOOLS = [
|
|
|
492
489
|
'"list" - List all windows with labels, titles, URLs, and state. ' +
|
|
493
490
|
'"info" - Get detailed info for a window (size, position, title, focus, visibility). ' +
|
|
494
491
|
'"resize" - Resize a window (requires width/height, uses logical pixels by default). ' +
|
|
492
|
+
'"focus" - Focus a window (bring to front). ' +
|
|
493
|
+
'"minimize" - Minimize a window. ' +
|
|
494
|
+
'"maximize" - Maximize a window. ' +
|
|
495
|
+
'Desktop-only actions (focus, minimize, maximize) require tauri-plugin-mcp-bridge 0.13.0+ ' +
|
|
496
|
+
'and return a version error on older plugins. ' +
|
|
495
497
|
'Requires active driver_session. ' +
|
|
496
498
|
'For browser windows, use Chrome DevTools MCP instead.',
|
|
497
499
|
category: TOOL_CATEGORIES.UI_AUTOMATION,
|
package/dist/version.d.ts
CHANGED
|
@@ -13,3 +13,8 @@ export declare const PLUGIN_VERSION_FULL: string;
|
|
|
13
13
|
* This is the major.minor version used in Cargo.toml dependency specifications.
|
|
14
14
|
*/
|
|
15
15
|
export declare const PLUGIN_VERSION_CARGO: string;
|
|
16
|
+
/**
|
|
17
|
+
* Describe version skew between plugin and server.
|
|
18
|
+
* Returns null if versions match (major.minor), otherwise returns an upgrade message.
|
|
19
|
+
*/
|
|
20
|
+
export declare function describeVersionSkew(pluginVersion: string | null): string | null;
|
package/dist/version.js
CHANGED
|
@@ -15,3 +15,19 @@ export const PLUGIN_VERSION_FULL = pkg.version;
|
|
|
15
15
|
* This is the major.minor version used in Cargo.toml dependency specifications.
|
|
16
16
|
*/
|
|
17
17
|
export const PLUGIN_VERSION_CARGO = `${major}.${minor}`;
|
|
18
|
+
/**
|
|
19
|
+
* Describe version skew between plugin and server.
|
|
20
|
+
* Returns null if versions match (major.minor), otherwise returns an upgrade message.
|
|
21
|
+
*/
|
|
22
|
+
export function describeVersionSkew(pluginVersion) {
|
|
23
|
+
if (!pluginVersion) {
|
|
24
|
+
return 'The connected app cannot report its plugin version. ' +
|
|
25
|
+
`Update tauri-plugin-mcp-bridge to ${PLUGIN_VERSION_CARGO} and rebuild the app.`;
|
|
26
|
+
}
|
|
27
|
+
const [pMajor, pMinor] = pluginVersion.split('.'), [sMajor, sMinor] = PLUGIN_VERSION_FULL.split('.');
|
|
28
|
+
if (pMajor === sMajor && pMinor === sMinor) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
return `Plugin ${pluginVersion} does not match server ${PLUGIN_VERSION_FULL}. ` +
|
|
32
|
+
`Set tauri-plugin-mcp-bridge = "${PLUGIN_VERSION_CARGO}" in Cargo.toml and rebuild the app.`;
|
|
33
|
+
}
|
package/package.json
CHANGED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Get computed CSS styles for elements
|
|
3
|
-
*
|
|
4
|
-
* @param {Object} params
|
|
5
|
-
* @param {string} params.selector - CSS selector, XPath, text, or ref ID (e.g., "ref=e3") for element(s)
|
|
6
|
-
* @param {string} params.strategy - Selector strategy: 'css', 'xpath', or 'text'
|
|
7
|
-
* @param {string[]} params.properties - Specific CSS properties to retrieve
|
|
8
|
-
* @param {boolean} params.multiple - Whether to get styles for all matching elements
|
|
9
|
-
*/
|
|
10
|
-
(function(params) {
|
|
11
|
-
const { selector, strategy, properties, multiple } = params;
|
|
12
|
-
|
|
13
|
-
var elements;
|
|
14
|
-
|
|
15
|
-
if (multiple) {
|
|
16
|
-
elements = window.__MCP__.resolveAll(selector, strategy);
|
|
17
|
-
} else {
|
|
18
|
-
var el = window.__MCP__.resolveRef(selector, strategy);
|
|
19
|
-
elements = el ? [el] : [];
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
if (!elements[0]) {
|
|
23
|
-
throw new Error('Element not found: ' + selector);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const results = elements.map(function(element) {
|
|
27
|
-
const styles = window.getComputedStyle(element);
|
|
28
|
-
|
|
29
|
-
if (properties.length > 0) {
|
|
30
|
-
const result = {};
|
|
31
|
-
properties.forEach(function(prop) {
|
|
32
|
-
result[prop] = styles.getPropertyValue(prop);
|
|
33
|
-
});
|
|
34
|
-
return result;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Return all styles
|
|
38
|
-
const allStyles = {};
|
|
39
|
-
for (let i = 0; i < styles.length; i++) {
|
|
40
|
-
const prop = styles[i];
|
|
41
|
-
allStyles[prop] = styles.getPropertyValue(prop);
|
|
42
|
-
}
|
|
43
|
-
return allStyles;
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
return JSON.stringify(multiple ? results : results[0]);
|
|
47
|
-
})
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Keyboard interaction scripts
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Type text into an element
|
|
7
|
-
* @param {Object} params
|
|
8
|
-
* @param {string} params.selector - CSS selector for the element
|
|
9
|
-
* @param {string} params.text - Text to type
|
|
10
|
-
*/
|
|
11
|
-
function typeText(params) {
|
|
12
|
-
const { selector, text } = params;
|
|
13
|
-
|
|
14
|
-
const element = document.querySelector(selector);
|
|
15
|
-
if (!element) {
|
|
16
|
-
throw new Error(`Element not found: ${selector}`);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// Focus the element
|
|
20
|
-
element.focus();
|
|
21
|
-
|
|
22
|
-
// Set the value
|
|
23
|
-
element.value = text;
|
|
24
|
-
|
|
25
|
-
// Trigger input event for frameworks that listen to it
|
|
26
|
-
element.dispatchEvent(new Event('input', { bubbles: true }));
|
|
27
|
-
element.dispatchEvent(new Event('change', { bubbles: true }));
|
|
28
|
-
|
|
29
|
-
return `Typed "${text}" into ${selector}`;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Send keyboard events (press, down, up)
|
|
34
|
-
* @param {Object} params
|
|
35
|
-
* @param {string} params.action - 'press', 'down', or 'up'
|
|
36
|
-
* @param {string} params.key - Key to press
|
|
37
|
-
* @param {string[]} params.modifiers - Modifier keys
|
|
38
|
-
*/
|
|
39
|
-
function keyEvent(params) {
|
|
40
|
-
const { action, key, modifiers } = params;
|
|
41
|
-
|
|
42
|
-
const eventOptions = {
|
|
43
|
-
key: key,
|
|
44
|
-
code: key,
|
|
45
|
-
bubbles: true,
|
|
46
|
-
cancelable: true,
|
|
47
|
-
ctrlKey: modifiers.includes('Control'),
|
|
48
|
-
altKey: modifiers.includes('Alt'),
|
|
49
|
-
shiftKey: modifiers.includes('Shift'),
|
|
50
|
-
metaKey: modifiers.includes('Meta'),
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
const activeElement = document.activeElement || document.body;
|
|
54
|
-
|
|
55
|
-
if (action === 'press') {
|
|
56
|
-
activeElement.dispatchEvent(new KeyboardEvent('keydown', eventOptions));
|
|
57
|
-
activeElement.dispatchEvent(new KeyboardEvent('keypress', eventOptions));
|
|
58
|
-
activeElement.dispatchEvent(new KeyboardEvent('keyup', eventOptions));
|
|
59
|
-
return `Pressed key: ${key}${modifiers.length ? ' with ' + modifiers.join('+') : ''}`;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (action === 'down') {
|
|
63
|
-
activeElement.dispatchEvent(new KeyboardEvent('keydown', eventOptions));
|
|
64
|
-
return `Key down: ${key}${modifiers.length ? ' with ' + modifiers.join('+') : ''}`;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (action === 'up') {
|
|
68
|
-
activeElement.dispatchEvent(new KeyboardEvent('keyup', eventOptions));
|
|
69
|
-
return `Key up: ${key}${modifiers.length ? ' with ' + modifiers.join('+') : ''}`;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
throw new Error(`Unknown action: ${action}`);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// Export for use
|
|
76
|
-
({ typeText, keyEvent })
|