@debugbundle/mcp 1.2.0 → 1.3.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/dist/main.cjs CHANGED
@@ -16786,7 +16786,7 @@ function isIpLikeHost(value) {
16786
16786
  return /^(?:\d{1,3}\.){3}\d{1,3}$/.test(host) || /^\[[0-9a-f:]+\]$/i.test(host) || host.includes(":") && /^[0-9a-f:]+$/i.test(host);
16787
16787
  }
16788
16788
 
16789
- // ../../packages/shared-types/src/capture-rules.ts
16789
+ // ../../packages/shared-types/src/capture-rule-schemas.ts
16790
16790
  var CAPTURE_RULE_EVENT_TYPES = [
16791
16791
  "backend_exception",
16792
16792
  "request_event",
@@ -16814,6 +16814,7 @@ var CaptureRuleSampleEventClassSchema = external_exports.enum(CaptureRuleSampleE
16814
16814
  var CaptureRuleRuntimeSchema = external_exports.enum(CAPTURE_RULE_RUNTIME_VALUES);
16815
16815
  var CaptureRuleEventTypeSchema = external_exports.enum(CAPTURE_RULE_EVENT_TYPES);
16816
16816
  var BrowserEventKindSchema = external_exports.enum(["window_error", "resource_error"]);
16817
+ var CaptureRuleClientKindSchema = external_exports.enum(["human", "bot", "unknown"]);
16817
16818
  function normalizeOptionalTrimmedString(value) {
16818
16819
  const trimmed = value?.trim();
16819
16820
  return trimmed && trimmed.length > 0 ? trimmed : void 0;
@@ -16891,6 +16892,9 @@ var CaptureRuleMatcherSchema = external_exports.object({
16891
16892
  message_contains: external_exports.string().min(1).max(500).optional(),
16892
16893
  message_equals: external_exports.string().min(1).max(500).optional(),
16893
16894
  browser_event_kind: BrowserEventKindSchema.optional(),
16895
+ browser_event_opaque: external_exports.boolean().optional(),
16896
+ client_kind: CaptureRuleClientKindSchema.optional(),
16897
+ bot_family: external_exports.string().min(1).max(120).optional(),
16894
16898
  resource_url: UrlMatcherSchema.optional(),
16895
16899
  request_url: UrlMatcherSchema.optional(),
16896
16900
  status_codes: external_exports.array(external_exports.number().int().min(100).max(599)).min(1).optional(),
@@ -16905,6 +16909,7 @@ var CaptureRuleMatcherSchema = external_exports.object({
16905
16909
  const errorName = normalizeOptionalTrimmedString(value.error_name);
16906
16910
  const messageContains = normalizeOptionalTrimmedString(value.message_contains);
16907
16911
  const messageEquals = normalizeOptionalTrimmedString(value.message_equals);
16912
+ const botFamily = normalizeOptionalTrimmedString(value.bot_family);
16908
16913
  const statusCodes = normalizeNumberArray(value.status_codes);
16909
16914
  if (eventTypes !== void 0) {
16910
16915
  normalized.event_types = eventTypes;
@@ -16933,6 +16938,15 @@ var CaptureRuleMatcherSchema = external_exports.object({
16933
16938
  if (value.browser_event_kind !== void 0) {
16934
16939
  normalized.browser_event_kind = value.browser_event_kind;
16935
16940
  }
16941
+ if (value.browser_event_opaque !== void 0) {
16942
+ normalized.browser_event_opaque = value.browser_event_opaque;
16943
+ }
16944
+ if (value.client_kind !== void 0) {
16945
+ normalized.client_kind = value.client_kind;
16946
+ }
16947
+ if (botFamily !== void 0) {
16948
+ normalized.bot_family = botFamily;
16949
+ }
16936
16950
  if (value.resource_url !== void 0) {
16937
16951
  normalized.resource_url = value.resource_url;
16938
16952
  }
@@ -16959,6 +16973,9 @@ var CaptureRuleMatcherSchema = external_exports.object({
16959
16973
  "message_contains",
16960
16974
  "message_equals",
16961
16975
  "browser_event_kind",
16976
+ "browser_event_opaque",
16977
+ "client_kind",
16978
+ "bot_family",
16962
16979
  "resource_url",
16963
16980
  "request_url",
16964
16981
  "status_codes",
@@ -17141,6 +17158,8 @@ var CaptureRulesFileSchema = external_exports.object({
17141
17158
  version: external_exports.literal(1),
17142
17159
  rules: external_exports.array(CaptureRuleSchema)
17143
17160
  });
17161
+
17162
+ // ../../packages/shared-types/src/capture-rule-evaluation.ts
17144
17163
  var CaptureRuleEvaluationUrlSchema = external_exports.object({
17145
17164
  host: external_exports.string().min(1).transform((value) => value.toLowerCase()).optional(),
17146
17165
  path: external_exports.string().min(1).transform((value) => value.startsWith("/") ? value : `/${value}`)
@@ -17156,11 +17175,40 @@ var CaptureRuleEvaluationContextSchema = external_exports.object({
17156
17175
  error_name: external_exports.string().min(1).optional(),
17157
17176
  message: external_exports.string().min(1).optional(),
17158
17177
  browser_event_kind: BrowserEventKindSchema.optional(),
17178
+ browser_event_opaque: external_exports.boolean().optional(),
17179
+ client_kind: CaptureRuleClientKindSchema.optional(),
17180
+ bot_family: external_exports.string().min(1).max(120).optional(),
17159
17181
  resource_url: CaptureRuleEvaluationUrlSchema.optional(),
17160
17182
  request_url: CaptureRuleEvaluationUrlSchema.optional(),
17161
17183
  status_code: external_exports.number().int().min(0).max(599).optional(),
17162
17184
  fingerprint: CaptureRuleFingerprintSchema.optional()
17163
17185
  });
17186
+ function classifyCaptureRuleClientFromUserAgent(userAgent) {
17187
+ if (userAgent === null || userAgent === void 0) {
17188
+ return { client_kind: "unknown" };
17189
+ }
17190
+ const lower = userAgent.toLowerCase();
17191
+ const knownBots = [
17192
+ { family: "Googlebot", markers: ["googlebot", "adsbot-google", "google-inspectiontool"] },
17193
+ { family: "Bingbot", markers: ["bingbot", "msnbot"] },
17194
+ { family: "DuckDuckBot", markers: ["duckduckbot"] },
17195
+ { family: "Applebot", markers: ["applebot"] },
17196
+ { family: "YandexBot", markers: ["yandexbot"] },
17197
+ { family: "Baiduspider", markers: ["baiduspider"] },
17198
+ { family: "FacebookBot", markers: ["facebookexternalhit", "facebot"] },
17199
+ { family: "LinkedInBot", markers: ["linkedinbot"] },
17200
+ { family: "TwitterBot", markers: ["twitterbot"] },
17201
+ { family: "Slackbot", markers: ["slackbot"] }
17202
+ ];
17203
+ const knownBot = knownBots.find((entry) => entry.markers.some((marker) => lower.includes(marker)));
17204
+ if (knownBot !== void 0) {
17205
+ return { client_kind: "bot", bot_family: knownBot.family };
17206
+ }
17207
+ if (["bot", "crawler", "spider", "slurp"].some((marker) => lower.includes(marker))) {
17208
+ return { client_kind: "bot", bot_family: "OtherBot" };
17209
+ }
17210
+ return { client_kind: "human" };
17211
+ }
17164
17212
 
17165
17213
  // ../../packages/shared-types/src/capture-rule-suggestions.ts
17166
17214
  var CaptureRuleSuggestionConfidenceSchema = external_exports.enum(["high", "medium", "low"]);
@@ -17370,6 +17418,12 @@ var BrowserExceptionEventSchema = external_exports.object({
17370
17418
  }).strict().optional(),
17371
17419
  opaque: external_exports.boolean()
17372
17420
  }).strict();
17421
+ var FrontendRejectionReasonSchema = external_exports.object({
17422
+ kind: external_exports.enum(["error", "string", "object", "null", "undefined", "unknown"]),
17423
+ name: external_exports.string().min(1).optional(),
17424
+ message: external_exports.string().min(1).optional(),
17425
+ preview: external_exports.string().min(1).optional()
17426
+ }).strict();
17373
17427
  var FrontendExceptionPayloadSchema = external_exports.object({
17374
17428
  name: external_exports.string().min(1),
17375
17429
  message: external_exports.string().min(1),
@@ -17382,6 +17436,7 @@ var FrontendExceptionPayloadSchema = external_exports.object({
17382
17436
  breadcrumbs: external_exports.array(FrontendExceptionBreadcrumbSchema).optional(),
17383
17437
  device: DeviceInfoSchema.nullable().optional(),
17384
17438
  browser_event: BrowserExceptionEventSchema.optional(),
17439
+ rejection_reason: FrontendRejectionReasonSchema.optional(),
17385
17440
  dom_context: external_exports.object({
17386
17441
  mode: external_exports.literal("lightweight"),
17387
17442
  html_excerpt: external_exports.string().min(1)
@@ -17816,7 +17871,7 @@ function buildSkill() {
17816
17871
  "2. Inspect the incident bundle and reproduction artifact before proposing a fix.",
17817
17872
  "3. Run `debugbundle analyze --type improvement --local` after local processing when you need a deterministic change plan.",
17818
17873
  "4. Apply the narrowest fix, then validate it with the repository test workflow from `.debugbundle/profile.json`.",
17819
- "5. When the fix is confirmed, or when the incident was intentionally generated for smoke, verification, or dogfooding, resolve it with `debugbundle resolve <incident-id>` or MCP `resolve_incident` so the open queue stays actionable.",
17874
+ "5. When the fix is confirmed, or when the incident was intentionally generated for smoke, verification, or dogfooding, resolve it with `debugbundle resolve <incident-id> [incident-id ...]` or MCP `resolve_incident` / `resolve_incidents` so the open queue stays actionable.",
17820
17875
  "",
17821
17876
  "## Incident Hygiene",
17822
17877
  "",
@@ -17825,6 +17880,15 @@ function buildSkill() {
17825
17880
  "- Reopen or leave open if the failure is still present, the validation is incomplete, or the incident represents a live unresolved problem.",
17826
17881
  "- If a resolved incident regresses, let the platform move it back to `regressed` through normal incident lifecycle behavior.",
17827
17882
  "",
17883
+ "## Noise Management",
17884
+ "",
17885
+ "When incident evidence shows repeated low-value operational noise rather than a product bug, evaluate whether a scoped capture rule or capture-policy path rule should handle future matches.",
17886
+ "",
17887
+ "- Run `debugbundle capture-rule suggest <incident-id> --json` before creating a manual rule. Apply deterministic suggestions with `debugbundle capture-rule create-from-suggestion <incident-id> --suggestion-id <id>` after confirming the scope is safe.",
17888
+ "- Prefer project capture rules for operational noise because they are centralized, auditable, and enforced by ingestion and processing. Use SDK `beforeSend` only for app-owned local policy such as final redaction or events that must never leave the runtime.",
17889
+ "- Scope frontend noise by structured evidence such as service, environment, `browser_event_kind`, `browser_event_opaque`, `client_kind`, `bot_family`, and message fields. Do not broadly demote generic `Unhandled promise rejection` incidents without bot-scoped or otherwise narrow evidence.",
17890
+ "- For expected or intentionally promoted 4xx responses on known routes, use capture-policy client-error path rules instead of promoting all client errors: `debugbundle capture-policy set --client-error-path-rule <status=/path/*@GET>`.",
17891
+ "",
17828
17892
  "## Profile Validation",
17829
17893
  "",
17830
17894
  "Use this task after setup or whenever architecture changes make the static profile stale.",
@@ -17887,10 +17951,21 @@ function buildCliReference() {
17887
17951
  "- `debugbundle explain <incident-id> [--source <local|cloud>] [--json]`",
17888
17952
  "- `debugbundle bundle <incident-id> [--source <local|cloud>] [--json]`",
17889
17953
  "- `debugbundle reproduce <incident-id> [--source <local|cloud>] [--json]`",
17890
- "- `debugbundle resolve <incident-id> [--source <local|cloud>] [--json]`",
17891
- "- `debugbundle reopen <incident-id> [--source <local|cloud>] [--json]`",
17954
+ "- `debugbundle resolve <incident-id> [incident-id ...] [--source <local|cloud>] [--json]`",
17955
+ "- `debugbundle reopen <incident-id> [incident-id ...] [--source <local|cloud>] [--json]`",
17892
17956
  "- `debugbundle analyze --type improvement --local`",
17893
17957
  "",
17958
+ "## Noise Management",
17959
+ "",
17960
+ "- `debugbundle capture-rule suggest <incident-id> [--auth-file <path>] [--json]`",
17961
+ "- `debugbundle capture-rule create-from-suggestion <incident-id> --suggestion-id <id> [--name <name>] [--expires-at <ISO8601>] [--auth-file <path>] [--json]`",
17962
+ "- `debugbundle capture-rule list --project-id <id> [--auth-file <path>] [--json]`",
17963
+ "- `debugbundle capture-rule create --project-id <id> --name <name> --action <demote|sample|drop> --matcher-json <json> [--auth-file <path>] [--json]`",
17964
+ "- `debugbundle capture-policy get [--project <id>] [--json]`",
17965
+ "- `debugbundle capture-policy set [--project <id>] --client-error-path-rule <404=/path/*@GET,POST> [--json]`",
17966
+ "",
17967
+ "Use capture-rule suggestions for repeated operational noise after inspecting an incident bundle. Use capture-policy client-error path rules for route-scoped 4xx incidents instead of promoting all client errors.",
17968
+ "",
17894
17969
  "## Operational Paths",
17895
17970
  "",
17896
17971
  "- `.debugbundle/profile.json` \u2014 committed project map and agent validation state",
@@ -17921,7 +17996,7 @@ function buildCliReference() {
17921
17996
  "```bash",
17922
17997
  "debugbundle incidents --status open --json \\",
17923
17998
  ` | jq -r '.incidents[] | select(.title | test("smoke test|dogfood|verification|synthetic"; "i")) | .incident_id' \\`,
17924
- " | xargs -n1 debugbundle resolve",
17999
+ " | xargs debugbundle resolve",
17925
18000
  "```",
17926
18001
  ""
17927
18002
  ].join("\n");
@@ -17940,19 +18015,28 @@ function buildMcpReference() {
17940
18015
  "- `get_incident_context` \u2014 fetch deterministic explanation context for triage.",
17941
18016
  "- `get_bundle` \u2014 fetch the full debug bundle before proposing a fix.",
17942
18017
  "- `get_reproduction` \u2014 fetch reproduction guidance before editing code.",
17943
- "- `resolve_incident` / `reopen_incident` \u2014 update lifecycle state after validation.",
18018
+ "- `resolve_incident` / `resolve_incidents` / `reopen_incident` / `reopen_incidents` \u2014 update lifecycle state after validation.",
17944
18019
  "- `analyze` \u2014 run local agent-oriented analysis from local bundles and skill schemas.",
17945
18020
  "",
17946
18021
  "- Prefer bundle retrieval tools before reading raw repository files.",
17947
18022
  "- Use MCP bundle access when the current issue originated in production.",
17948
- "- Resolve fixed or intentionally generated incidents with `resolve_incident` so open incidents stay actionable.",
18023
+ "- Resolve fixed or intentionally generated incidents with `resolve_incident` or `resolve_incidents` so open incidents stay actionable.",
17949
18024
  "- Fall back to local CLI processing when the project is local-only.",
17950
18025
  "",
18026
+ "## Noise and Capture Policy Tools",
18027
+ "",
18028
+ "- `suggest_capture_rules_from_incident` \u2014 generate deterministic capture-rule suggestions from an incident bundle.",
18029
+ "- `create_capture_rule_from_incident_suggestion` \u2014 apply a confirmed suggestion.",
18030
+ "- `list_capture_rules`, `create_capture_rule`, `update_capture_rule`, `delete_capture_rule` \u2014 manage project capture rules.",
18031
+ "- `get_capture_policy`, `update_capture_policy` \u2014 review or update capture policy, including path-scoped client-error incident rules.",
18032
+ "",
18033
+ "Use these tools for repeated low-value operational noise only after inspecting incident evidence. Keep frontend suppression scoped by structured browser and client signals, and use path-scoped capture policy for known 4xx routes.",
18034
+ "",
17951
18035
  "## Smoke-Test Cleanup Recipe",
17952
18036
  "",
17953
18037
  '1. Call `list_incidents` with `status: "open"`.',
17954
18038
  "2. Filter incidents whose titles show they were intentionally generated for smoke, dogfood, verification, or synthetic checks.",
17955
- "3. Call `resolve_incident` for each verified synthetic incident.",
18039
+ "3. Call `resolve_incidents` for verified synthetic incidents, or `resolve_incident` for a single incident.",
17956
18040
  "4. Call `list_incidents` again and confirm the open queue only contains actionable failures.",
17957
18041
  ""
17958
18042
  ].join("\n");
@@ -18072,6 +18156,16 @@ function buildSkillEvals() {
18072
18156
  "Leave unresolved incidents open when the failure is still live or unverified."
18073
18157
  ]
18074
18158
  },
18159
+ {
18160
+ name: "noise_management_guidance",
18161
+ prompt: "The same low-value frontend incident keeps reopening. Confirm the skill tells the agent how to evaluate operational noise without hiding real bugs.",
18162
+ expected_behavior: [
18163
+ "Inspect incident evidence before creating a rule.",
18164
+ "Use capture-rule suggestions for repeated operational noise.",
18165
+ "Keep generic frontend suppression narrow with structured browser or bot signals.",
18166
+ "Use capture-policy path rules for known route-scoped 4xx incidents."
18167
+ ]
18168
+ },
18075
18169
  {
18076
18170
  name: "artifact_path_discovery",
18077
18171
  prompt: "The user reports an unknown local runtime error. Confirm the skill tells the agent which DebugBundle paths and commands to inspect first.",
@@ -20128,6 +20222,33 @@ function buildRedactionRecord(bundleBody) {
20128
20222
  notes: readString(redaction["notes"])
20129
20223
  };
20130
20224
  }
20225
+ function buildBrowserSignalRecord(bundleBody) {
20226
+ const bundle = isRecord(bundleBody) ? bundleBody : {};
20227
+ const context = isRecord(bundle["context"]) ? bundle["context"] : {};
20228
+ const frontend = isRecord(context["frontend"]) ? context["frontend"] : {};
20229
+ const exceptions = Array.isArray(frontend["exceptions"]) ? frontend["exceptions"] : [];
20230
+ let exception;
20231
+ for (let index = exceptions.length - 1; index >= 0; index -= 1) {
20232
+ const candidate = exceptions[index];
20233
+ if (isRecord(candidate) && isRecord(candidate["browser_event"])) {
20234
+ exception = candidate;
20235
+ break;
20236
+ }
20237
+ }
20238
+ const browserEvent = isRecord(exception) && isRecord(exception["browser_event"]) ? exception["browser_event"] : null;
20239
+ const device = isRecord(context["device"]) ? context["device"] : {};
20240
+ const client = classifyCaptureRuleClientFromUserAgent(readString(device["user_agent"]) ?? void 0);
20241
+ if (browserEvent === null && client.client_kind === "unknown") {
20242
+ return null;
20243
+ }
20244
+ return {
20245
+ browser_event_kind: readString(browserEvent?.["kind"]),
20246
+ browser_event_opaque: readBoolean(browserEvent?.["opaque"]),
20247
+ browser_event_message: readString(browserEvent?.["message"]),
20248
+ client_kind: client.client_kind,
20249
+ bot_family: client.bot_family ?? null
20250
+ };
20251
+ }
20131
20252
  function buildVisibilityRecord(input) {
20132
20253
  const routeTarget = input.primarySignal.route_template ?? input.primarySignal.request_path;
20133
20254
  const matchedFields = input.incident.matched_fields.length === 0 ? "none" : input.incident.matched_fields.join(", ");
@@ -20165,6 +20286,14 @@ function buildSuggestedNextChecks(input) {
20165
20286
  if (input.deploy.regression_window === true || input.incident.status === "regressed") {
20166
20287
  suggestions.push("Compare this incident against the most recent deploy and recent regressions.");
20167
20288
  }
20289
+ if (input.browserSignal?.browser_event_opaque === true) {
20290
+ suggestions.push("Treat the browser event as opaque; inspect CSP, cross-origin scripts, resource loading, and framework error boundaries before changing application code.");
20291
+ }
20292
+ if (input.browserSignal?.client_kind === "bot") {
20293
+ suggestions.push(
20294
+ `Review whether ${input.browserSignal.bot_family ?? "bot"} traffic is operational noise before applying a bot-scoped capture rule.`
20295
+ );
20296
+ }
20168
20297
  if (input.reproduction.status === "pending") {
20169
20298
  suggestions.push("Recheck reproduction guidance after the reproduction artifact is ready.");
20170
20299
  }
@@ -20185,6 +20314,7 @@ function buildIncidentContextRecord(input) {
20185
20314
  primarySignal
20186
20315
  });
20187
20316
  const redaction = buildRedactionRecord(bundleBody);
20317
+ const browserSignal = buildBrowserSignalRecord(bundleBody);
20188
20318
  return {
20189
20319
  incident: input.incident,
20190
20320
  incident_reason: incidentReason,
@@ -20200,13 +20330,15 @@ function buildIncidentContextRecord(input) {
20200
20330
  },
20201
20331
  visibility,
20202
20332
  redaction,
20333
+ browser_signal: browserSignal,
20203
20334
  suggested_next_checks: buildSuggestedNextChecks({
20204
20335
  incident: input.incident,
20205
20336
  bundle: input.bundle,
20206
20337
  reproduction: input.reproduction,
20207
20338
  logs,
20208
20339
  primarySignal,
20209
- deploy
20340
+ deploy,
20341
+ browserSignal
20210
20342
  })
20211
20343
  };
20212
20344
  }
@@ -28676,7 +28808,7 @@ var zodToJsonSchema = (schema, options) => {
28676
28808
  var package_default = {
28677
28809
  name: "@debugbundle/mcp",
28678
28810
  mcpName: "com.debugbundle/mcp",
28679
- version: "1.2.0",
28811
+ version: "1.3.0",
28680
28812
  private: false,
28681
28813
  description: "Model Context Protocol server for DebugBundle",
28682
28814
  license: "AGPL-3.0-only",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@debugbundle/mcp",
3
3
  "mcpName": "com.debugbundle/mcp",
4
- "version": "1.2.0",
4
+ "version": "1.3.0",
5
5
  "private": false,
6
6
  "description": "Model Context Protocol server for DebugBundle",
7
7
  "license": "AGPL-3.0-only",
package/server.json CHANGED
@@ -8,13 +8,13 @@
8
8
  "source": "github",
9
9
  "subfolder": "apps/mcp"
10
10
  },
11
- "version": "1.2.0",
11
+ "version": "1.3.0",
12
12
  "packages": [
13
13
  {
14
14
  "registryType": "npm",
15
15
  "registryBaseUrl": "https://registry.npmjs.org",
16
16
  "identifier": "@debugbundle/mcp",
17
- "version": "1.2.0",
17
+ "version": "1.3.0",
18
18
  "transport": {
19
19
  "type": "stdio"
20
20
  },