@everydaydevopsio/pilot 0.5.2 → 0.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.
Files changed (306) hide show
  1. package/.mcp.json +9 -0
  2. package/AGENTS.md +9 -0
  3. package/CHANGELOG.md +64 -0
  4. package/CLAUDE.md +7 -7
  5. package/README.md +282 -69
  6. package/dist/browser/browser-manager.d.ts +60 -0
  7. package/dist/browser/browser-manager.d.ts.map +1 -0
  8. package/dist/browser/browser-manager.js +355 -0
  9. package/dist/browser/browser-manager.js.map +1 -0
  10. package/dist/browser/chrome-launcher.d.ts +31 -0
  11. package/dist/browser/chrome-launcher.d.ts.map +1 -0
  12. package/dist/browser/chrome-launcher.js +225 -0
  13. package/dist/browser/chrome-launcher.js.map +1 -0
  14. package/dist/browser/connection.d.ts +23 -0
  15. package/dist/browser/connection.d.ts.map +1 -0
  16. package/dist/browser/connection.js +53 -0
  17. package/dist/browser/connection.js.map +1 -0
  18. package/dist/browser/events.d.ts +9 -0
  19. package/dist/browser/events.d.ts.map +1 -0
  20. package/dist/browser/events.js +99 -0
  21. package/dist/browser/events.js.map +1 -0
  22. package/dist/browser/index.d.ts +4 -0
  23. package/dist/browser/index.d.ts.map +1 -0
  24. package/dist/browser/index.js +4 -0
  25. package/dist/browser/index.js.map +1 -0
  26. package/dist/browser/inspect/element-ref.d.ts +23 -0
  27. package/dist/browser/inspect/element-ref.d.ts.map +1 -0
  28. package/dist/browser/inspect/element-ref.js +52 -0
  29. package/dist/browser/inspect/element-ref.js.map +1 -0
  30. package/dist/browser/inspect/snapshot.d.ts +11 -0
  31. package/dist/browser/inspect/snapshot.d.ts.map +1 -0
  32. package/dist/browser/inspect/snapshot.js +282 -0
  33. package/dist/browser/inspect/snapshot.js.map +1 -0
  34. package/dist/browser/inspect/styles.d.ts +45 -0
  35. package/dist/browser/inspect/styles.d.ts.map +1 -0
  36. package/dist/browser/inspect/styles.js +190 -0
  37. package/dist/browser/inspect/styles.js.map +1 -0
  38. package/dist/browser/inspect/types.d.ts +35 -0
  39. package/dist/browser/inspect/types.d.ts.map +1 -0
  40. package/dist/browser/inspect/types.js +2 -0
  41. package/dist/browser/inspect/types.js.map +1 -0
  42. package/dist/browser/interaction/dialogs.d.ts +18 -0
  43. package/dist/browser/interaction/dialogs.d.ts.map +1 -0
  44. package/dist/browser/interaction/dialogs.js +35 -0
  45. package/dist/browser/interaction/dialogs.js.map +1 -0
  46. package/dist/browser/interaction/downloads.d.ts +23 -0
  47. package/dist/browser/interaction/downloads.d.ts.map +1 -0
  48. package/dist/browser/interaction/downloads.js +87 -0
  49. package/dist/browser/interaction/downloads.js.map +1 -0
  50. package/dist/browser/interaction/events.d.ts +17 -0
  51. package/dist/browser/interaction/events.d.ts.map +1 -0
  52. package/dist/browser/interaction/events.js +66 -0
  53. package/dist/browser/interaction/events.js.map +1 -0
  54. package/dist/browser/interaction/ref-resolver.d.ts +18 -0
  55. package/dist/browser/interaction/ref-resolver.d.ts.map +1 -0
  56. package/dist/browser/interaction/ref-resolver.js +32 -0
  57. package/dist/browser/interaction/ref-resolver.js.map +1 -0
  58. package/dist/browser/interaction/uploads.d.ts +4 -0
  59. package/dist/browser/interaction/uploads.d.ts.map +1 -0
  60. package/dist/browser/interaction/uploads.js +43 -0
  61. package/dist/browser/interaction/uploads.js.map +1 -0
  62. package/dist/browser/network/network-buffer.d.ts +19 -0
  63. package/dist/browser/network/network-buffer.d.ts.map +1 -0
  64. package/dist/browser/network/network-buffer.js +118 -0
  65. package/dist/browser/network/network-buffer.js.map +1 -0
  66. package/dist/browser/network/network-monitor.d.ts +8 -0
  67. package/dist/browser/network/network-monitor.d.ts.map +1 -0
  68. package/dist/browser/network/network-monitor.js +85 -0
  69. package/dist/browser/network/network-monitor.js.map +1 -0
  70. package/dist/browser/network/redaction.d.ts +3 -0
  71. package/dist/browser/network/redaction.d.ts.map +1 -0
  72. package/dist/browser/network/redaction.js +36 -0
  73. package/dist/browser/network/redaction.js.map +1 -0
  74. package/dist/browser/network/types.d.ts +45 -0
  75. package/dist/browser/network/types.d.ts.map +1 -0
  76. package/dist/browser/network/types.js +2 -0
  77. package/dist/browser/network/types.js.map +1 -0
  78. package/dist/browser/performance/analyze.d.ts +5 -0
  79. package/dist/browser/performance/analyze.d.ts.map +1 -0
  80. package/dist/browser/performance/analyze.js +230 -0
  81. package/dist/browser/performance/analyze.js.map +1 -0
  82. package/dist/browser/performance/trace.d.ts +10 -0
  83. package/dist/browser/performance/trace.d.ts.map +1 -0
  84. package/dist/browser/performance/trace.js +38 -0
  85. package/dist/browser/performance/trace.js.map +1 -0
  86. package/dist/browser/performance/types.d.ts +31 -0
  87. package/dist/browser/performance/types.d.ts.map +1 -0
  88. package/dist/browser/performance/types.js +2 -0
  89. package/dist/browser/performance/types.js.map +1 -0
  90. package/dist/browser/preflight.d.ts +20 -0
  91. package/dist/browser/preflight.d.ts.map +1 -0
  92. package/dist/browser/preflight.js +105 -0
  93. package/dist/browser/preflight.js.map +1 -0
  94. package/dist/browser/security/origins.d.ts +18 -0
  95. package/dist/browser/security/origins.d.ts.map +1 -0
  96. package/dist/browser/security/origins.js +84 -0
  97. package/dist/browser/security/origins.js.map +1 -0
  98. package/dist/browser/tabs.d.ts +15 -0
  99. package/dist/browser/tabs.d.ts.map +1 -0
  100. package/dist/browser/tabs.js +71 -0
  101. package/dist/browser/tabs.js.map +1 -0
  102. package/dist/browser/types.d.ts +32 -0
  103. package/dist/browser/types.d.ts.map +1 -0
  104. package/dist/browser/types.js +2 -0
  105. package/dist/browser/types.js.map +1 -0
  106. package/dist/browser.d.ts +2 -99
  107. package/dist/browser.d.ts.map +1 -1
  108. package/dist/browser.js +3 -653
  109. package/dist/browser.js.map +1 -1
  110. package/dist/cli/init.d.ts +3 -0
  111. package/dist/cli/init.d.ts.map +1 -1
  112. package/dist/cli/init.js +33 -48
  113. package/dist/cli/init.js.map +1 -1
  114. package/dist/cli/linux-check.d.ts +2 -0
  115. package/dist/cli/linux-check.d.ts.map +1 -0
  116. package/dist/cli/linux-check.js +20 -0
  117. package/dist/cli/linux-check.js.map +1 -0
  118. package/dist/cli/skill-template.d.ts +1 -1
  119. package/dist/cli/skill-template.d.ts.map +1 -1
  120. package/dist/cli/skill-template.js +3 -113
  121. package/dist/cli/skill-template.js.map +1 -1
  122. package/dist/commands/check.d.ts +17 -0
  123. package/dist/commands/check.d.ts.map +1 -0
  124. package/dist/commands/check.js +38 -0
  125. package/dist/commands/check.js.map +1 -0
  126. package/dist/commands/click.d.ts +3 -1
  127. package/dist/commands/click.d.ts.map +1 -1
  128. package/dist/commands/click.js +16 -4
  129. package/dist/commands/click.js.map +1 -1
  130. package/dist/commands/connect.d.ts +14 -0
  131. package/dist/commands/connect.d.ts.map +1 -0
  132. package/dist/commands/connect.js +19 -0
  133. package/dist/commands/connect.js.map +1 -0
  134. package/dist/commands/dialog.d.ts +19 -0
  135. package/dist/commands/dialog.d.ts.map +1 -0
  136. package/dist/commands/dialog.js +51 -0
  137. package/dist/commands/dialog.js.map +1 -0
  138. package/dist/commands/downloads.d.ts +30 -0
  139. package/dist/commands/downloads.d.ts.map +1 -0
  140. package/dist/commands/downloads.js +66 -0
  141. package/dist/commands/downloads.js.map +1 -0
  142. package/dist/commands/fill.d.ts +16 -0
  143. package/dist/commands/fill.d.ts.map +1 -0
  144. package/dist/commands/fill.js +15 -0
  145. package/dist/commands/fill.js.map +1 -0
  146. package/dist/commands/find.d.ts +14 -0
  147. package/dist/commands/find.d.ts.map +1 -0
  148. package/dist/commands/find.js +26 -0
  149. package/dist/commands/find.js.map +1 -0
  150. package/dist/commands/hover.d.ts +13 -0
  151. package/dist/commands/hover.d.ts.map +1 -0
  152. package/dist/commands/hover.js +24 -0
  153. package/dist/commands/hover.js.map +1 -0
  154. package/dist/commands/navigate.d.ts.map +1 -1
  155. package/dist/commands/navigate.js +13 -0
  156. package/dist/commands/navigate.js.map +1 -1
  157. package/dist/commands/network.d.ts +33 -0
  158. package/dist/commands/network.d.ts.map +1 -0
  159. package/dist/commands/network.js +84 -0
  160. package/dist/commands/network.js.map +1 -0
  161. package/dist/commands/performance.d.ts +12 -0
  162. package/dist/commands/performance.d.ts.map +1 -0
  163. package/dist/commands/performance.js +26 -0
  164. package/dist/commands/performance.js.map +1 -0
  165. package/dist/commands/press_key.d.ts +10 -0
  166. package/dist/commands/press_key.d.ts.map +1 -0
  167. package/dist/commands/press_key.js +103 -0
  168. package/dist/commands/press_key.js.map +1 -0
  169. package/dist/commands/scroll.d.ts +21 -0
  170. package/dist/commands/scroll.d.ts.map +1 -0
  171. package/dist/commands/scroll.js +54 -0
  172. package/dist/commands/scroll.js.map +1 -0
  173. package/dist/commands/select.d.ts +18 -0
  174. package/dist/commands/select.d.ts.map +1 -0
  175. package/dist/commands/select.js +53 -0
  176. package/dist/commands/select.js.map +1 -0
  177. package/dist/commands/snapshot.d.ts +9 -0
  178. package/dist/commands/snapshot.d.ts.map +1 -0
  179. package/dist/commands/snapshot.js +7 -0
  180. package/dist/commands/snapshot.js.map +1 -0
  181. package/dist/commands/styles.d.ts +13 -0
  182. package/dist/commands/styles.d.ts.map +1 -0
  183. package/dist/commands/styles.js +7 -0
  184. package/dist/commands/styles.js.map +1 -0
  185. package/dist/commands/type.d.ts +3 -1
  186. package/dist/commands/type.d.ts.map +1 -1
  187. package/dist/commands/type.js +11 -2
  188. package/dist/commands/type.js.map +1 -1
  189. package/dist/commands/upload.d.ts +12 -0
  190. package/dist/commands/upload.d.ts.map +1 -0
  191. package/dist/commands/upload.js +13 -0
  192. package/dist/commands/upload.js.map +1 -0
  193. package/dist/mcp/console-buffer.d.ts +9 -0
  194. package/dist/mcp/console-buffer.d.ts.map +1 -1
  195. package/dist/mcp/console-buffer.js.map +1 -1
  196. package/dist/mcp/index.js +20 -2
  197. package/dist/mcp/index.js.map +1 -1
  198. package/dist/mcp/server.d.ts +10 -0
  199. package/dist/mcp/server.d.ts.map +1 -1
  200. package/dist/mcp/server.js +63 -2
  201. package/dist/mcp/server.js.map +1 -1
  202. package/dist/mcp/tools/browser.d.ts.map +1 -1
  203. package/dist/mcp/tools/browser.js +109 -11
  204. package/dist/mcp/tools/browser.js.map +1 -1
  205. package/dist/mcp/tools/connect.d.ts +5 -0
  206. package/dist/mcp/tools/connect.d.ts.map +1 -0
  207. package/dist/mcp/tools/connect.js +48 -0
  208. package/dist/mcp/tools/connect.js.map +1 -0
  209. package/dist/mcp/tools/files.d.ts +4 -0
  210. package/dist/mcp/tools/files.d.ts.map +1 -0
  211. package/dist/mcp/tools/files.js +85 -0
  212. package/dist/mcp/tools/files.js.map +1 -0
  213. package/dist/mcp/tools/interaction.d.ts +4 -0
  214. package/dist/mcp/tools/interaction.d.ts.map +1 -0
  215. package/dist/mcp/tools/interaction.js +176 -0
  216. package/dist/mcp/tools/interaction.js.map +1 -0
  217. package/dist/mcp/tools/names.d.ts +1 -1
  218. package/dist/mcp/tools/names.d.ts.map +1 -1
  219. package/dist/mcp/tools/names.js +19 -1
  220. package/dist/mcp/tools/names.js.map +1 -1
  221. package/dist/mcp/tools/network.d.ts +4 -0
  222. package/dist/mcp/tools/network.d.ts.map +1 -0
  223. package/dist/mcp/tools/network.js +68 -0
  224. package/dist/mcp/tools/network.js.map +1 -0
  225. package/dist/mcp/tools/performance.d.ts +4 -0
  226. package/dist/mcp/tools/performance.d.ts.map +1 -0
  227. package/dist/mcp/tools/performance.js +26 -0
  228. package/dist/mcp/tools/performance.js.map +1 -0
  229. package/dist/mcp/tools/runtime.d.ts +4 -0
  230. package/dist/mcp/tools/runtime.d.ts.map +1 -0
  231. package/dist/mcp/tools/runtime.js +128 -0
  232. package/dist/mcp/tools/runtime.js.map +1 -0
  233. package/dist/mcp/tools/snapshot.d.ts +4 -0
  234. package/dist/mcp/tools/snapshot.d.ts.map +1 -0
  235. package/dist/mcp/tools/snapshot.js +42 -0
  236. package/dist/mcp/tools/snapshot.js.map +1 -0
  237. package/dist/mcp/tools/styles.d.ts +4 -0
  238. package/dist/mcp/tools/styles.d.ts.map +1 -0
  239. package/dist/mcp/tools/styles.js +27 -0
  240. package/dist/mcp/tools/styles.js.map +1 -0
  241. package/dist/util/config.d.ts.map +1 -1
  242. package/dist/util/config.js +3 -2
  243. package/dist/util/config.js.map +1 -1
  244. package/package.json +5 -4
  245. package/skills/pilot/SKILL.md +48 -0
  246. package/src/browser/browser-manager.ts +465 -0
  247. package/src/browser/chrome-launcher.ts +282 -0
  248. package/src/browser/connection.ts +84 -0
  249. package/src/browser/events.ts +121 -0
  250. package/src/browser/index.ts +20 -0
  251. package/src/browser/inspect/element-ref.ts +68 -0
  252. package/src/browser/inspect/snapshot.ts +348 -0
  253. package/src/browser/inspect/styles.ts +258 -0
  254. package/src/browser/inspect/types.ts +37 -0
  255. package/src/browser/interaction/dialogs.ts +54 -0
  256. package/src/browser/interaction/downloads.ts +116 -0
  257. package/src/browser/interaction/events.ts +79 -0
  258. package/src/browser/interaction/ref-resolver.ts +53 -0
  259. package/src/browser/interaction/uploads.ts +60 -0
  260. package/src/browser/network/network-buffer.ts +133 -0
  261. package/src/browser/network/network-monitor.ts +107 -0
  262. package/src/browser/network/redaction.ts +42 -0
  263. package/src/browser/network/types.ts +47 -0
  264. package/src/browser/performance/analyze.ts +298 -0
  265. package/src/browser/performance/trace.ts +60 -0
  266. package/src/browser/performance/types.ts +34 -0
  267. package/src/browser/preflight.ts +144 -0
  268. package/src/browser/security/origins.ts +102 -0
  269. package/src/browser/tabs.ts +110 -0
  270. package/src/browser/types.ts +32 -0
  271. package/src/browser.ts +22 -798
  272. package/src/cli/init.ts +40 -49
  273. package/src/cli/linux-check.ts +23 -0
  274. package/src/cli/skill-template.ts +4 -113
  275. package/src/commands/check.ts +59 -0
  276. package/src/commands/click.ts +18 -4
  277. package/src/commands/connect.ts +40 -0
  278. package/src/commands/dialog.ts +79 -0
  279. package/src/commands/downloads.ts +111 -0
  280. package/src/commands/fill.ts +34 -0
  281. package/src/commands/find.ts +52 -0
  282. package/src/commands/hover.ts +42 -0
  283. package/src/commands/navigate.ts +20 -0
  284. package/src/commands/network.ts +141 -0
  285. package/src/commands/performance.ts +51 -0
  286. package/src/commands/press_key.ts +134 -0
  287. package/src/commands/scroll.ts +79 -0
  288. package/src/commands/select.ts +78 -0
  289. package/src/commands/snapshot.ts +18 -0
  290. package/src/commands/styles.ts +24 -0
  291. package/src/commands/type.ts +12 -2
  292. package/src/commands/upload.ts +36 -0
  293. package/src/mcp/console-buffer.ts +10 -0
  294. package/src/mcp/index.ts +24 -2
  295. package/src/mcp/server.ts +74 -2
  296. package/src/mcp/tools/browser.ts +125 -9
  297. package/src/mcp/tools/connect.ts +62 -0
  298. package/src/mcp/tools/files.ts +120 -0
  299. package/src/mcp/tools/interaction.ts +232 -0
  300. package/src/mcp/tools/names.ts +19 -1
  301. package/src/mcp/tools/network.ts +86 -0
  302. package/src/mcp/tools/performance.ts +40 -0
  303. package/src/mcp/tools/runtime.ts +164 -0
  304. package/src/mcp/tools/snapshot.ts +64 -0
  305. package/src/mcp/tools/styles.ts +41 -0
  306. package/src/util/config.ts +3 -2
@@ -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
+ }
@@ -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];
@@ -0,0 +1,86 @@
1
+ import { z } from 'zod';
2
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ import type { BrowserContext } from '../server.js';
4
+ import {
5
+ executeNetwork,
6
+ formatNetworkList,
7
+ formatNetworkDetail
8
+ } from '../../commands/network.js';
9
+
10
+ const networkShape = {
11
+ action: z
12
+ .enum(['list', 'get', 'clear'])
13
+ .describe('Action: list requests, get request detail, or clear buffer'),
14
+ requestId: z
15
+ .string()
16
+ .optional()
17
+ .describe('Request ID (required for "get" action)'),
18
+ url: z.string().optional().describe('Filter by URL substring (list only)'),
19
+ method: z
20
+ .string()
21
+ .optional()
22
+ .describe('Filter by HTTP method, e.g. GET, POST (list only)'),
23
+ statusMin: z
24
+ .number()
25
+ .int()
26
+ .optional()
27
+ .describe('Filter by minimum status code (list only)'),
28
+ statusMax: z
29
+ .number()
30
+ .int()
31
+ .optional()
32
+ .describe('Filter by maximum status code (list only)'),
33
+ resourceType: z
34
+ .string()
35
+ .optional()
36
+ .describe(
37
+ 'Filter by resource type: Document, Stylesheet, Script, Image, XHR, Fetch, etc. (list only)'
38
+ ),
39
+ failed: z
40
+ .boolean()
41
+ .optional()
42
+ .describe('Filter to only failed requests (list only)'),
43
+ limit: z
44
+ .number()
45
+ .int()
46
+ .positive()
47
+ .optional()
48
+ .describe('Maximum number of results (list only)')
49
+ };
50
+
51
+ function requireContext(context: BrowserContext) {
52
+ const manager = context.manager;
53
+ if (!manager || !manager.isConnected()) {
54
+ throw new Error('Browser not started. Call browser_start first.');
55
+ }
56
+ const client = manager.getClient()!;
57
+ return { client, networkBuffer: context.networkBuffer };
58
+ }
59
+
60
+ export function registerNetworkTools(
61
+ server: McpServer,
62
+ context: BrowserContext
63
+ ): void {
64
+ server.tool(
65
+ 'browser_network',
66
+ 'Inspect captured network requests. Actions: "list" shows request summaries with filters (url, method, status, resourceType, failed); "get" returns full detail for a request ID including headers and response body; "clear" resets the buffer.',
67
+ networkShape,
68
+ async (params) => {
69
+ const { client, networkBuffer } = requireContext(context);
70
+ const result = await executeNetwork(client, networkBuffer, params);
71
+
72
+ let text: string;
73
+ if (result.action === 'list') {
74
+ text = formatNetworkList(result);
75
+ } else if (result.action === 'get') {
76
+ text = formatNetworkDetail(result);
77
+ } else {
78
+ text = `Cleared ${result.cleared} network records.`;
79
+ }
80
+
81
+ return {
82
+ content: [{ type: 'text' as const, text }]
83
+ };
84
+ }
85
+ );
86
+ }
@@ -0,0 +1,40 @@
1
+ import { z } from 'zod';
2
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ import type { BrowserContext } from '../server.js';
4
+ import { executePerformance } from '../../commands/performance.js';
5
+
6
+ const performanceShape = {
7
+ action: z
8
+ .enum(['start', 'stop', 'analyze'])
9
+ .describe(
10
+ 'Action: "start" begins tracing, "stop" ends collection, "analyze" returns a summary of navigation timing, long tasks, slow requests, and large resources'
11
+ )
12
+ };
13
+
14
+ function requireContext(context: BrowserContext) {
15
+ const manager = context.manager;
16
+ if (!manager || !manager.isConnected()) {
17
+ throw new Error('Browser not started. Call browser_start first.');
18
+ }
19
+ return { client: manager.getClient()! };
20
+ }
21
+
22
+ export function registerPerformanceTools(
23
+ server: McpServer,
24
+ context: BrowserContext
25
+ ): void {
26
+ server.tool(
27
+ 'browser_performance',
28
+ 'Inspect page performance. Actions: "start" begins tracing (call before navigating), "stop" ends collection, "analyze" returns an agent-friendly summary with navigation timing, long tasks, slow requests, large resources, and JS execution time.',
29
+ performanceShape,
30
+ async ({ action }) => {
31
+ const { client } = requireContext(context);
32
+ const result = await executePerformance(client, context.traceState, {
33
+ action
34
+ });
35
+ return {
36
+ content: [{ type: 'text' as const, text: result.text }]
37
+ };
38
+ }
39
+ );
40
+ }
@@ -0,0 +1,164 @@
1
+ import { z } from 'zod';
2
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ import type {
4
+ ConsoleBuffer,
5
+ ConsoleLevel,
6
+ ConsoleMessage
7
+ } from '../console-buffer.js';
8
+
9
+ const consoleShape = {
10
+ action: z
11
+ .enum(['list', 'clear'])
12
+ .default('list')
13
+ .describe('Action: list messages or clear the buffer'),
14
+ level: z
15
+ .enum(['log', 'warn', 'error', 'info', 'debug'])
16
+ .optional()
17
+ .describe('Filter by single log level'),
18
+ levels: z
19
+ .array(z.enum(['log', 'warn', 'error', 'info', 'debug']))
20
+ .optional()
21
+ .describe('Filter by multiple log levels'),
22
+ sinceMs: z
23
+ .number()
24
+ .int()
25
+ .positive()
26
+ .optional()
27
+ .describe('Only messages from the last N milliseconds'),
28
+ limit: z
29
+ .number()
30
+ .int()
31
+ .positive()
32
+ .default(100)
33
+ .describe('Maximum messages to return')
34
+ };
35
+
36
+ const errorsShape = {
37
+ action: z
38
+ .enum(['list', 'clear'])
39
+ .default('list')
40
+ .describe('Action: list errors or clear the buffer'),
41
+ sinceMs: z
42
+ .number()
43
+ .int()
44
+ .positive()
45
+ .optional()
46
+ .describe('Only errors from the last N milliseconds'),
47
+ limit: z
48
+ .number()
49
+ .int()
50
+ .positive()
51
+ .default(50)
52
+ .describe('Maximum errors to return'),
53
+ includeWarnings: z
54
+ .boolean()
55
+ .default(false)
56
+ .describe('Include warnings in addition to errors')
57
+ };
58
+
59
+ // CDP line/column numbers are 0-based; convert to 1-based for display
60
+ function line1(n: number): number {
61
+ return n + 1;
62
+ }
63
+
64
+ function formatMessage(msg: ConsoleMessage): string {
65
+ const parts = [`[${msg.level.toUpperCase()}] ${msg.text}`];
66
+ if (msg.url) {
67
+ const col =
68
+ msg.columnNumber !== undefined ? `:${line1(msg.columnNumber)}` : '';
69
+ parts.push(` at ${msg.url}:${line1(msg.lineNumber)}${col}`);
70
+ }
71
+ if (msg.stackFrames && msg.stackFrames.length > 0) {
72
+ for (const frame of msg.stackFrames) {
73
+ const fn = frame.functionName || '<anonymous>';
74
+ parts.push(
75
+ ` at ${fn} (${frame.url}:${line1(frame.lineNumber)}:${line1(frame.columnNumber)})`
76
+ );
77
+ }
78
+ }
79
+ return parts.join('\n');
80
+ }
81
+
82
+ export function registerRuntimeTools(
83
+ server: McpServer,
84
+ buffer: ConsoleBuffer
85
+ ): void {
86
+ server.tool(
87
+ 'browser_console',
88
+ 'Get or clear console messages. Actions: "list" returns messages with optional level/sinceMs/limit filters; "clear" resets the buffer. Messages include source location and stack traces for exceptions.',
89
+ consoleShape,
90
+ async ({ action, level, levels, sinceMs, limit }) => {
91
+ if (action === 'clear') {
92
+ const cleared = buffer.clear();
93
+ return {
94
+ content: [
95
+ {
96
+ type: 'text' as const,
97
+ text: `Cleared ${cleared} console messages.`
98
+ }
99
+ ]
100
+ };
101
+ }
102
+
103
+ let filterLevels: ConsoleLevel | ConsoleLevel[] | undefined;
104
+ if (levels && levels.length > 0) {
105
+ filterLevels = levels as ConsoleLevel[];
106
+ } else if (level) {
107
+ filterLevels = level as ConsoleLevel;
108
+ }
109
+
110
+ const messages = buffer.getAll({ level: filterLevels, sinceMs, limit });
111
+
112
+ if (messages.length === 0) {
113
+ return {
114
+ content: [{ type: 'text' as const, text: 'No console messages.' }]
115
+ };
116
+ }
117
+
118
+ const formatted = messages.map(formatMessage).join('\n\n');
119
+ const header = `Console messages (${messages.length}):\n`;
120
+
121
+ return {
122
+ content: [{ type: 'text' as const, text: header + formatted }]
123
+ };
124
+ }
125
+ );
126
+
127
+ server.tool(
128
+ 'browser_errors',
129
+ 'Get or clear runtime errors and exceptions. Actions: "list" returns errors with stack traces; "clear" resets the buffer. Captures both console.error calls and uncaught exceptions.',
130
+ errorsShape,
131
+ async ({ action, sinceMs, limit, includeWarnings }) => {
132
+ if (action === 'clear') {
133
+ const cleared = buffer.clear();
134
+ return {
135
+ content: [
136
+ {
137
+ type: 'text' as const,
138
+ text: `Cleared ${cleared} console messages.`
139
+ }
140
+ ]
141
+ };
142
+ }
143
+
144
+ const levels: ConsoleLevel[] = includeWarnings
145
+ ? ['error', 'warn']
146
+ : ['error'];
147
+
148
+ const errors = buffer.getAll({ level: levels, sinceMs, limit });
149
+
150
+ if (errors.length === 0) {
151
+ return {
152
+ content: [{ type: 'text' as const, text: 'No errors found.' }]
153
+ };
154
+ }
155
+
156
+ const formatted = errors.map(formatMessage).join('\n\n');
157
+ const header = `Errors (${errors.length}):\n`;
158
+
159
+ return {
160
+ content: [{ type: 'text' as const, text: header + formatted }]
161
+ };
162
+ }
163
+ );
164
+ }
@@ -0,0 +1,64 @@
1
+ import { z } from 'zod';
2
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ import type { BrowserContext } from '../server.js';
4
+ import { executeSnapshot } from '../../commands/snapshot.js';
5
+ import { executeFind } from '../../commands/find.js';
6
+
7
+ const findShape = {
8
+ role: z
9
+ .string()
10
+ .optional()
11
+ .describe(
12
+ 'Filter by ARIA role (e.g. button, link, textbox, checkbox, radio, heading)'
13
+ ),
14
+ name: z
15
+ .string()
16
+ .optional()
17
+ .describe('Filter by accessible name (substring, case-insensitive)'),
18
+ text: z
19
+ .string()
20
+ .optional()
21
+ .describe(
22
+ 'Filter by text content — matches name, value, or description (substring, case-insensitive)'
23
+ )
24
+ };
25
+
26
+ function requireContext(context: BrowserContext) {
27
+ const manager = context.manager;
28
+ if (!manager || !manager.isConnected()) {
29
+ throw new Error('Browser not started. Call browser_start first.');
30
+ }
31
+ const client = manager.getClient()!;
32
+ return { client, refMap: context.elementRefMap };
33
+ }
34
+
35
+ export function registerSnapshotTools(
36
+ server: McpServer,
37
+ context: BrowserContext
38
+ ): void {
39
+ server.tool(
40
+ 'browser_snapshot',
41
+ 'Capture a structured accessibility snapshot of the current page. Returns interactive and meaningful elements with short refs (e1, e2, ...) that can be used with browser_click and other interaction tools instead of CSS selectors.',
42
+ {},
43
+ async () => {
44
+ const { client, refMap } = requireContext(context);
45
+ const result = await executeSnapshot(client, refMap);
46
+ return {
47
+ content: [{ type: 'text' as const, text: result.text }]
48
+ };
49
+ }
50
+ );
51
+
52
+ server.tool(
53
+ 'browser_find',
54
+ 'Find elements in the current page matching a query. Takes a new snapshot and filters by role, name, or text. Returns matching elements with refs.',
55
+ findShape,
56
+ async ({ role, name, text }) => {
57
+ const { client, refMap } = requireContext(context);
58
+ const result = await executeFind(client, refMap, { role, name, text });
59
+ return {
60
+ content: [{ type: 'text' as const, text: result.text }]
61
+ };
62
+ }
63
+ );
64
+ }
@@ -0,0 +1,41 @@
1
+ import { z } from 'zod';
2
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ import type { BrowserContext } from '../server.js';
4
+ import { executeStyles } from '../../commands/styles.js';
5
+
6
+ const stylesShape = {
7
+ ref: z.string().describe('Element ref from browser_snapshot (e.g. "e3")'),
8
+ properties: z
9
+ .array(z.string())
10
+ .optional()
11
+ .describe(
12
+ 'CSS properties to return (e.g. ["display", "color"]). Omit for a default diagnostic set covering layout, visibility, and common properties.'
13
+ )
14
+ };
15
+
16
+ function requireContext(context: BrowserContext) {
17
+ const manager = context.manager;
18
+ if (!manager || !manager.isConnected()) {
19
+ throw new Error('Browser not started. Call browser_start first.');
20
+ }
21
+ const client = manager.getClient()!;
22
+ return { client, refMap: context.elementRefMap };
23
+ }
24
+
25
+ export function registerStylesTools(
26
+ server: McpServer,
27
+ context: BrowserContext
28
+ ): void {
29
+ server.tool(
30
+ 'browser_styles',
31
+ 'Inspect computed styles, matched CSS rules, and box model for an element by ref. Helps diagnose visibility issues (display:none, opacity:0), layout problems (margins, positioning, overflow), and identify which CSS rule is responsible for a property. Use browser_snapshot first to get refs.',
32
+ stylesShape,
33
+ async ({ ref, properties }) => {
34
+ const { client, refMap } = requireContext(context);
35
+ const result = await executeStyles(client, refMap, { ref, properties });
36
+ return {
37
+ content: [{ type: 'text' as const, text: result.text }]
38
+ };
39
+ }
40
+ );
41
+ }
@@ -9,7 +9,7 @@ const ConfigSchema = z.object({
9
9
  .enum(['trace', 'debug', 'info', 'warn', 'error', 'fatal'])
10
10
  .default('info'),
11
11
  chromePath: z.string().optional(),
12
- headless: z.boolean().default(true),
12
+ headless: z.boolean().default(false),
13
13
  profileName: z.string().default('profile1'),
14
14
  viewport: z.string().default('desktop'),
15
15
  responsive: z.boolean().optional()
@@ -44,7 +44,8 @@ export function loadConfig(cliArgs: CliArgs = {}): Config {
44
44
  chromePath: process.env.PILOT_CHROME_PATH,
45
45
  headless:
46
46
  process.env.PILOT_HEADLESS !== undefined
47
- ? process.env.PILOT_HEADLESS !== 'false'
47
+ ? process.env.PILOT_HEADLESS === 'true' ||
48
+ process.env.PILOT_HEADLESS === '1'
48
49
  : undefined,
49
50
  profileName: process.env.PILOT_PROFILE_NAME,
50
51
  viewport: process.env.PILOT_VIEWPORT,