@laststance/electron-mcp-server 1.5.2 → 1.6.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/index.js +152 -9
- package/dist/index.js.map +1 -1
- package/dist/schemas.d.ts +13 -0
- package/dist/tools.d.ts +2 -1
- package/dist/utils/electron-connection.d.ts +15 -2
- package/dist/utils/electron-discovery.d.ts +14 -0
- package/dist/utils/electron-enhanced-commands.d.ts +6 -2
- package/package.json +5 -2
package/dist/index.js
CHANGED
|
@@ -2122,6 +2122,14 @@ const CommandArgsSchema = external_zod_namespaceObject.z
|
|
|
2122
2122
|
const SendCommandToElectronSchema = external_zod_namespaceObject.z.object({
|
|
2123
2123
|
command: external_zod_namespaceObject.z.string().describe('Command to send to the Electron process'),
|
|
2124
2124
|
args: CommandArgsSchema.optional().describe('Arguments for the command - must be an object with appropriate properties based on the command type'),
|
|
2125
|
+
targetId: external_zod_namespaceObject.z
|
|
2126
|
+
.string()
|
|
2127
|
+
.optional()
|
|
2128
|
+
.describe('CDP target ID to send the command to a specific window (exact match)'),
|
|
2129
|
+
windowTitle: external_zod_namespaceObject.z
|
|
2130
|
+
.string()
|
|
2131
|
+
.optional()
|
|
2132
|
+
.describe('Window title to target (case-insensitive partial match). Use list_electron_windows to see available windows.'),
|
|
2125
2133
|
});
|
|
2126
2134
|
const TakeScreenshotSchema = external_zod_namespaceObject.z.object({
|
|
2127
2135
|
outputPath: external_zod_namespaceObject.z
|
|
@@ -2141,6 +2149,12 @@ const ReadElectronLogsSchema = external_zod_namespaceObject.z.object({
|
|
|
2141
2149
|
const GetElectronWindowInfoSchema = external_zod_namespaceObject.z.object({
|
|
2142
2150
|
includeChildren: external_zod_namespaceObject.z.boolean().optional().describe('Include child windows information'),
|
|
2143
2151
|
});
|
|
2152
|
+
const ListElectronWindowsSchema = external_zod_namespaceObject.z.object({
|
|
2153
|
+
includeDevTools: external_zod_namespaceObject.z
|
|
2154
|
+
.boolean()
|
|
2155
|
+
.optional()
|
|
2156
|
+
.describe('Include DevTools windows in the list (default: false)'),
|
|
2157
|
+
});
|
|
2144
2158
|
|
|
2145
2159
|
;// ./src/tools.ts
|
|
2146
2160
|
|
|
@@ -2152,6 +2166,7 @@ var ToolName;
|
|
|
2152
2166
|
ToolName["TAKE_SCREENSHOT"] = "take_screenshot";
|
|
2153
2167
|
ToolName["READ_ELECTRON_LOGS"] = "read_electron_logs";
|
|
2154
2168
|
ToolName["GET_ELECTRON_WINDOW_INFO"] = "get_electron_window_info";
|
|
2169
|
+
ToolName["LIST_ELECTRON_WINDOWS"] = "list_electron_windows";
|
|
2155
2170
|
})(ToolName || (ToolName = {}));
|
|
2156
2171
|
// Define tools available to the MCP server
|
|
2157
2172
|
const tools = [
|
|
@@ -2193,9 +2208,20 @@ Examples:
|
|
|
2193
2208
|
- send_keyboard_shortcut: {"text": "Enter"}
|
|
2194
2209
|
- eval: {"code": "document.title"}
|
|
2195
2210
|
|
|
2196
|
-
Use 'get_page_structure' or 'debug_elements' first to understand available elements, then use specific interaction commands
|
|
2211
|
+
Use 'get_page_structure' or 'debug_elements' first to understand available elements, then use specific interaction commands.
|
|
2212
|
+
|
|
2213
|
+
Multi-window support:
|
|
2214
|
+
- targetId: Specify a CDP target ID to send commands to a specific window (exact match)
|
|
2215
|
+
- windowTitle: Specify a window title to target (case-insensitive partial match)
|
|
2216
|
+
- If neither is specified, commands are sent to the first available main window (backward compatible)
|
|
2217
|
+
- Use 'list_electron_windows' to see available windows and their IDs`,
|
|
2197
2218
|
inputSchema: (0,external_zod_to_json_schema_namespaceObject.zodToJsonSchema)(SendCommandToElectronSchema),
|
|
2198
2219
|
},
|
|
2220
|
+
{
|
|
2221
|
+
name: ToolName.LIST_ELECTRON_WINDOWS,
|
|
2222
|
+
description: "List all available Electron window targets across all detected applications. Returns window IDs, titles, URLs, and ports. Use the returned IDs with send_command_to_electron's targetId parameter to target specific windows.",
|
|
2223
|
+
inputSchema: (0,external_zod_to_json_schema_namespaceObject.zodToJsonSchema)(ListElectronWindowsSchema),
|
|
2224
|
+
},
|
|
2199
2225
|
{
|
|
2200
2226
|
name: ToolName.READ_ELECTRON_LOGS,
|
|
2201
2227
|
description: 'Read console logs and output from running Electron applications. Useful for debugging and monitoring app behavior.',
|
|
@@ -2371,6 +2397,31 @@ function findMainTarget(targets) {
|
|
|
2371
2397
|
return (targets.find((target) => target.type === 'page' && !target.title.includes('DevTools')) ||
|
|
2372
2398
|
targets.find((target) => target.type === 'page'));
|
|
2373
2399
|
}
|
|
2400
|
+
/**
|
|
2401
|
+
* List all available Electron window targets across all detected apps.
|
|
2402
|
+
* @param includeDevTools - Whether to include DevTools windows (default: false)
|
|
2403
|
+
* @returns Array of window targets with id, title, url, port, and type
|
|
2404
|
+
*/
|
|
2405
|
+
async function listElectronWindows(includeDevTools = false) {
|
|
2406
|
+
const foundApps = await scanForElectronApps();
|
|
2407
|
+
const windows = [];
|
|
2408
|
+
for (const app of foundApps) {
|
|
2409
|
+
for (const target of app.targets) {
|
|
2410
|
+
// Filter out DevTools windows unless explicitly requested
|
|
2411
|
+
if (!includeDevTools && target.url && target.url.startsWith('devtools://')) {
|
|
2412
|
+
continue;
|
|
2413
|
+
}
|
|
2414
|
+
windows.push({
|
|
2415
|
+
id: target.id,
|
|
2416
|
+
title: target.title || '',
|
|
2417
|
+
url: target.url || '',
|
|
2418
|
+
port: app.port,
|
|
2419
|
+
type: target.type || 'page',
|
|
2420
|
+
});
|
|
2421
|
+
}
|
|
2422
|
+
}
|
|
2423
|
+
return windows;
|
|
2424
|
+
}
|
|
2374
2425
|
/**
|
|
2375
2426
|
* Get window information from any running Electron app
|
|
2376
2427
|
*/
|
|
@@ -2430,14 +2481,56 @@ async function getElectronWindowInfo(includeChildren = false) {
|
|
|
2430
2481
|
|
|
2431
2482
|
|
|
2432
2483
|
/**
|
|
2433
|
-
* Find and connect to a running Electron application
|
|
2484
|
+
* Find and connect to a running Electron application.
|
|
2485
|
+
* @param options - Optional targeting options to select a specific window
|
|
2486
|
+
* @returns The DevTools target matching the given options
|
|
2487
|
+
* @example
|
|
2488
|
+
* findElectronTarget() // first available main window
|
|
2489
|
+
* findElectronTarget({ targetId: 'ABC123' }) // exact ID match
|
|
2490
|
+
* findElectronTarget({ windowTitle: 'Settings' }) // partial title match
|
|
2434
2491
|
*/
|
|
2435
|
-
async function findElectronTarget() {
|
|
2492
|
+
async function findElectronTarget(options) {
|
|
2436
2493
|
logger.debug('Looking for running Electron applications...');
|
|
2437
2494
|
const foundApps = await scanForElectronApps();
|
|
2438
2495
|
if (foundApps.length === 0) {
|
|
2439
2496
|
throw new Error('No running Electron application found with remote debugging enabled. Start your app with: electron . --remote-debugging-port=9222');
|
|
2440
2497
|
}
|
|
2498
|
+
// If targetId is specified, search all apps for exact ID match
|
|
2499
|
+
if (options?.targetId) {
|
|
2500
|
+
for (const app of foundApps) {
|
|
2501
|
+
const match = app.targets.find((t) => t.id === options.targetId);
|
|
2502
|
+
if (match) {
|
|
2503
|
+
logger.debug(`Found target by ID "${options.targetId}" on port ${app.port}`);
|
|
2504
|
+
return {
|
|
2505
|
+
id: match.id,
|
|
2506
|
+
title: match.title,
|
|
2507
|
+
url: match.url,
|
|
2508
|
+
webSocketDebuggerUrl: match.webSocketDebuggerUrl,
|
|
2509
|
+
type: match.type,
|
|
2510
|
+
};
|
|
2511
|
+
}
|
|
2512
|
+
}
|
|
2513
|
+
throw new Error(`No window found with targetId "${options.targetId}". Use list_electron_windows to see available targets.`);
|
|
2514
|
+
}
|
|
2515
|
+
// If windowTitle is specified, search all apps for case-insensitive partial match
|
|
2516
|
+
if (options?.windowTitle) {
|
|
2517
|
+
const searchTitle = options.windowTitle.toLowerCase();
|
|
2518
|
+
for (const app of foundApps) {
|
|
2519
|
+
const match = app.targets.find((t) => t.title && t.title.toLowerCase().includes(searchTitle));
|
|
2520
|
+
if (match) {
|
|
2521
|
+
logger.debug(`Found target by title "${options.windowTitle}" on port ${app.port}`);
|
|
2522
|
+
return {
|
|
2523
|
+
id: match.id,
|
|
2524
|
+
title: match.title,
|
|
2525
|
+
url: match.url,
|
|
2526
|
+
webSocketDebuggerUrl: match.webSocketDebuggerUrl,
|
|
2527
|
+
type: match.type,
|
|
2528
|
+
};
|
|
2529
|
+
}
|
|
2530
|
+
}
|
|
2531
|
+
throw new Error(`No window found with title matching "${options.windowTitle}". Use list_electron_windows to see available targets.`);
|
|
2532
|
+
}
|
|
2533
|
+
// Default: use first app's main target (backward compatible)
|
|
2441
2534
|
const app = foundApps[0];
|
|
2442
2535
|
const mainTarget = findMainTarget(app.targets);
|
|
2443
2536
|
if (!mainTarget) {
|
|
@@ -3610,11 +3703,14 @@ function generatePageStructureCommand() {
|
|
|
3610
3703
|
|
|
3611
3704
|
|
|
3612
3705
|
/**
|
|
3613
|
-
* Enhanced command executor with improved React support
|
|
3706
|
+
* Enhanced command executor with improved React support.
|
|
3707
|
+
* @param command - The command to execute
|
|
3708
|
+
* @param args - Command-specific arguments
|
|
3709
|
+
* @param windowOptions - Optional window targeting (targetId or windowTitle)
|
|
3614
3710
|
*/
|
|
3615
|
-
async function sendCommandToElectron(command, args) {
|
|
3711
|
+
async function sendCommandToElectron(command, args, windowOptions) {
|
|
3616
3712
|
try {
|
|
3617
|
-
const target = await findElectronTarget();
|
|
3713
|
+
const target = await findElectronTarget(windowOptions);
|
|
3618
3714
|
let javascriptCode;
|
|
3619
3715
|
switch (command.toLowerCase()) {
|
|
3620
3716
|
case 'get_title':
|
|
@@ -5661,7 +5757,7 @@ async function handleToolCall(request) {
|
|
|
5661
5757
|
return { content, isError: false };
|
|
5662
5758
|
}
|
|
5663
5759
|
case ToolName.SEND_COMMAND_TO_ELECTRON: {
|
|
5664
|
-
const { command, args: commandArgs } = SendCommandToElectronSchema.parse(args);
|
|
5760
|
+
const { command, args: commandArgs, targetId, windowTitle, } = SendCommandToElectronSchema.parse(args);
|
|
5665
5761
|
// Execute command through security manager
|
|
5666
5762
|
const securityResult = await securityManager.executeSecurely({
|
|
5667
5763
|
command,
|
|
@@ -5692,8 +5788,10 @@ async function handleToolCall(request) {
|
|
|
5692
5788
|
isError: true,
|
|
5693
5789
|
};
|
|
5694
5790
|
}
|
|
5791
|
+
// Build window target options if specified
|
|
5792
|
+
const windowOptions = targetId || windowTitle ? { targetId, windowTitle } : undefined;
|
|
5695
5793
|
// Execute the actual command if security checks pass
|
|
5696
|
-
const result = await sendCommandToElectron(command, commandArgs);
|
|
5794
|
+
const result = await sendCommandToElectron(command, commandArgs, windowOptions);
|
|
5697
5795
|
return {
|
|
5698
5796
|
content: [{ type: 'text', text: result }],
|
|
5699
5797
|
isError: false,
|
|
@@ -5723,6 +5821,51 @@ async function handleToolCall(request) {
|
|
|
5723
5821
|
isError: false,
|
|
5724
5822
|
};
|
|
5725
5823
|
}
|
|
5824
|
+
case ToolName.LIST_ELECTRON_WINDOWS: {
|
|
5825
|
+
const { includeDevTools } = ListElectronWindowsSchema.parse(args);
|
|
5826
|
+
const securityResult = await securityManager.executeSecurely({
|
|
5827
|
+
command: 'list_windows',
|
|
5828
|
+
args,
|
|
5829
|
+
sourceIP,
|
|
5830
|
+
userAgent,
|
|
5831
|
+
operationType: 'window_info',
|
|
5832
|
+
});
|
|
5833
|
+
if (securityResult.blocked) {
|
|
5834
|
+
return {
|
|
5835
|
+
content: [
|
|
5836
|
+
{
|
|
5837
|
+
type: 'text',
|
|
5838
|
+
text: `Operation blocked: ${securityResult.error}`,
|
|
5839
|
+
},
|
|
5840
|
+
],
|
|
5841
|
+
isError: true,
|
|
5842
|
+
};
|
|
5843
|
+
}
|
|
5844
|
+
const windows = await listElectronWindows(includeDevTools);
|
|
5845
|
+
if (windows.length === 0) {
|
|
5846
|
+
return {
|
|
5847
|
+
content: [
|
|
5848
|
+
{
|
|
5849
|
+
type: 'text',
|
|
5850
|
+
text: 'No Electron windows found. Ensure your app is running with --remote-debugging-port=9222',
|
|
5851
|
+
},
|
|
5852
|
+
],
|
|
5853
|
+
isError: false,
|
|
5854
|
+
};
|
|
5855
|
+
}
|
|
5856
|
+
const formatted = windows
|
|
5857
|
+
.map((w) => `- [${w.id}] "${w.title}" (port: ${w.port}, type: ${w.type})\n URL: ${w.url}`)
|
|
5858
|
+
.join('\n');
|
|
5859
|
+
return {
|
|
5860
|
+
content: [
|
|
5861
|
+
{
|
|
5862
|
+
type: 'text',
|
|
5863
|
+
text: `Available Electron windows (${windows.length}):\n\n${formatted}`,
|
|
5864
|
+
},
|
|
5865
|
+
],
|
|
5866
|
+
isError: false,
|
|
5867
|
+
};
|
|
5868
|
+
}
|
|
5726
5869
|
default:
|
|
5727
5870
|
return {
|
|
5728
5871
|
content: [
|
|
@@ -5765,7 +5908,7 @@ async function handleToolCall(request) {
|
|
|
5765
5908
|
|
|
5766
5909
|
|
|
5767
5910
|
|
|
5768
|
-
(0,external_dotenv_namespaceObject.config)();
|
|
5911
|
+
(0,external_dotenv_namespaceObject.config)({ quiet: true });
|
|
5769
5912
|
// Create MCP server instance
|
|
5770
5913
|
const server = new Server({
|
|
5771
5914
|
name: 'electron-mcp-server',
|