Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 110 additions & 0 deletions docs/reference/api/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1015,6 +1015,116 @@ components:
commit: "abc123def456"
timestamp: "2023-12-01T10:30:00Z"
pipelineId: "build-789"
io.modelcontextprotocol.registry/security-scan:
type: array
description: "Optional scanner-neutral security scan receipts. Each receipt is scoped to the scanned artifact, scanner version, rule set, policy profile, scan scope, and evidence reference; a clean verdict is not a global safety claim."
items:
type: object
required:
- scannedArtifactDigest
- scanScope
- verdict
- attestation
properties:
scanner:
type: string
description: "Name or identifier of the scanner that produced the receipt."
example: "example-scanner"
maxLength: 200
scannerVersion:
type: string
description: "Version of the scanner that produced the receipt."
example: "1.2.3"
maxLength: 100
ruleSetRef:
type: string
description: "Scanner-specific rule set reference, preferably pinned by digest."
example: "agent-threat-rules@sha256:abc123..."
maxLength: 500
policyProfile:
type: string
description: "Policy profile or scan configuration used to evaluate the artifact."
example: "default-mcp-registry-v1"
maxLength: 200
scannedArtifactRef:
type: string
description: "Package URL, image reference, source archive reference, or other stable identifier for the artifact that was scanned."
example: "pkg:npm/@modelcontextprotocol/server-filesystem@1.0.2"
maxLength: 500
scannedArtifactDigest:
type: string
description: "Digest of the artifact that was scanned. Registry clients should only display artifact-bound claims when this digest matches the current package or artifact."
example: "sha256:abc123..."
pattern: "^[a-z0-9][a-z0-9+.-]*:.+$"
maxLength: 200
scanScope:
type: array
description: "Machine-readable list of surfaces evaluated by this scan. This describes what was checked, not every capability the server exposes."
minItems: 1
uniqueItems: true
items:
type: string
enum:
- dependency
- package
- source
- handler-validation
- runtime-behavior
- configuration
- unknown
example: ["dependency", "package"]
verdict:
type: string
description: "Scanner verdict for the stated artifact, rule set, policy profile, and scan scope."
enum:
- clean
- warnings
- findings
- inconclusive
example: "warnings"
inconclusiveReason:
type: string
description: "Machine-readable reason when the verdict is inconclusive. Omit or set to other only when no more specific value applies."
enum:
- artifact_digest_mismatch
- unsupported_package_type
- scope_excludes_handler_validation
- evidence_unavailable
- stale_scan
- scanner_error
- policy_not_supported
- other
example: "scope_excludes_handler_validation"
scannedAt:
type: string
format: date-time
description: "Timestamp when the scan was performed."
example: "2026-06-28T00:00:00Z"
freshnessExpiresAt:
type: string
format: date-time
description: "Timestamp after which clients should treat the receipt as stale unless refreshed."
example: "2026-07-28T00:00:00Z"
evidenceRef:
type: string
format: uri
description: "URL for the full machine-readable report or attestation evidence."
example: "https://example.org/report.json"
evidenceDigest:
type: string
description: "Digest of the evidence referenced by evidenceRef."
example: "sha256:def456..."
pattern: "^[a-z0-9][a-z0-9+.-]*:.+$"
maxLength: 200
attestation:
type: string
description: "Who asserts or attests the receipt. This does not define signature or key-distribution semantics."
enum:
- publisher-asserted
- registry-attested
- third-party-attested
example: "third-party-attested"
additionalProperties: true

ServerResponse:
description: API response format with separated server data and registry metadata
Expand Down
10 changes: 9 additions & 1 deletion docs/reference/server-json/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ Changes to the server.json schema and format.

This section tracks changes that are in development and not yet released. The draft schema is available at [`server.schema.json`](./draft/server.schema.json) in this repository.

### Added

#### Security Scan Receipt Metadata

The `_meta` field can now document optional scanner-neutral security scan receipts under `io.modelcontextprotocol.registry/security-scan`.

Each receipt is scoped to a scanned artifact digest, scan scope, verdict, attestation, and optional evidence reference/digest. The shape keeps `clean` scoped to the exact artifact, scanner, rule set, policy profile, and scan scope instead of making a global server-safety claim. `inconclusiveReason` provides machine-readable failure modes such as artifact digest mismatch, unsupported package type, excluded handler-validation scope, unavailable evidence, and stale scans.

### Changed

#### Transport URL Pattern Now Accepts Template Variables
Expand Down Expand Up @@ -313,4 +321,4 @@ All JSON field names standardized to camelCase. **All existing `server.json` fil

## 2025-07-09

Initial release of the server.json schema.
Initial release of the server.json schema.
136 changes: 136 additions & 0 deletions docs/reference/server-json/draft/server.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,142 @@
"version": "1.2.3"
},
"type": "object"
},
"io.modelcontextprotocol.registry/security-scan": {
"description": "Optional scanner-neutral security scan receipts. Each receipt is scoped to the scanned artifact, scanner version, rule set, policy profile, scan scope, and evidence reference; a clean verdict is not a global safety claim.",
"items": {
"additionalProperties": true,
"properties": {
"attestation": {
"description": "Who asserts or attests the receipt. This does not define signature or key-distribution semantics.",
"enum": [
"publisher-asserted",
"registry-attested",
"third-party-attested"
],
"example": "third-party-attested",
"type": "string"
},
"evidenceDigest": {
"description": "Digest of the evidence referenced by evidenceRef.",
"example": "sha256:def456...",
"maxLength": 200,
"pattern": "^[a-z0-9][a-z0-9+.-]*:.+$",
"type": "string"
},
"evidenceRef": {
"description": "URL for the full machine-readable report or attestation evidence.",
"example": "https://example.org/report.json",
"format": "uri",
"type": "string"
},
"freshnessExpiresAt": {
"description": "Timestamp after which clients should treat the receipt as stale unless refreshed.",
"example": "2026-07-28T00:00:00Z",
"format": "date-time",
"type": "string"
},
"inconclusiveReason": {
"description": "Machine-readable reason when the verdict is inconclusive. Omit or set to other only when no more specific value applies.",
"enum": [
"artifact_digest_mismatch",
"unsupported_package_type",
"scope_excludes_handler_validation",
"evidence_unavailable",
"stale_scan",
"scanner_error",
"policy_not_supported",
"other"
],
"example": "scope_excludes_handler_validation",
"type": "string"
},
"policyProfile": {
"description": "Policy profile or scan configuration used to evaluate the artifact.",
"example": "default-mcp-registry-v1",
"maxLength": 200,
"type": "string"
},
"ruleSetRef": {
"description": "Scanner-specific rule set reference, preferably pinned by digest.",
"example": "agent-threat-rules@sha256:abc123...",
"maxLength": 500,
"type": "string"
},
"scanScope": {
"description": "Machine-readable list of surfaces evaluated by this scan. This describes what was checked, not every capability the server exposes.",
"example": [
"dependency",
"package"
],
"items": {
"enum": [
"dependency",
"package",
"source",
"handler-validation",
"runtime-behavior",
"configuration",
"unknown"
],
"type": "string"
},
"minItems": 1,
"type": "array",
"uniqueItems": true
},
"scannedArtifactDigest": {
"description": "Digest of the artifact that was scanned. Registry clients should only display artifact-bound claims when this digest matches the current package or artifact.",
"example": "sha256:abc123...",
"maxLength": 200,
"pattern": "^[a-z0-9][a-z0-9+.-]*:.+$",
"type": "string"
},
"scannedArtifactRef": {
"description": "Package URL, image reference, source archive reference, or other stable identifier for the artifact that was scanned.",
"example": "pkg:npm/@modelcontextprotocol/server-filesystem@1.0.2",
"maxLength": 500,
"type": "string"
},
"scannedAt": {
"description": "Timestamp when the scan was performed.",
"example": "2026-06-28T00:00:00Z",
"format": "date-time",
"type": "string"
},
"scanner": {
"description": "Name or identifier of the scanner that produced the receipt.",
"example": "example-scanner",
"maxLength": 200,
"type": "string"
},
"scannerVersion": {
"description": "Version of the scanner that produced the receipt.",
"example": "1.2.3",
"maxLength": 100,
"type": "string"
},
"verdict": {
"description": "Scanner verdict for the stated artifact, rule set, policy profile, and scan scope.",
"enum": [
"clean",
"warnings",
"findings",
"inconclusive"
],
"example": "warnings",
"type": "string"
}
},
"required": [
"scannedArtifactDigest",
"scanScope",
"verdict",
"attestation"
],
"type": "object"
},
"type": "array"
}
},
"type": "object"
Expand Down
37 changes: 37 additions & 0 deletions docs/reference/server-json/generic-server-json.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,43 @@ The optional `_meta` field allows publishers to include custom metadata alongsid

When publishing to the official registry, custom metadata must be placed under the key `io.modelcontextprotocol.registry/publisher-provided`. See the [official registry requirements](./official-registry-requirements.md) for detailed restrictions and examples.

### Optional Security Scan Receipts

Generic registries and subregistries may expose scanner-neutral security scan receipts under `_meta["io.modelcontextprotocol.registry/security-scan"]`.

Each receipt is scoped to the evidence that produced it. A `clean` verdict means the stated artifact was clean for the listed scanner, scanner version, rule set, policy profile, and scan scope. It is not a global claim that the server is safe.

```jsonc
{
"_meta": {
"io.modelcontextprotocol.registry/security-scan": [
{
"scanner": "example-scanner",
"scannerVersion": "1.2.3",
"ruleSetRef": "agent-threat-rules@sha256:abc123...",
"policyProfile": "default-mcp-registry-v1",
"scannedArtifactRef": "pkg:npm/@modelcontextprotocol/server-filesystem@1.0.2",
"scannedArtifactDigest": "sha256:abc123...",
"scanScope": ["dependency", "package"],
"verdict": "warnings",
"inconclusiveReason": "scope_excludes_handler_validation",
"scannedAt": "2026-06-28T00:00:00Z",
"freshnessExpiresAt": "2026-07-28T00:00:00Z",
"evidenceRef": "https://example.org/report.json",
"evidenceDigest": "sha256:def456...",
"attestation": "third-party-attested"
}
]
}
}
```

Registry clients should only display artifact-bound security claims when `scannedArtifactDigest` matches the current package or artifact. Clients should also include the displayed `scanScope`, because a dependency or package scan can be clean while handler-side validation remains unassessed.

Use `verdict: "inconclusive"` with an `inconclusiveReason` when the receipt cannot support a stronger claim, such as `artifact_digest_mismatch`, `unsupported_package_type`, `scope_excludes_handler_validation`, `evidence_unavailable`, or `stale_scan`.

The `attestation` field distinguishes self-asserted publisher metadata from registry- or third-party-attested receipts. It does not define signature or key-distribution semantics.

## Examples

<!-- As a heads up, these are used as part of tests/integration/main.go -->
Expand Down
Loading