addedOutput schema / $defs
Added value: +{
+ "CheckHeadersResponse": {
+ "properties": {
+ "by_severity": {
+ "additionalProperties": {
+ "type": "integer"
+ },
+ "description": "Finding counts bucketed by severity, e.g. {'high': 2, 'medium': 1, 'low': 0}.",
+ "title": "By Severity",
+ "type": "object"
+ },
+ "findings": {
+ "description": "Per-header validation findings — one entry per header you submitted that the validator recognized.",
+ "items": {
+ "$ref": "#/$defs/HeaderFinding"
+ },
+ "title": "Findings",
+ "type": "array"
+ },
+ "grade": {
+ "default": "F",
+ "description": "Letter grade derived from score: A=90+, B=75+, C=60+, D=40+, else F.",
+ "enum": [
+ "A",
+ "B",
+ "C",
+ "D",
+ "F"
+ ],
+ "title": "Grade",
+ "type": "string"
+ },
+ "headers_missing": {
+ "description": "Header names the ruleset expects but were not present in the submitted set.",
+ "items": {
+ "type": "string"
+ },
+ "title": "Headers Missing",
+ "type": "array"
+ },
+ "headers_present": {
+ "description": "Header names from the submitted set that the validator recognized as present.",
+ "items": {
+ "type": "string"
+ },
+ "title": "Headers Present",
+ "type": "array"
+ },
+ "next_calls": {
+ "anyOf": [
+ {
+ "items": {
+ "$ref": "#/$defs/PivotHint"
+ },
+ "type": "array"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "Suggested follow-up MCP tool calls. Ordered by relevance; agents should chain these without re-prompting the user.",
+ "title": "Next Calls"
+ },
+ "score": {
+ "default": 0,
+ "description": "Aggregate header-posture score (0-100) computed from per-finding severity weights.",
+ "title": "Score",
+ "type": "integer"
+ },
+ "summary": {
+ "default": "",
+ "description": "One-line human-readable summary of grade + key issues.",
+ "title": "Summary",
+ "type": "string"
+ },
+ "total": {
+ "default": 0,
+ "description": "Total number of findings emitted (== len(findings)).",
+ "title": "Total",
+ "type": "integer"
+ },
+ "verdict": {
+ "anyOf": [
+ {
+ "$ref": "#/$defs/Verdict"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "Falsifiability metadata: sources_queried, sources_unavailable, completeness, deterministic flag. Lets agents distinguish 'no data' from 'source failed' without re-running the call."
+ }
+ },
+ "title": "CheckHeadersResponse",
+ "type": "object"
+ },
+ "ErrorDetail": {
+ "description": "Structured failure body. Codes mirror app/exceptions.AppException\nsubclasses; agent retry / upgrade decisions key off `code`, not `message`.",
+ "properties": {
+ "code": {
+ "description": "Stable machine-readable failure category. Agents key retry/upgrade decisions off this.",
+ "enum": [
+ "invalid_argument",
+ "not_found",
+ "rate_limit_exceeded",
+ "auth_required",
+ "tier_limit",
+ "upstream_timeout",
+ "upstream_error",
+ "internal_error"
+ ],
+ "title": "Code",
+ "type": "string"
+ },
+ "docs_url": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "Documentation pointer (e.g. tool input contract) when code='invalid_argument'.",
+ "title": "Docs Url"
+ },
+ "message": {
+ "description": "Human-readable detail. Free text — never parse. Capped at 500 chars to prevent oversized upstream errors from bloating responses.",
+ "maxLength": 500,
+ "title": "Message",
+ "type": "string"
+ },
+ "retry_after_seconds": {
+ "anyOf": [
+ {
+ "type": "integer"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "When code='rate_limit_exceeded', the minimum seconds to wait before retrying.",
+ "title": "Retry After Seconds"
+ },
+ "upgrade_url": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "Pricing/upgrade URL when code='tier_limit' or 'rate_limit_exceeded' on the Free tier.",
+ "title": "Upgrade Url"
+ }
+ },
+ "required": [
+ "code",
+ "message"
+ ],
+ "title": "ErrorDetail",
+ "type": "object"
+ },
+ "ErrorResponse": {
+ "description": "MCP error envelope. Tool return type is always\n`SpecificResponse | ErrorResponse` — Union flag tells the agent which arm\narrived without parsing the inner body.",
+ "properties": {
+ "error": {
+ "$ref": "#/$defs/ErrorDetail"
+ }
+ },
+ "required": [
+ "error"
+ ],
+ "title": "ErrorResponse",
+ "type": "object"
+ },
+ "HeaderFinding": {
+ "properties": {
+ "description": {
+ "default": "",
+ "description": "Human-readable explanation of what this header protects against.",
+ "title": "Description",
+ "type": "string"
+ },
+ "header": {
+ "description": "Canonical header name as defined by the ruleset (e.g. 'Strict-Transport-Security', 'Content-Security-Policy').",
+ "title": "Header",
+ "type": "string"
+ },
+ "issues": {
+ "description": "Machine-readable issue codes emitted by the validator for present-but-invalid headers (e.g. 'hsts_max_age_too_short', 'csp_wildcard_script_src', 'xfo_allowall'). Empty when the header is absent, valid, or has no validator.",
+ "items": {
+ "type": "string"
+ },
+ "title": "Issues",
+ "type": "array"
+ },
+ "present": {
+ "description": "True when the response sent this header at all (regardless of whether the value is valid).",
+ "title": "Present",
+ "type": "boolean"
+ },
+ "reference": {
+ "default": "",
+ "description": "URL to authoritative spec/documentation (MDN, OWASP, RFC).",
+ "title": "Reference",
+ "type": "string"
+ },
+ "remediation": {
+ "default": "",
+ "description": "Concrete recommended header value or configuration snippet.",
+ "title": "Remediation",
+ "type": "string"
+ },
+ "severity": {
+ "description": "Impact weight assigned by the ruleset: 'high' (25 pts), 'medium' (15 pts), 'low' (10 pts). Drives the overall score/grade — missing a 'high' header costs more than missing a 'low' one.",
+ "enum": [
+ "high",
+ "medium",
+ "low"
+ ],
+ "title": "Severity",
+ "type": "string"
+ },
+ "total_value_length": {
+ "anyOf": [
+ {
+ "type": "integer"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "Honest pre-truncation char length of the raw header value. Only emitted when the value was actually truncated (raw length > 500). Null when no truncation occurred, when no validator applies, or when the header is absent.",
+ "title": "Total Value Length"
+ },
+ "valid": {
+ "default": false,
+ "description": "Value-level validation result. True when the header is present AND its value passes the header-specific validator (e.g. HSTS max-age >= 1 year + includeSubDomains; CSP has no wildcard source in script-src). True also when the header is present but no validator exists for it. False when the header is absent, or present-but-invalid. Inspect `issues` for the specific reasons a present-but-invalid header failed.",
+ "title": "Valid",
+ "type": "boolean"
+ },
+ "value": {
+ "anyOf": [
+ {
+ "type": "string"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "Raw header value as sent by the origin, when the header is present AND a validator exists for it. Null when the header is absent, or when it's present but no validator applies to it. By default the value is capped at the first 500 chars (CSP headers can exceed 4 KB); inspect total_value_length to see if truncation occurred and refetch with include=full to restore the full value.",
+ "title": "Value"
+ }
+ },
+ "required": [
+ "header",
+ "severity",
+ "present"
+ ],
+ "title": "HeaderFinding",
+ "type": "object"
+ },
+ "PivotHint": {
+ "additionalProperties": true,
+ "description": "A suggested follow-up MCP tool call. Surfaced inside response.next_calls so\nLLM agents can chain related lookups without manual prompting. Each hint names\nthe tool, the input value to pass, and a short reason explaining why this\npivot adds value in the current context.",
+ "properties": {
+ "input": {
+ "description": "Suggested input value to pass to the tool — typically a CVE ID, CWE ID, domain, or IP. Pre-populated from the current response so the agent can call the next tool without re-deriving the argument.",
+ "title": "Input",
+ "type": "string"
+ },
+ "params": {
+ "anyOf": [
+ {
+ "additionalProperties": {
+ "type": "string"
+ },
+ "type": "object"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "Optional extra kwargs to pass alongside `input`. Used by pivot generators when the next call benefits from a secondary parameter, e.g. {'exclude_id': 'AML.T0051'} to skip the originating technique from a sibling-tactic search. Omitted when no extra args are needed.",
+ "title": "Params"
+ },
+ "reason": {
+ "description": "Short rationale (one sentence) for why this follow-up call adds value, e.g. 'Federal patch deadline + ransomware association', 'Public exploits / PoC availability'.",
+ "title": "Reason",
+ "type": "string"
+ },
+ "tool": {
+ "description": "Canonical MCP tool name to call next. Constrained to known operation_ids in tools/list — adding a new tool here requires expanding the Literal.",
+ "enum": [
+ "cve_lookup",
+ "cve_search",
+ "cve_leading",
+ "bulk_cve_lookup",
+ "exploit_lookup",
+ "kev_detail",
+ "cwe_lookup",
+ "subdomain_enum",
+ "ssl_check",
+ "tech_fingerprint",
+ "asn_lookup",
+ "ip_lookup",
+ "ioc_lookup",
+ "bulk_ioc_lookup",
+ "hash_lookup",
+ "threat_intel",
+ "threat_report",
+ "audit_domain",
+ "domain_report",
+ "dns_lookup",
+ "whois_lookup",
+ "wayback_lookup",
+ "scan_headers",
+ "check_headers",
+ "check_secrets",
+ "check_injection",
+ "check_dependencies",
+ "email_mx",
+ "email_disposable",
+ "phone_lookup",
+ "username_lookup",
+ "password_check",
+ "phishing_check",
+ "atlas_technique_lookup",
+ "atlas_technique_search",
+ "bulk_atlas_technique_lookup",
+ "atlas_case_study_lookup",
+ "atlas_case_study_search",
+ "d3fend_defense_lookup",
+ "d3fend_defense_search",
+ "d3fend_defense_for_attack",
+ "d3fend_attack_coverage"
+ ],
+ "title": "Tool",
+ "type": "string"
+ }
+ },
+ "required": [
+ "tool",
+ "input",
+ "reason"
+ ],
+ "title": "PivotHint",
+ "type": "object"
+ },
+ "Verdict": {
+ "properties": {
+ "completeness": {
+ "default": "complete",
+ "description": "'complete' = every planned source returned data; 'partial' = at least one source in sources_unavailable failed or was skipped; 'minimal' = only the primary/required source returned, optional enrichment missing.",
+ "enum": [
+ "complete",
+ "partial",
+ "minimal"
+ ],
+ "title": "Completeness",
+ "type": "string"
+ },
+ "data_age_seconds": {
+ "anyOf": [
+ {
+ "type": "integer"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "default": null,
+ "description": "Seconds elapsed since the oldest cached source was fetched, or null when every source was queried live for this request. Use to judge freshness.",
+ "title": "Data Age Seconds"
+ },
+ "deterministic": {
+ "description": "True when the response is fully reproducible from the listed sources for the same input at the same moment (no randomness, no model inference). False for endpoints that include probabilistic scoring or LLM output.",
+ "title": "Deterministic",
+ "type": "boolean"
+ },
+ "falsifiable_fields": {
+ "description": "Top-level response fields whose values a caller can independently re-derive from the named upstream sources (e.g. 'dns', 'ssl', 'whois'). Fields not in this list are derived/computed and cannot be directly re-verified.",
+ "items": {
+ "type": "string"
+ },
+ "title": "Falsifiable Fields",
+ "type": "array"
+ },
+ "sources_queried": {
+ "description": "Canonical source identifiers successfully consulted for this response (e.g. 'ripe_stat', 'shodan_internetdb', 'firehol'). Agent-readable list, order not significant.",
+ "items": {
+ "type": "string"
+ },
+ "title": "Sources Queried",
+ "type": "array"
+ },
+ "sources_unavailable": {
+ "description": "Sources that were expected but not returned — either intentionally skipped (lite mode, tier gating) or failed (quota, timeout, upstream down). Empty list means every planned source produced data.",
+ "items": {
+ "type": "string"
+ },
+ "title": "Sources Unavailable",
+ "type": "array"
+ }
+ },
+ "required": [
+ "deterministic"
+ ],
+ "title": "Verdict",
+ "type": "object"
+ }
+}