blackveil-dns 1.4.2 → 2.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -9,7 +9,7 @@ Open-source DNS & email security scanner for Claude, Cursor, VS Code, and MCP cl
9
9
  [![GitHub stars](https://img.shields.io/github/stars/MadaBurns/bv-mcp?style=flat&logo=github)](https://github.com/MadaBurns/bv-mcp/stargazers)
10
10
  [![npm version](https://img.shields.io/npm/v/blackveil-dns)](https://www.npmjs.com/package/blackveil-dns)
11
11
  [![npm downloads](https://img.shields.io/npm/dm/blackveil-dns)](https://www.npmjs.com/package/blackveil-dns)
12
- [![Tests](https://img.shields.io/badge/Tests-1097-brightgreen)](https://github.com/MadaBurns/bv-mcp/actions)
12
+ [![Tests](https://img.shields.io/badge/Tests-1469-brightgreen)](https://github.com/MadaBurns/bv-mcp/actions)
13
13
  [![Coverage](https://img.shields.io/badge/Coverage-~90%25-brightgreen)](https://github.com/MadaBurns/bv-mcp/actions)
14
14
  [![BUSL-1.1 License](https://img.shields.io/badge/License-BUSL--1.1-blue.svg)](LICENSE)
15
15
  [![MCP](https://img.shields.io/badge/MCP-2025--03--26-blue)](https://modelcontextprotocol.io/)
@@ -61,9 +61,14 @@ Transport support:
61
61
  - **57+ checks across 20 categories** — SPF, DMARC, DKIM, DNSSEC, SSL/TLS, MTA-STS, NS, CAA, MX, BIMI, TLS-RPT, subdomain takeover, lookalike domains, HTTP security headers, DANE, shadow domains, TXT hygiene, MX reputation, SRV, zone hygiene
62
62
  - **Maturity staging** — Stage 0-4 classification (Unprotected to Hardened) with next steps
63
63
  - **Trust surface analysis** — detects shared SaaS platforms (Google, M365, SendGrid) and cross-references DMARC enforcement to determine real exposure
64
- - **Plain-English remediation** — `explain_finding` turns findings into guidance anyone can understand
64
+ - **Guided remediation** — `generate_fix_plan` produces prioritized actions; record generators output ready-to-publish SPF, DMARC, DKIM, and MTA-STS records
65
+ - **Spoofability scoring** — `assess_spoofability` computes a composite 0-100 email spoofability score from SPF trust surface, DMARC enforcement, and DKIM coverage with interaction multipliers
66
+ - **Intelligence layer** — `get_benchmark` and `get_provider_insights` expose anonymized aggregate insights from scan telemetry: percentile rankings, provider cohort comparisons, and 7-day trend analysis
67
+ - **Multi-resolver consistency** — `check_resolver_consistency` queries 4 public DoH resolvers to detect GeoDNS, split-horizon DNS, or poisoning
68
+ - **Interaction scoring** — correlated weaknesses (e.g., weak DKIM + permissive DMARC) receive additional penalties beyond individual finding scores
65
69
  - **Self-tuning scoring** — adaptive weights adjust category importance based on patterns seen across scans, so scores reflect real-world failure distributions rather than static assumptions
66
70
  - **Provider intelligence** — inbound/outbound email provider inference from MX, SPF, DKIM
71
+ - **Context-optimized** — tool schemas, prompts, and resources are tuned for minimal token consumption in LLM clients
67
72
  - **Passive and read-only** — all checks use public Cloudflare DNS-over-HTTPS; no authorization required from the target
68
73
 
69
74
  Full scope and limitations in the coverage table below.
@@ -72,7 +77,7 @@ Full scope and limitations in the coverage table below.
72
77
  scan_domain("anthropic.com")
73
78
 
74
79
  ████████████████████████████████████████░░░░░ 85 / 100
75
- Grade: A · Maturity: Intermediate
80
+ Grade: A · Maturity: Enforcing
76
81
 
77
82
  SPF ·········· 80 MTA-STS ····· 85
78
83
  DMARC ········ 90 NS ·········· 95
@@ -95,7 +100,7 @@ Full scope and limitations in the coverage table below.
95
100
  ## Tools
96
101
 
97
102
  ```
98
- 22 MCP tools
103
+ 33 MCP tools · 7 prompts · 6 resources
99
104
 
100
105
  Email Auth Infrastructure Brand & Threats Meta
101
106
  ──────────── ──────────────── ───────────────── ──────────────
@@ -104,17 +109,25 @@ Full scope and limitations in the coverage table below.
104
109
  check_dkim check_caa check_lookalikes compare_baseline
105
110
  check_mta_sts check_ssl check_shadow_domains
106
111
  check_mx check_http_security
107
- check_mx_reputation check_dane
108
- check_srv
109
- DNS Hygiene check_zone_hygiene
110
- ────────────
111
- check_txt_hygiene
112
+ check_mx_reputation check_dane Intelligence Remediation
113
+ check_dane_https ────────────── ──────────────
114
+ DNS Hygiene check_svcb_https get_benchmark generate_fix_plan
115
+ ──────────── check_srv get_provider_ generate_spf_record
116
+ check_txt_hygiene check_zone_hygiene insights generate_dmarc_record
117
+ check_resolver_ assess_spoofability generate_dkim_config
118
+ consistency generate_mta_sts_policy
112
119
 
113
120
  + check_subdomain_takeover (internal — runs inside scan_domain)
114
121
  ```
115
122
 
116
123
  `explain_finding` takes any finding and returns: what it means, potential impact, adverse consequences, specific steps to fix, and relevant RFCs.
117
124
 
125
+ `generate_fix_plan` scans a domain and produces a prioritized remediation plan with effort, impact, and dependency metadata. The record generators (`generate_spf_record`, `generate_dmarc_record`, `generate_dkim_config`, `generate_mta_sts_policy`) produce ready-to-publish DNS records based on detected configuration.
126
+
127
+ `get_benchmark` and `get_provider_insights` expose anonymized aggregate data from scan telemetry — percentile rankings, provider cohort scores, and 7-day trend analysis. `assess_spoofability` computes a composite email spoofability score (0-100) from SPF, DMARC, and DKIM with interaction multipliers.
128
+
129
+ `check_resolver_consistency` queries Cloudflare, Google, Quad9, and OpenDNS in parallel to detect GeoDNS, split-horizon DNS, or potential poisoning.
130
+
118
131
  **Confidence labels:**
119
132
  `deterministic` — direct protocol/record validation | `heuristic` — signal-based inference, may need manual validation | `verified` — high-confidence validation signal
120
133
 
@@ -125,6 +138,8 @@ Full scope and limitations in the coverage table below.
125
138
 
126
139
  ## Client setup
127
140
 
141
+ The free tier requires no authentication. If you have an API key, see the **With API key** tabs below to bypass rate limits.
142
+
128
143
  <details>
129
144
  <summary><b>VS Code / Copilot</b></summary>
130
145
 
@@ -140,6 +155,30 @@ Full scope and limitations in the coverage table below.
140
155
  }
141
156
  }
142
157
  ```
158
+
159
+ **With API key:**
160
+
161
+ ```json
162
+ {
163
+ "servers": {
164
+ "blackveil-dns": {
165
+ "type": "http",
166
+ "url": "https://dns-mcp.blackveilsecurity.com/mcp",
167
+ "headers": {
168
+ "Authorization": "Bearer ${input:bv-api-key}"
169
+ }
170
+ }
171
+ },
172
+ "inputs": [
173
+ {
174
+ "id": "bv-api-key",
175
+ "type": "promptString",
176
+ "description": "Blackveil DNS API key",
177
+ "password": true
178
+ }
179
+ ]
180
+ }
181
+ ```
143
182
  </details>
144
183
 
145
184
  <details>
@@ -163,6 +202,33 @@ Or via CLI:
163
202
  ```bash
164
203
  claude mcp add --transport http blackveil-dns https://dns-mcp.blackveilsecurity.com/mcp
165
204
  ```
205
+
206
+ **With API key** — use `mcp-remote` to reliably forward the auth header:
207
+
208
+ ```json
209
+ {
210
+ "mcpServers": {
211
+ "blackveil-dns": {
212
+ "command": "npx",
213
+ "args": [
214
+ "mcp-remote",
215
+ "https://dns-mcp.blackveilsecurity.com/mcp",
216
+ "--header",
217
+ "Authorization: Bearer YOUR_API_KEY"
218
+ ]
219
+ }
220
+ }
221
+ }
222
+ ```
223
+
224
+ Or via CLI:
225
+
226
+ ```bash
227
+ claude mcp add-json blackveil-dns \
228
+ '{"command":"npx","args":["mcp-remote","https://dns-mcp.blackveilsecurity.com/mcp","--header","Authorization: Bearer YOUR_API_KEY"]}'
229
+ ```
230
+
231
+ > **Why `mcp-remote`?** Claude Code's native HTTP transport does not currently forward custom `headers` from config files. The `mcp-remote` bridge reliably passes the `Authorization` header to the server. Restart Claude Code after adding the server.
166
232
  </details>
167
233
 
168
234
  <details>
@@ -170,7 +236,25 @@ claude mcp add --transport http blackveil-dns https://dns-mcp.blackveilsecurity.
170
236
 
171
237
  **Recommended:** Open [claude.ai](https://claude.ai) → **Settings → Connectors → Add custom connector** → paste `https://dns-mcp.blackveilsecurity.com/mcp`.
172
238
 
173
- **Advanced fallback:** If you want first-party local stdio instead of the hosted HTTP connector, open **Settings → Developer → Edit Config** (`claude_desktop_config.json`) and add:
239
+ **With API key** open **Settings → Developer → Edit Config** (`claude_desktop_config.json`) and add:
240
+
241
+ ```json
242
+ {
243
+ "mcpServers": {
244
+ "blackveil-dns": {
245
+ "command": "npx",
246
+ "args": [
247
+ "mcp-remote",
248
+ "https://dns-mcp.blackveilsecurity.com/mcp",
249
+ "--header",
250
+ "Authorization: Bearer YOUR_API_KEY"
251
+ ]
252
+ }
253
+ }
254
+ }
255
+ ```
256
+
257
+ **Without API key (local stdio):** If you want first-party local stdio instead of the hosted HTTP connector:
174
258
 
175
259
  ```json
176
260
  {
@@ -184,8 +268,6 @@ claude mcp add --transport http blackveil-dns https://dns-mcp.blackveilsecurity.
184
268
  }
185
269
  ```
186
270
 
187
- > Prefer the direct custom connector above when possible. The stdio route runs the server locally and depends on Node.js being available to Claude Desktop.
188
- >
189
271
  > On macOS GUI apps, `npx` may not resolve from `PATH`; if Homebrew is installed elsewhere, replace `/opt/homebrew/bin/npx` with your actual `npx` path. After editing the config, fully restart Claude Desktop. If you already have other servers, merge `"blackveil-dns"` into your existing `"mcpServers"` object — don't paste a second `{ }` wrapper.
190
272
 
191
273
  </details>
@@ -204,6 +286,52 @@ claude mcp add --transport http blackveil-dns https://dns-mcp.blackveilsecurity.
204
286
  }
205
287
  }
206
288
  ```
289
+
290
+ **With API key:**
291
+
292
+ ```json
293
+ {
294
+ "mcpServers": {
295
+ "blackveil-dns": {
296
+ "url": "https://dns-mcp.blackveilsecurity.com/mcp",
297
+ "headers": {
298
+ "Authorization": "Bearer YOUR_API_KEY"
299
+ }
300
+ }
301
+ }
302
+ }
303
+ ```
304
+ </details>
305
+
306
+ <details>
307
+ <summary><b>Windsurf</b></summary>
308
+
309
+ `~/.codeium/windsurf/mcp_config.json`
310
+
311
+ ```json
312
+ {
313
+ "mcpServers": {
314
+ "blackveil-dns": {
315
+ "serverUrl": "https://dns-mcp.blackveilsecurity.com/mcp"
316
+ }
317
+ }
318
+ }
319
+ ```
320
+
321
+ **With API key:**
322
+
323
+ ```json
324
+ {
325
+ "mcpServers": {
326
+ "blackveil-dns": {
327
+ "serverUrl": "https://dns-mcp.blackveilsecurity.com/mcp",
328
+ "headers": {
329
+ "Authorization": "Bearer YOUR_API_KEY"
330
+ }
331
+ }
332
+ }
333
+ }
334
+ ```
207
335
  </details>
208
336
 
209
337
  For hosted MCP setup, stdio usage, and legacy fallback endpoints, see `docs/client-setup.md`.
@@ -231,6 +359,30 @@ Get weekly DNS security reports in Slack or Discord. See [`examples/slack-discor
231
359
 
232
360
  ---
233
361
 
362
+ ## Pricing
363
+
364
+ Full API and MCP access at every tier — no enterprise gatekeeping.
365
+
366
+ | | **Free** | **Pro** | **Enterprise** |
367
+ |---|---|---|---|
368
+ | **Price** | $0 | $39/mo ($29/mo annual) | [Contact us](https://blackveilsecurity.com) |
369
+ | **Scans/day** | 75 | 500 | 10,000+ |
370
+ | **Checks/day** (per tool) | 200 | 5,000 | Unlimited |
371
+ | **Lookalike / Shadow scans** | 20/day | 200/day | Unlimited |
372
+ | **Rate limit** | 50 req/min | None | None |
373
+ | **API access** | Yes | Yes | Yes |
374
+ | **MCP access** | Yes | Yes | Yes |
375
+ | **GitHub Action** | Yes | Yes | Yes |
376
+ | **Batch API** | — | — | Up to 500 domains/call |
377
+ | **SLA** | Best effort | 99.5% | 99.9% + custom |
378
+ | **Support** | Community | Email | Dedicated |
379
+
380
+ The free tier is generous by design — use it for personal projects, evaluations, and AI agent integrations with no strings attached. Upgrade when you need higher throughput.
381
+
382
+ Get an API key at [blackveilsecurity.com](https://blackveilsecurity.com).
383
+
384
+ ---
385
+
234
386
  ## npm package
235
387
 
236
388
  Install from npm when you want to call the scanner from your own Node.js app, script, or service. If you are connecting from VS Code, Claude, Cursor, or another MCP client, use the MCP endpoint configuration above instead.
@@ -365,9 +517,9 @@ Run `explain_finding` on any result for plain-English remediation.
365
517
  | `POST` | `/internal/tools/call` | Service binding: single tool call (no auth/rate limits) |
366
518
  | `POST` | `/internal/tools/batch` | Service binding: bulk scan up to 500 domains |
367
519
 
368
- Supported methods: `initialize`, `ping`, `tools/list`, `tools/call`, `resources/list`, `resources/read`.
520
+ Supported methods: `initialize`, `ping`, `tools/list`, `tools/call`, `resources/list`, `resources/read`, `prompts/list`, `prompts/get`.
369
521
 
370
- Prompt methods (`prompts/list`, `prompts/get`) return `-32601 Method not found`.
522
+ 7 pre-built prompts guide common workflows: `full-security-audit`, `email-auth-check`, `policy-compliance-check`, `remediation-workflow`, `email-hardening-guide`, `provider-benchmark`, `attack-surface-assessment`.
371
523
 
372
524
  </details>
373
525
 
@@ -390,7 +542,7 @@ Prompt methods (`prompts/list`, `prompts/get`) return `-32601 Method not found`.
390
542
 
391
543
  ┌───▼──────────────────────┐
392
544
  │ Tool Handlers │
393
- 14 checks in parallel │
545
+ 16 checks in parallel │
394
546
  └───┬──────────────────────┘
395
547
 
396
548
  ┌───▼──────────────────────┐
@@ -406,6 +558,9 @@ Prompt methods (`prompts/list`, `prompts/get`) return `-32601 Method not found`.
406
558
  - `scan_domain` capped at 75/day per IP (results cached 5 min)
407
559
  - Scan result caching (KV + in-memory fallback)
408
560
  - Adaptive scoring via Durable Object telemetry (graceful fallback to static weights)
561
+ - Intelligence layer: score histograms, provider cohort benchmarks, hourly trend snapshots (ProfileAccumulator DO)
562
+ - Category interaction scoring: correlated weaknesses receive additional penalties
563
+ - Context-optimized schemas: tool descriptions, prompts, and resources tuned for minimal LLM token consumption
409
564
  - Structured JSON logging
410
565
 
411
566
  Implementation details in `CLAUDE.md`.
@@ -422,10 +577,18 @@ Full details in `CLAUDE.md` (security and observability sections).
422
577
  - SSRF protections block unsafe/private targets
423
578
  - Error responses sanitized — only known validation errors surface
424
579
  - DNS via Cloudflare DoH with optional secondary confirmation
425
- - Rate limits: `50/min` and `300/hr` per IP for `tools/call`
580
+ - Constant-time auth comparison (XOR accumulation on SHA-256 digests)
581
+ - DNS data sanitized at ingestion — HTML/markdown injection stripped before findings are created
582
+ - Outbound response body caps (64 KB for tool checks, 1 MB for provider signatures)
583
+ - Tool parameter validation with allowlists and per-element type/length checks
584
+ - Rate limits: `50/min` and `300/hr` per IP for `tools/call` (free tier; Pro and Enterprise bypass)
426
585
  - Control-plane traffic: `60/min` and `600/hr` per IP
427
586
  - Global daily cap: `500,000` unauthenticated tool calls/day (cost ceiling)
428
- - Session creation: `60/min` per IP
587
+ - Authenticated requests: per-tier daily quotas keyed by API key hash (see [Pricing](#pricing))
588
+ - Session creation: `60/min` per IP (enforced on both modern and legacy transports)
589
+ - Session TTL: 2 hours idle, dual-write (KV + in-memory) for cross-isolate resilience
590
+ - SSE notification stream exempt from rate limiting (prevents `mcp-remote` reconnection storms)
591
+ - Client IPs redacted in structured logs
429
592
 
430
593
  **Natural-language convenience:**
431
594
  `tools/call` supports `scan` as an alias for `scan_domain`. In chat clients, say `scan example.com`. Raw JSON-RPC expects `params.name` to be `scan` or `scan_domain`.
@@ -464,7 +627,7 @@ npm run dev # localhost:8787/mcp
464
627
  ```
465
628
 
466
629
  ```bash
467
- npm test # 1090+ tests, ~90% coverage
630
+ npm test # 1469 tests
468
631
  npm run typecheck
469
632
  ```
470
633
 
@@ -512,6 +675,6 @@ Featured in [SecurityBrief](https://securitybrief.co.nz/story/exclusive-how-cybe
512
675
 
513
676
  Want continuous monitoring? [BLACKVEIL](https://blackveilsecurity.com) provides real-time alerting and Buck AI to help you fix what this scanner finds.
514
677
 
515
- MIT License
678
+ BUSL-1.1 License (converts to MIT on 2030-03-17)
516
679
 
517
680
  </div>
package/dist/index.d.ts CHANGED
@@ -1,3 +1,7 @@
1
+ import { CheckResult, ScoringConfig, ScanScore, DomainContext } from '@blackveil/dns-checks/scoring';
2
+ export { CATEGORY_DISPLAY_WEIGHTS, CheckCategory, CheckResult, DomainContext, DomainProfile, Finding, FindingConfidence, SEVERITY_PENALTIES, ScanScore, Severity, buildCheckResult, computeCategoryScore, computeScanScore, createFinding, detectDomainContext, getProfileWeights, inferFindingConfidence, scoreToGrade } from '@blackveil/dns-checks/scoring';
3
+ export { parseDmarcTags } from '@blackveil/dns-checks';
4
+
1
5
  /** Standard DNS record type codes */
2
6
  declare const RecordType: {
3
7
  readonly A: 1;
@@ -14,6 +18,7 @@ declare const RecordType: {
14
18
  readonly RRSIG: 46;
15
19
  readonly PTR: 12;
16
20
  readonly SRV: 33;
21
+ readonly HTTPS: 65;
17
22
  };
18
23
  type RecordTypeName = keyof typeof RecordType;
19
24
  /** A single DNS answer record from the DoH JSON response */
@@ -128,124 +133,6 @@ declare function queryMxRecords(domain: string, opts?: QueryDnsOptions): Promise
128
133
  exchange: string;
129
134
  }>>;
130
135
 
131
- type Severity = 'critical' | 'high' | 'medium' | 'low' | 'info';
132
- type FindingConfidence = 'deterministic' | 'heuristic' | 'verified';
133
- type CheckCategory = 'spf' | 'dmarc' | 'dkim' | 'dnssec' | 'ssl' | 'mta_sts' | 'ns' | 'caa' | 'subdomain_takeover' | 'mx' | 'bimi' | 'tlsrpt' | 'lookalikes' | 'shadow_domains' | 'txt_hygiene' | 'http_security' | 'dane' | 'mx_reputation' | 'srv' | 'zone_hygiene';
134
- interface Finding {
135
- category: CheckCategory;
136
- title: string;
137
- severity: Severity;
138
- detail: string;
139
- metadata?: Record<string, unknown>;
140
- }
141
- interface CheckResult {
142
- category: CheckCategory;
143
- passed: boolean;
144
- score: number;
145
- findings: Finding[];
146
- }
147
- interface ScanScore {
148
- overall: number;
149
- grade: string;
150
- categoryScores: Record<CheckCategory, number>;
151
- findings: Finding[];
152
- summary: string;
153
- }
154
- /** Display/UI weight distribution for categories. NOT used in scoring — see IMPORTANCE_WEIGHTS for actual scoring weights. Exists for category registry and display purposes only. */
155
- declare const CATEGORY_DISPLAY_WEIGHTS: Record<CheckCategory, number>;
156
- /** Severity penalty multipliers applied to the category score */
157
- declare const SEVERITY_PENALTIES: Record<Severity, number>;
158
- /**
159
- * Infer how strongly a finding can be trusted based on available evidence.
160
- * - verified: explicit proof (currently only supported on takeover checks)
161
- * - heuristic: signal-based or partial-evidence checks
162
- * - deterministic: direct record/protocol validation
163
- */
164
- declare function inferFindingConfidence(finding: Finding): FindingConfidence;
165
- /**
166
- * Compute the score for a single check category based on its findings.
167
- * Starts at 100 and deducts points based on finding severities.
168
- */
169
- declare function computeCategoryScore(findings: Finding[]): number;
170
- /**
171
- * Build a CheckResult from a category and its findings.
172
- */
173
- declare function buildCheckResult(category: CheckCategory, findings: Finding[]): CheckResult;
174
- /**
175
- * Create a finding object with the given parameters.
176
- */
177
- declare function createFinding(category: CheckCategory, title: string, severity: Severity, detail: string, metadata?: Record<string, unknown>): Finding;
178
-
179
- /**
180
- * Runtime scoring configuration.
181
- *
182
- * All scoring weights, thresholds, and tuning constants are configurable
183
- * via the `SCORING_CONFIG` environment variable (JSON string). The open-source
184
- * codebase ships with reasonable defaults; production deployments can override
185
- * any subset of values.
186
- *
187
- * Parse once at request entry and thread through the call chain — never
188
- * re-parse per tool call.
189
- */
190
-
191
- /** All tunable scoring parameters. */
192
- interface ScoringConfig {
193
- /** Base importance weights per check category (used when no profile context). */
194
- weights: Record<CheckCategory, number>;
195
- /** Per-profile importance weights. */
196
- profileWeights: Record<DomainProfile, Record<CheckCategory, number>>;
197
- /** Scoring thresholds and constants. */
198
- thresholds: {
199
- emailBonusImportance: number;
200
- spfStrongThreshold: number;
201
- criticalOverallPenalty: number;
202
- criticalGapCeiling: number;
203
- };
204
- /** Grade boundaries (minimum score for each grade). */
205
- grades: {
206
- aPlus: number;
207
- a: number;
208
- bPlus: number;
209
- b: number;
210
- cPlus: number;
211
- c: number;
212
- dPlus: number;
213
- d: number;
214
- e: number;
215
- };
216
- /** Baseline failure rates for adaptive weight computation. */
217
- baselineFailureRates: Record<string, number>;
218
- }
219
-
220
- type DomainProfile = 'mail_enabled' | 'enterprise_mail' | 'non_mail' | 'web_only' | 'minimal';
221
- interface DomainContext {
222
- profile: DomainProfile;
223
- signals: string[];
224
- weights: Record<CheckCategory, ImportanceProfile>;
225
- detectedProvider: string | null;
226
- }
227
- interface ImportanceProfile {
228
- importance: number;
229
- }
230
- /**
231
- * Detect domain context from completed check results.
232
- * Pure function — reads findings metadata only, no DNS queries.
233
- */
234
- declare function detectDomainContext(results: CheckResult[]): DomainContext;
235
- /** Look up the weight table for a given profile, optionally from runtime config. */
236
- declare function getProfileWeights(profile: DomainProfile, config?: ScoringConfig): Record<CheckCategory, ImportanceProfile>;
237
-
238
- /** Map numeric score to letter grade */
239
- declare function scoreToGrade(score: number, config?: ScoringConfig): string;
240
- /**
241
- * Compute the overall scan score from individual check results.
242
- * Uses weighted average of category scores.
243
- *
244
- * When a `DomainContext` is provided, uses profile-specific weights,
245
- * critical gap categories, and email bonus eligibility instead of defaults.
246
- */
247
- declare function computeScanScore(results: CheckResult[], context?: DomainContext, config?: ScoringConfig): ScanScore;
248
-
249
136
  /**
250
137
  * Input sanitization and validation utilities for the DNS Security MCP Server.
251
138
  * Handles domain validation, input cleaning, and MCP error response helpers.
@@ -272,7 +159,7 @@ declare function sanitizeDomain(input: string): string;
272
159
  declare function sanitizeInput(input: string, maxLength?: number): string;
273
160
 
274
161
  /** Server version — keep in sync with package.json */
275
- declare const SERVER_VERSION = "1.4.2";
162
+ declare const SERVER_VERSION = "2.0.6";
276
163
 
277
164
  /**
278
165
  * Check BIMI records for a domain.
@@ -294,9 +181,6 @@ declare function checkCaa(domain: string, dnsOptions?: QueryDnsOptions): Promise
294
181
  */
295
182
  declare function checkDkim(domain: string, selector?: string, dnsOptions?: QueryDnsOptions): Promise<CheckResult>;
296
183
 
297
- /** Parse DMARC tag-value pairs from a DMARC record string. */
298
- declare function parseDmarcTags(record: string): Map<string, string>;
299
-
300
184
  /**
301
185
  * Check DMARC records for a domain.
302
186
  * Queries _dmarc.<domain> TXT records and validates policy configuration.
@@ -323,12 +207,6 @@ declare function checkLookalikes(domain: string): Promise<CheckResult>;
323
207
  */
324
208
  declare function checkMtaSts(domain: string, dnsOptions?: QueryDnsOptions): Promise<CheckResult>;
325
209
 
326
- /**
327
- * MX record check tool for MCP server.
328
- * Validates presence and quality of MX records for a domain.
329
- * Returns CheckResult with findings including RFC compliance, redundancy, and provider detection.
330
- */
331
-
332
210
  interface CheckMxOptions {
333
211
  providerSignaturesUrl?: string;
334
212
  providerSignaturesAllowedHosts?: string[];
@@ -350,25 +228,12 @@ declare function checkNs(domain: string, dnsOptions?: QueryDnsOptions): Promise<
350
228
  */
351
229
  declare function checkSpf(domain: string, dnsOptions?: QueryDnsOptions): Promise<CheckResult>;
352
230
 
353
- /**
354
- * SSL/TLS certificate check tool.
355
- * Validates SSL certificate by attempting HTTPS connection,
356
- * checks HSTS configuration,
357
- * and verifies HTTP→HTTPS redirect.
358
- * Workers-compatible: uses fetch API only (cert expiry/chain require external APIs).
359
- */
360
-
361
231
  /**
362
232
  * Check SSL/TLS configuration for a domain.
363
233
  * Validates HTTPS connectivity, HSTS headers, and HTTP→HTTPS redirect.
364
234
  */
365
235
  declare function checkSsl(domain: string): Promise<CheckResult>;
366
236
 
367
- /**
368
- * Subdomain Takeover / Dangling CNAME Detection Tool
369
- * Scans known/active subdomains for orphaned CNAME records pointing to deleted/unresolved third-party services.
370
- */
371
-
372
237
  /**
373
238
  * Check for dangling CNAME records on known/active subdomains.
374
239
  * Flags orphaned records and potential takeover vectors.
@@ -381,6 +246,8 @@ declare function checkSubdomainTakeover(domain: string, dnsOptions?: QueryDnsOpt
381
246
  */
382
247
  declare function checkTlsrpt(domain: string, dnsOptions?: QueryDnsOptions): Promise<CheckResult>;
383
248
 
249
+ type OutputFormat = 'full' | 'compact';
250
+
384
251
  interface ImpactNarrative {
385
252
  impact?: string;
386
253
  adverseConsequences?: string;
@@ -417,7 +284,22 @@ declare function resolveImpactNarrative(params: {
417
284
  detail?: string;
418
285
  }): ImpactNarrative;
419
286
  declare function explainFinding(checkType: string, status: string, details?: string): ExplanationResult;
420
- declare function formatExplanation(result: ExplanationResult): string;
287
+ declare function formatExplanation(result: ExplanationResult, format?: OutputFormat): string;
288
+
289
+ /**
290
+ * Category interaction scoring — post-scoring adjustments for correlated weaknesses.
291
+ *
292
+ * Applied after computeScanScore() as a separate penalty layer.
293
+ * Does NOT modify categoryScores — only adjusts the overall score.
294
+ * Existing compare_baseline CI/CD workflows continue to work identically.
295
+ */
296
+
297
+ /** Result of applying interaction rules to a scan score. */
298
+ interface InteractionEffect {
299
+ ruleId: string;
300
+ penalty: number;
301
+ narrative: string;
302
+ }
421
303
 
422
304
  interface ScanRuntimeOptions {
423
305
  providerSignaturesUrl?: string;
@@ -431,6 +313,8 @@ interface ScanRuntimeOptions {
431
313
  cacheTtlSeconds?: number;
432
314
  /** Custom secondary DoH resolver config (bv-dns). Threaded to scanDns but only active when skipSecondaryConfirmation is false. */
433
315
  secondaryDoh?: SecondaryDohConfig;
316
+ /** Bypass cache and run a fresh scan. Useful for troubleshooting after DNS changes. */
317
+ forceRefresh?: boolean;
434
318
  }
435
319
 
436
320
  /**
@@ -465,12 +349,27 @@ interface StructuredScanResult {
465
349
  scoringSignals: string[];
466
350
  scoringNote: string | null;
467
351
  adaptiveWeightDeltas: Record<string, number> | null;
352
+ /** Percentile rank within the scoring profile population (0–100). Null when insufficient benchmark data. */
353
+ percentileRank: number | null;
354
+ /** Composite email spoofability score (0–100, higher = more spoofable). Null when not computed. */
355
+ spoofabilityScore: number | null;
356
+ /** Category interaction effects applied as post-scoring adjustments. */
357
+ interactionEffects: Array<{
358
+ ruleId: string;
359
+ penalty: number;
360
+ narrative: string;
361
+ }>;
468
362
  timestamp: string;
469
363
  cached: boolean;
470
364
  }
365
+ /** Optional enrichment data for structured scan results. */
366
+ interface ScanResultEnrichment {
367
+ percentileRank?: number | null;
368
+ spoofabilityScore?: number | null;
369
+ }
471
370
  /** Build a machine-readable structured result from a scan. */
472
- declare function buildStructuredScanResult(result: ScanDomainResult): StructuredScanResult;
473
- declare function formatScanReport(result: ScanDomainResult): string;
371
+ declare function buildStructuredScanResult(result: ScanDomainResult, enrichment?: ScanResultEnrichment): StructuredScanResult;
372
+ declare function formatScanReport(result: ScanDomainResult, format?: OutputFormat): string;
474
373
 
475
374
  /**
476
375
  * scan-domain orchestrator tool.
@@ -492,6 +391,8 @@ interface ScanDomainResult {
492
391
  timestamp: string;
493
392
  scoringNote: string | null;
494
393
  adaptiveWeightDeltas: Record<string, number> | null;
394
+ /** Category interaction effects applied as post-scoring adjustments. Empty when no interactions triggered. */
395
+ interactionEffects: InteractionEffect[];
495
396
  }
496
397
  /**
497
398
  * Run a full DNS security scan on a domain.
@@ -503,4 +404,4 @@ interface ScanDomainResult {
503
404
  */
504
405
  declare function scanDomain(domain: string, kv?: KVNamespace, runtimeOptions?: ScanRuntimeOptions): Promise<ScanDomainResult>;
505
406
 
506
- export { CATEGORY_DISPLAY_WEIGHTS, type CaaRecord, type CheckCategory, type CheckMxOptions, type CheckResult, type DnsAnswer, type DnsAuthority, DnsQueryError, type DohResponse, type DomainContext, type DomainProfile, type ExplanationResult, type Finding, type FindingConfidence, type MaturityStage, type QueryDnsOptions, RecordType, type RecordTypeName, SERVER_VERSION, SEVERITY_PENALTIES, type ScanDomainResult, type ScanRuntimeOptions, type ScanScore, type Severity, type StructuredScanResult, buildCheckResult, buildStructuredScanResult, checkBimi, checkCaa, checkDkim, checkDmarc, checkDnssec, checkLookalikes, checkMtaSts, checkMx, checkNs, checkSpf, checkSsl, checkSubdomainTakeover, checkTlsrpt, computeCategoryScore, computeScanScore, createFinding, detectDomainContext, explainFinding, formatExplanation, formatScanReport, getProfileWeights, inferFindingConfidence, parseCaaRecord, parseDmarcTags, queryCaaRecords, queryDns, queryDnsRecords, queryMxRecords, queryTxtRecords, resolveImpactNarrative, sanitizeDomain, sanitizeInput, scanDomain, scoreToGrade, validateDomain };
407
+ export { type CaaRecord, type CheckMxOptions, type DnsAnswer, type DnsAuthority, DnsQueryError, type DohResponse, type ExplanationResult, type MaturityStage, type QueryDnsOptions, RecordType, type RecordTypeName, SERVER_VERSION, type ScanDomainResult, type ScanRuntimeOptions, type StructuredScanResult, buildStructuredScanResult, checkBimi, checkCaa, checkDkim, checkDmarc, checkDnssec, checkLookalikes, checkMtaSts, checkMx, checkNs, checkSpf, checkSsl, checkSubdomainTakeover, checkTlsrpt, explainFinding, formatExplanation, formatScanReport, parseCaaRecord, queryCaaRecords, queryDns, queryDnsRecords, queryMxRecords, queryTxtRecords, resolveImpactNarrative, sanitizeDomain, sanitizeInput, scanDomain, validateDomain };