@everydaydevopsio/pilot 0.5.2 → 0.6.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/CHANGELOG.md +64 -0
- package/CLAUDE.md +7 -7
- package/README.md +108 -53
- package/dist/browser/browser-manager.d.ts +60 -0
- package/dist/browser/browser-manager.d.ts.map +1 -0
- package/dist/browser/browser-manager.js +348 -0
- package/dist/browser/browser-manager.js.map +1 -0
- package/dist/browser/chrome-launcher.d.ts +30 -0
- package/dist/browser/chrome-launcher.d.ts.map +1 -0
- package/dist/browser/chrome-launcher.js +217 -0
- package/dist/browser/chrome-launcher.js.map +1 -0
- package/dist/browser/connection.d.ts +23 -0
- package/dist/browser/connection.d.ts.map +1 -0
- package/dist/browser/connection.js +53 -0
- package/dist/browser/connection.js.map +1 -0
- package/dist/browser/events.d.ts +9 -0
- package/dist/browser/events.d.ts.map +1 -0
- package/dist/browser/events.js +99 -0
- package/dist/browser/events.js.map +1 -0
- package/dist/browser/index.d.ts +4 -0
- package/dist/browser/index.d.ts.map +1 -0
- package/dist/browser/index.js +4 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/browser/inspect/element-ref.d.ts +23 -0
- package/dist/browser/inspect/element-ref.d.ts.map +1 -0
- package/dist/browser/inspect/element-ref.js +52 -0
- package/dist/browser/inspect/element-ref.js.map +1 -0
- package/dist/browser/inspect/snapshot.d.ts +11 -0
- package/dist/browser/inspect/snapshot.d.ts.map +1 -0
- package/dist/browser/inspect/snapshot.js +282 -0
- package/dist/browser/inspect/snapshot.js.map +1 -0
- package/dist/browser/inspect/styles.d.ts +45 -0
- package/dist/browser/inspect/styles.d.ts.map +1 -0
- package/dist/browser/inspect/styles.js +190 -0
- package/dist/browser/inspect/styles.js.map +1 -0
- package/dist/browser/inspect/types.d.ts +35 -0
- package/dist/browser/inspect/types.d.ts.map +1 -0
- package/dist/browser/inspect/types.js +2 -0
- package/dist/browser/inspect/types.js.map +1 -0
- package/dist/browser/interaction/dialogs.d.ts +18 -0
- package/dist/browser/interaction/dialogs.d.ts.map +1 -0
- package/dist/browser/interaction/dialogs.js +35 -0
- package/dist/browser/interaction/dialogs.js.map +1 -0
- package/dist/browser/interaction/downloads.d.ts +23 -0
- package/dist/browser/interaction/downloads.d.ts.map +1 -0
- package/dist/browser/interaction/downloads.js +87 -0
- package/dist/browser/interaction/downloads.js.map +1 -0
- package/dist/browser/interaction/events.d.ts +17 -0
- package/dist/browser/interaction/events.d.ts.map +1 -0
- package/dist/browser/interaction/events.js +66 -0
- package/dist/browser/interaction/events.js.map +1 -0
- package/dist/browser/interaction/ref-resolver.d.ts +18 -0
- package/dist/browser/interaction/ref-resolver.d.ts.map +1 -0
- package/dist/browser/interaction/ref-resolver.js +32 -0
- package/dist/browser/interaction/ref-resolver.js.map +1 -0
- package/dist/browser/interaction/uploads.d.ts +4 -0
- package/dist/browser/interaction/uploads.d.ts.map +1 -0
- package/dist/browser/interaction/uploads.js +43 -0
- package/dist/browser/interaction/uploads.js.map +1 -0
- package/dist/browser/network/network-buffer.d.ts +19 -0
- package/dist/browser/network/network-buffer.d.ts.map +1 -0
- package/dist/browser/network/network-buffer.js +118 -0
- package/dist/browser/network/network-buffer.js.map +1 -0
- package/dist/browser/network/network-monitor.d.ts +8 -0
- package/dist/browser/network/network-monitor.d.ts.map +1 -0
- package/dist/browser/network/network-monitor.js +85 -0
- package/dist/browser/network/network-monitor.js.map +1 -0
- package/dist/browser/network/redaction.d.ts +3 -0
- package/dist/browser/network/redaction.d.ts.map +1 -0
- package/dist/browser/network/redaction.js +36 -0
- package/dist/browser/network/redaction.js.map +1 -0
- package/dist/browser/network/types.d.ts +45 -0
- package/dist/browser/network/types.d.ts.map +1 -0
- package/dist/browser/network/types.js +2 -0
- package/dist/browser/network/types.js.map +1 -0
- package/dist/browser/performance/analyze.d.ts +5 -0
- package/dist/browser/performance/analyze.d.ts.map +1 -0
- package/dist/browser/performance/analyze.js +230 -0
- package/dist/browser/performance/analyze.js.map +1 -0
- package/dist/browser/performance/trace.d.ts +10 -0
- package/dist/browser/performance/trace.d.ts.map +1 -0
- package/dist/browser/performance/trace.js +38 -0
- package/dist/browser/performance/trace.js.map +1 -0
- package/dist/browser/performance/types.d.ts +31 -0
- package/dist/browser/performance/types.d.ts.map +1 -0
- package/dist/browser/performance/types.js +2 -0
- package/dist/browser/performance/types.js.map +1 -0
- package/dist/browser/security/origins.d.ts +18 -0
- package/dist/browser/security/origins.d.ts.map +1 -0
- package/dist/browser/security/origins.js +84 -0
- package/dist/browser/security/origins.js.map +1 -0
- package/dist/browser/tabs.d.ts +15 -0
- package/dist/browser/tabs.d.ts.map +1 -0
- package/dist/browser/tabs.js +71 -0
- package/dist/browser/tabs.js.map +1 -0
- package/dist/browser/types.d.ts +31 -0
- package/dist/browser/types.d.ts.map +1 -0
- package/dist/browser/types.js +2 -0
- package/dist/browser/types.js.map +1 -0
- package/dist/browser.d.ts +2 -99
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +3 -653
- package/dist/browser.js.map +1 -1
- package/dist/commands/check.d.ts +17 -0
- package/dist/commands/check.d.ts.map +1 -0
- package/dist/commands/check.js +38 -0
- package/dist/commands/check.js.map +1 -0
- package/dist/commands/click.d.ts +3 -1
- package/dist/commands/click.d.ts.map +1 -1
- package/dist/commands/click.js +16 -4
- package/dist/commands/click.js.map +1 -1
- package/dist/commands/connect.d.ts +14 -0
- package/dist/commands/connect.d.ts.map +1 -0
- package/dist/commands/connect.js +19 -0
- package/dist/commands/connect.js.map +1 -0
- package/dist/commands/dialog.d.ts +19 -0
- package/dist/commands/dialog.d.ts.map +1 -0
- package/dist/commands/dialog.js +51 -0
- package/dist/commands/dialog.js.map +1 -0
- package/dist/commands/downloads.d.ts +30 -0
- package/dist/commands/downloads.d.ts.map +1 -0
- package/dist/commands/downloads.js +66 -0
- package/dist/commands/downloads.js.map +1 -0
- package/dist/commands/fill.d.ts +16 -0
- package/dist/commands/fill.d.ts.map +1 -0
- package/dist/commands/fill.js +15 -0
- package/dist/commands/fill.js.map +1 -0
- package/dist/commands/find.d.ts +14 -0
- package/dist/commands/find.d.ts.map +1 -0
- package/dist/commands/find.js +26 -0
- package/dist/commands/find.js.map +1 -0
- package/dist/commands/hover.d.ts +13 -0
- package/dist/commands/hover.d.ts.map +1 -0
- package/dist/commands/hover.js +24 -0
- package/dist/commands/hover.js.map +1 -0
- package/dist/commands/navigate.d.ts.map +1 -1
- package/dist/commands/navigate.js +13 -0
- package/dist/commands/navigate.js.map +1 -1
- package/dist/commands/network.d.ts +33 -0
- package/dist/commands/network.d.ts.map +1 -0
- package/dist/commands/network.js +84 -0
- package/dist/commands/network.js.map +1 -0
- package/dist/commands/performance.d.ts +12 -0
- package/dist/commands/performance.d.ts.map +1 -0
- package/dist/commands/performance.js +26 -0
- package/dist/commands/performance.js.map +1 -0
- package/dist/commands/press_key.d.ts +10 -0
- package/dist/commands/press_key.d.ts.map +1 -0
- package/dist/commands/press_key.js +103 -0
- package/dist/commands/press_key.js.map +1 -0
- package/dist/commands/scroll.d.ts +21 -0
- package/dist/commands/scroll.d.ts.map +1 -0
- package/dist/commands/scroll.js +54 -0
- package/dist/commands/scroll.js.map +1 -0
- package/dist/commands/select.d.ts +18 -0
- package/dist/commands/select.d.ts.map +1 -0
- package/dist/commands/select.js +53 -0
- package/dist/commands/select.js.map +1 -0
- package/dist/commands/snapshot.d.ts +9 -0
- package/dist/commands/snapshot.d.ts.map +1 -0
- package/dist/commands/snapshot.js +7 -0
- package/dist/commands/snapshot.js.map +1 -0
- package/dist/commands/styles.d.ts +13 -0
- package/dist/commands/styles.d.ts.map +1 -0
- package/dist/commands/styles.js +7 -0
- package/dist/commands/styles.js.map +1 -0
- package/dist/commands/type.d.ts +3 -1
- package/dist/commands/type.d.ts.map +1 -1
- package/dist/commands/type.js +11 -2
- package/dist/commands/type.js.map +1 -1
- package/dist/commands/upload.d.ts +12 -0
- package/dist/commands/upload.d.ts.map +1 -0
- package/dist/commands/upload.js +13 -0
- package/dist/commands/upload.js.map +1 -0
- package/dist/mcp/console-buffer.d.ts +9 -0
- package/dist/mcp/console-buffer.d.ts.map +1 -1
- package/dist/mcp/console-buffer.js.map +1 -1
- package/dist/mcp/server.d.ts +10 -0
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +63 -2
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools/browser.d.ts.map +1 -1
- package/dist/mcp/tools/browser.js +99 -8
- package/dist/mcp/tools/browser.js.map +1 -1
- package/dist/mcp/tools/connect.d.ts +5 -0
- package/dist/mcp/tools/connect.d.ts.map +1 -0
- package/dist/mcp/tools/connect.js +48 -0
- package/dist/mcp/tools/connect.js.map +1 -0
- package/dist/mcp/tools/files.d.ts +4 -0
- package/dist/mcp/tools/files.d.ts.map +1 -0
- package/dist/mcp/tools/files.js +85 -0
- package/dist/mcp/tools/files.js.map +1 -0
- package/dist/mcp/tools/interaction.d.ts +4 -0
- package/dist/mcp/tools/interaction.d.ts.map +1 -0
- package/dist/mcp/tools/interaction.js +176 -0
- package/dist/mcp/tools/interaction.js.map +1 -0
- package/dist/mcp/tools/names.d.ts +1 -1
- package/dist/mcp/tools/names.d.ts.map +1 -1
- package/dist/mcp/tools/names.js +19 -1
- package/dist/mcp/tools/names.js.map +1 -1
- package/dist/mcp/tools/network.d.ts +4 -0
- package/dist/mcp/tools/network.d.ts.map +1 -0
- package/dist/mcp/tools/network.js +68 -0
- package/dist/mcp/tools/network.js.map +1 -0
- package/dist/mcp/tools/performance.d.ts +4 -0
- package/dist/mcp/tools/performance.d.ts.map +1 -0
- package/dist/mcp/tools/performance.js +26 -0
- package/dist/mcp/tools/performance.js.map +1 -0
- package/dist/mcp/tools/runtime.d.ts +4 -0
- package/dist/mcp/tools/runtime.d.ts.map +1 -0
- package/dist/mcp/tools/runtime.js +128 -0
- package/dist/mcp/tools/runtime.js.map +1 -0
- package/dist/mcp/tools/snapshot.d.ts +4 -0
- package/dist/mcp/tools/snapshot.d.ts.map +1 -0
- package/dist/mcp/tools/snapshot.js +42 -0
- package/dist/mcp/tools/snapshot.js.map +1 -0
- package/dist/mcp/tools/styles.d.ts +4 -0
- package/dist/mcp/tools/styles.d.ts.map +1 -0
- package/dist/mcp/tools/styles.js +27 -0
- package/dist/mcp/tools/styles.js.map +1 -0
- package/dist/util/config.d.ts.map +1 -1
- package/dist/util/config.js +3 -2
- package/dist/util/config.js.map +1 -1
- package/package.json +3 -3
- package/src/browser/browser-manager.ts +457 -0
- package/src/browser/chrome-launcher.ts +271 -0
- package/src/browser/connection.ts +84 -0
- package/src/browser/events.ts +121 -0
- package/src/browser/index.ts +20 -0
- package/src/browser/inspect/element-ref.ts +68 -0
- package/src/browser/inspect/snapshot.ts +348 -0
- package/src/browser/inspect/styles.ts +258 -0
- package/src/browser/inspect/types.ts +37 -0
- package/src/browser/interaction/dialogs.ts +54 -0
- package/src/browser/interaction/downloads.ts +116 -0
- package/src/browser/interaction/events.ts +79 -0
- package/src/browser/interaction/ref-resolver.ts +53 -0
- package/src/browser/interaction/uploads.ts +60 -0
- package/src/browser/network/network-buffer.ts +133 -0
- package/src/browser/network/network-monitor.ts +107 -0
- package/src/browser/network/redaction.ts +42 -0
- package/src/browser/network/types.ts +47 -0
- package/src/browser/performance/analyze.ts +298 -0
- package/src/browser/performance/trace.ts +60 -0
- package/src/browser/performance/types.ts +34 -0
- package/src/browser/security/origins.ts +102 -0
- package/src/browser/tabs.ts +110 -0
- package/src/browser/types.ts +31 -0
- package/src/browser.ts +22 -798
- package/src/commands/check.ts +59 -0
- package/src/commands/click.ts +18 -4
- package/src/commands/connect.ts +40 -0
- package/src/commands/dialog.ts +79 -0
- package/src/commands/downloads.ts +111 -0
- package/src/commands/fill.ts +34 -0
- package/src/commands/find.ts +52 -0
- package/src/commands/hover.ts +42 -0
- package/src/commands/navigate.ts +20 -0
- package/src/commands/network.ts +141 -0
- package/src/commands/performance.ts +51 -0
- package/src/commands/press_key.ts +134 -0
- package/src/commands/scroll.ts +79 -0
- package/src/commands/select.ts +78 -0
- package/src/commands/snapshot.ts +18 -0
- package/src/commands/styles.ts +24 -0
- package/src/commands/type.ts +12 -2
- package/src/commands/upload.ts +36 -0
- package/src/mcp/console-buffer.ts +10 -0
- package/src/mcp/server.ts +74 -2
- package/src/mcp/tools/browser.ts +113 -7
- package/src/mcp/tools/connect.ts +62 -0
- package/src/mcp/tools/files.ts +120 -0
- package/src/mcp/tools/interaction.ts +232 -0
- package/src/mcp/tools/names.ts +19 -1
- package/src/mcp/tools/network.ts +86 -0
- package/src/mcp/tools/performance.ts +40 -0
- package/src/mcp/tools/runtime.ts +164 -0
- package/src/mcp/tools/snapshot.ts +64 -0
- package/src/mcp/tools/styles.ts +41 -0
- package/src/util/config.ts +3 -2
package/src/mcp/tools/browser.ts
CHANGED
|
@@ -57,6 +57,10 @@ const navigateShape = {
|
|
|
57
57
|
};
|
|
58
58
|
|
|
59
59
|
const clickShape = {
|
|
60
|
+
ref: z
|
|
61
|
+
.string()
|
|
62
|
+
.optional()
|
|
63
|
+
.describe('Element ref from browser_snapshot (e.g. "e3")'),
|
|
60
64
|
selector: z.string().optional().describe('CSS selector to click'),
|
|
61
65
|
x: z.number().optional().describe('Viewport X coordinate'),
|
|
62
66
|
y: z.number().optional().describe('Viewport Y coordinate'),
|
|
@@ -80,6 +84,10 @@ const clickShape = {
|
|
|
80
84
|
|
|
81
85
|
const typeShape = {
|
|
82
86
|
text: z.string().describe('Text to type'),
|
|
87
|
+
ref: z
|
|
88
|
+
.string()
|
|
89
|
+
.optional()
|
|
90
|
+
.describe('Element ref from browser_snapshot (e.g. "e3")'),
|
|
83
91
|
selector: z.string().optional().describe('CSS selector to focus first'),
|
|
84
92
|
clearFirst: z
|
|
85
93
|
.boolean()
|
|
@@ -128,7 +136,7 @@ const startShape = {
|
|
|
128
136
|
.boolean()
|
|
129
137
|
.optional()
|
|
130
138
|
.describe(
|
|
131
|
-
'Run Chrome headless. When omitted, falls back to PILOT_HEADLESS (default:
|
|
139
|
+
'Run Chrome headless. When omitted, falls back to PILOT_HEADLESS (accepts true/1 or false/0; default: false).'
|
|
132
140
|
),
|
|
133
141
|
chromePath: z
|
|
134
142
|
.string()
|
|
@@ -190,6 +198,24 @@ const switchTabShape = {
|
|
|
190
198
|
targetId: z.string().describe('Target ID of the tab to switch to')
|
|
191
199
|
};
|
|
192
200
|
|
|
201
|
+
const tabsShape = {
|
|
202
|
+
action: z
|
|
203
|
+
.enum(['list', 'new', 'select', 'close'])
|
|
204
|
+
.describe(
|
|
205
|
+
'Action: list tabs, open new tab, select/switch tab, or close tab'
|
|
206
|
+
),
|
|
207
|
+
targetId: z
|
|
208
|
+
.string()
|
|
209
|
+
.optional()
|
|
210
|
+
.describe('Target ID (required for select and close actions)'),
|
|
211
|
+
url: z
|
|
212
|
+
.string()
|
|
213
|
+
.optional()
|
|
214
|
+
.describe(
|
|
215
|
+
'URL to open in the new tab (new action only, opens blank tab if omitted)'
|
|
216
|
+
)
|
|
217
|
+
};
|
|
218
|
+
|
|
193
219
|
const viewportResizeShape = {
|
|
194
220
|
width: z.number().int().positive().describe('New viewport width in pixels'),
|
|
195
221
|
height: z.number().int().positive().describe('New viewport height in pixels'),
|
|
@@ -361,10 +387,11 @@ export function registerBrowserTools(
|
|
|
361
387
|
|
|
362
388
|
server.tool(
|
|
363
389
|
'browser_click',
|
|
364
|
-
'Click an element by
|
|
390
|
+
'Click an element by ref (from browser_snapshot), CSS selector, or coordinates.',
|
|
365
391
|
clickShape,
|
|
366
392
|
async (params) => {
|
|
367
393
|
if (
|
|
394
|
+
params.ref === undefined &&
|
|
368
395
|
params.selector === undefined &&
|
|
369
396
|
(params.x === undefined || params.y === undefined)
|
|
370
397
|
) {
|
|
@@ -372,7 +399,7 @@ export function registerBrowserTools(
|
|
|
372
399
|
content: [
|
|
373
400
|
{
|
|
374
401
|
type: 'text' as const,
|
|
375
|
-
text: 'Error: Either selector or x/y coordinates are required'
|
|
402
|
+
text: 'Error: Either ref, selector, or x/y coordinates are required'
|
|
376
403
|
}
|
|
377
404
|
],
|
|
378
405
|
isError: true
|
|
@@ -380,7 +407,7 @@ export function registerBrowserTools(
|
|
|
380
407
|
}
|
|
381
408
|
|
|
382
409
|
const { client } = requireClient(context);
|
|
383
|
-
const result = await executeClick(client, params);
|
|
410
|
+
const result = await executeClick(client, params, context.elementRefMap);
|
|
384
411
|
|
|
385
412
|
return {
|
|
386
413
|
content: [
|
|
@@ -395,17 +422,18 @@ export function registerBrowserTools(
|
|
|
395
422
|
|
|
396
423
|
server.tool(
|
|
397
424
|
'browser_type',
|
|
398
|
-
'Type text into the focused element or a
|
|
425
|
+
'Type text into the focused element, a ref (from browser_snapshot), or a CSS selector. Generates keystroke events (use browser_fill to replace a field value entirely).',
|
|
399
426
|
typeShape,
|
|
400
427
|
async (params) => {
|
|
401
428
|
const { client } = requireClient(context);
|
|
402
|
-
await executeType(client, params);
|
|
429
|
+
await executeType(client, params, context.elementRefMap);
|
|
403
430
|
|
|
431
|
+
const target = params.ref ?? params.selector;
|
|
404
432
|
return {
|
|
405
433
|
content: [
|
|
406
434
|
{
|
|
407
435
|
type: 'text' as const,
|
|
408
|
-
text: `Typed "${params.text}"${
|
|
436
|
+
text: `Typed "${params.text}"${target ? ` into ${target}` : ''}`
|
|
409
437
|
}
|
|
410
438
|
]
|
|
411
439
|
};
|
|
@@ -602,4 +630,82 @@ export function registerBrowserTools(
|
|
|
602
630
|
};
|
|
603
631
|
}
|
|
604
632
|
);
|
|
633
|
+
|
|
634
|
+
server.tool(
|
|
635
|
+
'browser_tabs',
|
|
636
|
+
'Manage browser tabs. Actions: "list" shows all tabs, "new" opens a tab (optional url), "select" switches to a tab (requires targetId), "close" closes a tab (requires targetId).',
|
|
637
|
+
tabsShape,
|
|
638
|
+
async ({ action, targetId, url }) => {
|
|
639
|
+
const { manager } = requireClient(context);
|
|
640
|
+
|
|
641
|
+
switch (action) {
|
|
642
|
+
case 'list': {
|
|
643
|
+
const tabs = await executeListTabs(manager);
|
|
644
|
+
return {
|
|
645
|
+
content: [
|
|
646
|
+
{ type: 'text' as const, text: JSON.stringify(tabs, null, 2) }
|
|
647
|
+
]
|
|
648
|
+
};
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
case 'new': {
|
|
652
|
+
const result = await executeNewTab(manager, url);
|
|
653
|
+
return {
|
|
654
|
+
content: [
|
|
655
|
+
{
|
|
656
|
+
type: 'text' as const,
|
|
657
|
+
text: `New tab opened (targetId: ${result.targetId}, url: ${result.url})`
|
|
658
|
+
}
|
|
659
|
+
]
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
case 'select': {
|
|
664
|
+
if (!targetId) {
|
|
665
|
+
return {
|
|
666
|
+
content: [
|
|
667
|
+
{
|
|
668
|
+
type: 'text' as const,
|
|
669
|
+
text: 'Error: targetId is required for select action'
|
|
670
|
+
}
|
|
671
|
+
],
|
|
672
|
+
isError: true
|
|
673
|
+
};
|
|
674
|
+
}
|
|
675
|
+
await executeSwitchTab(manager, targetId);
|
|
676
|
+
return {
|
|
677
|
+
content: [
|
|
678
|
+
{
|
|
679
|
+
type: 'text' as const,
|
|
680
|
+
text: `Switched to tab ${targetId}.`
|
|
681
|
+
}
|
|
682
|
+
]
|
|
683
|
+
};
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
case 'close': {
|
|
687
|
+
if (!targetId) {
|
|
688
|
+
return {
|
|
689
|
+
content: [
|
|
690
|
+
{
|
|
691
|
+
type: 'text' as const,
|
|
692
|
+
text: 'Error: targetId is required for close action'
|
|
693
|
+
}
|
|
694
|
+
],
|
|
695
|
+
isError: true
|
|
696
|
+
};
|
|
697
|
+
}
|
|
698
|
+
await executeCloseTab(manager, targetId);
|
|
699
|
+
return {
|
|
700
|
+
content: [
|
|
701
|
+
{
|
|
702
|
+
type: 'text' as const,
|
|
703
|
+
text: `Tab ${targetId} closed.`
|
|
704
|
+
}
|
|
705
|
+
]
|
|
706
|
+
};
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
);
|
|
605
711
|
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
+
import type { BrowserContext } from '../server.js';
|
|
4
|
+
import type { BrowserManager } from '../../browser/browser-manager.js';
|
|
5
|
+
import { executeConnect, formatConnectResult } from '../../commands/connect.js';
|
|
6
|
+
|
|
7
|
+
const connectShape = {
|
|
8
|
+
host: z
|
|
9
|
+
.string()
|
|
10
|
+
.default('127.0.0.1')
|
|
11
|
+
.describe('Chrome debugging host (default: 127.0.0.1)'),
|
|
12
|
+
port: z
|
|
13
|
+
.number()
|
|
14
|
+
.int()
|
|
15
|
+
.min(1)
|
|
16
|
+
.max(65535)
|
|
17
|
+
.default(9222)
|
|
18
|
+
.describe('Chrome debugging port (default: 9222)')
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export function registerConnectTools(
|
|
22
|
+
server: McpServer,
|
|
23
|
+
context: BrowserContext,
|
|
24
|
+
makeBrowserManager: () => BrowserManager
|
|
25
|
+
): void {
|
|
26
|
+
server.tool(
|
|
27
|
+
'browser_connect',
|
|
28
|
+
'Connect to an existing Chrome instance with remote debugging enabled. Start Chrome with --remote-debugging-port=PORT, then use this tool to connect. Lists available tabs after connecting. Use browser_switch_tab to select a specific tab.',
|
|
29
|
+
connectShape,
|
|
30
|
+
async ({ host, port }) => {
|
|
31
|
+
if (context.manager?.isConnected()) {
|
|
32
|
+
return {
|
|
33
|
+
content: [
|
|
34
|
+
{
|
|
35
|
+
type: 'text' as const,
|
|
36
|
+
text: 'Already connected to a browser. Call browser_stop to disconnect first.'
|
|
37
|
+
}
|
|
38
|
+
]
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (context.manager) {
|
|
43
|
+
await context.manager.destroy();
|
|
44
|
+
context.manager = null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const manager = makeBrowserManager();
|
|
48
|
+
try {
|
|
49
|
+
const result = await executeConnect(manager, { host, port });
|
|
50
|
+
context.manager = manager;
|
|
51
|
+
return {
|
|
52
|
+
content: [
|
|
53
|
+
{ type: 'text' as const, text: formatConnectResult(result) }
|
|
54
|
+
]
|
|
55
|
+
};
|
|
56
|
+
} catch (err) {
|
|
57
|
+
await manager.destroy();
|
|
58
|
+
throw err;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
);
|
|
62
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
+
import type { BrowserContext } from '../server.js';
|
|
4
|
+
import { executeDialog, formatDialogResult } from '../../commands/dialog.js';
|
|
5
|
+
import { executeUpload } from '../../commands/upload.js';
|
|
6
|
+
import {
|
|
7
|
+
executeDownloads,
|
|
8
|
+
formatDownloadsResult
|
|
9
|
+
} from '../../commands/downloads.js';
|
|
10
|
+
|
|
11
|
+
const dialogShape = {
|
|
12
|
+
action: z
|
|
13
|
+
.enum(['list', 'accept', 'dismiss'])
|
|
14
|
+
.describe(
|
|
15
|
+
'Action: list pending dialogs, accept (OK/Yes), or dismiss (Cancel/No)'
|
|
16
|
+
),
|
|
17
|
+
promptText: z
|
|
18
|
+
.string()
|
|
19
|
+
.optional()
|
|
20
|
+
.describe('Text to enter for prompt dialogs (accept action only)')
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const uploadShape = {
|
|
24
|
+
ref: z
|
|
25
|
+
.string()
|
|
26
|
+
.describe('Element ref of a file input (from browser_snapshot)'),
|
|
27
|
+
files: z
|
|
28
|
+
.array(z.string())
|
|
29
|
+
.describe(
|
|
30
|
+
'File paths to upload. Must exist, be regular files, and be under PILOT_UPLOAD_ROOTS (default: cwd).'
|
|
31
|
+
)
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const downloadsShape = {
|
|
35
|
+
action: z
|
|
36
|
+
.enum(['list', 'wait', 'clear'])
|
|
37
|
+
.describe(
|
|
38
|
+
'Action: list tracked downloads, wait for one to complete, or clear'
|
|
39
|
+
),
|
|
40
|
+
guid: z
|
|
41
|
+
.string()
|
|
42
|
+
.optional()
|
|
43
|
+
.describe('Download GUID (required for wait action)'),
|
|
44
|
+
timeoutMs: z
|
|
45
|
+
.number()
|
|
46
|
+
.int()
|
|
47
|
+
.positive()
|
|
48
|
+
.optional()
|
|
49
|
+
.describe('Timeout for wait action in milliseconds (default: 30000)')
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
function requireContext(context: BrowserContext) {
|
|
53
|
+
const manager = context.manager;
|
|
54
|
+
if (!manager || !manager.isConnected()) {
|
|
55
|
+
throw new Error('Browser not started. Call browser_start first.');
|
|
56
|
+
}
|
|
57
|
+
const client = manager.getClient()!;
|
|
58
|
+
return { client };
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function registerFilesTools(
|
|
62
|
+
server: McpServer,
|
|
63
|
+
context: BrowserContext
|
|
64
|
+
): void {
|
|
65
|
+
server.tool(
|
|
66
|
+
'browser_dialog',
|
|
67
|
+
'Handle browser dialogs (alert, confirm, prompt). Use "list" to see pending dialogs, "accept" to click OK/Yes, or "dismiss" to click Cancel/No. For prompt dialogs, provide promptText with accept.',
|
|
68
|
+
dialogShape,
|
|
69
|
+
async ({ action, promptText }) => {
|
|
70
|
+
const { client } = requireContext(context);
|
|
71
|
+
const result = await executeDialog(client, context.dialogQueue, {
|
|
72
|
+
action,
|
|
73
|
+
promptText
|
|
74
|
+
});
|
|
75
|
+
return {
|
|
76
|
+
content: [{ type: 'text' as const, text: formatDialogResult(result) }]
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
server.tool(
|
|
82
|
+
'browser_upload',
|
|
83
|
+
'Upload files to a file input element by ref. Files must exist, be regular files, and be under allowed roots (PILOT_UPLOAD_ROOTS env, default: cwd). Use browser_snapshot to find file input refs.',
|
|
84
|
+
uploadShape,
|
|
85
|
+
async ({ ref, files }) => {
|
|
86
|
+
const { client } = requireContext(context);
|
|
87
|
+
const result = await executeUpload(client, context.elementRefMap, {
|
|
88
|
+
ref,
|
|
89
|
+
files
|
|
90
|
+
});
|
|
91
|
+
return {
|
|
92
|
+
content: [
|
|
93
|
+
{
|
|
94
|
+
type: 'text' as const,
|
|
95
|
+
text: `Uploaded ${result.files.length} file(s) to ${result.ref}`
|
|
96
|
+
}
|
|
97
|
+
]
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
server.tool(
|
|
103
|
+
'browser_downloads',
|
|
104
|
+
'Track file downloads. Actions: "list" shows tracked downloads with status/progress; "wait" blocks until a download (by GUID) completes; "clear" resets the tracker.',
|
|
105
|
+
downloadsShape,
|
|
106
|
+
async ({ action, guid, timeoutMs }) => {
|
|
107
|
+
requireContext(context);
|
|
108
|
+
const result = await executeDownloads(context.downloadTracker, {
|
|
109
|
+
action,
|
|
110
|
+
guid,
|
|
111
|
+
timeoutMs
|
|
112
|
+
});
|
|
113
|
+
return {
|
|
114
|
+
content: [
|
|
115
|
+
{ type: 'text' as const, text: formatDownloadsResult(result) }
|
|
116
|
+
]
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
);
|
|
120
|
+
}
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
+
import type { BrowserContext } from '../server.js';
|
|
4
|
+
import { executeFill } from '../../commands/fill.js';
|
|
5
|
+
import { executeHover } from '../../commands/hover.js';
|
|
6
|
+
import { executePressKey } from '../../commands/press_key.js';
|
|
7
|
+
import { executeSelect } from '../../commands/select.js';
|
|
8
|
+
import { executeCheck } from '../../commands/check.js';
|
|
9
|
+
import { executeScroll } from '../../commands/scroll.js';
|
|
10
|
+
|
|
11
|
+
function requireContext(context: BrowserContext) {
|
|
12
|
+
const manager = context.manager;
|
|
13
|
+
if (!manager || !manager.isConnected()) {
|
|
14
|
+
throw new Error('Browser not started. Call browser_start first.');
|
|
15
|
+
}
|
|
16
|
+
const client = manager.getClient()!;
|
|
17
|
+
return { client, refMap: context.elementRefMap };
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const fillShape = {
|
|
21
|
+
ref: z.string().describe('Element ref from browser_snapshot (e.g. "e3")'),
|
|
22
|
+
value: z.string().describe('Value to set in the field')
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const hoverShape = {
|
|
26
|
+
ref: z
|
|
27
|
+
.string()
|
|
28
|
+
.optional()
|
|
29
|
+
.describe('Element ref from browser_snapshot (e.g. "e3")'),
|
|
30
|
+
x: z.number().optional().describe('Viewport X coordinate'),
|
|
31
|
+
y: z.number().optional().describe('Viewport Y coordinate')
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const pressKeyShape = {
|
|
35
|
+
key: z
|
|
36
|
+
.string()
|
|
37
|
+
.describe(
|
|
38
|
+
'Key to press. Named keys: Enter, Tab, Escape, Backspace, Delete, Space, ArrowUp/Down/Left/Right, Home, End, PageUp/Down, F1-F12. Modifier combos: Control+a, Meta+c, Shift+Enter.'
|
|
39
|
+
)
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const selectShape = {
|
|
43
|
+
ref: z.string().describe('Element ref of a <select> element'),
|
|
44
|
+
value: z.string().optional().describe('Option value attribute to select'),
|
|
45
|
+
label: z.string().optional().describe('Option visible text to select'),
|
|
46
|
+
index: z
|
|
47
|
+
.number()
|
|
48
|
+
.int()
|
|
49
|
+
.min(0)
|
|
50
|
+
.optional()
|
|
51
|
+
.describe('Option index to select (0-based)')
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const checkShape = {
|
|
55
|
+
ref: z.string().describe('Element ref of a checkbox or radio button'),
|
|
56
|
+
checked: z.boolean().optional().describe('Desired state. Omit to toggle.')
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const scrollShape = {
|
|
60
|
+
ref: z.string().optional().describe('Element ref to scroll into view'),
|
|
61
|
+
direction: z
|
|
62
|
+
.enum(['up', 'down', 'left', 'right'])
|
|
63
|
+
.optional()
|
|
64
|
+
.describe('Scroll direction'),
|
|
65
|
+
amount: z
|
|
66
|
+
.number()
|
|
67
|
+
.int()
|
|
68
|
+
.positive()
|
|
69
|
+
.optional()
|
|
70
|
+
.describe('Scroll amount in pixels (default: 300)'),
|
|
71
|
+
x: z.number().optional().describe('Absolute scroll X position'),
|
|
72
|
+
y: z.number().optional().describe('Absolute scroll Y position')
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export function registerInteractionTools(
|
|
76
|
+
server: McpServer,
|
|
77
|
+
context: BrowserContext
|
|
78
|
+
): void {
|
|
79
|
+
server.tool(
|
|
80
|
+
'browser_fill',
|
|
81
|
+
'Fill a form field by element ref. Replaces the entire field value and fires input/change events compatible with React, Vue, and Svelte. Use browser_snapshot first to get refs.',
|
|
82
|
+
fillShape,
|
|
83
|
+
async ({ ref, value }) => {
|
|
84
|
+
const { client, refMap } = requireContext(context);
|
|
85
|
+
const result = await executeFill(client, refMap, { ref, value });
|
|
86
|
+
return {
|
|
87
|
+
content: [
|
|
88
|
+
{
|
|
89
|
+
type: 'text' as const,
|
|
90
|
+
text: `Filled ${result.ref} with "${result.value}"`
|
|
91
|
+
}
|
|
92
|
+
]
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
server.tool(
|
|
98
|
+
'browser_hover',
|
|
99
|
+
'Hover over an element by ref or coordinates. Dispatches a mouseMoved event.',
|
|
100
|
+
hoverShape,
|
|
101
|
+
async (params) => {
|
|
102
|
+
if (
|
|
103
|
+
params.ref === undefined &&
|
|
104
|
+
(params.x === undefined || params.y === undefined)
|
|
105
|
+
) {
|
|
106
|
+
return {
|
|
107
|
+
content: [
|
|
108
|
+
{
|
|
109
|
+
type: 'text' as const,
|
|
110
|
+
text: 'Error: Either ref or x/y coordinates are required'
|
|
111
|
+
}
|
|
112
|
+
],
|
|
113
|
+
isError: true
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
const { client, refMap } = requireContext(context);
|
|
117
|
+
const result = await executeHover(client, refMap, params);
|
|
118
|
+
return {
|
|
119
|
+
content: [
|
|
120
|
+
{
|
|
121
|
+
type: 'text' as const,
|
|
122
|
+
text: `Hovered at (${result.x}, ${result.y})`
|
|
123
|
+
}
|
|
124
|
+
]
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
server.tool(
|
|
130
|
+
'browser_press_key',
|
|
131
|
+
'Press a key or key combination. Supports named keys (Enter, Tab, Escape, etc.) and modifier combos (Control+a, Meta+c, Shift+Enter).',
|
|
132
|
+
pressKeyShape,
|
|
133
|
+
async ({ key }) => {
|
|
134
|
+
const { client } = requireContext(context);
|
|
135
|
+
const result = await executePressKey(client, { key });
|
|
136
|
+
const modStr =
|
|
137
|
+
result.modifiers.length > 0
|
|
138
|
+
? ` with modifiers: ${result.modifiers.join('+')}`
|
|
139
|
+
: '';
|
|
140
|
+
return {
|
|
141
|
+
content: [
|
|
142
|
+
{ type: 'text' as const, text: `Pressed ${result.key}${modStr}` }
|
|
143
|
+
]
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
server.tool(
|
|
149
|
+
'browser_select',
|
|
150
|
+
'Select an option in a <select> element by value, label, or index. Use browser_snapshot to get the ref.',
|
|
151
|
+
selectShape,
|
|
152
|
+
async (params) => {
|
|
153
|
+
if (
|
|
154
|
+
params.value === undefined &&
|
|
155
|
+
params.label === undefined &&
|
|
156
|
+
params.index === undefined
|
|
157
|
+
) {
|
|
158
|
+
return {
|
|
159
|
+
content: [
|
|
160
|
+
{
|
|
161
|
+
type: 'text' as const,
|
|
162
|
+
text: 'Error: One of value, label, or index is required'
|
|
163
|
+
}
|
|
164
|
+
],
|
|
165
|
+
isError: true
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
const { client, refMap } = requireContext(context);
|
|
169
|
+
const result = await executeSelect(client, refMap, params);
|
|
170
|
+
return {
|
|
171
|
+
content: [
|
|
172
|
+
{
|
|
173
|
+
type: 'text' as const,
|
|
174
|
+
text: `Selected "${result.selectedLabel}" (value="${result.selectedValue}") in ${result.ref}`
|
|
175
|
+
}
|
|
176
|
+
]
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
server.tool(
|
|
182
|
+
'browser_check',
|
|
183
|
+
'Toggle a checkbox or radio button by ref. Optionally set to a specific checked state.',
|
|
184
|
+
checkShape,
|
|
185
|
+
async ({ ref, checked }) => {
|
|
186
|
+
const { client, refMap } = requireContext(context);
|
|
187
|
+
const result = await executeCheck(client, refMap, { ref, checked });
|
|
188
|
+
return {
|
|
189
|
+
content: [
|
|
190
|
+
{
|
|
191
|
+
type: 'text' as const,
|
|
192
|
+
text: `${result.ref} is now ${result.checked ? 'checked' : 'unchecked'}`
|
|
193
|
+
}
|
|
194
|
+
]
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
server.tool(
|
|
200
|
+
'browser_scroll',
|
|
201
|
+
'Scroll the page or an element. Use ref to scroll an element into view, direction/amount for relative scrolling, or x/y for absolute scroll position.',
|
|
202
|
+
scrollShape,
|
|
203
|
+
async (params) => {
|
|
204
|
+
if (
|
|
205
|
+
params.ref === undefined &&
|
|
206
|
+
params.direction === undefined &&
|
|
207
|
+
params.x === undefined &&
|
|
208
|
+
params.y === undefined
|
|
209
|
+
) {
|
|
210
|
+
return {
|
|
211
|
+
content: [
|
|
212
|
+
{
|
|
213
|
+
type: 'text' as const,
|
|
214
|
+
text: 'Error: At least one of ref, direction, or x/y is required'
|
|
215
|
+
}
|
|
216
|
+
],
|
|
217
|
+
isError: true
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
const { client, refMap } = requireContext(context);
|
|
221
|
+
const result = await executeScroll(client, refMap, params);
|
|
222
|
+
return {
|
|
223
|
+
content: [
|
|
224
|
+
{
|
|
225
|
+
type: 'text' as const,
|
|
226
|
+
text: `Scrolled to (${result.scrollX}, ${result.scrollY})`
|
|
227
|
+
}
|
|
228
|
+
]
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
);
|
|
232
|
+
}
|
package/src/mcp/tools/names.ts
CHANGED
|
@@ -19,7 +19,25 @@ export const EXPECTED_TOOLS = [
|
|
|
19
19
|
'browser_viewport_resize',
|
|
20
20
|
'browser_get_console_logs',
|
|
21
21
|
'browser_get_errors',
|
|
22
|
-
'browser_clear_errors'
|
|
22
|
+
'browser_clear_errors',
|
|
23
|
+
'browser_snapshot',
|
|
24
|
+
'browser_find',
|
|
25
|
+
'browser_fill',
|
|
26
|
+
'browser_hover',
|
|
27
|
+
'browser_press_key',
|
|
28
|
+
'browser_select',
|
|
29
|
+
'browser_check',
|
|
30
|
+
'browser_scroll',
|
|
31
|
+
'browser_network',
|
|
32
|
+
'browser_console',
|
|
33
|
+
'browser_errors',
|
|
34
|
+
'browser_styles',
|
|
35
|
+
'browser_dialog',
|
|
36
|
+
'browser_upload',
|
|
37
|
+
'browser_downloads',
|
|
38
|
+
'browser_performance',
|
|
39
|
+
'browser_connect',
|
|
40
|
+
'browser_tabs'
|
|
23
41
|
] as const;
|
|
24
42
|
|
|
25
43
|
export type ToolName = (typeof EXPECTED_TOOLS)[number];
|