@diegosouzacdv/jev-browser-mcp 0.6.0 → 0.6.2
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/README.md +176 -66
- package/config/ui-testing.json +20 -3
- package/docs/jev-browser-mcp.md +176 -66
- package/mcp_servers/jev-browser-npm/src/accessibility.mjs +18 -9
- package/mcp_servers/jev-browser-npm/src/config.mjs +109 -52
- package/mcp_servers/jev-browser-npm/src/flow.mjs +1181 -315
- package/mcp_servers/jev-browser-npm/src/jev-client.mjs +22 -9
- package/mcp_servers/jev-browser-npm/src/server.mjs +109 -30
- package/package.json +1 -1
|
@@ -16,23 +16,31 @@ const CONFIG_KEYS = {
|
|
|
16
16
|
"max_flow_steps",
|
|
17
17
|
"max_text_entry_chars",
|
|
18
18
|
],
|
|
19
|
-
nodeBrowser: [
|
|
20
|
-
"max_action_timeout_seconds",
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
19
|
+
nodeBrowser: [
|
|
20
|
+
"max_action_timeout_seconds",
|
|
21
|
+
"mutation_confirmation_ttl_seconds",
|
|
22
|
+
"ready_timeout_seconds_default",
|
|
23
|
+
"max_ready_timeout_seconds",
|
|
24
|
+
"ready_network_idle_default",
|
|
25
|
+
"ready_stable_ms_default",
|
|
26
|
+
"max_ready_stable_ms",
|
|
27
|
+
"post_step_ready_timeout_seconds_default",
|
|
28
|
+
"max_step_timeout_seconds",
|
|
29
|
+
"key_delay_ms_default",
|
|
30
|
+
"reuse_page_default",
|
|
31
|
+
"stop_on_expected_default",
|
|
32
|
+
"snapshot_include_hidden_default",
|
|
33
|
+
"visibility_poll_interval_ms_default",
|
|
34
|
+
"capture_network_error_bodies_default",
|
|
34
35
|
"max_network_error_body_bytes",
|
|
35
36
|
"max_network_error_message_chars",
|
|
37
|
+
"max_network_history_events",
|
|
38
|
+
"max_tool_response_bytes",
|
|
39
|
+
"max_viewport_width",
|
|
40
|
+
"max_viewport_height",
|
|
41
|
+
"accessibility_fail_on_impact_default",
|
|
42
|
+
"record_video_width",
|
|
43
|
+
"record_video_height",
|
|
36
44
|
"max_upload_files",
|
|
37
45
|
"max_upload_path_chars",
|
|
38
46
|
"max_upload_file_bytes",
|
|
@@ -47,10 +55,19 @@ const CONFIG_KEYS = {
|
|
|
47
55
|
"max_frame_snapshots",
|
|
48
56
|
"fast_path_single_plan_default",
|
|
49
57
|
"screenshot_on_failure_default",
|
|
50
|
-
"trace_on_failure_default",
|
|
58
|
+
"trace_on_failure_default",
|
|
59
|
+
"trace_on_success_default",
|
|
51
60
|
"capture_console_errors_default",
|
|
52
61
|
"capture_network_errors_default",
|
|
53
62
|
"block_trackers_default",
|
|
63
|
+
"block_fonts_default",
|
|
64
|
+
"local_only_default",
|
|
65
|
+
"auto_angular_idle_default",
|
|
66
|
+
"return_snapshot_default",
|
|
67
|
+
"busy_selectors_default",
|
|
68
|
+
"login_url_contains_default",
|
|
69
|
+
"login_text_default",
|
|
70
|
+
"max_busy_selectors",
|
|
54
71
|
"snapshot_scope_default",
|
|
55
72
|
"tracker_host_suffixes",
|
|
56
73
|
"blocked_resource_types",
|
|
@@ -221,7 +238,7 @@ export function loadSettings({ env = process.env, configPath = CONFIG_PATH } = {
|
|
|
221
238
|
const uploadRoot = configuredUploadRoot
|
|
222
239
|
? configuredDirectory(configuredUploadRoot, `environment ${uploadRootEnv}`)
|
|
223
240
|
: null;
|
|
224
|
-
const snapshotScope = browserOptions.snapshot_scope_default;
|
|
241
|
+
const snapshotScope = browserOptions.snapshot_scope_default;
|
|
225
242
|
if (!new Set(["body", "main", "dialog"]).has(snapshotScope)) {
|
|
226
243
|
throw new JevBrowserError("config/ui-testing.json jev_browser_mcp.browser.snapshot_scope_default must be body, main, or dialog");
|
|
227
244
|
}
|
|
@@ -230,28 +247,49 @@ export function loadSettings({ env = process.env, configPath = CONFIG_PATH } = {
|
|
|
230
247
|
"jev_browser_mcp.browser.tracker_host_suffixes",
|
|
231
248
|
(host) => /^[a-z0-9.-]+$/i.test(host) && !host.startsWith(".") && !host.endsWith("."),
|
|
232
249
|
);
|
|
233
|
-
const blockedResourceTypes = stringList(
|
|
250
|
+
const blockedResourceTypes = stringList(
|
|
234
251
|
browserOptions.blocked_resource_types,
|
|
235
252
|
"jev_browser_mcp.browser.blocked_resource_types",
|
|
236
253
|
(type) => new Set(["font", "media", "image"]).has(type),
|
|
237
|
-
);
|
|
238
|
-
const
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
if (
|
|
243
|
-
throw new JevBrowserError("config/ui-testing.json
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
|
|
254
|
+
);
|
|
255
|
+
const busySelectorsDefault = stringList(
|
|
256
|
+
browserOptions.busy_selectors_default,
|
|
257
|
+
"jev_browser_mcp.browser.busy_selectors_default",
|
|
258
|
+
);
|
|
259
|
+
if (busySelectorsDefault.length > positiveNumber(browserOptions.max_busy_selectors, "jev_browser_mcp.browser.max_busy_selectors", true)) {
|
|
260
|
+
throw new JevBrowserError("config/ui-testing.json busy_selectors_default exceeds max_busy_selectors");
|
|
261
|
+
}
|
|
262
|
+
const loginUrlContainsDefault = stringList(
|
|
263
|
+
browserOptions.login_url_contains_default,
|
|
264
|
+
"jev_browser_mcp.browser.login_url_contains_default",
|
|
265
|
+
);
|
|
266
|
+
const loginTextDefault = stringList(
|
|
267
|
+
browserOptions.login_text_default,
|
|
268
|
+
"jev_browser_mcp.browser.login_text_default",
|
|
269
|
+
);
|
|
270
|
+
if (!new Set(["none", "diff", "full"]).has(browserOptions.return_snapshot_default)) {
|
|
271
|
+
throw new JevBrowserError("config/ui-testing.json return_snapshot_default must be none, diff, or full");
|
|
247
272
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
"jev_browser_mcp.browser.post_step_ready_timeout_seconds_default",
|
|
251
|
-
);
|
|
252
|
-
if (postStepReadyTimeoutSeconds > maxReadyTimeoutSeconds) {
|
|
253
|
-
throw new JevBrowserError("config/ui-testing.json post-step readiness timeout exceeds its configured maximum");
|
|
273
|
+
if (!new Set(["minor", "moderate", "serious", "critical"]).has(browserOptions.accessibility_fail_on_impact_default)) {
|
|
274
|
+
throw new JevBrowserError("config/ui-testing.json accessibility_fail_on_impact_default must be minor, moderate, serious, or critical");
|
|
254
275
|
}
|
|
276
|
+
const maxReadyTimeoutSeconds = positiveNumber(browserOptions.max_ready_timeout_seconds, "jev_browser_mcp.browser.max_ready_timeout_seconds");
|
|
277
|
+
const readyTimeoutSecondsDefault = positiveNumber(browserOptions.ready_timeout_seconds_default, "jev_browser_mcp.browser.ready_timeout_seconds_default");
|
|
278
|
+
const maxReadyStableMs = positiveNumber(browserOptions.max_ready_stable_ms, "jev_browser_mcp.browser.max_ready_stable_ms", true);
|
|
279
|
+
const readyStableMsDefault = positiveNumber(browserOptions.ready_stable_ms_default, "jev_browser_mcp.browser.ready_stable_ms_default", true);
|
|
280
|
+
if (readyTimeoutSecondsDefault > maxReadyTimeoutSeconds) {
|
|
281
|
+
throw new JevBrowserError("config/ui-testing.json ready timeout default exceeds its configured maximum");
|
|
282
|
+
}
|
|
283
|
+
if (readyStableMsDefault > maxReadyStableMs) {
|
|
284
|
+
throw new JevBrowserError("config/ui-testing.json stable snapshot default exceeds its configured maximum");
|
|
285
|
+
}
|
|
286
|
+
const postStepReadyTimeoutSeconds = positiveNumber(
|
|
287
|
+
browserOptions.post_step_ready_timeout_seconds_default,
|
|
288
|
+
"jev_browser_mcp.browser.post_step_ready_timeout_seconds_default",
|
|
289
|
+
);
|
|
290
|
+
if (postStepReadyTimeoutSeconds > maxReadyTimeoutSeconds) {
|
|
291
|
+
throw new JevBrowserError("config/ui-testing.json post-step readiness timeout exceeds its configured maximum");
|
|
292
|
+
}
|
|
255
293
|
|
|
256
294
|
return Object.freeze({
|
|
257
295
|
env,
|
|
@@ -261,15 +299,25 @@ export function loadSettings({ env = process.env, configPath = CONFIG_PATH } = {
|
|
|
261
299
|
profileDir: profileDirectory(profileTemplate, channel, env.JEV_BROWSER_PROFILE),
|
|
262
300
|
maxFlowSteps: positiveNumber(document.browser.max_flow_steps, "browser.max_flow_steps", true),
|
|
263
301
|
maxTextEntryChars: positiveNumber(document.browser.max_text_entry_chars, "browser.max_text_entry_chars", true),
|
|
264
|
-
actionTimeoutMs: positiveNumber(browserOptions.max_action_timeout_seconds, "jev_browser_mcp.browser.max_action_timeout_seconds") * 1000,
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
302
|
+
actionTimeoutMs: positiveNumber(browserOptions.max_action_timeout_seconds, "jev_browser_mcp.browser.max_action_timeout_seconds") * 1000,
|
|
303
|
+
mutationConfirmationTtlMs: positiveNumber(browserOptions.mutation_confirmation_ttl_seconds, "jev_browser_mcp.browser.mutation_confirmation_ttl_seconds") * 1000,
|
|
304
|
+
maxReadyTimeoutSeconds,
|
|
305
|
+
maxReadyStableMs,
|
|
306
|
+
postStepReadyTimeoutMs: postStepReadyTimeoutSeconds * 1000,
|
|
307
|
+
maxStepTimeoutSeconds: positiveNumber(browserOptions.max_step_timeout_seconds, "jev_browser_mcp.browser.max_step_timeout_seconds"),
|
|
308
|
+
keyDelayMs: positiveNumber(browserOptions.key_delay_ms_default, "jev_browser_mcp.browser.key_delay_ms_default", true),
|
|
309
|
+
visibilityPollMs: positiveNumber(browserOptions.visibility_poll_interval_ms_default, "jev_browser_mcp.browser.visibility_poll_interval_ms_default", true),
|
|
310
|
+
maxNetworkErrorBodyBytes: positiveNumber(browserOptions.max_network_error_body_bytes, "jev_browser_mcp.browser.max_network_error_body_bytes", true),
|
|
272
311
|
maxNetworkErrorMessageChars: positiveNumber(browserOptions.max_network_error_message_chars, "jev_browser_mcp.browser.max_network_error_message_chars", true),
|
|
312
|
+
maxNetworkHistoryEvents: positiveNumber(browserOptions.max_network_history_events, "jev_browser_mcp.browser.max_network_history_events", true),
|
|
313
|
+
maxToolResponseBytes: positiveNumber(browserOptions.max_tool_response_bytes, "jev_browser_mcp.browser.max_tool_response_bytes", true),
|
|
314
|
+
maxViewportWidth: positiveNumber(browserOptions.max_viewport_width, "jev_browser_mcp.browser.max_viewport_width", true),
|
|
315
|
+
maxViewportHeight: positiveNumber(browserOptions.max_viewport_height, "jev_browser_mcp.browser.max_viewport_height", true),
|
|
316
|
+
accessibilityFailOnImpactDefault: browserOptions.accessibility_fail_on_impact_default,
|
|
317
|
+
recordVideoSize: Object.freeze({
|
|
318
|
+
width: positiveNumber(browserOptions.record_video_width, "jev_browser_mcp.browser.record_video_width", true),
|
|
319
|
+
height: positiveNumber(browserOptions.record_video_height, "jev_browser_mcp.browser.record_video_height", true),
|
|
320
|
+
}),
|
|
273
321
|
maxUploadFiles: positiveNumber(browserOptions.max_upload_files, "jev_browser_mcp.browser.max_upload_files", true),
|
|
274
322
|
maxUploadPathChars: positiveNumber(browserOptions.max_upload_path_chars, "jev_browser_mcp.browser.max_upload_path_chars", true),
|
|
275
323
|
maxUploadFileBytes: positiveNumber(browserOptions.max_upload_file_bytes, "jev_browser_mcp.browser.max_upload_file_bytes", true),
|
|
@@ -284,21 +332,30 @@ export function loadSettings({ env = process.env, configPath = CONFIG_PATH } = {
|
|
|
284
332
|
defaults: Object.freeze({
|
|
285
333
|
fastPath: booleanValue(browserOptions.fast_path_single_plan_default, "jev_browser_mcp.browser.fast_path_single_plan_default"),
|
|
286
334
|
screenshotOnFailure: booleanValue(browserOptions.screenshot_on_failure_default, "jev_browser_mcp.browser.screenshot_on_failure_default"),
|
|
287
|
-
traceOnFailure: booleanValue(browserOptions.trace_on_failure_default, "jev_browser_mcp.browser.trace_on_failure_default"),
|
|
335
|
+
traceOnFailure: booleanValue(browserOptions.trace_on_failure_default, "jev_browser_mcp.browser.trace_on_failure_default"),
|
|
336
|
+
traceOnSuccess: booleanValue(browserOptions.trace_on_success_default, "jev_browser_mcp.browser.trace_on_success_default"),
|
|
288
337
|
captureConsoleErrors: booleanValue(browserOptions.capture_console_errors_default, "jev_browser_mcp.browser.capture_console_errors_default"),
|
|
289
|
-
captureNetworkErrors: booleanValue(browserOptions.capture_network_errors_default, "jev_browser_mcp.browser.capture_network_errors_default"),
|
|
290
|
-
captureNetworkErrorBodies: booleanValue(browserOptions.capture_network_error_bodies_default, "jev_browser_mcp.browser.capture_network_error_bodies_default"),
|
|
291
|
-
blockTrackers: booleanValue(browserOptions.block_trackers_default, "jev_browser_mcp.browser.block_trackers_default"),
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
338
|
+
captureNetworkErrors: booleanValue(browserOptions.capture_network_errors_default, "jev_browser_mcp.browser.capture_network_errors_default"),
|
|
339
|
+
captureNetworkErrorBodies: booleanValue(browserOptions.capture_network_error_bodies_default, "jev_browser_mcp.browser.capture_network_error_bodies_default"),
|
|
340
|
+
blockTrackers: booleanValue(browserOptions.block_trackers_default, "jev_browser_mcp.browser.block_trackers_default"),
|
|
341
|
+
blockFonts: booleanValue(browserOptions.block_fonts_default, "jev_browser_mcp.browser.block_fonts_default"),
|
|
342
|
+
localOnly: booleanValue(browserOptions.local_only_default, "jev_browser_mcp.browser.local_only_default"),
|
|
343
|
+
autoAngularIdle: booleanValue(browserOptions.auto_angular_idle_default, "jev_browser_mcp.browser.auto_angular_idle_default"),
|
|
344
|
+
returnSnapshot: browserOptions.return_snapshot_default,
|
|
345
|
+
readyNetworkIdle: booleanValue(browserOptions.ready_network_idle_default, "jev_browser_mcp.browser.ready_network_idle_default"),
|
|
346
|
+
reusePage: booleanValue(browserOptions.reuse_page_default, "jev_browser_mcp.browser.reuse_page_default"),
|
|
347
|
+
stopOnExpected: booleanValue(browserOptions.stop_on_expected_default, "jev_browser_mcp.browser.stop_on_expected_default"),
|
|
348
|
+
snapshotIncludeHidden: booleanValue(browserOptions.snapshot_include_hidden_default, "jev_browser_mcp.browser.snapshot_include_hidden_default"),
|
|
349
|
+
readyTimeoutSeconds: readyTimeoutSecondsDefault,
|
|
350
|
+
readyStableMs: readyStableMsDefault,
|
|
298
351
|
snapshotScope,
|
|
299
352
|
}),
|
|
300
353
|
trackerHostSuffixes: Object.freeze(trackerHostSuffixes),
|
|
301
354
|
blockedResourceTypes: Object.freeze(blockedResourceTypes),
|
|
355
|
+
busySelectorsDefault: Object.freeze(busySelectorsDefault),
|
|
356
|
+
loginUrlContainsDefault: Object.freeze(loginUrlContainsDefault),
|
|
357
|
+
loginTextDefault: Object.freeze(loginTextDefault),
|
|
358
|
+
maxBusySelectors: positiveNumber(browserOptions.max_busy_selectors, "jev_browser_mcp.browser.max_busy_selectors", true),
|
|
302
359
|
}),
|
|
303
360
|
jev: Object.freeze({
|
|
304
361
|
providerUrl,
|