@certscore/mcp 0.2.11 → 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"]);
@@ -20333,7 +20366,9 @@ var apiV2ScanCreationMetadataShape = {
20333
20366
  anonymousQuotaLimit: external_exports2.number().int().min(0).nullable().optional(),
20334
20367
  anonymousQuotaRemaining: external_exports2.number().int().min(0).nullable().optional(),
20335
20368
  anonymousQuotaResetAt: external_exports2.string().nullable().optional(),
20336
- recommendedNextTool: external_exports2.enum(["get_scan_status", "get_scan_bundle"]).optional()
20369
+ upgradeSupportEmail: external_exports2.string().email().nullable().optional(),
20370
+ upgradeMessage: external_exports2.string().nullable().optional(),
20371
+ recommendedNextTool: external_exports2.enum(["certscore_get_scan_status", "certscore_get_scan_bundle"]).optional()
20337
20372
  };
20338
20373
  var apiV2LinksSchema = external_exports2.object({
20339
20374
  self: external_exports2.string().optional(),
@@ -20349,7 +20384,19 @@ var apiV2ErrorSchema = external_exports2.object({
20349
20384
  error: external_exports2.object({
20350
20385
  code: external_exports2.enum(["invalid_request", "invalid_url", "not_found", "rate_limited", "unauthorized", "forbidden", "scan_unavailable", "internal_error"]),
20351
20386
  message: external_exports2.string(),
20352
- 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()
20353
20400
  }).passthrough(),
20354
20401
  links: apiV2LinksSchema.optional(),
20355
20402
  disclaimer: external_exports2.string().optional(),
@@ -20367,6 +20414,7 @@ var apiV2ScanJobSchema = external_exports2.object({
20367
20414
  jobId: external_exports2.string(),
20368
20415
  scanId: external_exports2.string().nullable().optional(),
20369
20416
  domain: external_exports2.string().nullable().optional(),
20417
+ url: external_exports2.string().nullable().optional(),
20370
20418
  status: apiV2ScanStatusSchema,
20371
20419
  resultDisposition: scanResultDispositionSchema.optional(),
20372
20420
  noGo: scanNoGoResultSchema.optional(),
@@ -20375,8 +20423,33 @@ var apiV2ScanJobSchema = external_exports2.object({
20375
20423
  startedAt: external_exports2.string().nullable().optional(),
20376
20424
  completedAt: external_exports2.string().nullable().optional(),
20377
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(),
20378
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(),
20379
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(),
20380
20453
  links: apiV2LinksSchema.optional(),
20381
20454
  disclaimer: external_exports2.string().optional(),
20382
20455
  ...apiV2ScanCreationMetadataShape
@@ -20395,6 +20468,9 @@ var apiV2ScanResourceSchema = external_exports2.object({
20395
20468
  completedAt: external_exports2.string().nullable().optional(),
20396
20469
  scanTimeSeconds: external_exports2.number().nullable().optional(),
20397
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(),
20398
20474
  riskLevel: external_exports2.string().nullable().optional(),
20399
20475
  coverage: external_exports2.object({
20400
20476
  status: external_exports2.string().optional(),
@@ -20440,6 +20516,13 @@ var apiV2EvidenceSummarySchema = external_exports2.object({
20440
20516
  authRequiredForExamples: external_exports2.boolean().optional(),
20441
20517
  examples: external_exports2.array(apiV2EvidenceEventSummarySchema).max(5).optional(),
20442
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(),
20443
20526
  hasTimingAnchor: external_exports2.boolean().optional(),
20444
20527
  hasVendorAnchor: external_exports2.boolean().optional(),
20445
20528
  hasConsentContext: external_exports2.boolean().optional(),
@@ -20498,6 +20581,35 @@ var apiV2ScanDiagnosticPhaseSchema = external_exports2.object({
20498
20581
  durationMs: external_exports2.number().int().min(0),
20499
20582
  outcome: external_exports2.enum(["success", "degraded", "failed", "unknown"])
20500
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();
20501
20613
  var apiV2PolicyDiscoveryDiagnosticsSchema = external_exports2.object({
20502
20614
  candidatesDiscovered: external_exports2.number().int().min(0).nullable(),
20503
20615
  candidatesAfterDeduplication: external_exports2.number().int().min(0).nullable(),
@@ -20515,6 +20627,7 @@ var apiV2ScanDiagnosticsSchema = external_exports2.object({
20515
20627
  generatedAt: external_exports2.string().nullable(),
20516
20628
  totalWallMs: external_exports2.number().int().min(0).nullable(),
20517
20629
  phases: external_exports2.array(apiV2ScanDiagnosticPhaseSchema).max(20),
20630
+ lanes: external_exports2.array(apiV2ScanLaneRunSchema).max(8).default([]),
20518
20631
  policyDiscovery: apiV2PolicyDiscoveryDiagnosticsSchema,
20519
20632
  links: apiV2LinksSchema.optional(),
20520
20633
  disclaimer: external_exports2.string().optional()
@@ -20531,6 +20644,65 @@ var apiV2PreConsentCookiesTrackersRowSchema = external_exports2.object({
20531
20644
  priority: apiV2PreConsentInventoryPrioritySchema.optional(),
20532
20645
  confidence: apiV2PreConsentInventoryConfidenceSchema.optional(),
20533
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(),
20534
20706
  requestCount: external_exports2.number().int().min(0).nullable().optional(),
20535
20707
  phase: apiV2PreConsentInventoryPhaseSchema,
20536
20708
  observedBeforeConsent: external_exports2.boolean(),
@@ -20542,7 +20714,9 @@ var apiV2PreConsentCookiesTrackersSummarySchema = external_exports2.object({
20542
20714
  rowCount: external_exports2.number().int().min(0),
20543
20715
  trackerCount: external_exports2.number().int().min(0),
20544
20716
  cookieCount: external_exports2.number().int().min(0),
20545
- 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)
20546
20720
  }).strict();
20547
20721
  var apiV2PreConsentCookiesTrackersSchema = external_exports2.object({
20548
20722
  type: external_exports2.literal("certscore_pre_consent_cookies_trackers"),
@@ -20560,7 +20734,7 @@ var mcpPulseDetailSchema = external_exports2.enum(["tiny", "quick", "standard",
20560
20734
  var mcpGptSafePulseDetailSchema = external_exports2.enum(["tiny", "standard", "summary"]);
20561
20735
  var mcpPulseFormatSchema = external_exports2.enum(["json", "markdown"]);
20562
20736
  var mcpPulseFreshnessSchema = external_exports2.enum(["latest", "refresh"]);
20563
- var mcpScanFromSchema = external_exports2.enum(["eu_ie"]);
20737
+ var mcpScanFromSchema = apiV2ScanFromSchema;
20564
20738
  var mcpCreateScanInputSchema = {
20565
20739
  url: external_exports2.string().min(1).describe("Public URL or domain to scan."),
20566
20740
  detail: mcpPulseDetailSchema.optional().describe("Pulse detail level. Defaults to summary."),
@@ -20576,8 +20750,7 @@ var mcpScanSiteInputSchema = {
20576
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.")
20577
20751
  };
20578
20752
  var mcpGetScanStatusInputSchema = {
20579
- jobId: external_exports2.string().min(1).optional().describe("Pulse job ID for a just-created scan that has not yet returned a scanId."),
20580
- 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.")
20581
20754
  };
20582
20755
  var mcpGetScanInputSchema = {
20583
20756
  scanId: external_exports2.string().min(1).describe("Stable CertScore scan ID.")
@@ -20592,8 +20765,10 @@ var mcpGetEvidenceInputSchema = {
20592
20765
  };
20593
20766
  var mcpGetScanBundleInputSchema = {
20594
20767
  scanId: external_exports2.string().min(1).describe("Stable CertScore scan ID."),
20595
- maxFindings: external_exports2.number().int().min(1).max(50).optional().describe("Maximum compact findings to return. Defaults to 20."),
20596
- 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.")
20597
20772
  };
20598
20773
  var mcpExportFindingsInputSchema = {
20599
20774
  scanId: external_exports2.string().min(1).describe("Stable CertScore scan ID.")
@@ -20640,6 +20815,26 @@ var mcpToolErrorPayloadSchema = external_exports2.object({
20640
20815
  responseBody: external_exports2.unknown().optional()
20641
20816
  }).passthrough()
20642
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();
20643
20838
  var mcpCreateScanOutputSchema = external_exports2.object({
20644
20839
  type: external_exports2.literal("certscore_mcp_scan_created"),
20645
20840
  status: external_exports2.string().nullable().optional(),
@@ -20653,18 +20848,41 @@ var mcpCreateScanOutputSchema = external_exports2.object({
20653
20848
  resultDisposition: scanResultDispositionSchema.nullable().optional(),
20654
20849
  noGo: scanNoGoResultSchema.nullable().optional()
20655
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();
20656
20863
  var mcpScanSiteOutputSchema = external_exports2.object({
20657
- type: external_exports2.enum(["certscore_scan", "certscore_scan_job"]),
20864
+ type: external_exports2.enum(["certscore_scan", "certscore_scan_job", "certscore_tool_error"]),
20658
20865
  scanId: external_exports2.string().nullable().optional(),
20659
20866
  jobId: external_exports2.string().optional(),
20660
20867
  domain: external_exports2.string().nullable().optional(),
20661
- status: apiV2ScanStatusSchema,
20868
+ status: external_exports2.union([apiV2ScanStatusSchema, external_exports2.literal("invalid_arguments")]),
20662
20869
  resultDisposition: scanResultDispositionSchema.optional(),
20663
20870
  noGo: scanNoGoResultSchema.optional(),
20664
20871
  scanFrom: apiV2ScanFromSchema.optional(),
20872
+ createdAt: external_exports2.string().nullable().optional(),
20665
20873
  startedAt: external_exports2.string().nullable().optional(),
20666
20874
  completedAt: external_exports2.string().nullable().optional(),
20667
- 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()
20668
20886
  }).passthrough();
20669
20887
  var mcpScanStatusOutputSchema = external_exports2.object({
20670
20888
  type: external_exports2.enum(["certscore_scan_job", "certscore_pulse_status"]).optional(),
@@ -20672,13 +20890,35 @@ var mcpScanStatusOutputSchema = external_exports2.object({
20672
20890
  scanId: external_exports2.string().nullable().optional(),
20673
20891
  scan_id: external_exports2.string().nullable().optional(),
20674
20892
  domain: external_exports2.string().nullable().optional(),
20893
+ url: external_exports2.string().nullable().optional(),
20675
20894
  status: external_exports2.union([apiV2ScanStatusSchema, pulseStatusSchema.shape.status]).optional(),
20676
20895
  resultDisposition: scanResultDispositionSchema.optional(),
20677
20896
  noGo: scanNoGoResultSchema.optional(),
20678
20897
  startedAt: external_exports2.string().nullable().optional(),
20898
+ createdAt: external_exports2.string().nullable().optional(),
20679
20899
  completedAt: external_exports2.string().nullable().optional(),
20680
20900
  scanTimeSeconds: external_exports2.number().nullable().optional(),
20681
- 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()
20682
20922
  }).passthrough();
20683
20923
  var mcpReportOutputSchema = external_exports2.object({
20684
20924
  type: external_exports2.enum(["certscore_pulse", "certscore_pulse_summary", "certscore_pulse_evidence"]).optional(),
@@ -20690,17 +20930,63 @@ var mcpReportOutputSchema = external_exports2.object({
20690
20930
  }).passthrough();
20691
20931
  var mcpScanBundleOutputSchema = external_exports2.object({
20692
20932
  type: external_exports2.literal("certscore_scan_bundle"),
20933
+ detail: external_exports2.enum(["summary", "findings", "evidence", "full"]),
20693
20934
  scanId: external_exports2.string(),
20935
+ domain: external_exports2.string(),
20936
+ url: external_exports2.string().nullable(),
20694
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(),
20695
20943
  resultDisposition: scanResultDispositionSchema.nullable().optional(),
20696
20944
  noGo: scanNoGoResultSchema.nullable().optional(),
20697
- scan: apiV2ScanResourceSchema,
20698
- summary: external_exports2.unknown().nullable(),
20699
- findings: external_exports2.array(external_exports2.unknown()),
20700
- evidenceSummary: external_exports2.unknown().nullable(),
20701
- 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(),
20702
20971
  links: external_exports2.record(external_exports2.string()).optional(),
20703
- 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(),
20704
20990
  disclaimer: external_exports2.string().nullable()
20705
20991
  }).passthrough();
20706
20992
  var mcpFindingsExportOutputSchema = external_exports2.object({
@@ -20744,23 +21030,15 @@ var mcpPreConsentCookiesTrackersOutputSchema = apiV2PreConsentCookiesTrackersSch
20744
21030
  });
20745
21031
  var certScoreMcpToolContracts = [
20746
21032
  {
20747
- name: "create_scan",
20748
- title: "Deprecated \u2014 Create CertScore Pulse scan",
20749
- 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.",
20750
- inputSchema: mcpCreateScanInputSchema,
20751
- outputSchema: mcpCreateScanOutputSchema,
20752
- annotations: scanCreationAnnotations
20753
- },
20754
- {
20755
- name: "scan_site",
21033
+ name: "certscore_scan_site",
20756
21034
  title: "Scan site",
20757
- 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.",
20758
21036
  inputSchema: mcpScanSiteInputSchema,
20759
21037
  outputSchema: mcpScanSiteOutputSchema,
20760
21038
  annotations: scanCreationAnnotations
20761
21039
  },
20762
21040
  {
20763
- name: "get_scan",
21041
+ name: "certscore_get_scan",
20764
21042
  title: "Get CertScore scan",
20765
21043
  description: "Retrieve the API v2 public-safe scan resource, including completed-limited no-go disposition, reason-specific guidance, and timing when available.",
20766
21044
  inputSchema: mcpGetScanInputSchema,
@@ -20768,23 +21046,23 @@ var certScoreMcpToolContracts = [
20768
21046
  annotations: readOnlyOpenWorldAnnotations
20769
21047
  },
20770
21048
  {
20771
- name: "get_scan_status",
20772
- title: "Get CertScore Pulse scan status",
20773
- 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.",
20774
21052
  inputSchema: mcpGetScanStatusInputSchema,
20775
21053
  outputSchema: mcpScanStatusOutputSchema,
20776
21054
  annotations: readOnlyOpenWorldAnnotations
20777
21055
  },
20778
21056
  {
20779
- name: "get_report",
21057
+ name: "certscore_get_report",
20780
21058
  title: "Get CertScore Pulse report",
20781
- 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.",
20782
21060
  inputSchema: mcpGetReportInputSchema,
20783
21061
  outputSchema: mcpReportOutputSchema,
20784
21062
  annotations: readOnlyOpenWorldAnnotations
20785
21063
  },
20786
21064
  {
20787
- name: "get_evidence",
21065
+ name: "certscore_get_evidence",
20788
21066
  title: "Get CertScore Pulse evidence",
20789
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.",
20790
21068
  inputSchema: mcpGetEvidenceInputSchema,
@@ -20792,15 +21070,15 @@ var certScoreMcpToolContracts = [
20792
21070
  annotations: readOnlyOpenWorldAnnotations
20793
21071
  },
20794
21072
  {
20795
- name: "get_scan_bundle",
20796
- title: "Get compact CertScore scan bundle",
20797
- 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.",
20798
21076
  inputSchema: mcpGetScanBundleInputSchema,
20799
21077
  outputSchema: mcpScanBundleOutputSchema,
20800
21078
  annotations: readOnlyOpenWorldAnnotations
20801
21079
  },
20802
21080
  {
20803
- name: "export_findings",
21081
+ name: "certscore_export_findings",
20804
21082
  title: "Export CertScore findings",
20805
21083
  description: "Return structured findings plus completed-limited no-go disposition and guidance for downstream review or ticketing workflows.",
20806
21084
  inputSchema: mcpExportFindingsInputSchema,
@@ -20808,7 +21086,7 @@ var certScoreMcpToolContracts = [
20808
21086
  annotations: readOnlyOpenWorldAnnotations
20809
21087
  },
20810
21088
  {
20811
- name: "list_findings",
21089
+ name: "certscore_list_findings",
20812
21090
  title: "List CertScore findings",
20813
21091
  description: "List API v2 public-safe findings already projected for a scan.",
20814
21092
  inputSchema: mcpListFindingsInputSchema,
@@ -20816,7 +21094,7 @@ var certScoreMcpToolContracts = [
20816
21094
  annotations: readOnlyOpenWorldAnnotations
20817
21095
  },
20818
21096
  {
20819
- name: "get_pre_consent_cookies_trackers",
21097
+ name: "certscore_get_pre_consent_cookies_trackers",
20820
21098
  title: "Get pre-consent cookies and trackers",
20821
21099
  description: "Retrieve the public-safe Cookies & Trackers (Pre-consent) report table as compact JSON for a scan.",
20822
21100
  inputSchema: mcpGetPreConsentCookiesTrackersInputSchema,
@@ -20824,7 +21102,7 @@ var certScoreMcpToolContracts = [
20824
21102
  annotations: readOnlyOpenWorldAnnotations
20825
21103
  },
20826
21104
  {
20827
- name: "explain_finding",
21105
+ name: "certscore_explain_finding",
20828
21106
  title: "Explain CertScore finding",
20829
21107
  description: "Explain one projected finding with public evidence, caveats, reviewer next steps, and reason-specific no-go context when applicable.",
20830
21108
  inputSchema: mcpExplainFindingInputSchema,
@@ -20832,7 +21110,7 @@ var certScoreMcpToolContracts = [
20832
21110
  annotations: readOnlyOpenWorldAnnotations
20833
21111
  },
20834
21112
  {
20835
- name: "get_latest_domain_scan",
21113
+ name: "certscore_get_latest_domain_scan",
20836
21114
  title: "Get latest domain scan",
20837
21115
  description: "Retrieve the latest eligible API v2 public-safe scan for a domain.",
20838
21116
  inputSchema: mcpGetLatestDomainScanInputSchema,
@@ -20840,7 +21118,7 @@ var certScoreMcpToolContracts = [
20840
21118
  annotations: readOnlyOpenWorldAnnotations
20841
21119
  },
20842
21120
  {
20843
- name: "get_latest_domain_pre_consent_cookies_trackers",
21121
+ name: "certscore_get_latest_domain_pre_consent_cookies_trackers",
20844
21122
  title: "Get latest domain pre-consent cookies and trackers",
20845
21123
  description: "Retrieve the public-safe Cookies & Trackers (Pre-consent) table from the latest eligible scan for a domain.",
20846
21124
  inputSchema: mcpGetLatestDomainPreConsentCookiesTrackersInputSchema,
@@ -20850,10 +21128,17 @@ var certScoreMcpToolContracts = [
20850
21128
  ];
20851
21129
 
20852
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
+ };
20853
21138
  var preConsentCookiesTrackersExample = {
20854
21139
  type: "certscore_pre_consent_cookies_trackers",
20855
21140
  scanId: "00000000-0000-4000-8000-000000000123",
20856
- domain: "example.com",
21141
+ domain: "ergoveritas.com",
20857
21142
  generatedAt: "2026-06-30T12:00:10.000Z",
20858
21143
  summary: {
20859
21144
  rowCount: 2,
@@ -20879,7 +21164,7 @@ var preConsentCookiesTrackersExample = {
20879
21164
  observedBeforeConsent: true,
20880
21165
  evidenceBasis: "public_report_projection",
20881
21166
  firstObservedAtMs: 1234,
20882
- pageUrlHost: "example.com"
21167
+ pageUrlHost: "ergoveritas.com"
20883
21168
  },
20884
21169
  {
20885
21170
  id: "cookie:google:advertising:doubleclick-net",
@@ -20898,7 +21183,7 @@ var preConsentCookiesTrackersExample = {
20898
21183
  observedBeforeConsent: true,
20899
21184
  evidenceBasis: "public_report_projection",
20900
21185
  firstObservedAtMs: 512,
20901
- pageUrlHost: "example.com"
21186
+ pageUrlHost: "ergoveritas.com"
20902
21187
  }
20903
21188
  ],
20904
21189
  links: {
@@ -20915,6 +21200,56 @@ var emptyPreConsentCookiesTrackersExample = {
20915
21200
  summary: { rowCount: 0, trackerCount: 0, cookieCount: 0, requestCount: 0 },
20916
21201
  rows: []
20917
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
+ };
20918
21253
 
20919
21254
  // ../../node_modules/@modelcontextprotocol/sdk/node_modules/zod/v3/helpers/util.js
20920
21255
  var util2;
@@ -24920,17 +25255,33 @@ function normalizeObjectSchema(schema) {
24920
25255
  }
24921
25256
  return void 0;
24922
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
+ }
24923
25272
  function getParseErrorMessage(error2) {
24924
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
+ }
24925
25282
  if ("message" in error2 && typeof error2.message === "string") {
24926
25283
  return error2.message;
24927
25284
  }
24928
- if ("issues" in error2 && Array.isArray(error2.issues) && error2.issues.length > 0) {
24929
- const firstIssue = error2.issues[0];
24930
- if (firstIssue && typeof firstIssue === "object" && "message" in firstIssue) {
24931
- return String(firstIssue.message);
24932
- }
24933
- }
24934
25285
  try {
24935
25286
  return JSON.stringify(error2);
24936
25287
  } catch {
@@ -31523,16 +31874,7 @@ var Server = class extends Protocol {
31523
31874
  if (!methodSchema) {
31524
31875
  throw new Error("Schema is missing a method literal");
31525
31876
  }
31526
- let methodValue;
31527
- if (isZ4Schema(methodSchema)) {
31528
- const v4Schema = methodSchema;
31529
- const v4Def = v4Schema._zod?.def;
31530
- methodValue = v4Def?.value ?? v4Schema.value;
31531
- } else {
31532
- const v3Schema = methodSchema;
31533
- const legacyDef = v3Schema._def;
31534
- methodValue = legacyDef?.value ?? v3Schema.value;
31535
- }
31877
+ const methodValue = getLiteralValue(methodSchema);
31536
31878
  if (typeof methodValue !== "string") {
31537
31879
  throw new Error("Schema method literal must be a string");
31538
31880
  }
@@ -32729,6 +33071,18 @@ var MAX_EVIDENCE_PACKET_CHARS = 25e4;
32729
33071
  var EVIDENCE_STRING_CHARS = 4e3;
32730
33072
  var EVIDENCE_ARRAY_ITEMS = 40;
32731
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
+ }
32732
33086
  function toToolResult(payload) {
32733
33087
  const structuredContent = payload !== null && typeof payload === "object" && !Array.isArray(payload) ? payload : { value: payload };
32734
33088
  return {
@@ -32736,25 +33090,32 @@ function toToolResult(payload) {
32736
33090
  content: [
32737
33091
  {
32738
33092
  type: "text",
32739
- text: JSON.stringify(payload)
33093
+ text: toolResultSummary(payload)
32740
33094
  }
32741
33095
  ]
32742
33096
  };
32743
33097
  }
32744
33098
  function toToolError(error2) {
32745
- 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 = {
32746
33108
  error: {
32747
- name: error2.name,
32748
- message: error2.message,
32749
- status: error2.status,
32750
- code: error2.code,
32751
- retryAfterSeconds: "retryAfterSeconds" in error2 ? error2.retryAfterSeconds : void 0,
32752
- responseBody: truncateErrorResponseBody(error2.responseBody)
32753
- }
32754
- } : {
32755
- error: {
32756
- name: error2 instanceof Error ? error2.name : "Error",
32757
- 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
+ } : {}
32758
33119
  }
32759
33120
  };
32760
33121
  return {
@@ -32762,6 +33123,95 @@ function toToolError(error2) {
32762
33123
  isError: true
32763
33124
  };
32764
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
+ }
32765
33215
  function boundEvidencePacket(payload, maxSerializedChars = MAX_EVIDENCE_PACKET_CHARS) {
32766
33216
  const originalSerializedChars = measureSerializedChars(payload);
32767
33217
  if (originalSerializedChars <= maxSerializedChars) {
@@ -32805,6 +33255,107 @@ function boundEvidencePacket(payload, maxSerializedChars = MAX_EVIDENCE_PACKET_C
32805
33255
  function measureSerializedChars(value) {
32806
33256
  return JSON.stringify(value)?.length ?? 0;
32807
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
+ }
32808
33359
  function compactEvidenceValue(value, options) {
32809
33360
  if (value === null || value === void 0) {
32810
33361
  return value;
@@ -32933,9 +33484,6 @@ function normalizeDetail2(detail) {
32933
33484
  function normalizeFormat2(format) {
32934
33485
  return format ?? "json";
32935
33486
  }
32936
- function scanIdFromStatus(status) {
32937
- return status.scanId ?? status.scan_id ?? null;
32938
- }
32939
33487
  function scanIdFromPulse(report) {
32940
33488
  const nestedScan = "scan" in report && report.scan && typeof report.scan === "object" ? report.scan : void 0;
32941
33489
  return report.scanId ?? report.scan_id ?? nestedScan?.scanId ?? null;
@@ -33012,69 +33560,261 @@ function limitPreConsentRows(payload, options = {}) {
33012
33560
  };
33013
33561
  }
33014
33562
  function buildScanBundle(input) {
33015
- 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)));
33016
33565
  const maxPreConsentRows = Math.min(50, Math.max(1, input.maxPreConsentRows ?? 20));
33017
- const evidence = input.evidence;
33018
- const report = input.report;
33019
- const findings = Array.isArray(input.findings.findings) ? input.findings.findings.slice(0, maxFindings) : [];
33020
- 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) : [];
33021
33571
  const links = {
33022
33572
  ...input.scan.links ?? {},
33023
33573
  ...report.links && typeof report.links === "object" && !Array.isArray(report.links) ? report.links : {}
33024
33574
  };
33025
- 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 = {
33026
33588
  type: "certscore_scan_bundle",
33589
+ detail,
33027
33590
  scanId: input.scan.scanId,
33591
+ domain: input.scan.domain,
33592
+ url: input.scan.url ?? null,
33028
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,
33029
33599
  resultDisposition: input.scan.resultDisposition ?? null,
33030
33600
  noGo: input.scan.noGo ?? null,
33031
- 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
+ },
33032
33612
  summary: {
33033
- summary: report.summary ?? null,
33613
+ headline: report.summary && typeof report.summary === "object" && !Array.isArray(report.summary) ? report.summary.headline ?? null : null,
33034
33614
  executiveSummary: report.executiveSummary ?? null,
33035
33615
  counts: report.counts ?? null,
33036
- coverage: report.coverage ?? input.scan.coverage ?? null,
33037
33616
  agentInterpretation: report.agentInterpretation ?? null
33038
33617
  },
33039
33618
  findings,
33040
33619
  findingsMetadata: {
33041
33620
  shown: findings.length,
33042
- total: Array.isArray(input.findings.findings) ? input.findings.findings.length : 0,
33043
- truncated: Array.isArray(input.findings.findings) && input.findings.findings.length > findings.length
33621
+ total: allFindings.length,
33622
+ truncated: allFindings.length > findings.length
33044
33623
  },
33045
- evidenceSummary: {
33046
- evidenceSafetyNotes: evidence.evidenceSafetyNotes ?? null,
33047
- projectionDiagnostics: evidence.projectionDiagnostics ?? null,
33048
- projectedFindings: compactEvidenceValue(evidence.projectedFindings ?? [], {
33049
- arrayItems: maxFindings,
33050
- depth: 5,
33051
- objectKeys: 40,
33052
- stringChars: 1e3
33053
- }),
33054
- coverageDiagnostics: compactEvidenceValue(evidence.coverageDiagnostics ?? null, {
33055
- arrayItems: 20,
33056
- depth: 5,
33057
- objectKeys: 40,
33058
- stringChars: 1e3
33059
- }),
33060
- policySurfaceCoverage: compactEvidenceValue(evidence.policySurfaceCoverage ?? null, {
33061
- arrayItems: 20,
33062
- depth: 5,
33063
- objectKeys: 40,
33064
- 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
33065
33631
  })
33066
- },
33067
- preConsentCookiesTrackers: {
33632
+ } : {},
33633
+ ...input.preConsentCookiesTrackers ? { preConsentCookiesTrackers: {
33068
33634
  summary: input.preConsentCookiesTrackers.summary,
33069
33635
  rows: preConsentRows,
33070
33636
  shown: preConsentRows.length,
33071
33637
  total: Array.isArray(input.preConsentCookiesTrackers.rows) ? input.preConsentCookiesTrackers.rows.length : 0,
33072
33638
  truncated: Array.isArray(input.preConsentCookiesTrackers.rows) && input.preConsentCookiesTrackers.rows.length > preConsentRows.length
33073
- },
33639
+ } } : {},
33074
33640
  links,
33075
- recommendedNextTool: findings.length > 0 ? "explain_finding" : null,
33076
- 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
33077
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;
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;
33078
33818
  }
33079
33819
  function explainFinding(report, findingId) {
33080
33820
  const finding = findingsFromReport(report).find((candidate) => candidate.id === findingId);
@@ -33112,8 +33852,18 @@ function explainFinding(report, findingId) {
33112
33852
  }
33113
33853
 
33114
33854
  // src/server.ts
33115
- var createScanDeprecationWarningPrinted = false;
33116
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
+ }
33117
33867
  function scanCreationMetadata(value) {
33118
33868
  return {
33119
33869
  executionMode: value.executionMode,
@@ -33123,7 +33873,9 @@ function scanCreationMetadata(value) {
33123
33873
  quotaConsumed: value.quotaConsumed,
33124
33874
  anonymousQuotaLimit: value.anonymousQuotaLimit,
33125
33875
  anonymousQuotaRemaining: value.anonymousQuotaRemaining,
33126
- anonymousQuotaResetAt: value.anonymousQuotaResetAt
33876
+ anonymousQuotaResetAt: value.anonymousQuotaResetAt,
33877
+ upgradeSupportEmail: value.upgradeSupportEmail,
33878
+ upgradeMessage: value.upgradeMessage
33127
33879
  };
33128
33880
  }
33129
33881
  function toolContract(name) {
@@ -33152,46 +33904,19 @@ function createCertScoreMcpServer(options = {}) {
33152
33904
  name: "certscore",
33153
33905
  version: CERTSCORE_MCP_VERSION
33154
33906
  });
33155
- const registerTool = server.registerTool.bind(server);
33156
- async function createPulseScanTool(input) {
33157
- const result = await client.submitScan(input.url, {
33158
- detail: normalizeDetail2(input.detail),
33159
- format: normalizeFormat2(input.format),
33160
- freshness: input.freshness ?? "latest",
33161
- scanFrom: input.scanFrom
33162
- });
33163
- return {
33164
- type: "certscore_mcp_scan_created",
33165
- status: result.status,
33166
- jobId: result.jobId ?? null,
33167
- scanId: result.scanId ?? result.scan_id ?? null,
33168
- completed: result.completed ?? false,
33169
- statusUrl: result.statusUrl ?? result.nextCheckUrl ?? null,
33170
- resultUrl: result.resultUrl ?? null,
33171
- reportUrl: result.reportUrl ?? null,
33172
- pulse: result.pulse ?? null,
33173
- resultDisposition: result.resultDisposition ?? result.pulse?.resultDisposition ?? null,
33174
- noGo: result.noGo ?? result.pulse?.noGo ?? null
33175
- };
33176
- }
33177
- registerTool(
33178
- "create_scan",
33179
- toolContract("create_scan"),
33180
- async (input) => {
33181
- try {
33182
- if (!createScanDeprecationWarningPrinted) {
33183
- createScanDeprecationWarningPrinted = true;
33184
- console.error("[certscore-mcp] create_scan is deprecated in the 0.2.x line. Use scan_site for new integrations.");
33185
- }
33186
- return toToolResult(await createPulseScanTool(input));
33187
- } catch (error2) {
33188
- return toToolError(error2);
33189
- }
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"]);
33910
+ const registerMcpTool = server.registerTool.bind(server);
33911
+ const registerTool = (name, contract, handler) => {
33912
+ if (options.toolProfile === "light" && !lightTools.has(name)) {
33913
+ return;
33190
33914
  }
33191
- );
33915
+ registerMcpTool(name, contract, handler);
33916
+ };
33192
33917
  registerTool(
33193
- "scan_site",
33194
- toolContract("scan_site"),
33918
+ "certscore_scan_site",
33919
+ toolContract("certscore_scan_site"),
33195
33920
  async (input) => {
33196
33921
  try {
33197
33922
  const created = await client.scans.create(input.url, {
@@ -33199,30 +33924,35 @@ function createCertScoreMcpServer(options = {}) {
33199
33924
  scanFrom: input.scanFrom
33200
33925
  });
33201
33926
  if (input.waitForCompletion === false || created.type === "certscore_scan") {
33202
- return toToolResult(created);
33927
+ return toToolResult(withMcpAgentGuidance(created));
33203
33928
  }
33204
33929
  try {
33205
33930
  const completed = await client.scans.wait(created, {
33206
33931
  maxWaitMs: Math.min(input.maxWaitSeconds ? input.maxWaitSeconds * 1e3 : DEFAULT_MCP_SCAN_WAIT_MS, DEFAULT_MCP_SCAN_WAIT_MS)
33207
33932
  });
33208
- return toToolResult({
33933
+ return toToolResult(withMcpAgentGuidance({
33209
33934
  ...completed,
33210
- ...scanCreationMetadata(created),
33211
- recommendedNextTool: "get_scan_bundle"
33212
- });
33935
+ ...scanCreationMetadata(created)
33936
+ }));
33213
33937
  } catch (error2) {
33214
- if (!(error2 instanceof CertScoreTimeoutError)) {
33215
- throw error2;
33216
- }
33217
33938
  const scanId = created.scanId ?? created.scan_id;
33218
- if (scanId) {
33219
- return toToolResult({
33220
- ...await client.scans.status(scanId),
33221
- ...scanCreationMetadata(created),
33222
- recommendedNextTool: "get_scan_status"
33223
- });
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
+ }
33224
33954
  }
33225
- return toToolResult(created);
33955
+ return toToolResult(withMcpAgentGuidance(created));
33226
33956
  }
33227
33957
  } catch (error2) {
33228
33958
  return toToolError(error2);
@@ -33230,8 +33960,8 @@ function createCertScoreMcpServer(options = {}) {
33230
33960
  }
33231
33961
  );
33232
33962
  registerTool(
33233
- "get_scan",
33234
- toolContract("get_scan"),
33963
+ "certscore_get_scan",
33964
+ toolContract("certscore_get_scan"),
33235
33965
  async ({ scanId }) => {
33236
33966
  try {
33237
33967
  return toToolResult(await client.scans.get(scanId));
@@ -33241,54 +33971,48 @@ function createCertScoreMcpServer(options = {}) {
33241
33971
  }
33242
33972
  );
33243
33973
  registerTool(
33244
- "get_scan_status",
33245
- toolContract("get_scan_status"),
33246
- async ({ jobId, scanId }) => {
33974
+ "certscore_get_scan_status",
33975
+ toolContract("certscore_get_scan_status"),
33976
+ async ({ scanId }) => {
33247
33977
  try {
33248
- if (scanId) {
33249
- const status2 = await client.scans.status(scanId);
33250
- const needsTerminalHydration = status2.status === "completed" || status2.status === "completed_limited";
33251
- if (needsTerminalHydration) {
33252
- try {
33253
- const scan = await client.scans.get(scanId);
33254
- return toToolResult({
33255
- ...status2,
33256
- type: "certscore_scan_job",
33257
- status: scan.status,
33258
- domain: scan.domain,
33259
- resultDisposition: scan.resultDisposition,
33260
- noGo: scan.noGo,
33261
- startedAt: scan.startedAt,
33262
- completedAt: scan.completedAt,
33263
- scanTimeSeconds: scan.scanTimeSeconds,
33264
- recommendedNextTool: "get_scan_bundle"
33265
- });
33266
- } catch {
33267
- }
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 {
33268
34005
  }
33269
- return toToolResult(status2);
33270
- }
33271
- if (!jobId) {
33272
- return toToolResult({
33273
- error: {
33274
- name: "InvalidToolInput",
33275
- message: "Provide either scanId for API v2 scan status or jobId for Pulse job status."
33276
- }
33277
- });
33278
34006
  }
33279
- const status = await client.getJobStatus(jobId);
33280
- return toToolResult({
33281
- ...status,
33282
- scanId: scanIdFromStatus(status)
33283
- });
34007
+ return toToolResult(withMcpAgentGuidance(status));
33284
34008
  } catch (error2) {
33285
34009
  return toToolError(error2);
33286
34010
  }
33287
34011
  }
33288
34012
  );
33289
34013
  registerTool(
33290
- "get_report",
33291
- toolContract("get_report"),
34014
+ "certscore_get_report",
34015
+ toolContract("certscore_get_report"),
33292
34016
  async ({ scanId, detail, format }) => {
33293
34017
  try {
33294
34018
  const normalizedFormat = normalizeFormat2(format);
@@ -33306,8 +34030,8 @@ function createCertScoreMcpServer(options = {}) {
33306
34030
  }
33307
34031
  );
33308
34032
  registerTool(
33309
- "get_evidence",
33310
- toolContract("get_evidence"),
34033
+ "certscore_get_evidence",
34034
+ toolContract("certscore_get_evidence"),
33311
34035
  async ({ scanId }) => {
33312
34036
  try {
33313
34037
  return toToolResult(boundEvidencePacket(await client.getScan(scanId, { detail: "evidence", format: "json" })));
@@ -33317,20 +34041,37 @@ function createCertScoreMcpServer(options = {}) {
33317
34041
  }
33318
34042
  );
33319
34043
  registerTool(
33320
- "get_scan_bundle",
33321
- toolContract("get_scan_bundle"),
33322
- async ({ scanId, maxFindings, maxPreConsentRows }) => {
34044
+ "certscore_get_scan_bundle",
34045
+ toolContract("certscore_get_scan_bundle"),
34046
+ async ({ scanId, detail = "summary", maxBytes, maxFindings, maxPreConsentRows }) => {
33323
34047
  try {
33324
- const [scan, report, evidence, findings, preConsentCookiesTrackers] = await Promise.all([
33325
- client.scans.get(scanId),
33326
- client.getScan(scanId, { detail: "summary", format: "json" }),
33327
- client.getScan(scanId, { detail: "evidence", format: "json" }),
33328
- client.findings.list(scanId),
33329
- 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)
33330
34068
  ]);
34069
+ const evidence = includeEvidence ? report : null;
33331
34070
  return toToolResult(buildScanBundle({
34071
+ detail,
33332
34072
  evidence,
33333
34073
  findings,
34074
+ maxBytes,
33334
34075
  maxFindings,
33335
34076
  maxPreConsentRows,
33336
34077
  preConsentCookiesTrackers,
@@ -33343,8 +34084,8 @@ function createCertScoreMcpServer(options = {}) {
33343
34084
  }
33344
34085
  );
33345
34086
  registerTool(
33346
- "export_findings",
33347
- toolContract("export_findings"),
34087
+ "certscore_export_findings",
34088
+ toolContract("certscore_export_findings"),
33348
34089
  async ({ scanId }) => {
33349
34090
  try {
33350
34091
  const report = await client.getScan(scanId, { detail: "full", format: "json" });
@@ -33355,8 +34096,8 @@ function createCertScoreMcpServer(options = {}) {
33355
34096
  }
33356
34097
  );
33357
34098
  registerTool(
33358
- "list_findings",
33359
- toolContract("list_findings"),
34099
+ "certscore_list_findings",
34100
+ toolContract("certscore_list_findings"),
33360
34101
  async ({ limit, offset, scanId }) => {
33361
34102
  try {
33362
34103
  return toToolResult(paginateFindingList(await client.findings.list(scanId), { limit, offset }));
@@ -33366,8 +34107,8 @@ function createCertScoreMcpServer(options = {}) {
33366
34107
  }
33367
34108
  );
33368
34109
  registerTool(
33369
- "get_pre_consent_cookies_trackers",
33370
- toolContract("get_pre_consent_cookies_trackers"),
34110
+ "certscore_get_pre_consent_cookies_trackers",
34111
+ toolContract("certscore_get_pre_consent_cookies_trackers"),
33371
34112
  async ({ maxRows, scanId }) => {
33372
34113
  try {
33373
34114
  return toToolResult(limitPreConsentRows(await client.scans.preConsentCookiesTrackers(scanId), { maxRows }));
@@ -33377,8 +34118,8 @@ function createCertScoreMcpServer(options = {}) {
33377
34118
  }
33378
34119
  );
33379
34120
  registerTool(
33380
- "explain_finding",
33381
- toolContract("explain_finding"),
34121
+ "certscore_explain_finding",
34122
+ toolContract("certscore_explain_finding"),
33382
34123
  async ({ scanId, findingId }) => {
33383
34124
  try {
33384
34125
  return toToolResult(await client.findings.explain(scanId, findingId));
@@ -33388,8 +34129,8 @@ function createCertScoreMcpServer(options = {}) {
33388
34129
  }
33389
34130
  );
33390
34131
  registerTool(
33391
- "get_latest_domain_scan",
33392
- toolContract("get_latest_domain_scan"),
34132
+ "certscore_get_latest_domain_scan",
34133
+ toolContract("certscore_get_latest_domain_scan"),
33393
34134
  async ({ domain: domain2, scanFrom }) => {
33394
34135
  try {
33395
34136
  return toToolResult(await client.domains.latest(domain2, { scanFrom }));
@@ -33399,8 +34140,8 @@ function createCertScoreMcpServer(options = {}) {
33399
34140
  }
33400
34141
  );
33401
34142
  registerTool(
33402
- "get_latest_domain_pre_consent_cookies_trackers",
33403
- 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"),
33404
34145
  async ({ domain: domain2, maxRows, scanFrom }) => {
33405
34146
  try {
33406
34147
  return toToolResult(limitPreConsentRows(await client.domains.latestPreConsentCookiesTrackers(domain2, { scanFrom }), { maxRows }));