v0.2.0 · live
CAPFRAME
← capframe/docs/findings.v1
§ schemacapframe.findings.v1JSON Schema 2020-12

findings.v1

The shared wire format every Capframe module emits or consumes. View raw JSON Schema →

Producers
capframe-find · mcp-recon · capframe-report
Consumers
capframe-bind · capframe-guard · capframe-report
Frameworks
OWASP LLM · NIST AI RMF · MITRE ATLAS

Top-level envelope

Every findings.v1 document is an object with these required fields. Anything else is rejected by the schema.

fieldtypenotesrequired?
schema_versionconstliteral capframe.findings.v1required
scanned_atstring · date-timeRFC 3339required
scan_idstring · uuidstable per scanoptional
scannerScannerwho produced thisrequired
targetTargetwhat was scannedrequired
toolsarray of Tooltool surface seenrequired
findingsarray of Findingwhat the classifier emittedrequired
summarySummaryaggregated counts + mappingsrequired

Scanner

Identifies the tool that emitted the document.

fieldtypenotesrequired?
namestringe.g. capframe-find, mcp-reconrequired
versionstringe.g. 0.2.0required

Target

Describes the artefact under scan.

fieldtypenotesrequired?
kindTargetKinddiscriminatorrequired
namestringfree-form display nameoptional
urlstring · urifor HTTP targetsoptional
pathstringfor filesystem targetsoptional
transportenum: stdio | http | sse | websocketfor MCP serversoptional

TargetKind enum

Tool

One entry per tool in the scanned surface. Same shape regardless of TargetKind.

fieldtypenotesrequired?
namestringtool identityrequired
descriptionstringfree-form blurboptional
parametersobject · JSON Schemathe tool's input contractoptional
side_effectsarray of SideEffectdeclared, not inferredoptional
auth_requiredbooleandid the manifest claim auth?optional
rate_limitedbooleanmanifest claimoptional

SideEffect enum

Finding

One rule firing on one tool (or, occasionally, server-level). Findings are the unit of cross-tool exchange — the same Finding object can flow from mcp-recon capnagent for caveat issuance, or → capframe-report for OWASP/NIST/ATLAS reporting.

fieldtypenotesrequired?
idstringstable hash; safe to diff across scansrequired
severitySeverityinfo | low | medium | high | criticalrequired
categoryCategorystable taxonomyrequired
titlestring · max 200one-line summaryrequired
descriptionstringlonger bodyoptional
toolstringname of the tool this finding relates tooptional
evidenceobjectscanner-specific structured detailoptional
remediationstringactionable fix textoptional
mappingsMappingscompliance-framework IDsoptional
first_seenstring · date-timecarried across scans by the consumeroptional
last_seenstring · date-timecarried similarlyoptional

Severity enum

Category enum

Mappings — compliance IDs

Each finding can carry compliance-framework references. Patterns are enforced by the schema, so consumers can trust the strings.

fieldtypenotesrequired?
owasp_llm[]stringpattern ^LLM(0[1-9]|10)$e.g. LLM08
nist_rmf[]stringpattern ^(GOVERN|MAP|MEASURE|MANAGE)-[0-9]+(\.[0-9]+)*$e.g. MANAGE-2.2
mitre_atlas[]stringpattern ^T[0-9]{4}(\.[0-9]{3})?$e.g. T0051

Summary

Aggregated counts. Computed by the scanner; consumers should not recompute. The fields are flat and stable for diffing across scans.

fieldtypenotesrequired?
totalinteger ≥ 0findings.lengthrequired
by_severitySeverityCountsfive-key tallyrequired
by_categoryobject · keys are Categoryk → count of findings in that categoryoptional
mappingsobjectroll-up of Mappings IDs across all findingsoptional

SeverityCounts

All five severity keys present, default 0. Sum equals summary.total.

Example envelope

Minimal but valid. Strip the tools and findings arrays empty and you have the empty-scan shape that mcp-recon emits when its input can't be parsed.

{
  "schema_version": "capframe.findings.v1",
  "scanned_at": "2026-05-30T13:47:37Z",
  "scan_id": "0c81b6d2-7a91-4c52-9c1e-aa8e90e3f6b1",
  "scanner": { "name": "mcp-recon", "version": "0.2.0" },
  "target":  { "kind": "mcp_server", "name": "shopify-mcp", "transport": "stdio" },
  "tools": [
    {
      "name": "order.refund",
      "description": "Issue a refund on an order",
      "side_effects": ["write", "money", "irreversible"],
      "auth_required": true
    }
  ],
  "findings": [
    {
      "id": "f-order-refund-unbounded",
      "severity": "high",
      "category": "excessive_agency",
      "title": "order.refund has no monetary cap",
      "description": "Accepts arbitrary amount with no policy-side cap.",
      "tool": "order.refund",
      "remediation": "Bind a capability with --max-refund.",
      "mappings": {
        "owasp_llm":   ["LLM08"],
        "nist_rmf":    ["MANAGE-2.2"],
        "mitre_atlas": ["T0051"]
      }
    }
  ],
  "summary": {
    "total": 1,
    "by_severity": { "info": 0, "low": 0, "medium": 0, "high": 1, "critical": 0 },
    "by_category": { "excessive_agency": 1 }
  }
}

Versioning

Schema changes that add optional fields are backwards-compatible and don't bump the version. Renaming, removing, or changing semantics of an existing field bumps the version (capframe.findings.v2, etc.). Consumers should accept unknown optional fields silently.

Canonical JSON Schema: raw.githubusercontent.com/capframe/capframe/main/schemas/findings.v1.json