@certscore/mcp 0.2.12 → 0.2.15

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.
@@ -15294,8 +15294,17 @@ var UrlElicitationRequiredError = class extends McpError {
15294
15294
  };
15295
15295
 
15296
15296
  // ../../node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js
15297
+ var STDIO_DEFAULT_MAX_BUFFER_SIZE = 10 * 1024 * 1024;
15297
15298
  var ReadBuffer = class {
15299
+ constructor(options) {
15300
+ this._maxBufferSize = options?.maxBufferSize ?? STDIO_DEFAULT_MAX_BUFFER_SIZE;
15301
+ }
15298
15302
  append(chunk) {
15303
+ const newSize = (this._buffer?.length ?? 0) + chunk.length;
15304
+ if (newSize > this._maxBufferSize) {
15305
+ this.clear();
15306
+ throw new Error(`ReadBuffer exceeded maximum size of ${this._maxBufferSize} bytes`);
15307
+ }
15299
15308
  this._buffer = this._buffer ? Buffer.concat([this._buffer, chunk]) : chunk;
15300
15309
  }
15301
15310
  readMessage() {
@@ -15323,18 +15332,24 @@ function serializeMessage(message) {
15323
15332
 
15324
15333
  // ../../node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
15325
15334
  var StdioServerTransport = class {
15326
- constructor(_stdin = process3.stdin, _stdout = process3.stdout) {
15335
+ constructor(_stdin = process3.stdin, _stdout = process3.stdout, options) {
15327
15336
  this._stdin = _stdin;
15328
15337
  this._stdout = _stdout;
15329
- this._readBuffer = new ReadBuffer();
15330
15338
  this._started = false;
15331
15339
  this._ondata = (chunk) => {
15332
- this._readBuffer.append(chunk);
15333
- this.processReadBuffer();
15340
+ try {
15341
+ this._readBuffer.append(chunk);
15342
+ this.processReadBuffer();
15343
+ } catch (error2) {
15344
+ this.onerror?.(error2);
15345
+ this.close().catch(() => {
15346
+ });
15347
+ }
15334
15348
  };
15335
15349
  this._onerror = (error2) => {
15336
15350
  this.onerror?.(error2);
15337
15351
  };
15352
+ this._readBuffer = new ReadBuffer({ maxBufferSize: options?.maxBufferSize });
15338
15353
  }
15339
15354
  /**
15340
15355
  * Starts listening for messages on stdin.
@@ -15439,11 +15454,13 @@ var ThrottledError = class extends CertScoreError {
15439
15454
  var CertScoreScanFailedError = class extends CertScoreError {
15440
15455
  scanId;
15441
15456
  jobId;
15457
+ retryAfterSeconds;
15442
15458
  constructor(message, options = {}) {
15443
15459
  super(message, options);
15444
15460
  this.name = "CertScoreScanFailedError";
15445
15461
  this.scanId = options.scanId ?? void 0;
15446
15462
  this.jobId = options.jobId ?? void 0;
15463
+ this.retryAfterSeconds = options.retryAfterSeconds;
15447
15464
  }
15448
15465
  };
15449
15466
 
@@ -15512,9 +15529,10 @@ function throwForTerminalStatus(status) {
15512
15529
  });
15513
15530
  }
15514
15531
  if (FAILURE_STATUSES.has(status.status)) {
15515
- throw new CertScoreScanFailedError(status.message ?? `Pulse scan ended with status ${status.status}.`, {
15516
- code: status.status,
15532
+ throw new CertScoreScanFailedError(status.error?.message ?? status.message ?? `Pulse scan ended with status ${status.status}.`, {
15533
+ code: status.error?.code ?? status.status,
15517
15534
  jobId: status.jobId,
15535
+ retryAfterSeconds: status.error?.retryAfterSeconds ?? void 0,
15518
15536
  scanId: status.scanId ?? status.scan_id ?? void 0,
15519
15537
  responseBody: status
15520
15538
  });
@@ -15873,7 +15891,10 @@ var CertScoreClient = class {
15873
15891
  const fallbackMs = options.adaptivePolling ? adaptivePollIntervalMs(elapsedMs) : options.pollIntervalMs;
15874
15892
  const delay = Math.min(retryDelayMs(status, void 0, fallbackMs), Math.max(0, options.maxWaitMs - elapsedMs));
15875
15893
  await sleep(delay, options.signal);
15876
- const response = await this.fetch(this.scanResourceStatusUrlFor(status), { signal: options.signal });
15894
+ let response = await this.fetch(this.scanResourceStatusUrlFor(status), { signal: options.signal });
15895
+ if (response.status === 404 && status.jobId) {
15896
+ response = await this.fetch(this.statusUrlFor(status), { signal: options.signal });
15897
+ }
15877
15898
  if (response.status === 202 || response.status === 200 || response.status === 429) {
15878
15899
  status = await response.json();
15879
15900
  options.onStatusUpdate?.(status);
@@ -20100,6 +20121,7 @@ var publicScanNoGoReasonCodes = [
20100
20121
  "maintenance_or_unavailable",
20101
20122
  "tls_or_certificate_error",
20102
20123
  "unsupported_region",
20124
+ "target_unreachable_or_unsuitable",
20103
20125
  "navigation_transport_failure",
20104
20126
  "visual_capture_failed_or_placeholder",
20105
20127
  "retained_visual_error_shell",
@@ -20301,7 +20323,18 @@ var pulseErrorSchema = external_exports2.object({
20301
20323
  error: external_exports2.object({
20302
20324
  code: pulseErrorCodeSchema,
20303
20325
  message: external_exports2.string(),
20304
- retryAfterSeconds: external_exports2.number().int().nullable().optional()
20326
+ retryAfterSeconds: external_exports2.number().int().nullable().optional(),
20327
+ recommendedNextAction: external_exports2.string().nullable().optional(),
20328
+ rateLimit: external_exports2.object({
20329
+ limitUnits: external_exports2.number().int().positive(),
20330
+ policyVersion: external_exports2.string(),
20331
+ profile: external_exports2.enum(["terminal", "status"]),
20332
+ requestedUnits: external_exports2.number().int().positive(),
20333
+ scope: external_exports2.enum(["callerTarget", "target", "caller"]),
20334
+ usedUnits: external_exports2.number().int().nonnegative(),
20335
+ windowId: external_exports2.enum(["burst", "daily"]),
20336
+ windowSeconds: external_exports2.number().int().positive()
20337
+ }).nullable().optional()
20305
20338
  }).passthrough(),
20306
20339
  feedback: pulseFeedbackSchema.optional(),
20307
20340
  resolution: external_exports2.object({
@@ -20316,7 +20349,7 @@ var pulseErrorSchema = external_exports2.object({
20316
20349
  var apiV2Disclaimer = "CertScore outputs are automated public-web observations for review. They are not legal advice, certification, or a compliance determination.";
20317
20350
  var apiV2ScanStatusSchema = external_exports2.enum(["queued", "running", "finalizing", "completed", "completed_limited", "failed", "expired", "rate_limited"]);
20318
20351
  var apiV2ScanFreshnessSchema = external_exports2.enum(["latest", "refresh"]);
20319
- var apiV2ScanFromSchema = external_exports2.enum(["eu_ie"]);
20352
+ var apiV2ScanFromSchema = external_exports2.enum(["eu_de", "eu_ie", "california"]);
20320
20353
  var apiV2FindingCriticalitySchema = external_exports2.enum(["critical", "high", "medium", "low", "info", "unknown"]);
20321
20354
  var apiV2FindingConfidenceSchema = external_exports2.enum(["strong", "good", "moderate", "weak", "unknown"]);
20322
20355
  var apiV2EvidenceBasisSchema = external_exports2.enum(["runtime_observation", "policy_surface_detection", "accessibility_check", "public_report_projection"]);
@@ -20335,7 +20368,7 @@ var apiV2ScanCreationMetadataShape = {
20335
20368
  anonymousQuotaResetAt: external_exports2.string().nullable().optional(),
20336
20369
  upgradeSupportEmail: external_exports2.string().email().nullable().optional(),
20337
20370
  upgradeMessage: external_exports2.string().nullable().optional(),
20338
- recommendedNextTool: external_exports2.enum(["get_scan_status", "get_scan_bundle"]).optional()
20371
+ recommendedNextTool: external_exports2.enum(["certscore_get_scan_status", "certscore_get_scan_bundle"]).optional()
20339
20372
  };
20340
20373
  var apiV2LinksSchema = external_exports2.object({
20341
20374
  self: external_exports2.string().optional(),
@@ -20351,7 +20384,19 @@ var apiV2ErrorSchema = external_exports2.object({
20351
20384
  error: external_exports2.object({
20352
20385
  code: external_exports2.enum(["invalid_request", "invalid_url", "not_found", "rate_limited", "unauthorized", "forbidden", "scan_unavailable", "internal_error"]),
20353
20386
  message: external_exports2.string(),
20354
- retryAfterSeconds: external_exports2.number().int().nullable().optional()
20387
+ retryable: external_exports2.boolean(),
20388
+ retryAfterSeconds: external_exports2.number().int().nullable(),
20389
+ recommendedNextAction: external_exports2.string(),
20390
+ rateLimit: external_exports2.object({
20391
+ limitUnits: external_exports2.number().int().positive(),
20392
+ policyVersion: external_exports2.string(),
20393
+ profile: external_exports2.enum(["terminal", "status"]),
20394
+ requestedUnits: external_exports2.number().int().positive(),
20395
+ scope: external_exports2.enum(["callerTarget", "target", "caller"]),
20396
+ usedUnits: external_exports2.number().int().nonnegative(),
20397
+ windowId: external_exports2.enum(["burst", "daily"]),
20398
+ windowSeconds: external_exports2.number().int().positive()
20399
+ }).optional()
20355
20400
  }).passthrough(),
20356
20401
  links: apiV2LinksSchema.optional(),
20357
20402
  disclaimer: external_exports2.string().optional(),
@@ -20369,6 +20414,7 @@ var apiV2ScanJobSchema = external_exports2.object({
20369
20414
  jobId: external_exports2.string(),
20370
20415
  scanId: external_exports2.string().nullable().optional(),
20371
20416
  domain: external_exports2.string().nullable().optional(),
20417
+ url: external_exports2.string().nullable().optional(),
20372
20418
  status: apiV2ScanStatusSchema,
20373
20419
  resultDisposition: scanResultDispositionSchema.optional(),
20374
20420
  noGo: scanNoGoResultSchema.optional(),
@@ -20377,8 +20423,33 @@ var apiV2ScanJobSchema = external_exports2.object({
20377
20423
  startedAt: external_exports2.string().nullable().optional(),
20378
20424
  completedAt: external_exports2.string().nullable().optional(),
20379
20425
  scanTimeSeconds: external_exports2.number().nullable().optional(),
20426
+ score: external_exports2.number().int().min(0).max(100).nullable().optional(),
20427
+ scoreStatus: external_exports2.enum(["provisional", "final"]).optional(),
20428
+ scoreVersion: external_exports2.string().nullable().optional(),
20429
+ scoreUpdatedAt: external_exports2.string().nullable().optional(),
20430
+ riskLevel: external_exports2.string().nullable().optional(),
20431
+ coverage: external_exports2.object({
20432
+ status: external_exports2.string().optional(),
20433
+ summary: external_exports2.string().optional(),
20434
+ limitations: external_exports2.array(external_exports2.string()).optional()
20435
+ }).passthrough().nullable().optional(),
20380
20436
  lastUpdatedAt: external_exports2.string().optional(),
20437
+ phaseStartedAt: external_exports2.string().nullable().optional(),
20438
+ lastHeartbeatAt: external_exports2.string().nullable().optional(),
20439
+ progressPercent: external_exports2.number().int().min(0).max(100).optional(),
20440
+ progressIsEstimate: external_exports2.boolean().optional(),
20441
+ estimatedRemainingSeconds: external_exports2.number().int().min(0).nullable().optional(),
20442
+ stalled: external_exports2.boolean().optional(),
20381
20443
  retryAfterSeconds: external_exports2.number().int().nullable().optional(),
20444
+ error: external_exports2.object({
20445
+ code: external_exports2.string(),
20446
+ message: external_exports2.string(),
20447
+ retryable: external_exports2.boolean(),
20448
+ retryAfterSeconds: external_exports2.number().int().nullable(),
20449
+ recommendedNextAction: external_exports2.string()
20450
+ }).strict().optional(),
20451
+ reportUrl: external_exports2.string().nullable().optional(),
20452
+ recommendedNextAction: external_exports2.string().optional(),
20382
20453
  links: apiV2LinksSchema.optional(),
20383
20454
  disclaimer: external_exports2.string().optional(),
20384
20455
  ...apiV2ScanCreationMetadataShape
@@ -20397,6 +20468,9 @@ var apiV2ScanResourceSchema = external_exports2.object({
20397
20468
  completedAt: external_exports2.string().nullable().optional(),
20398
20469
  scanTimeSeconds: external_exports2.number().nullable().optional(),
20399
20470
  score: external_exports2.number().int().min(0).max(100).nullable().optional(),
20471
+ scoreStatus: external_exports2.enum(["provisional", "final"]).optional(),
20472
+ scoreVersion: external_exports2.string().nullable().optional(),
20473
+ scoreUpdatedAt: external_exports2.string().nullable().optional(),
20400
20474
  riskLevel: external_exports2.string().nullable().optional(),
20401
20475
  coverage: external_exports2.object({
20402
20476
  status: external_exports2.string().optional(),
@@ -20442,6 +20516,13 @@ var apiV2EvidenceSummarySchema = external_exports2.object({
20442
20516
  authRequiredForExamples: external_exports2.boolean().optional(),
20443
20517
  examples: external_exports2.array(apiV2EvidenceEventSummarySchema).max(5).optional(),
20444
20518
  projectionWarnings: external_exports2.array(external_exports2.string().max(120)).max(20).optional(),
20519
+ excerpt: external_exports2.object({
20520
+ excerpt: external_exports2.string(),
20521
+ isTruncated: external_exports2.boolean(),
20522
+ truncationMarker: external_exports2.string().nullable(),
20523
+ sourceUrl: external_exports2.string().max(2048).nullable(),
20524
+ evidenceUrl: external_exports2.string().max(2048)
20525
+ }).strict().optional(),
20445
20526
  hasTimingAnchor: external_exports2.boolean().optional(),
20446
20527
  hasVendorAnchor: external_exports2.boolean().optional(),
20447
20528
  hasConsentContext: external_exports2.boolean().optional(),
@@ -20500,6 +20581,35 @@ var apiV2ScanDiagnosticPhaseSchema = external_exports2.object({
20500
20581
  durationMs: external_exports2.number().int().min(0),
20501
20582
  outcome: external_exports2.enum(["success", "degraded", "failed", "unknown"])
20502
20583
  }).strict();
20584
+ var apiV2ScanLaneRunSchema = external_exports2.object({
20585
+ laneId: external_exports2.enum(["consent_proof", "runtime_evidence", "policy_evidence"]),
20586
+ physicalInvocationId: external_exports2.string().max(160),
20587
+ region: external_exports2.string().max(80),
20588
+ phaseName: external_exports2.enum(["preConsentRuntimeScanner", "policySurfaceScanner"]),
20589
+ startedAt: external_exports2.string(),
20590
+ firstResponse: external_exports2.object({
20591
+ at: external_exports2.string(),
20592
+ offsetMs: external_exports2.number().int().min(0),
20593
+ httpStatus: external_exports2.number().int().min(100).max(599),
20594
+ effectiveUrl: external_exports2.string().max(500).nullable()
20595
+ }).strict().nullable(),
20596
+ navigationCount: external_exports2.number().int().min(0),
20597
+ challengeDetection: external_exports2.object({
20598
+ detected: external_exports2.boolean(),
20599
+ type: external_exports2.string().max(120).nullable()
20600
+ }).strict(),
20601
+ executionOutcome: external_exports2.enum(["success", "degraded", "failed"]),
20602
+ accessOutcome: external_exports2.enum([
20603
+ "representative_page",
20604
+ "bot_challenge",
20605
+ "access_denied",
20606
+ "blank_or_unusable",
20607
+ "navigation_failed",
20608
+ "unknown"
20609
+ ]),
20610
+ completedAt: external_exports2.string().nullable(),
20611
+ durationMs: external_exports2.number().int().min(0)
20612
+ }).strict();
20503
20613
  var apiV2PolicyDiscoveryDiagnosticsSchema = external_exports2.object({
20504
20614
  candidatesDiscovered: external_exports2.number().int().min(0).nullable(),
20505
20615
  candidatesAfterDeduplication: external_exports2.number().int().min(0).nullable(),
@@ -20517,6 +20627,7 @@ var apiV2ScanDiagnosticsSchema = external_exports2.object({
20517
20627
  generatedAt: external_exports2.string().nullable(),
20518
20628
  totalWallMs: external_exports2.number().int().min(0).nullable(),
20519
20629
  phases: external_exports2.array(apiV2ScanDiagnosticPhaseSchema).max(20),
20630
+ lanes: external_exports2.array(apiV2ScanLaneRunSchema).max(8).default([]),
20520
20631
  policyDiscovery: apiV2PolicyDiscoveryDiagnosticsSchema,
20521
20632
  links: apiV2LinksSchema.optional(),
20522
20633
  disclaimer: external_exports2.string().optional()
@@ -20533,6 +20644,65 @@ var apiV2PreConsentCookiesTrackersRowSchema = external_exports2.object({
20533
20644
  priority: apiV2PreConsentInventoryPrioritySchema.optional(),
20534
20645
  confidence: apiV2PreConsentInventoryConfidenceSchema.optional(),
20535
20646
  party: external_exports2.enum(["first_party", "third_party", "mixed", "unknown"]).optional(),
20647
+ setByThirdPartyScript: external_exports2.boolean().optional(),
20648
+ set_by_third_party_script: external_exports2.boolean().optional(),
20649
+ cookieDetails: external_exports2.array(external_exports2.object({
20650
+ name: external_exports2.string(),
20651
+ domain: external_exports2.string().nullable(),
20652
+ category: external_exports2.string(),
20653
+ essentiality: external_exports2.enum(["essential", "non_essential", "unknown"]),
20654
+ essentialityConfidence: external_exports2.number().min(0).max(1).nullable(),
20655
+ essentialityReasonCodes: external_exports2.array(external_exports2.string().max(120)).max(20),
20656
+ essentialitySource: external_exports2.enum(["canonical_registry", "deterministic_classifier", "retained_explicit_classification", "unknown"]),
20657
+ description: external_exports2.string(),
20658
+ dataTypes: external_exports2.array(external_exports2.string()),
20659
+ expiresAt: external_exports2.string().nullable(),
20660
+ lifespanSeconds: external_exports2.number().int().min(0).nullable(),
20661
+ lifespanSource: external_exports2.string().nullable(),
20662
+ longLived: external_exports2.boolean(),
20663
+ setByThirdPartyScript: external_exports2.boolean(),
20664
+ set_by_third_party_script: external_exports2.boolean(),
20665
+ setterScriptUrl: external_exports2.string().nullable(),
20666
+ initiatorChain: external_exports2.array(external_exports2.string())
20667
+ }).strict()).optional(),
20668
+ requestDetails: external_exports2.array(external_exports2.object({
20669
+ cookieNamesSent: external_exports2.array(external_exports2.string().max(256)).max(24),
20670
+ essentiality: external_exports2.enum(["non_essential", "unknown"]),
20671
+ hostname: external_exports2.string().max(253).nullable(),
20672
+ identifierParameterNames: external_exports2.array(external_exports2.string().max(256)).max(24),
20673
+ initiatorUrl: external_exports2.string().max(500).nullable(),
20674
+ method: external_exports2.string().max(24).nullable(),
20675
+ path: external_exports2.string().max(2e3).nullable(),
20676
+ responseCookieNamesSet: external_exports2.array(external_exports2.string().max(256)).max(24),
20677
+ responseObserved: external_exports2.boolean(),
20678
+ responseStorageAttempted: external_exports2.boolean(),
20679
+ vendor: external_exports2.string().max(160).nullable()
20680
+ }).strict()).max(50).optional(),
20681
+ canonicalEntity: external_exports2.string().nullable().optional(),
20682
+ purposes: external_exports2.array(external_exports2.string()).optional(),
20683
+ domains: external_exports2.array(external_exports2.string()).optional(),
20684
+ products: external_exports2.array(external_exports2.string()).optional(),
20685
+ dataFlows: external_exports2.array(external_exports2.object({
20686
+ endpoint: external_exports2.string(),
20687
+ idSync: external_exports2.boolean(),
20688
+ networkDestination: external_exports2.object({
20689
+ ip: external_exports2.string().nullable(),
20690
+ country: external_exports2.string().nullable(),
20691
+ countryCode: external_exports2.string().nullable(),
20692
+ asn: external_exports2.number().int().positive().nullable(),
20693
+ provider: external_exports2.string().nullable(),
20694
+ label: external_exports2.literal("server location (may be CDN edge)")
20695
+ }).strict(),
20696
+ controllingEntity: external_exports2.object({
20697
+ legalEntity: external_exports2.string().nullable(),
20698
+ headquartersCountry: external_exports2.string().nullable()
20699
+ }).strict(),
20700
+ transferMechanism: external_exports2.object({
20701
+ mechanism: external_exports2.enum(["adequacy_decision", "dpf_certified", "sccs_assumed_unverified", "unknown"]),
20702
+ basis: external_exports2.string(),
20703
+ verifiedAsOf: external_exports2.string()
20704
+ }).strict()
20705
+ }).strict()).optional(),
20536
20706
  requestCount: external_exports2.number().int().min(0).nullable().optional(),
20537
20707
  phase: apiV2PreConsentInventoryPhaseSchema,
20538
20708
  observedBeforeConsent: external_exports2.boolean(),
@@ -20544,7 +20714,9 @@ var apiV2PreConsentCookiesTrackersSummarySchema = external_exports2.object({
20544
20714
  rowCount: external_exports2.number().int().min(0),
20545
20715
  trackerCount: external_exports2.number().int().min(0),
20546
20716
  cookieCount: external_exports2.number().int().min(0),
20547
- requestCount: external_exports2.number().int().min(0)
20717
+ requestCount: external_exports2.number().int().min(0),
20718
+ vendorCount: external_exports2.number().int().min(0).default(0),
20719
+ domainCount: external_exports2.number().int().min(0).default(0)
20548
20720
  }).strict();
20549
20721
  var apiV2PreConsentCookiesTrackersSchema = external_exports2.object({
20550
20722
  type: external_exports2.literal("certscore_pre_consent_cookies_trackers"),
@@ -20562,7 +20734,7 @@ var mcpPulseDetailSchema = external_exports2.enum(["tiny", "quick", "standard",
20562
20734
  var mcpGptSafePulseDetailSchema = external_exports2.enum(["tiny", "standard", "summary"]);
20563
20735
  var mcpPulseFormatSchema = external_exports2.enum(["json", "markdown"]);
20564
20736
  var mcpPulseFreshnessSchema = external_exports2.enum(["latest", "refresh"]);
20565
- var mcpScanFromSchema = external_exports2.enum(["eu_ie"]);
20737
+ var mcpScanFromSchema = apiV2ScanFromSchema;
20566
20738
  var mcpCreateScanInputSchema = {
20567
20739
  url: external_exports2.string().min(1).describe("Public URL or domain to scan."),
20568
20740
  detail: mcpPulseDetailSchema.optional().describe("Pulse detail level. Defaults to summary."),
@@ -20578,8 +20750,7 @@ var mcpScanSiteInputSchema = {
20578
20750
  maxWaitSeconds: external_exports2.number().int().min(1).max(45).optional().describe("Maximum time to wait before returning the still-running job. Defaults to 45 seconds; never turns an active scan into an error.")
20579
20751
  };
20580
20752
  var mcpGetScanStatusInputSchema = {
20581
- jobId: external_exports2.string().min(1).optional().describe("Pulse job ID for a just-created scan that has not yet returned a scanId."),
20582
- scanId: external_exports2.string().min(1).optional().describe("Preferred stable CertScore scan ID for API v2 scan status.")
20753
+ scanId: external_exports2.string().min(1).describe("Stable CertScore scan ID returned by certscore_scan_site.")
20583
20754
  };
20584
20755
  var mcpGetScanInputSchema = {
20585
20756
  scanId: external_exports2.string().min(1).describe("Stable CertScore scan ID.")
@@ -20594,8 +20765,10 @@ var mcpGetEvidenceInputSchema = {
20594
20765
  };
20595
20766
  var mcpGetScanBundleInputSchema = {
20596
20767
  scanId: external_exports2.string().min(1).describe("Stable CertScore scan ID."),
20597
- maxFindings: external_exports2.number().int().min(1).max(50).optional().describe("Maximum compact findings to return. Defaults to 20."),
20598
- maxPreConsentRows: external_exports2.number().int().min(1).max(50).optional().describe("Maximum pre-consent inventory rows to return. Defaults to 20.")
20768
+ detail: external_exports2.enum(["summary", "findings", "evidence", "full"]).optional().describe("Response detail. Defaults to summary; evidence and full opt into heavier retained context."),
20769
+ maxBytes: external_exports2.number().int().min(5e3).max(2e5).optional().describe("Maximum serialized structured response size in bytes. Defaults to 50000."),
20770
+ maxFindings: external_exports2.number().int().min(1).max(50).optional().describe("Maximum compact findings to return. Defaults to 5 for summary and 20 otherwise."),
20771
+ maxPreConsentRows: external_exports2.number().int().min(1).max(50).optional().describe("Maximum pre-consent inventory rows when evidence is requested. Defaults to 20.")
20599
20772
  };
20600
20773
  var mcpExportFindingsInputSchema = {
20601
20774
  scanId: external_exports2.string().min(1).describe("Stable CertScore scan ID.")
@@ -20642,6 +20815,26 @@ var mcpToolErrorPayloadSchema = external_exports2.object({
20642
20815
  responseBody: external_exports2.unknown().optional()
20643
20816
  }).passthrough()
20644
20817
  }).passthrough();
20818
+ var mcpExecutiveSummarySchema = external_exports2.object({
20819
+ completionSummary: external_exports2.string().optional(),
20820
+ domain: external_exports2.string().optional(),
20821
+ score: external_exports2.number().int().min(0).max(100).nullable().optional(),
20822
+ scoreLabel: external_exports2.string().optional(),
20823
+ scoreMetadata: external_exports2.object({
20824
+ coverageConfidence: external_exports2.string().optional(),
20825
+ coverageRatio: external_exports2.number().nullable().optional(),
20826
+ kind: external_exports2.string().optional(),
20827
+ metricLabel: external_exports2.string().optional(),
20828
+ source: external_exports2.string().optional(),
20829
+ status: external_exports2.string().optional(),
20830
+ version: external_exports2.string().nullable().optional(),
20831
+ withholdingReason: external_exports2.string().nullable().optional()
20832
+ }).passthrough().optional(),
20833
+ riskLevel: external_exports2.string().optional(),
20834
+ actionLabel: external_exports2.string().optional(),
20835
+ issuesToReview: external_exports2.number().int().min(0).optional(),
20836
+ scanTimeSeconds: external_exports2.number().nullable().optional()
20837
+ }).passthrough();
20645
20838
  var mcpCreateScanOutputSchema = external_exports2.object({
20646
20839
  type: external_exports2.literal("certscore_mcp_scan_created"),
20647
20840
  status: external_exports2.string().nullable().optional(),
@@ -20655,18 +20848,41 @@ var mcpCreateScanOutputSchema = external_exports2.object({
20655
20848
  resultDisposition: scanResultDispositionSchema.nullable().optional(),
20656
20849
  noGo: scanNoGoResultSchema.nullable().optional()
20657
20850
  }).passthrough();
20851
+ var mcpActionableErrorSchema = external_exports2.object({
20852
+ code: external_exports2.string(),
20853
+ message: external_exports2.string(),
20854
+ retryable: external_exports2.boolean(),
20855
+ retryAfterSeconds: external_exports2.number().int().nullable(),
20856
+ recommendedNextAction: external_exports2.string(),
20857
+ field: external_exports2.string().optional(),
20858
+ mcpCode: external_exports2.number().int().optional(),
20859
+ name: external_exports2.string().optional(),
20860
+ status: external_exports2.number().int().optional(),
20861
+ responseBody: external_exports2.unknown().optional()
20862
+ }).strict();
20658
20863
  var mcpScanSiteOutputSchema = external_exports2.object({
20659
- type: external_exports2.enum(["certscore_scan", "certscore_scan_job"]),
20864
+ type: external_exports2.enum(["certscore_scan", "certscore_scan_job", "certscore_tool_error"]),
20660
20865
  scanId: external_exports2.string().nullable().optional(),
20661
20866
  jobId: external_exports2.string().optional(),
20662
20867
  domain: external_exports2.string().nullable().optional(),
20663
- status: apiV2ScanStatusSchema,
20868
+ status: external_exports2.union([apiV2ScanStatusSchema, external_exports2.literal("invalid_arguments")]),
20664
20869
  resultDisposition: scanResultDispositionSchema.optional(),
20665
20870
  noGo: scanNoGoResultSchema.optional(),
20666
20871
  scanFrom: apiV2ScanFromSchema.optional(),
20872
+ createdAt: external_exports2.string().nullable().optional(),
20667
20873
  startedAt: external_exports2.string().nullable().optional(),
20668
20874
  completedAt: external_exports2.string().nullable().optional(),
20669
- scanTimeSeconds: external_exports2.number().nullable().optional()
20875
+ scanTimeSeconds: external_exports2.number().nullable().optional(),
20876
+ score: external_exports2.number().int().min(0).max(100).nullable().optional(),
20877
+ scoreStatus: external_exports2.enum(["provisional", "final"]).optional(),
20878
+ scoreVersion: external_exports2.string().nullable().optional(),
20879
+ scoreUpdatedAt: external_exports2.string().nullable().optional(),
20880
+ riskLevel: external_exports2.string().nullable().optional(),
20881
+ coverage: apiV2ScanResourceSchema.shape.coverage.nullable().optional(),
20882
+ error: mcpActionableErrorSchema.nullable(),
20883
+ recommendedNextTool: external_exports2.enum(["certscore_get_scan_status", "certscore_get_scan_bundle"]).nullable(),
20884
+ recommendedNextAction: external_exports2.string(),
20885
+ observationOnlyDisclaimer: external_exports2.string()
20670
20886
  }).passthrough();
20671
20887
  var mcpScanStatusOutputSchema = external_exports2.object({
20672
20888
  type: external_exports2.enum(["certscore_scan_job", "certscore_pulse_status"]).optional(),
@@ -20674,13 +20890,35 @@ var mcpScanStatusOutputSchema = external_exports2.object({
20674
20890
  scanId: external_exports2.string().nullable().optional(),
20675
20891
  scan_id: external_exports2.string().nullable().optional(),
20676
20892
  domain: external_exports2.string().nullable().optional(),
20893
+ url: external_exports2.string().nullable().optional(),
20677
20894
  status: external_exports2.union([apiV2ScanStatusSchema, pulseStatusSchema.shape.status]).optional(),
20678
20895
  resultDisposition: scanResultDispositionSchema.optional(),
20679
20896
  noGo: scanNoGoResultSchema.optional(),
20680
20897
  startedAt: external_exports2.string().nullable().optional(),
20898
+ createdAt: external_exports2.string().nullable().optional(),
20681
20899
  completedAt: external_exports2.string().nullable().optional(),
20682
20900
  scanTimeSeconds: external_exports2.number().nullable().optional(),
20683
- error: mcpToolErrorPayloadSchema.shape.error.optional()
20901
+ score: external_exports2.number().int().min(0).max(100).nullable().optional(),
20902
+ scoreStatus: external_exports2.enum(["provisional", "final"]).optional(),
20903
+ scoreVersion: external_exports2.string().nullable().optional(),
20904
+ scoreUpdatedAt: external_exports2.string().nullable().optional(),
20905
+ riskLevel: external_exports2.string().nullable().optional(),
20906
+ coverage: apiV2ScanResourceSchema.shape.coverage.nullable().optional(),
20907
+ phase: external_exports2.string().optional(),
20908
+ phaseStartedAt: external_exports2.string().nullable().optional(),
20909
+ lastUpdatedAt: external_exports2.string().optional(),
20910
+ lastHeartbeatAt: external_exports2.string().nullable().optional(),
20911
+ progressPercent: external_exports2.number().int().min(0).max(100).optional(),
20912
+ progressIsEstimate: external_exports2.boolean().optional(),
20913
+ estimatedRemainingSeconds: external_exports2.number().int().min(0).nullable().optional(),
20914
+ stalled: external_exports2.boolean().optional(),
20915
+ retryAfterSeconds: external_exports2.number().int().nullable().optional(),
20916
+ error: mcpActionableErrorSchema.nullable(),
20917
+ reportUrl: external_exports2.string().nullable().optional(),
20918
+ links: apiV2ScanResourceSchema.shape.links.optional(),
20919
+ recommendedNextTool: external_exports2.enum(["certscore_get_scan_status", "certscore_get_scan_bundle"]).nullable(),
20920
+ recommendedNextAction: external_exports2.string(),
20921
+ observationOnlyDisclaimer: external_exports2.string()
20684
20922
  }).passthrough();
20685
20923
  var mcpReportOutputSchema = external_exports2.object({
20686
20924
  type: external_exports2.enum(["certscore_pulse", "certscore_pulse_summary", "certscore_pulse_evidence"]).optional(),
@@ -20692,17 +20930,63 @@ var mcpReportOutputSchema = external_exports2.object({
20692
20930
  }).passthrough();
20693
20931
  var mcpScanBundleOutputSchema = external_exports2.object({
20694
20932
  type: external_exports2.literal("certscore_scan_bundle"),
20933
+ detail: external_exports2.enum(["summary", "findings", "evidence", "full"]),
20695
20934
  scanId: external_exports2.string(),
20935
+ domain: external_exports2.string(),
20936
+ url: external_exports2.string().nullable(),
20696
20937
  status: apiV2ScanStatusSchema,
20938
+ score: external_exports2.number().int().min(0).max(100).nullable(),
20939
+ scoreStatus: external_exports2.enum(["provisional", "final"]),
20940
+ scoreVersion: external_exports2.string().nullable(),
20941
+ scoreUpdatedAt: external_exports2.string().nullable(),
20942
+ riskLevel: external_exports2.string().nullable(),
20697
20943
  resultDisposition: scanResultDispositionSchema.nullable().optional(),
20698
20944
  noGo: scanNoGoResultSchema.nullable().optional(),
20699
- scan: apiV2ScanResourceSchema,
20700
- summary: external_exports2.unknown().nullable(),
20701
- findings: external_exports2.array(external_exports2.unknown()),
20702
- evidenceSummary: external_exports2.unknown().nullable(),
20703
- preConsentCookiesTrackers: external_exports2.unknown().nullable(),
20945
+ coverage: apiV2ScanResourceSchema.shape.coverage.nullable(),
20946
+ createdAt: external_exports2.string().nullable(),
20947
+ startedAt: external_exports2.string().nullable(),
20948
+ completedAt: external_exports2.string().nullable(),
20949
+ scanTimeSeconds: external_exports2.number().nullable(),
20950
+ timing: external_exports2.object({
20951
+ createdAt: external_exports2.string().nullable(),
20952
+ startedAt: external_exports2.string().nullable(),
20953
+ completedAt: external_exports2.string().nullable(),
20954
+ scanTimeSeconds: external_exports2.number().nullable()
20955
+ }).strict(),
20956
+ summary: external_exports2.object({
20957
+ headline: external_exports2.string().nullable(),
20958
+ executiveSummary: mcpExecutiveSummarySchema.nullable(),
20959
+ counts: external_exports2.record(external_exports2.union([external_exports2.number(), external_exports2.boolean(), external_exports2.null()])).nullable(),
20960
+ agentInterpretation: pulseAgentInterpretationSchema.nullable()
20961
+ }).strict(),
20962
+ findings: external_exports2.array(apiV2FindingDetailSchema),
20963
+ findingsMetadata: external_exports2.object({
20964
+ shown: external_exports2.number().int().min(0),
20965
+ total: external_exports2.number().int().min(0),
20966
+ truncated: external_exports2.boolean()
20967
+ }).strict(),
20968
+ evidenceSummary: external_exports2.record(external_exports2.unknown()).optional(),
20969
+ fullReport: pulseResponseSchema.optional(),
20970
+ preConsentCookiesTrackers: external_exports2.record(external_exports2.unknown()).optional(),
20704
20971
  links: external_exports2.record(external_exports2.string()).optional(),
20705
- recommendedNextTool: external_exports2.string().nullable(),
20972
+ reportUrl: external_exports2.string().nullable(),
20973
+ recommendedNextTool: external_exports2.enum(["certscore_get_scan_status", "certscore_get_scan_bundle"]).nullable(),
20974
+ recommendedNextAction: external_exports2.string(),
20975
+ error: mcpActionableErrorSchema.nullable(),
20976
+ mcpMetadata: external_exports2.object({
20977
+ detail: external_exports2.enum(["summary", "findings", "evidence", "full"]),
20978
+ heavyEvidenceIncluded: external_exports2.boolean(),
20979
+ findingsTruncated: external_exports2.boolean(),
20980
+ requestedMaxBytes: external_exports2.number().int().min(5e3),
20981
+ actualBytes: external_exports2.number().int().min(0),
20982
+ truncated: external_exports2.boolean(),
20983
+ truncationReason: external_exports2.string().nullable(),
20984
+ omittedSections: external_exports2.array(external_exports2.string()),
20985
+ nextRecommendedMaxBytes: external_exports2.number().int().min(5e3).max(2e5).nullable(),
20986
+ omittedContentAvailableViaUrl: external_exports2.boolean(),
20987
+ contentUrls: external_exports2.record(external_exports2.string())
20988
+ }).strict(),
20989
+ observationOnlyDisclaimer: external_exports2.string(),
20706
20990
  disclaimer: external_exports2.string().nullable()
20707
20991
  }).passthrough();
20708
20992
  var mcpFindingsExportOutputSchema = external_exports2.object({
@@ -20746,23 +21030,15 @@ var mcpPreConsentCookiesTrackersOutputSchema = apiV2PreConsentCookiesTrackersSch
20746
21030
  });
20747
21031
  var certScoreMcpToolContracts = [
20748
21032
  {
20749
- name: "create_scan",
20750
- title: "Deprecated \u2014 Create CertScore Pulse scan",
20751
- description: "Deprecated compatibility alias of scan_site. Use scan_site for new integrations. Returns completed-limited no-go disposition and reason-specific guidance when applicable.",
20752
- inputSchema: mcpCreateScanInputSchema,
20753
- outputSchema: mcpCreateScanOutputSchema,
20754
- annotations: scanCreationAnnotations
20755
- },
20756
- {
20757
- name: "scan_site",
21033
+ name: "certscore_scan_site",
20758
21034
  title: "Scan site",
20759
- description: "Recommended first call. Starts or reuses a public-web scan, reports freshness and anonymous quota decisions, and waits up to 45 seconds by default. If still running, use get_scan_status; otherwise use get_scan_bundle. Completed no-go scans retain completed_limited status and reason-specific guidance.",
21035
+ description: "First call. Starts or reuses a public-web scan and waits up to 45 seconds by default. If status is queued, running, or finalizing, retain scanId and poll certscore_get_scan_status using only that scanId. Stop polling at completed, completed_limited, failed, expired, or rate_limited. For usable completion, call certscore_get_scan_bundle. No-go and limited coverage are observations, never proof of compliance.",
20760
21036
  inputSchema: mcpScanSiteInputSchema,
20761
21037
  outputSchema: mcpScanSiteOutputSchema,
20762
21038
  annotations: scanCreationAnnotations
20763
21039
  },
20764
21040
  {
20765
- name: "get_scan",
21041
+ name: "certscore_get_scan",
20766
21042
  title: "Get CertScore scan",
20767
21043
  description: "Retrieve the API v2 public-safe scan resource, including completed-limited no-go disposition, reason-specific guidance, and timing when available.",
20768
21044
  inputSchema: mcpGetScanInputSchema,
@@ -20770,23 +21046,23 @@ var certScoreMcpToolContracts = [
20770
21046
  annotations: readOnlyOpenWorldAnnotations
20771
21047
  },
20772
21048
  {
20773
- name: "get_scan_status",
20774
- title: "Get CertScore Pulse scan status",
20775
- description: "Retrieve terminal status, including completed_limited no-go disposition and reason-specific guidance. Pass jobId only before a stable scanId is available.",
21049
+ name: "certscore_get_scan_status",
21050
+ title: "Get scan status",
21051
+ description: "Poll with only the stable scanId returned by certscore_scan_site. Active responses include phase, heartbeat, estimated progress, stalled state, and retry delay. Terminal responses include the canonical score, risk, coverage, timestamps, report URL, and an explicit next action. Stop polling at any terminal status.",
20776
21052
  inputSchema: mcpGetScanStatusInputSchema,
20777
21053
  outputSchema: mcpScanStatusOutputSchema,
20778
21054
  annotations: readOnlyOpenWorldAnnotations
20779
21055
  },
20780
21056
  {
20781
- name: "get_report",
21057
+ name: "certscore_get_report",
20782
21058
  title: "Get CertScore Pulse report",
20783
- description: "Retrieve a summary Pulse report, including customer-safe no-go messaging when coverage is completed-limited. Use get_evidence for the larger bounded packet.",
21059
+ description: "Retrieve a summary Pulse report, including customer-safe no-go messaging when coverage is completed-limited. Use certscore_get_evidence for the larger bounded packet.",
20784
21060
  inputSchema: mcpGetReportInputSchema,
20785
21061
  outputSchema: mcpReportOutputSchema,
20786
21062
  annotations: readOnlyOpenWorldAnnotations
20787
21063
  },
20788
21064
  {
20789
- name: "get_evidence",
21065
+ name: "certscore_get_evidence",
20790
21066
  title: "Get CertScore Pulse evidence",
20791
21067
  description: "Retrieve the bounded structured Evidence JSON packet for a stable scan ID. Excludes raw cookie values, raw bodies, sensitive payloads, full DOM, and unredacted query values.",
20792
21068
  inputSchema: mcpGetEvidenceInputSchema,
@@ -20794,15 +21070,15 @@ var certScoreMcpToolContracts = [
20794
21070
  annotations: readOnlyOpenWorldAnnotations
20795
21071
  },
20796
21072
  {
20797
- name: "get_scan_bundle",
20798
- title: "Get compact CertScore scan bundle",
20799
- description: "Recommended second call after scan_site. Returns the canonical scan state, compact report summary, findings, bounded evidence summary, and pre-consent inventory in one agent-friendly response.",
21073
+ name: "certscore_get_scan_bundle",
21074
+ title: "Get scan bundle",
21075
+ description: "Call after completed or completed_limited status. summary returns the canonical overview without finding bodies; findings reserves space for compact findings; evidence reserves findings plus bounded evidence digests and references; full adds all available bounded sections. Every response declares detail and byte-budget metadata, omittedSections, retrieval URLs, and nextRecommendedMaxBytes when truncated. Never interpret no-go, not-observed, or limited coverage as proof of compliance.",
20800
21076
  inputSchema: mcpGetScanBundleInputSchema,
20801
21077
  outputSchema: mcpScanBundleOutputSchema,
20802
21078
  annotations: readOnlyOpenWorldAnnotations
20803
21079
  },
20804
21080
  {
20805
- name: "export_findings",
21081
+ name: "certscore_export_findings",
20806
21082
  title: "Export CertScore findings",
20807
21083
  description: "Return structured findings plus completed-limited no-go disposition and guidance for downstream review or ticketing workflows.",
20808
21084
  inputSchema: mcpExportFindingsInputSchema,
@@ -20810,7 +21086,7 @@ var certScoreMcpToolContracts = [
20810
21086
  annotations: readOnlyOpenWorldAnnotations
20811
21087
  },
20812
21088
  {
20813
- name: "list_findings",
21089
+ name: "certscore_list_findings",
20814
21090
  title: "List CertScore findings",
20815
21091
  description: "List API v2 public-safe findings already projected for a scan.",
20816
21092
  inputSchema: mcpListFindingsInputSchema,
@@ -20818,7 +21094,7 @@ var certScoreMcpToolContracts = [
20818
21094
  annotations: readOnlyOpenWorldAnnotations
20819
21095
  },
20820
21096
  {
20821
- name: "get_pre_consent_cookies_trackers",
21097
+ name: "certscore_get_pre_consent_cookies_trackers",
20822
21098
  title: "Get pre-consent cookies and trackers",
20823
21099
  description: "Retrieve the public-safe Cookies & Trackers (Pre-consent) report table as compact JSON for a scan.",
20824
21100
  inputSchema: mcpGetPreConsentCookiesTrackersInputSchema,
@@ -20826,7 +21102,7 @@ var certScoreMcpToolContracts = [
20826
21102
  annotations: readOnlyOpenWorldAnnotations
20827
21103
  },
20828
21104
  {
20829
- name: "explain_finding",
21105
+ name: "certscore_explain_finding",
20830
21106
  title: "Explain CertScore finding",
20831
21107
  description: "Explain one projected finding with public evidence, caveats, reviewer next steps, and reason-specific no-go context when applicable.",
20832
21108
  inputSchema: mcpExplainFindingInputSchema,
@@ -20834,7 +21110,7 @@ var certScoreMcpToolContracts = [
20834
21110
  annotations: readOnlyOpenWorldAnnotations
20835
21111
  },
20836
21112
  {
20837
- name: "get_latest_domain_scan",
21113
+ name: "certscore_get_latest_domain_scan",
20838
21114
  title: "Get latest domain scan",
20839
21115
  description: "Retrieve the latest eligible API v2 public-safe scan for a domain.",
20840
21116
  inputSchema: mcpGetLatestDomainScanInputSchema,
@@ -20842,7 +21118,7 @@ var certScoreMcpToolContracts = [
20842
21118
  annotations: readOnlyOpenWorldAnnotations
20843
21119
  },
20844
21120
  {
20845
- name: "get_latest_domain_pre_consent_cookies_trackers",
21121
+ name: "certscore_get_latest_domain_pre_consent_cookies_trackers",
20846
21122
  title: "Get latest domain pre-consent cookies and trackers",
20847
21123
  description: "Retrieve the public-safe Cookies & Trackers (Pre-consent) table from the latest eligible scan for a domain.",
20848
21124
  inputSchema: mcpGetLatestDomainPreConsentCookiesTrackersInputSchema,
@@ -20852,10 +21128,17 @@ var certScoreMcpToolContracts = [
20852
21128
  ];
20853
21129
 
20854
21130
  // ../certscore-api-contracts/src/openapi-v2.ts
21131
+ var diagnosticHeaders = {
21132
+ "x-certscore-api-version": { schema: { type: "string", const: "v2" }, description: "CertScore API version marker." },
21133
+ "x-certscore-request-id": { schema: { type: "string" }, description: "Request identifier for support and diagnostics." }
21134
+ };
21135
+ var retryAfterHeader = {
21136
+ "Retry-After": { schema: { type: "integer" }, description: "Recommended retry or polling delay in seconds." }
21137
+ };
20855
21138
  var preConsentCookiesTrackersExample = {
20856
21139
  type: "certscore_pre_consent_cookies_trackers",
20857
21140
  scanId: "00000000-0000-4000-8000-000000000123",
20858
- domain: "example.com",
21141
+ domain: "ergoveritas.com",
20859
21142
  generatedAt: "2026-06-30T12:00:10.000Z",
20860
21143
  summary: {
20861
21144
  rowCount: 2,
@@ -20881,7 +21164,7 @@ var preConsentCookiesTrackersExample = {
20881
21164
  observedBeforeConsent: true,
20882
21165
  evidenceBasis: "public_report_projection",
20883
21166
  firstObservedAtMs: 1234,
20884
- pageUrlHost: "example.com"
21167
+ pageUrlHost: "ergoveritas.com"
20885
21168
  },
20886
21169
  {
20887
21170
  id: "cookie:google:advertising:doubleclick-net",
@@ -20900,7 +21183,7 @@ var preConsentCookiesTrackersExample = {
20900
21183
  observedBeforeConsent: true,
20901
21184
  evidenceBasis: "public_report_projection",
20902
21185
  firstObservedAtMs: 512,
20903
- pageUrlHost: "example.com"
21186
+ pageUrlHost: "ergoveritas.com"
20904
21187
  }
20905
21188
  ],
20906
21189
  links: {
@@ -20917,6 +21200,56 @@ var emptyPreConsentCookiesTrackersExample = {
20917
21200
  summary: { rowCount: 0, trackerCount: 0, cookieCount: 0, requestCount: 0 },
20918
21201
  rows: []
20919
21202
  };
21203
+ var errorContent = {
21204
+ "application/json": {
21205
+ schema: { $ref: "#/components/schemas/ApiError" },
21206
+ examples: {
21207
+ invalidRequest: {
21208
+ summary: "Invalid request",
21209
+ value: { type: "certscore_api_error", error: { code: "invalid_request", message: "Invalid request.", retryable: false, retryAfterSeconds: null, recommendedNextAction: "Correct the request before retrying." }, disclaimer: apiV2Disclaimer }
21210
+ },
21211
+ unauthorized: {
21212
+ summary: "Missing or invalid API key",
21213
+ value: { type: "certscore_api_error", error: { code: "unauthorized", message: "Missing or invalid API key.", retryable: false, retryAfterSeconds: null, recommendedNextAction: "Stop and review authentication before retrying." }, disclaimer: apiV2Disclaimer }
21214
+ },
21215
+ forbidden: {
21216
+ summary: "Missing required scope",
21217
+ value: { type: "certscore_api_error", error: { code: "forbidden", message: "API key is missing the required scope.", retryable: false, retryAfterSeconds: null, recommendedNextAction: "Stop and request the required scope before retrying." }, disclaimer: apiV2Disclaimer }
21218
+ },
21219
+ notFound: {
21220
+ summary: "Resource not found",
21221
+ value: { type: "certscore_api_error", error: { code: "not_found", message: "Scan not found.", retryable: false, retryAfterSeconds: null, recommendedNextAction: "Stop and verify the scan ID." }, disclaimer: apiV2Disclaimer }
21222
+ },
21223
+ rateLimited: {
21224
+ summary: "Rate limited",
21225
+ value: {
21226
+ type: "certscore_api_error",
21227
+ error: {
21228
+ code: "rate_limited",
21229
+ message: "Completed scan resource read limit exceeded. Retry after 60 seconds.",
21230
+ retryable: true,
21231
+ retryAfterSeconds: 60,
21232
+ recommendedNextAction: "Wait for Retry-After, then make one bounded retrieval. Do not poll terminal scan resources."
21233
+ },
21234
+ disclaimer: apiV2Disclaimer
21235
+ }
21236
+ },
21237
+ internalError: {
21238
+ summary: "Temporary service error",
21239
+ value: {
21240
+ type: "certscore_api_error",
21241
+ error: { code: "internal_error", message: "CertScore API v2 is temporarily unavailable. Try again later.", retryable: true, retryAfterSeconds: 30, recommendedNextAction: "Retry after 30 seconds. If the error repeats, stop and contact CertScore support." },
21242
+ disclaimer: apiV2Disclaimer
21243
+ }
21244
+ }
21245
+ }
21246
+ }
21247
+ };
21248
+ var readRateLimitedResponse = {
21249
+ description: "Weighted scan-resource read limit reached. Honor Retry-After before retrying and do not poll terminal scan resources.",
21250
+ headers: { ...diagnosticHeaders, ...retryAfterHeader },
21251
+ content: errorContent
21252
+ };
20920
21253
 
20921
21254
  // ../../node_modules/@modelcontextprotocol/sdk/node_modules/zod/v3/helpers/util.js
20922
21255
  var util2;
@@ -24922,17 +25255,33 @@ function normalizeObjectSchema(schema) {
24922
25255
  }
24923
25256
  return void 0;
24924
25257
  }
25258
+ function getDotPath(path) {
25259
+ if (path.length === 0) {
25260
+ return "object root";
25261
+ }
25262
+ return path.reduce((acc, seg, index) => {
25263
+ if (index === 0) {
25264
+ return String(seg);
25265
+ }
25266
+ if (typeof seg === "number") {
25267
+ return `${acc}[${seg}]`;
25268
+ }
25269
+ return `${acc}.${seg}`;
25270
+ }, "");
25271
+ }
24925
25272
  function getParseErrorMessage(error2) {
24926
25273
  if (error2 && typeof error2 === "object") {
25274
+ if ("issues" in error2 && Array.isArray(error2.issues) && error2.issues.length > 0) {
25275
+ return error2.issues.map((i) => {
25276
+ if (!i.path?.length) {
25277
+ return i.message;
25278
+ }
25279
+ return `${i.message} at ${getDotPath(i.path)}`;
25280
+ }).join("\n");
25281
+ }
24927
25282
  if ("message" in error2 && typeof error2.message === "string") {
24928
25283
  return error2.message;
24929
25284
  }
24930
- if ("issues" in error2 && Array.isArray(error2.issues) && error2.issues.length > 0) {
24931
- const firstIssue = error2.issues[0];
24932
- if (firstIssue && typeof firstIssue === "object" && "message" in firstIssue) {
24933
- return String(firstIssue.message);
24934
- }
24935
- }
24936
25285
  try {
24937
25286
  return JSON.stringify(error2);
24938
25287
  } catch {
@@ -31525,16 +31874,7 @@ var Server = class extends Protocol {
31525
31874
  if (!methodSchema) {
31526
31875
  throw new Error("Schema is missing a method literal");
31527
31876
  }
31528
- let methodValue;
31529
- if (isZ4Schema(methodSchema)) {
31530
- const v4Schema = methodSchema;
31531
- const v4Def = v4Schema._zod?.def;
31532
- methodValue = v4Def?.value ?? v4Schema.value;
31533
- } else {
31534
- const v3Schema = methodSchema;
31535
- const legacyDef = v3Schema._def;
31536
- methodValue = legacyDef?.value ?? v3Schema.value;
31537
- }
31877
+ const methodValue = getLiteralValue(methodSchema);
31538
31878
  if (typeof methodValue !== "string") {
31539
31879
  throw new Error("Schema method literal must be a string");
31540
31880
  }
@@ -32731,6 +33071,18 @@ var MAX_EVIDENCE_PACKET_CHARS = 25e4;
32731
33071
  var EVIDENCE_STRING_CHARS = 4e3;
32732
33072
  var EVIDENCE_ARRAY_ITEMS = 40;
32733
33073
  var EVIDENCE_OBJECT_KEYS = 80;
33074
+ var OBSERVATION_ONLY_DISCLAIMER = "Observation only: no-go, not-observed, and limited-coverage results are not proof of compliance.";
33075
+ function toolResultSummary(payload) {
33076
+ if (payload === null || typeof payload !== "object" || Array.isArray(payload)) {
33077
+ return "CertScore tool call completed. Read structuredContent for the result.";
33078
+ }
33079
+ const record2 = payload;
33080
+ const type = typeof record2.type === "string" ? record2.type : "result";
33081
+ const status = typeof record2.status === "string" ? `; status=${record2.status}` : "";
33082
+ const scanId = typeof record2.scanId === "string" ? `; scanId=${record2.scanId}` : "";
33083
+ const score = typeof record2.score === "number" ? `; score=${record2.score}` : "";
33084
+ return `CertScore ${type}${status}${scanId}${score}. Full result is in structuredContent.`;
33085
+ }
32734
33086
  function toToolResult(payload) {
32735
33087
  const structuredContent = payload !== null && typeof payload === "object" && !Array.isArray(payload) ? payload : { value: payload };
32736
33088
  return {
@@ -32738,25 +33090,32 @@ function toToolResult(payload) {
32738
33090
  content: [
32739
33091
  {
32740
33092
  type: "text",
32741
- text: JSON.stringify(payload)
33093
+ text: toolResultSummary(payload)
32742
33094
  }
32743
33095
  ]
32744
33096
  };
32745
33097
  }
32746
33098
  function toToolError(error2) {
32747
- const payload = error2 instanceof CertScoreError ? {
33099
+ const responseRecord = error2 instanceof CertScoreError && error2.responseBody && typeof error2.responseBody === "object" && !Array.isArray(error2.responseBody) ? error2.responseBody : null;
33100
+ const terminalError = responseRecord?.error && typeof responseRecord.error === "object" && !Array.isArray(responseRecord.error) ? responseRecord.error : null;
33101
+ const status = error2 instanceof CertScoreError ? error2.status : void 0;
33102
+ const retryable = typeof terminalError?.retryable === "boolean" ? terminalError.retryable : status === 429 || typeof status === "number" && status >= 500;
33103
+ const retryAfterSeconds = typeof terminalError?.retryAfterSeconds === "number" ? terminalError.retryAfterSeconds : error2 instanceof CertScoreError && "retryAfterSeconds" in error2 && typeof error2.retryAfterSeconds === "number" ? error2.retryAfterSeconds : retryable ? 30 : null;
33104
+ const code = error2 instanceof CertScoreError ? error2.code : "internal_error";
33105
+ const message = error2 instanceof Error ? error2.message : "Unknown CertScore MCP error.";
33106
+ const recommendedNextAction = typeof terminalError?.recommendedNextAction === "string" ? terminalError.recommendedNextAction : retryable ? `Wait ${retryAfterSeconds ?? 30} seconds, then retry the same request. Stop and contact CertScore support if the error repeats.` : "Correct the request using the error details, then retry only if the requested operation is still appropriate.";
33107
+ const payload = {
32748
33108
  error: {
32749
- name: error2.name,
32750
- message: error2.message,
32751
- status: error2.status,
32752
- code: error2.code,
32753
- retryAfterSeconds: "retryAfterSeconds" in error2 ? error2.retryAfterSeconds : void 0,
32754
- responseBody: truncateErrorResponseBody(error2.responseBody)
32755
- }
32756
- } : {
32757
- error: {
32758
- name: error2 instanceof Error ? error2.name : "Error",
32759
- message: error2 instanceof Error ? error2.message : "Unknown CertScore MCP error."
33109
+ code,
33110
+ message,
33111
+ retryable,
33112
+ retryAfterSeconds,
33113
+ recommendedNextAction,
33114
+ ...error2 instanceof CertScoreError ? {
33115
+ name: error2.name,
33116
+ status: error2.status,
33117
+ responseBody: truncateErrorResponseBody(error2.responseBody)
33118
+ } : {}
32760
33119
  }
32761
33120
  };
32762
33121
  return {
@@ -32764,6 +33123,95 @@ function toToolError(error2) {
32764
33123
  isError: true
32765
33124
  };
32766
33125
  }
33126
+ function toInvalidArgumentsToolError(errorMessage) {
33127
+ const tool = errorMessage.match(/tool ([a-z_]+)/i)?.[1] ?? null;
33128
+ const field = errorMessage.match(/\bat ([a-zA-Z0-9_.-]+)/)?.[1] ?? (errorMessage.includes("url") ? "url" : errorMessage.includes("scanId") ? "scanId" : null);
33129
+ const missing = /required|expected string, received undefined/i.test(errorMessage);
33130
+ const message = field ? missing ? `The ${field} field is required.` : `The ${field} field is invalid.` : `The arguments for ${tool ?? "this tool"} are invalid.`;
33131
+ const recommendedNextAction = field === "url" ? "Provide a public URL or domain." : field === "scanId" ? "Provide the stable scanId returned by certscore_scan_site." : "Correct the named fields using the tool input schema, then retry.";
33132
+ const error2 = {
33133
+ code: "invalid_arguments",
33134
+ message,
33135
+ ...field ? { field } : {},
33136
+ retryable: false,
33137
+ retryAfterSeconds: null,
33138
+ recommendedNextAction,
33139
+ mcpCode: -32602
33140
+ };
33141
+ const payload = tool === "certscore_scan_site" ? {
33142
+ type: "certscore_tool_error",
33143
+ status: "invalid_arguments",
33144
+ error: error2,
33145
+ recommendedNextTool: null,
33146
+ recommendedNextAction,
33147
+ observationOnlyDisclaimer: OBSERVATION_ONLY_DISCLAIMER
33148
+ } : { error: error2 };
33149
+ return {
33150
+ content: [{ type: "text", text: JSON.stringify(payload) }],
33151
+ ...tool === "certscore_scan_site" ? { structuredContent: payload } : {},
33152
+ isError: true
33153
+ };
33154
+ }
33155
+ function terminalErrorForResult(value) {
33156
+ const existing = value.error && typeof value.error === "object" && !Array.isArray(value.error) ? value.error : null;
33157
+ if (existing) {
33158
+ const retryable = existing.retryable === true;
33159
+ return {
33160
+ code: typeof existing.code === "string" ? existing.code : String(value.status ?? "scan_failed"),
33161
+ message: typeof existing.message === "string" ? existing.message : "The scan did not produce a canonical result.",
33162
+ retryable,
33163
+ retryAfterSeconds: typeof existing.retryAfterSeconds === "number" ? existing.retryAfterSeconds : retryable ? 30 : null,
33164
+ recommendedNextAction: typeof existing.recommendedNextAction === "string" ? existing.recommendedNextAction : retryable ? "Wait for the recommended delay, then retry certscore_scan_site with freshness=refresh." : "Stop and review the scan limitations before deciding whether to change the URL."
33165
+ };
33166
+ }
33167
+ if (value.status === "completed_limited" && value.noGo) {
33168
+ const retryable = value.noGo.retryLikelyToHelp === true;
33169
+ return {
33170
+ code: typeof value.noGo.reasonCode === "string" ? value.noGo.reasonCode : "completed_limited",
33171
+ message: typeof value.noGo.explanation === "string" ? value.noGo.explanation : "The scan completed with a no-go limitation.",
33172
+ retryable,
33173
+ retryAfterSeconds: retryable ? 30 : null,
33174
+ recommendedNextAction: typeof value.noGo.recommendedNextAction === "string" ? value.noGo.recommendedNextAction : "Review the retained limitation and change the URL or site state before retrying."
33175
+ };
33176
+ }
33177
+ const fallback = {
33178
+ failed: {
33179
+ code: "scanner_runtime_failure",
33180
+ message: "The scan ended before a canonical result could be produced.",
33181
+ retryable: true,
33182
+ retryAfterSeconds: 30,
33183
+ recommendedNextAction: "Wait 30 seconds, then retry certscore_scan_site with freshness=refresh. Stop if the failure repeats."
33184
+ },
33185
+ expired: {
33186
+ code: "scan_expired",
33187
+ message: "The scan expired before a canonical result was available.",
33188
+ retryable: true,
33189
+ retryAfterSeconds: 30,
33190
+ recommendedNextAction: "Wait 30 seconds, then retry certscore_scan_site with freshness=refresh."
33191
+ },
33192
+ rate_limited: {
33193
+ code: "rate_limited",
33194
+ message: "The scan is rate limited.",
33195
+ retryable: true,
33196
+ retryAfterSeconds: typeof value.retryAfterSeconds === "number" ? value.retryAfterSeconds : 30,
33197
+ recommendedNextAction: "Wait for the recommended delay, then retry the same certscore_scan_site request."
33198
+ }
33199
+ };
33200
+ return fallback[String(value.status)] ?? null;
33201
+ }
33202
+ function withMcpAgentGuidance(value) {
33203
+ const status = String(value.status ?? "");
33204
+ const active = status === "queued" || status === "running" || status === "finalizing";
33205
+ const usable = status === "completed" || status === "completed_limited";
33206
+ const error2 = terminalErrorForResult(value);
33207
+ return {
33208
+ ...value,
33209
+ error: error2,
33210
+ recommendedNextTool: active ? "certscore_get_scan_status" : usable ? "certscore_get_scan_bundle" : null,
33211
+ recommendedNextAction: error2?.recommendedNextAction ?? value.recommendedNextAction ?? (active ? `Poll certscore_get_scan_status with scanId ${value.scanId ?? value.jobId} after the recommended delay.` : usable ? `Call certscore_get_scan_bundle with scanId ${value.scanId ?? value.jobId} for the canonical findings and limitations.` : "Review the result and retained limitations."),
33212
+ observationOnlyDisclaimer: OBSERVATION_ONLY_DISCLAIMER
33213
+ };
33214
+ }
32767
33215
  function boundEvidencePacket(payload, maxSerializedChars = MAX_EVIDENCE_PACKET_CHARS) {
32768
33216
  const originalSerializedChars = measureSerializedChars(payload);
32769
33217
  if (originalSerializedChars <= maxSerializedChars) {
@@ -32807,6 +33255,107 @@ function boundEvidencePacket(payload, maxSerializedChars = MAX_EVIDENCE_PACKET_C
32807
33255
  function measureSerializedChars(value) {
32808
33256
  return JSON.stringify(value)?.length ?? 0;
32809
33257
  }
33258
+ function measureSerializedBytes(value) {
33259
+ return new TextEncoder().encode(JSON.stringify(value)).byteLength;
33260
+ }
33261
+ function updateBundleActualBytes(bundle) {
33262
+ bundle.mcpMetadata.actualBytes = 0;
33263
+ for (let attempt = 0; attempt < 3; attempt += 1) {
33264
+ const measured = measureSerializedBytes(bundle);
33265
+ if (bundle.mcpMetadata.actualBytes === measured) {
33266
+ break;
33267
+ }
33268
+ bundle.mcpMetadata.actualBytes = measured;
33269
+ }
33270
+ return bundle.mcpMetadata.actualBytes;
33271
+ }
33272
+ function boundedText(value, maxChars) {
33273
+ if (typeof value !== "string") {
33274
+ return value;
33275
+ }
33276
+ return value.length > maxChars ? `${value.slice(0, maxChars)}\u2026[truncated]` : value;
33277
+ }
33278
+ function compactBundleFinding(finding) {
33279
+ const evidence = finding.evidence && typeof finding.evidence === "object" && !Array.isArray(finding.evidence) ? finding.evidence : {};
33280
+ return {
33281
+ type: finding.type,
33282
+ id: finding.id,
33283
+ scanId: finding.scanId,
33284
+ label: boundedText(finding.label, 140),
33285
+ criticality: finding.criticality,
33286
+ confidence: finding.confidence,
33287
+ plainEnglish: boundedText(finding.plainEnglish, 280),
33288
+ ...finding.resultDisposition ? { resultDisposition: finding.resultDisposition } : {},
33289
+ ...finding.noGo ? { noGo: finding.noGo } : {},
33290
+ reviewLenses: Array.isArray(finding.reviewLenses) ? finding.reviewLenses.slice(0, 2) : [],
33291
+ evidence: {
33292
+ basis: evidence.basis,
33293
+ summary: boundedText(evidence.summary, 220),
33294
+ ...evidence.phase !== void 0 ? { phase: evidence.phase } : {},
33295
+ exampleCount: evidence.exampleCount,
33296
+ examplesShown: evidence.examplesShown,
33297
+ ...evidence.hasTimingAnchor !== void 0 ? { hasTimingAnchor: evidence.hasTimingAnchor } : {},
33298
+ ...evidence.hasVendorAnchor !== void 0 ? { hasVendorAnchor: evidence.hasVendorAnchor } : {},
33299
+ ...evidence.hasConsentContext !== void 0 ? { hasConsentContext: evidence.hasConsentContext } : {},
33300
+ ...evidence.hasPolicyAnchor !== void 0 ? { hasPolicyAnchor: evidence.hasPolicyAnchor } : {}
33301
+ },
33302
+ ...finding.nextStep !== void 0 ? { nextStep: boundedText(finding.nextStep, 180) } : {}
33303
+ };
33304
+ }
33305
+ function compactPriorityEvidenceSummary(summary) {
33306
+ const firstDigest = Array.isArray(summary.digests) ? summary.digests[0] : null;
33307
+ const firstReference = summary.references && typeof summary.references === "object" && !Array.isArray(summary.references) ? Object.entries(summary.references).find(([, value]) => typeof value === "string") : null;
33308
+ return {
33309
+ digests: firstDigest ? [{
33310
+ findingId: firstDigest.findingId,
33311
+ basis: firstDigest.basis ?? null,
33312
+ summary: boundedText(firstDigest.summary, 180) ?? null,
33313
+ phase: firstDigest.phase ?? null,
33314
+ evidenceUrl: firstDigest.evidenceUrl ?? firstReference?.[1] ?? null
33315
+ }] : [],
33316
+ evidenceAvailable: summary.evidenceAvailable === true,
33317
+ evidenceSafetyNotes: [],
33318
+ references: firstDigest ? {} : firstReference ? { [firstReference[0]]: firstReference[1] } : {}
33319
+ };
33320
+ }
33321
+ function bundleEvidenceSummary(evidence, findings, links, includeDiagnostics) {
33322
+ const digests = findings.slice(0, 3).map((finding) => {
33323
+ const findingEvidence = finding.evidence && typeof finding.evidence === "object" && !Array.isArray(finding.evidence) ? finding.evidence : {};
33324
+ return {
33325
+ findingId: finding.id,
33326
+ basis: findingEvidence.basis ?? null,
33327
+ summary: boundedText(findingEvidence.summary, 500) ?? null,
33328
+ phase: findingEvidence.phase ?? null,
33329
+ evidenceUrl: findingEvidence.excerpt && typeof findingEvidence.excerpt === "object" && !Array.isArray(findingEvidence.excerpt) ? findingEvidence.excerpt.evidenceUrl ?? null : typeof links.findings === "string" ? links.findings : typeof links.report === "string" ? links.report : null
33330
+ };
33331
+ });
33332
+ return {
33333
+ digests,
33334
+ evidenceAvailable: digests.length > 0 || Object.keys(evidence).length > 0,
33335
+ evidenceSafetyNotes: Array.isArray(evidence.evidenceSafetyNotes) ? evidence.evidenceSafetyNotes.slice(0, 3).map((note) => boundedText(note, 300)) : [],
33336
+ references: Object.fromEntries(Object.entries(links).filter(([key, value]) => ["findings", "pulse", "report", "preConsentCookiesTrackers"].includes(key) && typeof value === "string")),
33337
+ ...includeDiagnostics ? {
33338
+ projectionDiagnostics: compactEvidenceValue(evidence.projectionDiagnostics ?? null, {
33339
+ arrayItems: 12,
33340
+ depth: 4,
33341
+ objectKeys: 24,
33342
+ stringChars: 600
33343
+ }),
33344
+ coverageDiagnostics: compactEvidenceValue(evidence.coverageDiagnostics ?? null, {
33345
+ arrayItems: 12,
33346
+ depth: 4,
33347
+ objectKeys: 24,
33348
+ stringChars: 600
33349
+ }),
33350
+ policySurfaceCoverage: compactEvidenceValue(evidence.policySurfaceCoverage ?? null, {
33351
+ arrayItems: 12,
33352
+ depth: 4,
33353
+ objectKeys: 24,
33354
+ stringChars: 600
33355
+ })
33356
+ } : {}
33357
+ };
33358
+ }
32810
33359
  function compactEvidenceValue(value, options) {
32811
33360
  if (value === null || value === void 0) {
32812
33361
  return value;
@@ -32935,9 +33484,6 @@ function normalizeDetail2(detail) {
32935
33484
  function normalizeFormat2(format) {
32936
33485
  return format ?? "json";
32937
33486
  }
32938
- function scanIdFromStatus(status) {
32939
- return status.scanId ?? status.scan_id ?? null;
32940
- }
32941
33487
  function scanIdFromPulse(report) {
32942
33488
  const nestedScan = "scan" in report && report.scan && typeof report.scan === "object" ? report.scan : void 0;
32943
33489
  return report.scanId ?? report.scan_id ?? nestedScan?.scanId ?? null;
@@ -33014,69 +33560,261 @@ function limitPreConsentRows(payload, options = {}) {
33014
33560
  };
33015
33561
  }
33016
33562
  function buildScanBundle(input) {
33017
- const maxFindings = Math.min(50, Math.max(1, input.maxFindings ?? 20));
33563
+ const detail = input.detail ?? "summary";
33564
+ const maxFindings = Math.min(50, Math.max(1, input.maxFindings ?? (detail === "summary" ? 5 : 20)));
33018
33565
  const maxPreConsentRows = Math.min(50, Math.max(1, input.maxPreConsentRows ?? 20));
33019
- const evidence = input.evidence;
33020
- const report = input.report;
33021
- const findings = Array.isArray(input.findings.findings) ? input.findings.findings.slice(0, maxFindings) : [];
33022
- const preConsentRows = Array.isArray(input.preConsentCookiesTrackers.rows) ? input.preConsentCookiesTrackers.rows.slice(0, maxPreConsentRows) : [];
33566
+ const evidence = input.evidence ?? {};
33567
+ const report = input.report ?? {};
33568
+ const allFindings = Array.isArray(input.findings.findings) ? input.findings.findings : [];
33569
+ const findings = detail === "summary" ? [] : allFindings.slice(0, maxFindings).map((finding) => detail === "full" ? finding : compactBundleFinding(finding));
33570
+ const preConsentRows = Array.isArray(input.preConsentCookiesTrackers?.rows) ? input.preConsentCookiesTrackers.rows.slice(0, maxPreConsentRows) : [];
33023
33571
  const links = {
33024
33572
  ...input.scan.links ?? {},
33025
33573
  ...report.links && typeof report.links === "object" && !Array.isArray(report.links) ? report.links : {}
33026
33574
  };
33027
- return {
33575
+ const maxBytes = Math.min(2e5, Math.max(5e3, input.maxBytes ?? 5e4));
33576
+ const contentUrls = Object.fromEntries(Object.entries({
33577
+ report: input.scan.links?.report ?? links.report,
33578
+ findings: links.findings,
33579
+ evidence: links.pulse,
33580
+ preConsentCookiesTrackers: links.preConsentCookiesTrackers
33581
+ }).filter(([, value]) => typeof value === "string"));
33582
+ const intentionallyOmitted = /* @__PURE__ */ new Set();
33583
+ if (detail === "summary" && allFindings.length > 0) intentionallyOmitted.add("findings");
33584
+ if ((detail === "summary" || detail === "findings") && (Object.keys(evidence).length > 0 || allFindings.length > 0)) intentionallyOmitted.add("evidence");
33585
+ if (detail !== "full" && Object.keys(report).length > 0) intentionallyOmitted.add("fullReport");
33586
+ const guidedScan = withMcpAgentGuidance(input.scan);
33587
+ const bundle = {
33028
33588
  type: "certscore_scan_bundle",
33589
+ detail,
33029
33590
  scanId: input.scan.scanId,
33591
+ domain: input.scan.domain,
33592
+ url: input.scan.url ?? null,
33030
33593
  status: input.scan.status,
33594
+ score: input.scan.score ?? null,
33595
+ scoreStatus: input.scan.scoreStatus ?? "final",
33596
+ scoreVersion: input.scan.scoreVersion ?? null,
33597
+ scoreUpdatedAt: input.scan.scoreUpdatedAt ?? null,
33598
+ riskLevel: input.scan.riskLevel ?? null,
33031
33599
  resultDisposition: input.scan.resultDisposition ?? null,
33032
33600
  noGo: input.scan.noGo ?? null,
33033
- scan: input.scan,
33601
+ coverage: input.scan.coverage ?? null,
33602
+ createdAt: input.scan.createdAt ?? null,
33603
+ startedAt: input.scan.startedAt ?? null,
33604
+ completedAt: input.scan.completedAt ?? null,
33605
+ scanTimeSeconds: input.scan.scanTimeSeconds ?? null,
33606
+ timing: {
33607
+ createdAt: input.scan.createdAt ?? null,
33608
+ startedAt: input.scan.startedAt ?? null,
33609
+ completedAt: input.scan.completedAt ?? null,
33610
+ scanTimeSeconds: input.scan.scanTimeSeconds ?? null
33611
+ },
33034
33612
  summary: {
33035
- summary: report.summary ?? null,
33613
+ headline: report.summary && typeof report.summary === "object" && !Array.isArray(report.summary) ? report.summary.headline ?? null : null,
33036
33614
  executiveSummary: report.executiveSummary ?? null,
33037
33615
  counts: report.counts ?? null,
33038
- coverage: report.coverage ?? input.scan.coverage ?? null,
33039
33616
  agentInterpretation: report.agentInterpretation ?? null
33040
33617
  },
33041
33618
  findings,
33042
33619
  findingsMetadata: {
33043
33620
  shown: findings.length,
33044
- total: Array.isArray(input.findings.findings) ? input.findings.findings.length : 0,
33045
- truncated: Array.isArray(input.findings.findings) && input.findings.findings.length > findings.length
33621
+ total: allFindings.length,
33622
+ truncated: allFindings.length > findings.length
33046
33623
  },
33047
- evidenceSummary: {
33048
- evidenceSafetyNotes: evidence.evidenceSafetyNotes ?? null,
33049
- projectionDiagnostics: evidence.projectionDiagnostics ?? null,
33050
- projectedFindings: compactEvidenceValue(evidence.projectedFindings ?? [], {
33051
- arrayItems: maxFindings,
33052
- depth: 5,
33053
- objectKeys: 40,
33054
- stringChars: 1e3
33055
- }),
33056
- coverageDiagnostics: compactEvidenceValue(evidence.coverageDiagnostics ?? null, {
33057
- arrayItems: 20,
33058
- depth: 5,
33059
- objectKeys: 40,
33060
- stringChars: 1e3
33061
- }),
33062
- policySurfaceCoverage: compactEvidenceValue(evidence.policySurfaceCoverage ?? null, {
33063
- arrayItems: 20,
33064
- depth: 5,
33065
- objectKeys: 40,
33066
- stringChars: 1e3
33624
+ ...detail === "evidence" || detail === "full" ? { evidenceSummary: bundleEvidenceSummary(evidence, allFindings, links, detail === "full") } : {},
33625
+ ...detail === "full" ? {
33626
+ fullReport: compactEvidenceValue(report, {
33627
+ arrayItems: 50,
33628
+ depth: 8,
33629
+ objectKeys: 100,
33630
+ stringChars: 4e3
33067
33631
  })
33068
- },
33069
- preConsentCookiesTrackers: {
33632
+ } : {},
33633
+ ...input.preConsentCookiesTrackers ? { preConsentCookiesTrackers: {
33070
33634
  summary: input.preConsentCookiesTrackers.summary,
33071
33635
  rows: preConsentRows,
33072
33636
  shown: preConsentRows.length,
33073
33637
  total: Array.isArray(input.preConsentCookiesTrackers.rows) ? input.preConsentCookiesTrackers.rows.length : 0,
33074
33638
  truncated: Array.isArray(input.preConsentCookiesTrackers.rows) && input.preConsentCookiesTrackers.rows.length > preConsentRows.length
33075
- },
33639
+ } } : {},
33076
33640
  links,
33077
- recommendedNextTool: findings.length > 0 ? "explain_finding" : null,
33078
- disclaimer: input.scan.disclaimer ?? input.report.disclaimer ?? null
33641
+ reportUrl: input.scan.links?.report ?? (typeof links.report === "string" ? links.report : null),
33642
+ recommendedNextTool: null,
33643
+ recommendedNextAction: guidedScan.error?.recommendedNextAction ?? (detail === "summary" && allFindings.length > 0 ? "Review this overview, then request detail=findings for bounded finding objects or open the report URL." : findings.length > 0 ? "Review the returned findings and follow their evidence references. Use detail=evidence only when deeper retained context is needed." : "Review coverage and limitations before interpreting the absence of findings."),
33644
+ error: guidedScan.error,
33645
+ mcpMetadata: {
33646
+ detail,
33647
+ heavyEvidenceIncluded: detail === "evidence" || detail === "full",
33648
+ findingsTruncated: allFindings.length > findings.length,
33649
+ requestedMaxBytes: maxBytes,
33650
+ actualBytes: 0,
33651
+ truncated: false,
33652
+ truncationReason: null,
33653
+ omittedSections: [...intentionallyOmitted],
33654
+ nextRecommendedMaxBytes: null,
33655
+ omittedContentAvailableViaUrl: intentionallyOmitted.size > 0 && Object.keys(contentUrls).length > 0,
33656
+ contentUrls
33657
+ },
33658
+ observationOnlyDisclaimer: OBSERVATION_ONLY_DISCLAIMER,
33659
+ disclaimer: input.scan.disclaimer ?? input.report?.disclaimer ?? OBSERVATION_ONLY_DISCLAIMER
33660
+ };
33661
+ const recommendationCandidates = [];
33662
+ const markBudgetOmitted = (section, reason, requiredBytes = bundle.mcpMetadata.actualBytes) => {
33663
+ bundle.mcpMetadata.truncated = true;
33664
+ bundle.mcpMetadata.truncationReason ??= reason;
33665
+ if (!bundle.mcpMetadata.omittedSections.includes(section)) {
33666
+ bundle.mcpMetadata.omittedSections.push(section);
33667
+ }
33668
+ recommendationCandidates.push(requiredBytes);
33669
+ bundle.mcpMetadata.omittedContentAvailableViaUrl = Object.keys(contentUrls).length > 0;
33079
33670
  };
33671
+ const refresh = () => updateBundleActualBytes(bundle);
33672
+ refresh();
33673
+ if (bundle.mcpMetadata.actualBytes > maxBytes && bundle.fullReport) {
33674
+ markBudgetOmitted("fullReport", "full_report_omitted_to_byte_limit");
33675
+ delete bundle.fullReport;
33676
+ refresh();
33677
+ }
33678
+ if (bundle.mcpMetadata.actualBytes > maxBytes && detail === "full" && bundle.evidenceSummary) {
33679
+ const compactSummary = bundleEvidenceSummary(evidence, allFindings, links, false);
33680
+ markBudgetOmitted("evidenceDiagnostics", "evidence_diagnostics_omitted_to_byte_limit");
33681
+ bundle.evidenceSummary = compactSummary;
33682
+ refresh();
33683
+ }
33684
+ const inventoryRows = bundle.preConsentCookiesTrackers?.rows;
33685
+ while (bundle.mcpMetadata.actualBytes > maxBytes && Array.isArray(inventoryRows) && inventoryRows.length > 0) {
33686
+ markBudgetOmitted("preConsentCookiesTrackers", "evidence_inventory_reduced_to_byte_limit");
33687
+ inventoryRows.pop();
33688
+ bundle.preConsentCookiesTrackers.shown = inventoryRows.length;
33689
+ bundle.preConsentCookiesTrackers.truncated = true;
33690
+ refresh();
33691
+ }
33692
+ if (bundle.mcpMetadata.actualBytes > maxBytes && bundle.preConsentCookiesTrackers) {
33693
+ markBudgetOmitted("preConsentCookiesTrackers", "evidence_inventory_omitted_to_byte_limit");
33694
+ delete bundle.preConsentCookiesTrackers;
33695
+ refresh();
33696
+ }
33697
+ while (bundle.mcpMetadata.actualBytes > maxBytes && bundle.findings.length > 1) {
33698
+ markBudgetOmitted("additionalFindings", "findings_reduced_to_byte_limit");
33699
+ bundle.findings.pop();
33700
+ bundle.findingsMetadata.shown = bundle.findings.length;
33701
+ bundle.findingsMetadata.truncated = true;
33702
+ bundle.mcpMetadata.findingsTruncated = true;
33703
+ refresh();
33704
+ }
33705
+ if (bundle.mcpMetadata.actualBytes > maxBytes) {
33706
+ markBudgetOmitted("summaryDetail", "summary_compacted_to_byte_limit");
33707
+ bundle.summary = {
33708
+ headline: boundedText(bundle.summary?.headline, 240) ?? null,
33709
+ executiveSummary: null,
33710
+ counts: bundle.summary?.counts ? { totalAutomatedFindingCount: bundle.findingsMetadata.total } : null,
33711
+ agentInterpretation: null
33712
+ };
33713
+ refresh();
33714
+ }
33715
+ if (bundle.mcpMetadata.actualBytes > maxBytes) {
33716
+ markBudgetOmitted("coverageDetail", "coverage_compacted_to_byte_limit");
33717
+ bundle.coverage = compactEvidenceValue(bundle.coverage, {
33718
+ arrayItems: 3,
33719
+ depth: 3,
33720
+ objectKeys: 8,
33721
+ stringChars: 240
33722
+ });
33723
+ refresh();
33724
+ }
33725
+ if (bundle.mcpMetadata.actualBytes > maxBytes && bundle.links) {
33726
+ markBudgetOmitted("additionalLinks", "links_compacted_to_byte_limit");
33727
+ bundle.links = Object.fromEntries(Object.entries(bundle.links).filter(([key]) => ["self", "report"].includes(key)));
33728
+ refresh();
33729
+ }
33730
+ if (bundle.mcpMetadata.actualBytes > maxBytes && bundle.evidenceSummary) {
33731
+ markBudgetOmitted("evidenceDetail", "evidence_compacted_to_preserve_priority_content");
33732
+ bundle.evidenceSummary = compactPriorityEvidenceSummary(bundle.evidenceSummary);
33733
+ refresh();
33734
+ }
33735
+ if (bundle.mcpMetadata.actualBytes > maxBytes && bundle.disclaimer === OBSERVATION_ONLY_DISCLAIMER) {
33736
+ markBudgetOmitted("duplicateDisclaimer", "duplicate_disclaimer_omitted_to_byte_limit");
33737
+ bundle.disclaimer = null;
33738
+ refresh();
33739
+ }
33740
+ if (bundle.mcpMetadata.actualBytes > maxBytes && bundle.findings.length > 0) {
33741
+ markBudgetOmitted("findings", "finding_omitted_to_byte_limit");
33742
+ bundle.findings = [];
33743
+ bundle.findingsMetadata.shown = 0;
33744
+ bundle.findingsMetadata.truncated = bundle.findingsMetadata.total > 0;
33745
+ bundle.mcpMetadata.findingsTruncated = bundle.findingsMetadata.total > 0;
33746
+ refresh();
33747
+ }
33748
+ if (bundle.mcpMetadata.actualBytes > maxBytes && bundle.evidenceSummary) {
33749
+ markBudgetOmitted("evidence", "evidence_digest_omitted_to_byte_limit");
33750
+ delete bundle.evidenceSummary;
33751
+ bundle.mcpMetadata.heavyEvidenceIncluded = false;
33752
+ refresh();
33753
+ }
33754
+ if (bundle.mcpMetadata.truncated) {
33755
+ const required2 = Math.min(...recommendationCandidates.filter((value) => Number.isFinite(value) && value > maxBytes));
33756
+ bundle.mcpMetadata.nextRecommendedMaxBytes = Math.min(2e5, Math.max(maxBytes + 1e3, Math.ceil((Number.isFinite(required2) ? required2 : maxBytes + 1e3) / 1e3) * 1e3));
33757
+ bundle.recommendedNextAction = `Retry with maxBytes=${bundle.mcpMetadata.nextRecommendedMaxBytes} or open ${bundle.reportUrl ? "the report URL" : "an available content URL"}.`;
33758
+ refresh();
33759
+ }
33760
+ if (bundle.mcpMetadata.actualBytes > maxBytes) {
33761
+ const minimal = {
33762
+ type: bundle.type,
33763
+ detail: bundle.detail,
33764
+ scanId: bundle.scanId,
33765
+ domain: bundle.domain,
33766
+ url: bundle.url,
33767
+ status: bundle.status,
33768
+ score: bundle.score,
33769
+ scoreStatus: bundle.scoreStatus,
33770
+ scoreVersion: bundle.scoreVersion,
33771
+ scoreUpdatedAt: bundle.scoreUpdatedAt,
33772
+ riskLevel: bundle.riskLevel,
33773
+ resultDisposition: bundle.resultDisposition,
33774
+ noGo: bundle.noGo,
33775
+ coverage: null,
33776
+ createdAt: bundle.createdAt,
33777
+ startedAt: bundle.startedAt,
33778
+ completedAt: bundle.completedAt,
33779
+ scanTimeSeconds: bundle.scanTimeSeconds,
33780
+ timing: bundle.timing,
33781
+ summary: {
33782
+ headline: bundle.summary?.headline ?? null,
33783
+ executiveSummary: null,
33784
+ counts: bundle.summary?.counts ?? null,
33785
+ agentInterpretation: null
33786
+ },
33787
+ findings: [],
33788
+ findingsMetadata: {
33789
+ shown: 0,
33790
+ total: bundle.findingsMetadata.total,
33791
+ truncated: bundle.findingsMetadata.total > 0
33792
+ },
33793
+ links: Object.fromEntries(Object.entries(bundle.links ?? {}).filter(([key]) => ["docs", "report", "self"].includes(key))),
33794
+ reportUrl: bundle.reportUrl,
33795
+ recommendedNextTool: null,
33796
+ recommendedNextAction: bundle.recommendedNextAction,
33797
+ error: bundle.error,
33798
+ mcpMetadata: {
33799
+ detail,
33800
+ heavyEvidenceIncluded: false,
33801
+ findingsTruncated: bundle.findingsMetadata.total > 0,
33802
+ requestedMaxBytes: maxBytes,
33803
+ actualBytes: 0,
33804
+ truncated: true,
33805
+ truncationReason: "minimal_canonical_result_returned_to_byte_limit",
33806
+ omittedSections: [.../* @__PURE__ */ new Set([...bundle.mcpMetadata.omittedSections, "summaryDetail", "findings", "evidence"])],
33807
+ nextRecommendedMaxBytes: bundle.mcpMetadata.nextRecommendedMaxBytes ?? Math.min(2e5, maxBytes + 1e3),
33808
+ omittedContentAvailableViaUrl: Object.keys(contentUrls).length > 0,
33809
+ contentUrls
33810
+ },
33811
+ observationOnlyDisclaimer: bundle.observationOnlyDisclaimer,
33812
+ disclaimer: bundle.disclaimer
33813
+ };
33814
+ updateBundleActualBytes(minimal);
33815
+ return minimal;
33816
+ }
33817
+ return bundle;
33080
33818
  }
33081
33819
  function explainFinding(report, findingId) {
33082
33820
  const finding = findingsFromReport(report).find((candidate) => candidate.id === findingId);
@@ -33114,8 +33852,18 @@ function explainFinding(report, findingId) {
33114
33852
  }
33115
33853
 
33116
33854
  // src/server.ts
33117
- var createScanDeprecationWarningPrinted = false;
33118
33855
  var DEFAULT_MCP_SCAN_WAIT_MS = 45e3;
33856
+ async function retryTransientOriginFailure(operation) {
33857
+ try {
33858
+ return await operation();
33859
+ } catch (error2) {
33860
+ const retryable = error2 instanceof Error && "status" in error2 && [502, 503, 504].includes(Number(error2.status));
33861
+ if (!retryable) {
33862
+ throw error2;
33863
+ }
33864
+ return operation();
33865
+ }
33866
+ }
33119
33867
  function scanCreationMetadata(value) {
33120
33868
  return {
33121
33869
  executionMode: value.executionMode,
@@ -33156,7 +33904,9 @@ function createCertScoreMcpServer(options = {}) {
33156
33904
  name: "certscore",
33157
33905
  version: CERTSCORE_MCP_VERSION
33158
33906
  });
33159
- const lightTools = /* @__PURE__ */ new Set(["scan_site", "get_scan_status", "get_scan_bundle"]);
33907
+ const sdkCreateToolError = server.createToolError.bind(server);
33908
+ server.createToolError = (message) => message.includes("Input validation error:") ? toInvalidArgumentsToolError(message) : sdkCreateToolError(message);
33909
+ const lightTools = /* @__PURE__ */ new Set(["certscore_scan_site", "certscore_get_scan_status", "certscore_get_scan_bundle"]);
33160
33910
  const registerMcpTool = server.registerTool.bind(server);
33161
33911
  const registerTool = (name, contract, handler) => {
33162
33912
  if (options.toolProfile === "light" && !lightTools.has(name)) {
@@ -33164,45 +33914,9 @@ function createCertScoreMcpServer(options = {}) {
33164
33914
  }
33165
33915
  registerMcpTool(name, contract, handler);
33166
33916
  };
33167
- async function createPulseScanTool(input) {
33168
- const result = await client.submitScan(input.url, {
33169
- detail: normalizeDetail2(input.detail),
33170
- format: normalizeFormat2(input.format),
33171
- freshness: input.freshness ?? "latest",
33172
- scanFrom: input.scanFrom
33173
- });
33174
- return {
33175
- type: "certscore_mcp_scan_created",
33176
- status: result.status,
33177
- jobId: result.jobId ?? null,
33178
- scanId: result.scanId ?? result.scan_id ?? null,
33179
- completed: result.completed ?? false,
33180
- statusUrl: result.statusUrl ?? result.nextCheckUrl ?? null,
33181
- resultUrl: result.resultUrl ?? null,
33182
- reportUrl: result.reportUrl ?? null,
33183
- pulse: result.pulse ?? null,
33184
- resultDisposition: result.resultDisposition ?? result.pulse?.resultDisposition ?? null,
33185
- noGo: result.noGo ?? result.pulse?.noGo ?? null
33186
- };
33187
- }
33188
- registerTool(
33189
- "create_scan",
33190
- toolContract("create_scan"),
33191
- async (input) => {
33192
- try {
33193
- if (!createScanDeprecationWarningPrinted) {
33194
- createScanDeprecationWarningPrinted = true;
33195
- console.error("[certscore-mcp] create_scan is deprecated in the 0.2.x line. Use scan_site for new integrations.");
33196
- }
33197
- return toToolResult(await createPulseScanTool(input));
33198
- } catch (error2) {
33199
- return toToolError(error2);
33200
- }
33201
- }
33202
- );
33203
33917
  registerTool(
33204
- "scan_site",
33205
- toolContract("scan_site"),
33918
+ "certscore_scan_site",
33919
+ toolContract("certscore_scan_site"),
33206
33920
  async (input) => {
33207
33921
  try {
33208
33922
  const created = await client.scans.create(input.url, {
@@ -33210,30 +33924,35 @@ function createCertScoreMcpServer(options = {}) {
33210
33924
  scanFrom: input.scanFrom
33211
33925
  });
33212
33926
  if (input.waitForCompletion === false || created.type === "certscore_scan") {
33213
- return toToolResult(created);
33927
+ return toToolResult(withMcpAgentGuidance(created));
33214
33928
  }
33215
33929
  try {
33216
33930
  const completed = await client.scans.wait(created, {
33217
33931
  maxWaitMs: Math.min(input.maxWaitSeconds ? input.maxWaitSeconds * 1e3 : DEFAULT_MCP_SCAN_WAIT_MS, DEFAULT_MCP_SCAN_WAIT_MS)
33218
33932
  });
33219
- return toToolResult({
33933
+ return toToolResult(withMcpAgentGuidance({
33220
33934
  ...completed,
33221
- ...scanCreationMetadata(created),
33222
- recommendedNextTool: "get_scan_bundle"
33223
- });
33935
+ ...scanCreationMetadata(created)
33936
+ }));
33224
33937
  } catch (error2) {
33225
- if (!(error2 instanceof CertScoreTimeoutError)) {
33226
- throw error2;
33227
- }
33228
33938
  const scanId = created.scanId ?? created.scan_id;
33229
- if (scanId) {
33230
- return toToolResult({
33231
- ...await client.scans.status(scanId),
33232
- ...scanCreationMetadata(created),
33233
- recommendedNextTool: "get_scan_status"
33234
- });
33939
+ console.warn(JSON.stringify({
33940
+ event: "mcp.certscore_scan_site.wait_deferred",
33941
+ errorName: error2 instanceof Error ? error2.name : "UnknownError",
33942
+ jobId: created.jobId ?? null,
33943
+ scanId: scanId ?? null,
33944
+ status: created.status ?? null
33945
+ }));
33946
+ if (error2 instanceof CertScoreTimeoutError && scanId) {
33947
+ try {
33948
+ return toToolResult(withMcpAgentGuidance({
33949
+ ...await client.scans.status(scanId),
33950
+ ...scanCreationMetadata(created)
33951
+ }));
33952
+ } catch {
33953
+ }
33235
33954
  }
33236
- return toToolResult(created);
33955
+ return toToolResult(withMcpAgentGuidance(created));
33237
33956
  }
33238
33957
  } catch (error2) {
33239
33958
  return toToolError(error2);
@@ -33241,8 +33960,8 @@ function createCertScoreMcpServer(options = {}) {
33241
33960
  }
33242
33961
  );
33243
33962
  registerTool(
33244
- "get_scan",
33245
- toolContract("get_scan"),
33963
+ "certscore_get_scan",
33964
+ toolContract("certscore_get_scan"),
33246
33965
  async ({ scanId }) => {
33247
33966
  try {
33248
33967
  return toToolResult(await client.scans.get(scanId));
@@ -33252,54 +33971,48 @@ function createCertScoreMcpServer(options = {}) {
33252
33971
  }
33253
33972
  );
33254
33973
  registerTool(
33255
- "get_scan_status",
33256
- toolContract("get_scan_status"),
33257
- async ({ jobId, scanId }) => {
33974
+ "certscore_get_scan_status",
33975
+ toolContract("certscore_get_scan_status"),
33976
+ async ({ scanId }) => {
33258
33977
  try {
33259
- if (scanId) {
33260
- const status2 = await client.scans.status(scanId);
33261
- const needsTerminalHydration = status2.status === "completed" || status2.status === "completed_limited";
33262
- if (needsTerminalHydration) {
33263
- try {
33264
- const scan = await client.scans.get(scanId);
33265
- return toToolResult({
33266
- ...status2,
33267
- type: "certscore_scan_job",
33268
- status: scan.status,
33269
- domain: scan.domain,
33270
- resultDisposition: scan.resultDisposition,
33271
- noGo: scan.noGo,
33272
- startedAt: scan.startedAt,
33273
- completedAt: scan.completedAt,
33274
- scanTimeSeconds: scan.scanTimeSeconds,
33275
- recommendedNextTool: "get_scan_bundle"
33276
- });
33277
- } catch {
33278
- }
33978
+ const status = await client.scans.status(scanId);
33979
+ const needsTerminalHydration = status.status === "completed" || status.status === "completed_limited";
33980
+ if (needsTerminalHydration) {
33981
+ try {
33982
+ const scan = await client.scans.get(scanId);
33983
+ return toToolResult(withMcpAgentGuidance({
33984
+ ...status,
33985
+ type: "certscore_scan_job",
33986
+ status: scan.status,
33987
+ domain: scan.domain,
33988
+ url: scan.url ?? null,
33989
+ resultDisposition: scan.resultDisposition,
33990
+ noGo: scan.noGo,
33991
+ createdAt: scan.createdAt ?? null,
33992
+ startedAt: scan.startedAt,
33993
+ completedAt: scan.completedAt,
33994
+ scanTimeSeconds: scan.scanTimeSeconds,
33995
+ score: scan.score ?? null,
33996
+ scoreStatus: scan.scoreStatus,
33997
+ scoreVersion: scan.scoreVersion ?? null,
33998
+ scoreUpdatedAt: scan.scoreUpdatedAt ?? null,
33999
+ riskLevel: scan.riskLevel ?? null,
34000
+ coverage: scan.coverage ?? null,
34001
+ reportUrl: scan.links?.report ?? status.reportUrl ?? null,
34002
+ links: { ...status.links, ...scan.links }
34003
+ }));
34004
+ } catch {
33279
34005
  }
33280
- return toToolResult(status2);
33281
- }
33282
- if (!jobId) {
33283
- return toToolResult({
33284
- error: {
33285
- name: "InvalidToolInput",
33286
- message: "Provide either scanId for API v2 scan status or jobId for Pulse job status."
33287
- }
33288
- });
33289
34006
  }
33290
- const status = await client.getJobStatus(jobId);
33291
- return toToolResult({
33292
- ...status,
33293
- scanId: scanIdFromStatus(status)
33294
- });
34007
+ return toToolResult(withMcpAgentGuidance(status));
33295
34008
  } catch (error2) {
33296
34009
  return toToolError(error2);
33297
34010
  }
33298
34011
  }
33299
34012
  );
33300
34013
  registerTool(
33301
- "get_report",
33302
- toolContract("get_report"),
34014
+ "certscore_get_report",
34015
+ toolContract("certscore_get_report"),
33303
34016
  async ({ scanId, detail, format }) => {
33304
34017
  try {
33305
34018
  const normalizedFormat = normalizeFormat2(format);
@@ -33317,8 +34030,8 @@ function createCertScoreMcpServer(options = {}) {
33317
34030
  }
33318
34031
  );
33319
34032
  registerTool(
33320
- "get_evidence",
33321
- toolContract("get_evidence"),
34033
+ "certscore_get_evidence",
34034
+ toolContract("certscore_get_evidence"),
33322
34035
  async ({ scanId }) => {
33323
34036
  try {
33324
34037
  return toToolResult(boundEvidencePacket(await client.getScan(scanId, { detail: "evidence", format: "json" })));
@@ -33328,20 +34041,37 @@ function createCertScoreMcpServer(options = {}) {
33328
34041
  }
33329
34042
  );
33330
34043
  registerTool(
33331
- "get_scan_bundle",
33332
- toolContract("get_scan_bundle"),
33333
- async ({ scanId, maxFindings, maxPreConsentRows }) => {
34044
+ "certscore_get_scan_bundle",
34045
+ toolContract("certscore_get_scan_bundle"),
34046
+ async ({ scanId, detail = "summary", maxBytes, maxFindings, maxPreConsentRows }) => {
33334
34047
  try {
33335
- const [scan, report, evidence, findings, preConsentCookiesTrackers] = await Promise.all([
33336
- client.scans.get(scanId),
33337
- client.getScan(scanId, { detail: "summary", format: "json" }),
33338
- client.getScan(scanId, { detail: "evidence", format: "json" }),
33339
- client.findings.list(scanId),
33340
- client.scans.preConsentCookiesTrackers(scanId)
34048
+ const scan = await retryTransientOriginFailure(() => client.scans.get(scanId));
34049
+ if (scan.status === "completed_limited" && scan.resultDisposition === "no_go") {
34050
+ return toToolResult(buildScanBundle({
34051
+ detail,
34052
+ evidence: null,
34053
+ findings: { type: "certscore_finding_list", scanId, findings: [] },
34054
+ maxBytes,
34055
+ maxFindings,
34056
+ maxPreConsentRows,
34057
+ preConsentCookiesTrackers: null,
34058
+ report: null,
34059
+ scan
34060
+ }));
34061
+ }
34062
+ const includeEvidence = detail === "evidence" || detail === "full";
34063
+ const reportDetail = detail === "full" ? "full" : includeEvidence ? "evidence" : "summary";
34064
+ const [report, findings, preConsentCookiesTrackers] = await Promise.all([
34065
+ retryTransientOriginFailure(() => client.getScan(scanId, { detail: reportDetail, format: "json" })),
34066
+ retryTransientOriginFailure(() => client.findings.list(scanId)),
34067
+ includeEvidence ? retryTransientOriginFailure(() => client.scans.preConsentCookiesTrackers(scanId)) : Promise.resolve(null)
33341
34068
  ]);
34069
+ const evidence = includeEvidence ? report : null;
33342
34070
  return toToolResult(buildScanBundle({
34071
+ detail,
33343
34072
  evidence,
33344
34073
  findings,
34074
+ maxBytes,
33345
34075
  maxFindings,
33346
34076
  maxPreConsentRows,
33347
34077
  preConsentCookiesTrackers,
@@ -33354,8 +34084,8 @@ function createCertScoreMcpServer(options = {}) {
33354
34084
  }
33355
34085
  );
33356
34086
  registerTool(
33357
- "export_findings",
33358
- toolContract("export_findings"),
34087
+ "certscore_export_findings",
34088
+ toolContract("certscore_export_findings"),
33359
34089
  async ({ scanId }) => {
33360
34090
  try {
33361
34091
  const report = await client.getScan(scanId, { detail: "full", format: "json" });
@@ -33366,8 +34096,8 @@ function createCertScoreMcpServer(options = {}) {
33366
34096
  }
33367
34097
  );
33368
34098
  registerTool(
33369
- "list_findings",
33370
- toolContract("list_findings"),
34099
+ "certscore_list_findings",
34100
+ toolContract("certscore_list_findings"),
33371
34101
  async ({ limit, offset, scanId }) => {
33372
34102
  try {
33373
34103
  return toToolResult(paginateFindingList(await client.findings.list(scanId), { limit, offset }));
@@ -33377,8 +34107,8 @@ function createCertScoreMcpServer(options = {}) {
33377
34107
  }
33378
34108
  );
33379
34109
  registerTool(
33380
- "get_pre_consent_cookies_trackers",
33381
- toolContract("get_pre_consent_cookies_trackers"),
34110
+ "certscore_get_pre_consent_cookies_trackers",
34111
+ toolContract("certscore_get_pre_consent_cookies_trackers"),
33382
34112
  async ({ maxRows, scanId }) => {
33383
34113
  try {
33384
34114
  return toToolResult(limitPreConsentRows(await client.scans.preConsentCookiesTrackers(scanId), { maxRows }));
@@ -33388,8 +34118,8 @@ function createCertScoreMcpServer(options = {}) {
33388
34118
  }
33389
34119
  );
33390
34120
  registerTool(
33391
- "explain_finding",
33392
- toolContract("explain_finding"),
34121
+ "certscore_explain_finding",
34122
+ toolContract("certscore_explain_finding"),
33393
34123
  async ({ scanId, findingId }) => {
33394
34124
  try {
33395
34125
  return toToolResult(await client.findings.explain(scanId, findingId));
@@ -33399,8 +34129,8 @@ function createCertScoreMcpServer(options = {}) {
33399
34129
  }
33400
34130
  );
33401
34131
  registerTool(
33402
- "get_latest_domain_scan",
33403
- toolContract("get_latest_domain_scan"),
34132
+ "certscore_get_latest_domain_scan",
34133
+ toolContract("certscore_get_latest_domain_scan"),
33404
34134
  async ({ domain: domain2, scanFrom }) => {
33405
34135
  try {
33406
34136
  return toToolResult(await client.domains.latest(domain2, { scanFrom }));
@@ -33410,8 +34140,8 @@ function createCertScoreMcpServer(options = {}) {
33410
34140
  }
33411
34141
  );
33412
34142
  registerTool(
33413
- "get_latest_domain_pre_consent_cookies_trackers",
33414
- toolContract("get_latest_domain_pre_consent_cookies_trackers"),
34143
+ "certscore_get_latest_domain_pre_consent_cookies_trackers",
34144
+ toolContract("certscore_get_latest_domain_pre_consent_cookies_trackers"),
33415
34145
  async ({ domain: domain2, maxRows, scanFrom }) => {
33416
34146
  try {
33417
34147
  return toToolResult(limitPreConsentRows(await client.domains.latestPreConsentCookiesTrackers(domain2, { scanFrom }), { maxRows }));