Skip to main content

mcp-lock.json schema

ToolPin writes lockfile version 2. The file is keyed by server:client, so one server can be locked differently for different MCP clients.

{
"lockfileVersion": 2,
"generatedAt": "2026-06-25T00:00:00.000Z",
"updatedAt": "2026-06-25T00:00:00.000Z",
"servers": {
"io.github.example/server:claude": {
"name": "io.github.example/server",
"version": "1.2.3",
"client": "claude",
"selectedTarget": {
"kind": "package",
"registryType": "oci",
"identifier": "ghcr.io/example/server@sha256:...",
"version": "1.2.3",
"fileSha256": "abcd1234...",
"transport": "stdio"
},
"trust": {
"score": 85,
"tier": "conditional",
"gatedBy": [],
"evidence": [
{
"code": "digest_present",
"status": "declared",
"message": "OCI image ghcr.io/example/server@sha256:... declares a digest pin; image bytes were not resolved by ToolPin.",
"verificationMethod": "metadata-presence",
"verifiedByToolPin": false
},
{
"code": "lock_integrity",
"status": "passed",
"message": "Lock entry integrity digest is computed over the reviewed install plan.",
"verificationMethod": "canonical-json-sha256",
"verifiedByToolPin": true
}
],
"badges": [],
"issues": []
},
"config": {},
"notes": [],
"capabilityManifest": {
"version": 1,
"generatedAt": "2026-06-25T00:00:00.000Z",
"serverName": "io.github.example/server",
"serverVersion": "1.2.3",
"registrySource": "official",
"packageTypes": ["oci"],
"transports": ["stdio"],
"remoteHosts": [],
"secrets": [],
"toolDescriptionHash": {
"algorithm": "sha256",
"value": "ef5678...",
"toolCount": 12,
"generatedAt": "2026-06-25T00:00:00.000Z"
},
"toolManifestHash": {
"algorithm": "sha256",
"value": "ab7890...",
"toolCount": 12,
"generatedAt": "2026-06-25T00:00:00.000Z"
},
"toolDescriptionScan": {
"version": 1,
"generatedAt": "2026-06-25T00:00:00.000Z",
"scannedDescriptions": 12,
"findings": []
}
},
"resolvedAt": "2026-06-25T00:00:00.000Z",
"lockedAt": "2026-06-25T00:00:00.000Z",
"resolved": {
"source": "official",
"name": "io.github.example/server",
"version": "1.2.3"
},
"original": {
"name": "io.github.example/server",
"version": "1.2.3",
"client": "claude"
},
"locked": {
"selectedTarget": {},
"config": {},
"capabilityManifest": {}
},
"integrity": "sha256-..."
}
}
}

Required top-level fields

FieldTypeMeaning
lockfileVersion2Current supported schema version. v1 lockfiles must be regenerated.
generatedAtstringOriginal file creation timestamp. Ignored by whole-lock digest calculations.
serversobjectMap of lock entries keyed by <server-name>:<client>.
updatedAtstring (optional)Last write timestamp, present after the first mutation. Ignored by whole-lock digest calculations.

Entry fields

Required unless noted. resolved, original, and locked are synthesized by ToolPin on write; capabilityManifest, lockedAt, and integrity are optional on read but ci will reject entries missing integrity.

FieldTypeMeaning
namestringRegistry server name.
versionstringLocked server version.
clientclient nameClient this generated config targets.
selectedTargetobjectPackage or remote target selected for install. Package targets include fileSha256 for MCPB.
trustobjectMetadata completeness score, optional tier/gating/evidence, badges, and review issues at lock time.
configany JSON valueGenerated client config fragment.
notesstring arrayHuman-readable install notes.
capabilityManifestobject (optional)Derived capability manifest. See Capability manifest. toolDescriptionHash, toolManifestHash, and toolDescriptionScan appear only after a successful --verify live probe of the selected MCP launch target.
resolvedAtstringTime the entry was resolved. Included in per-entry integrity and whole-lock digest calculations.
lockedAtstring (optional)Time the entry was written. Included in per-entry integrity and whole-lock digest calculations.
resolvedobject (synthesized)Registry source, name, and version resolved by ToolPin.
originalobject (synthesized)Original name, version, and client at lock time.
lockedobject (synthesized)Snapshot used for drift checks.
integritystring (optional on read, enforced by ci)sha256-... over the reviewed entry contents, including entry timestamps.

The whole-lock digest from toolpin lock digest excludes only top-level file metadata timestamps (generatedAt, updatedAt) and covers the canonical set of locked server/client entries, including entry timestamps such as resolvedAt and lockedAt.

Trust object

trust.score remains a 0–100 metadata completeness score for compatibility with older lockfiles and score-based policy. Newer entries may also include:

FieldTypeMeaning
tier"verified" | "conditional" | "unverified" | "blocked" (optional)Evidence-gated trust tier. verified means required ToolPin-verified evidence passed, not that the server is safe.
overallScorenumber (optional)Machine-readable gated score after provenance/evidence caps. A capped value such as 69 is an evidence gate limit, not a percentile-like quality score.
metadataCompletenessnumber (optional)The legacy 0–100 metadata/profile score recorded explicitly for UI/explanations and human-facing numeric differentiation.
capReasonstring (optional)Reason the evidence gate capped overallScore, such as automated evidence incomplete, no verified provenance, or a critical gate code.
gatedBystring array (optional)Issue or evidence codes that prevented a stronger tier.
gates / vetoesobject arrays (optional)Non-blocking gates and blocking vetoes derived from critical issues or required evidence failures.
pillarsobject (optional)Breakdown of provenance, integrity, reputation, and metadata completeness scores.
evidenceobject array (optional)Automated evidence entries. Older lockfiles without this field remain valid and are not rewritten on read.

Evidence entries are { code, status, message, source?, claim?, verificationMethod?, verifiedByToolPin?, verifiedAt?, failureReason?, required? }, where status is passed, declared, failed, or unavailable. Current codes include package_pin, digest_present, file_hash_present, lock_integrity, lock_signature, oci_digest_verified, mcpb_sha256_verified, npm_integrity_verified, and attestation_declared. Declared pins, hashes, and attestations are not treated as ToolPin-verified unless a future verifier records verifiedByToolPin: true on a passed evidence entry.

automated evidence incomplete means the entry has not satisfied all evidence required for verified. In practice this usually means an exact package pin exists but artifact proof is missing, stale, unavailable, or only declared: ToolPin could not resolve the OCI manifest digest, recompute MCPB bytes from a trusted HTTPS host, verify npm tarball integrity, or verify an attestation. Declared pins and declared attestations alone do not count as ToolPin-verified proof.

Capability manifest

The optional capabilityManifest object is derived by toolpin verify (and persisted by toolpin install --verify or toolpin lock --verify) from normalized registry metadata and an optional live tools/list probe of the selected package or remote launch target. Array fields are de-duplicated and sorted deterministically.

FieldTypeMeaning
version1Capability manifest schema version.
serverNamestringRegistry server name.
serverVersionstringServer version.
registrySourcestringRegistry source id the manifest was derived from.
packageTypesstring arraySorted unique package registry types declared (e.g. npm, pypi, nuget, cargo, oci, mcpb).
transportsstring arraySorted unique transport types declared by packages and remotes.
remoteHostsstring arraySorted unique egress hosts parsed from remote URLs.
secretsobject arraySorted declared secret inputs. Each entry is { name, source: "env" | "header", required }, covering package environment variables and remote headers marked isSecret or isRequired.
generatedAtstringISO timestamp the manifest was generated. Required.
toolDescriptionHashobject (optional)Present only after a successful live tools/list probe of the selected launch target. { algorithm: "sha256", value, toolCount, generatedAt } over the sorted name/description pairs returned by the probe.
toolManifestHashobject (optional)Present only after a successful live tools/list probe of the selected launch target. { algorithm: "sha256", value, toolCount, generatedAt } over the sorted tool name, description, and inputSchema values returned by the probe.
toolDescriptionScanobject (optional)Present only after a successful live tools/list probe. { version: 1, generatedAt, scannedDescriptions, findings } of advisory review signals (see below).

Verification rules

toolpin verify derives the manifest above and adds a critical issue (so the report is not ok) when:

  • an OCI package identifier is not pinned by digest (@sha256:) — code mutable_oci_tag;
  • an MCPB package is missing fileSha256 — code missing_mcpb_hash;
  • a remote live probe is enabled but fails to connect or list tools — code remote_probe_failed;
  • a package live probe is enabled but fails to start or list tools — code package_probe_failed;
  • no install target (package or remote) is available — code no_install_target.

A valid OCI digest pin earns the digest-pinned badge and is required before ToolPin attempts best-effort registry digest verification. A valid MCPB fileSha256 earns the fileSha256 badge and is required before ToolPin attempts best-effort byte hashing from code-allowlisted HTTPS artifact hosts. Skipping the live probe (--skip-live-verification) leaves package manifests metadata-only and downgrades remote tool-description pinning to a remote_probe_skipped warning rather than a blocker. A successful live probe earns tool-description-pinned and tool-manifest-pinned.

Attestation metadata read from _meta (dev.toolpin/attestations) is surfaced in the report and each entry emits a <type>-declared badge; a manifest already pinned in _meta (dev.toolpin/capabilities) earns capability-pinned.

Advisory tool-description scan

The server's own registry name/description is always scanned, and when the live probe succeeds each returned tool name/description is scanned too. Findings are severity info or warning only — they never fail verification on their own — and are recorded in toolDescriptionScan.findings (mirrored as info/warning trust issues):

  • agent_instruction_override, agent_hidden_behavior, agent_forced_tool_order — agent-directed phrasing in descriptions;
  • hidden_control_characters — hidden, control, or bidirectional formatting characters;
  • duplicate_tool_name — a tool name appears more than once in the tools/list response;
  • cross_tool_instruction — a description instructs the agent to call a sibling tool.

These are advisory human-review signals, not prompt-injection detection, not a sandbox, and not an install blocker.