@debugg-ai/debugg-ai-mcp 4.1.0 → 4.2.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/README.md CHANGED
@@ -75,7 +75,7 @@ Runs an AI browser agent against your app. The agent navigates, interacts, and r
75
75
  | `username` | string | Username for login (ephemeral — not persisted) |
76
76
  | `password` | string | Password for login (ephemeral — not persisted) |
77
77
  | `loginCredentials` | array | Accounts for logins the agent hits **during** the task — `[{username, password, label?}]` |
78
- | `useEnvironmentCredentials` | boolean | Default `true`. `false` forbids auto-filling the environment's stored credentials |
78
+ | `useEnvironmentCredentials` | boolean | Default `true`. `false` forbids auto-filling the environment's stored credentials; with no account named it means **do not log in at all** |
79
79
  | `freshSession` | boolean | Default `false`. `true` forces a real login instead of reusing the warm session held for that account |
80
80
  | `auth` | object | Auth precondition — `{precondition, entryUrl, deepUrl, environmentId, username, password}` |
81
81
  | `repoName` | string | Override auto-detected git repo name (e.g. `my-org/my-repo`) |
@@ -90,7 +90,9 @@ Naming an account only in `description` does **not** make the agent use it — i
90
90
  - `auth.username` / `auth.password` — pins the precondition login when you also use `auth.precondition: "login"`.
91
91
  - `loginCredentials` — accounts for a login form the agent reaches **part-way through** the task. This is the one for flows like *set a password → get bounced to sign-in → log in as the account you just created*, where splitting into separate calls would lose browser state.
92
92
 
93
- Set `useEnvironmentCredentials: false` when a silent fallback to the default test user would invalidate the check. The call is rejected if you opt out without naming an account, since the run would have no way to authenticate.
93
+ Set `useEnvironmentCredentials: false` when a silent fallback to the default test user would invalidate the check.
94
+
95
+ **Checking a page that needs no login at all?** Pass `useEnvironmentCredentials: false` and name no account. That combination means exactly what it says — *do not log in* — and the run skips authentication entirely instead of hunting for a login form. Use it for public pages, marketing sites, docs, and anything pre-auth. It is also faster: on the default (`auto`) the agent will follow a "Log in" link off your page and try the environment's stored account before it evaluates anything.
94
96
 
95
97
  ##### Session reuse: why a check can report "no login form"
96
98
 
@@ -140,13 +142,13 @@ Fires a server-side browser-agent crawl to populate the project's knowledge grap
140
142
 
141
143
  #### `probe_page`
142
144
 
143
- **Lightweight no-LLM batch page probe.** Pass 1-20 URLs; each navigates, waits for load, and returns rendered state — screenshot + page metadata + structured console errors + network summary. No agent loop, no LLM cost, no scenario assertions. Use it for "did I just break /settings?", multi-route smoke after a refactor, CI per-PR sweeps, and quick is-it-up checks where `check_app_in_browser`'s 60-150s agent loop is overkill.
145
+ **Lightweight no-LLM batch page probe.** Pass 1-20 URLs; each navigates, settles on content (the DOM going quiet, bounded — never on network silence, which a live app never reaches), and returns rendered state — screenshot + page metadata + structured console errors + network summary. No agent loop, no LLM cost, no scenario assertions. Use it for "did I just break /settings?", multi-route smoke after a refactor, CI per-PR sweeps, and quick is-it-up checks where `check_app_in_browser`'s 60-150s agent loop is overkill.
144
146
 
145
147
  | Parameter | Type | Description |
146
148
  |-----------|------|-------------|
147
149
  | `targets` | array **required** | 1-20 entries: `[{url, waitForSelector?, waitForLoadState?, timeoutMs?}]` |
148
150
  | `targets[].url` | string **required** | Public URL or localhost (auto-tunneled) |
149
- | `targets[].waitForLoadState` | enum | `'load'` (default) / `'domcontentloaded'` / `'networkidle'` |
151
+ | `targets[].waitForLoadState` | enum | `'domcontentloaded'` (default, + a bounded content settle) / `'load'` (also blocks on third-party embeds) / `'networkidle'` (accepted, never issued — a live site's network does not go idle) |
150
152
  | `targets[].waitForSelector` | string | Optional CSS selector to wait for after navigation |
151
153
  | `targets[].timeoutMs` | number | Per-URL timeout, 1000-30000 (default 10000) |
152
154
  | `includeHtml` | boolean | Return raw HTML in each result (default false) |
@@ -3,6 +3,7 @@
3
3
  * Executes the App Evaluation Workflow via the 4-step pattern:
4
4
  * find template → execute → poll → result
5
5
  */
6
+ import { meansDoNotLogIn, } from '../types/index.js';
6
7
  import { config } from '../config/index.js';
7
8
  import { Logger } from '../utils/logger.js';
8
9
  import { handleExternalServiceError } from '../utils/errors.js';
@@ -419,6 +420,18 @@ async function testPageChangesHandlerInner(input, context, rawProgressCallback)
419
420
  if (input.useEnvironmentCredentials === false) {
420
421
  env.useEnvironmentCredentials = false;
421
422
  }
423
+ // sentinal-oj7dp.3: opting out of the environment's credentials WITHOUT naming
424
+ // an account means "do not log in" — say so in the language the backend already
425
+ // speaks instead of leaving auth_mode on its 'auto' default. On 'auto' the auth
426
+ // subworkflow hunts for a login on a page that needs none: measured 2026-08-18,
427
+ // a public-homepage check spent 38 of its 111 seconds following the site's login
428
+ // link to a sibling host, submitting the environment's default credential three
429
+ // times, and parking the browser on a login screen the run was then graded
430
+ // against (execution 2c787273). no_auth short-circuits that cleanly and marks
431
+ // the run auth.skipped, which is explicitly NOT an auth failure (sentinal-76f8y.12).
432
+ if (meansDoNotLogIn(input)) {
433
+ contextData.auth_mode = 'no_auth';
434
+ }
422
435
  // Same rule for the session opt-out: send it only when it IS one, so the
423
436
  // default (reuse a warm session when one exists for this account) is
424
437
  // expressed by absence rather than by an explicit false.
@@ -22,6 +22,8 @@ LOCALHOST SUPPORT: any localhost URL is auto-tunneled. Pre-flight TCP probe fail
22
22
 
23
23
  BATCH MODE: pass up to 20 targets in one call to share browser session + tunnel — dramatically faster than firing parallel single-URL probes (one execution unit, not N). Per-URL waitForSelector / waitForLoadState / timeoutMs override defaults.
24
24
 
25
+ READINESS: navigation settles on CONTENT (the page's DOM going quiet), bounded — not on network silence, which never arrives on a live app, and not on 'load', which blocks on third-party embeds. The default is right for SPAs; reach for waitForSelector, not waitForLoadState, when you need to wait for something specific.
26
+
25
27
  A single failed target's error appears in result.error without failing the whole batch — the other results stay valid.`;
26
28
  const TARGET_PROPERTIES = {
27
29
  url: {
@@ -35,11 +37,15 @@ const TARGET_PROPERTIES = {
35
37
  waitForLoadState: {
36
38
  type: 'string',
37
39
  enum: ['load', 'domcontentloaded', 'networkidle'],
38
- description: "When to consider the page 'loaded' before capturing. Default 'load'. Use 'networkidle' for SPAs to wait until the bundle finishes rendering.",
40
+ // sentinal-kvoou. This description used to read "Default 'load'. Use 'networkidle'
41
+ // for SPAs to wait until the bundle finishes rendering" — advice that hangs on
42
+ // exactly the class of app it names. See __tests__/tools/probePageWaitContract.ts
43
+ // for the measurement against https://debugg.ai.
44
+ description: "When to consider the page ready to capture. Default 'domcontentloaded', followed by a bounded content settle (the page's DOM going quiet) — that is what actually makes a client-rendered SPA safe to screenshot, and it needs no override. Only override for a specific reason: 'load' additionally blocks on every sub-resource, including third-party iframes and images we do not control, so a slow embed can time the whole probe out. 'networkidle' is accepted for compatibility but is never issued — a live site's network does not go idle (analytics, polling, websockets, ads) — and behaves as 'domcontentloaded'. To wait on something specific, use waitForSelector.",
39
45
  },
40
46
  timeoutMs: {
41
47
  type: 'number',
42
- description: 'Per-URL navigation timeout in milliseconds (1000-30000, default 10000).',
48
+ description: "Per-URL budget in milliseconds for navigating AND settling this target (1000-30000, default 10000). The content settle spends what the navigation left over, so this is the whole cost of the target, not just the goto.",
43
49
  },
44
50
  };
45
51
  export function buildProbePageTool() {
@@ -66,14 +66,23 @@ export const TestPageChangesInputSchema = z.object({
66
66
  freshSession: z.boolean().optional(),
67
67
  // Auth-precondition deep-link intent (bead 56kd.6) — "log in THEN go to X".
68
68
  auth: AuthPreconditionSchema.optional(),
69
- }).refine((v) => !(v.useEnvironmentCredentials === false
70
- && !v.username && !v.credentialId && !v.credentialRole
71
- && !(v.loginCredentials && v.loginCredentials.length > 0)
72
- && !v.auth?.username), {
73
- message: 'useEnvironmentCredentials:false leaves the run with no way to authenticate. '
74
- + 'Pass username/password, credentialId, credentialRole, or loginCredentials alongside it.',
75
- path: ['useEnvironmentCredentials'],
76
69
  });
70
+ /**
71
+ * True when the caller opted out of the environment's credentials AND named no
72
+ * account of their own — i.e. "do not log in at all".
73
+ *
74
+ * This used to be a hard validation error ("leaves the run with no way to
75
+ * authenticate"), which made the single most common check — "is my PUBLIC page
76
+ * still up?" — the one thing the tool refused to express. It is not an error; it
77
+ * is an instruction, and the backend already has the enum for it
78
+ * (auth_mode: no_auth, sentinal-i7fnc). See sentinal-oj7dp.3.
79
+ */
80
+ export function meansDoNotLogIn(v) {
81
+ return v.useEnvironmentCredentials === false
82
+ && !v.username && !v.credentialId && !v.credentialRole
83
+ && !(v.loginCredentials && v.loginCredentials.length > 0)
84
+ && !v.auth?.username;
85
+ }
77
86
  export const TriggerCrawlInputSchema = z.object({
78
87
  url: z.preprocess(normalizeUrl, z.string().url('Invalid URL. Pass a full URL like "http://localhost:3000" or "https://example.com". Localhost URLs are auto-tunneled to the remote browser.')),
79
88
  projectUuid: z.string().uuid().optional(),
@@ -217,7 +226,15 @@ export var LogLevel;
217
226
  export const ProbePageTargetSchema = z.object({
218
227
  url: z.preprocess(normalizeUrl, z.string().url('Invalid URL. Pass a full URL like "http://localhost:3000" or "https://example.com". Localhost URLs are auto-tunneled to the remote browser.')),
219
228
  waitForSelector: z.string().optional(),
220
- waitForLoadState: z.enum(['load', 'domcontentloaded', 'networkidle']).default('load'),
229
+ // sentinal-kvoou: 'domcontentloaded', NOT 'load'. 'load' blocks on every
230
+ // sub-resource including third-party iframes we do not control — measured against
231
+ // https://debugg.ai (two YouTube embeds), the 'load' default timed the goto out at
232
+ // 10s and reported statusCode 0 on a page that renders in 3.5s. Readiness comes from
233
+ // the backend's bounded CONTENT settle after the goto, not from a load state.
234
+ // 'networkidle' stays in the enum (this package is published; removing it would turn
235
+ // an existing caller's probe into a hard validation error) and is neutralized
236
+ // server-side — never a wait, always domcontentloaded + settle.
237
+ waitForLoadState: z.enum(['load', 'domcontentloaded', 'networkidle']).default('domcontentloaded'),
221
238
  timeoutMs: z.number().int().min(1000, 'timeoutMs minimum is 1000 (1s)').max(30000, 'timeoutMs maximum is 30000 (30s) — longer probes should use check_app_in_browser').default(10000),
222
239
  }).strict();
223
240
  export const ProbePageInputSchema = z.object({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@debugg-ai/debugg-ai-mcp",
3
- "version": "4.1.0",
3
+ "version": "4.2.1",
4
4
  "description": "Zero-Config, Fully AI-Managed End-to-End Testing for all code gen platforms.",
5
5
  "type": "module",
6
6
  "caddy": "2.11.3",