@ledgerproof/mcp-server
Provides tools for issuing and verifying EU AI Act Article 50 transparency receipts, with daily Merkle roots anchored to the Bitcoin blockchain for immutability.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@@ledgerproof/mcp-serverissue a receipt for the AI-generated blog post"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
@ledgerproof/mcp-server
A Model Context Protocol server that lets any
MCP client (Claude Desktop, Claude Code, IDEs, agents) issue and verify
EU AI Act Article 50 transparency receipts through
@ledgerproof/sdk.
LedgerProof implements the IETF SCITT architecture drafts
(draft-ietf-scitt-architecture-22) with COSE Receipts
(draft-ietf-cose-merkle-tree-proofs-18), and additionally anchors a daily
Merkle root to Bitcoin (OP_RETURN). It is an early implementation of live
IETF Internet-Drafts — not an RFC, not a standard, not certified, not "SCITT
compliant." That precision is deliberate; please keep it in any derived copy.
Issuing a receipt is a real, deliberate action: each receipt's daily Merkle root is anchored to Bitcoin, which costs a Bitcoin transaction fee. Do not wire agents to auto-issue on loose triggers. The bundled
ledgerproof_when_to_issueprompt spells out when issuance is (and isn't) appropriate.
Transports
This server speaks the two current MCP transports. The deprecated HTTP+SSE transport is intentionally not used.
stdio (default) — for local clients that launch the server as a subprocess.
Streamable HTTP (
StreamableHTTPServerTransport) — for networked clients. In this modeledgerproof_issue_receiptrequiresprecomputed_sha256and rejects raw payloads, so artifact bytes never cross the network.
Related MCP server: @humanaccepted/mcp
Tools
Tool | Purpose |
| Produce an Article-50 record for AI-generated content and register it. Exactly one of |
| Verify by |
| Poll a |
| SHA-256 a |
Prompt
ledgerproof_when_to_issue— scoped guidance: issue only when deliberately "producing an Article-50 transparency record for AI-generated content," and a reminder that anchoring costs a Bitcoin tx fee, so do not auto-fire on loose triggers.
Honest behavior notes / gaps
Anchoring is asynchronous. Issuance always returns
anchor_status: "pending". The server never reports a fabricated "anchored" status —ledgerproof_check_anchorreportsanchoredonly when the API returns a real Bitcointxid. Poll until then.Raw payloads stay local even on stdio. The SDK hashes the artifact locally and only the
artifact_hash(never the bytes) is sent to the LedgerProof API. Streamable HTTP additionally keeps the bytes off the MCP hop by requiringprecomputed_sha256.SCITT verification is guarded.
verifyTransparentStatementlives in the SDK'sscitt/module, which is being built in parallel and may not be exported yet. If it's absent,ledgerproof_verify_receipt(Transparent Statement mode) returns a clear "not available in the installed SDK" error instead of failing the build. Sequence-mode verification works today.precomputed_sha256issuance depends on an SDK feature. The basepublishAiArticle50always hashes raw bytes and exposes no precomputed-hash entrypoint. The server passes the hash through optimistically (forward-compat); if the installed SDK can't accept it, the tool returns a precise error rather than registering a record with the wrongartifact_hash. Until the SDK adds a precomputed-hash publish path, issue from rawartifactover stdio.
Configuration (environment variables)
Variable | Required | Default | Notes |
| yes | — | Legal-entity id (LEI/EUID/VAT/DID). Not an email. |
| yes | — | ISO country code, e.g. |
| yes | — | LedgerProof API key. |
| no |
| API base URL ( |
| no | ephemeral | Ed25519 signing seed (hex). Never logged. |
| no | — | Path to a file containing the hex seed (alt to |
| no |
| Key id registered with the service. |
HTTP-only (optional): PORT/LEDGERPROOF_MCP_PORT (default 3000),
LEDGERPROOF_MCP_HOST (default 127.0.0.1),
LEDGERPROOF_MCP_TRANSPORT=http (same as --http).
The Ed25519 signing key is never logged, never returned by any tool, and never serialized. Only its presence (
providedvsephemeral) is printed at boot.
Install / build
npm install
npm run build # tsc → dist/
npm run lint # tsc --noEmitRun
# stdio (default)
npx @ledgerproof/mcp-server
# Streamable HTTP on http://127.0.0.1:3000/mcp
npx @ledgerproof/mcp-server --http --port 3000MCP client config
stdio
{
"mcpServers": {
"ledgerproof": {
"command": "npx",
"args": ["-y", "@ledgerproof/mcp-server"],
"env": {
"LEDGERPROOF_PUBLISHER_ID": "LEI:5493001KJTIIGC8Y1R12",
"LEDGERPROOF_DEPLOYER_COUNTRY": "DE",
"LEDGERPROOF_API_KEY": "sk_live_...",
"LEDGERPROOF_API_BASE": "https://api-eu.ledgerproofhq.io",
"LEDGERPROOF_SIGNING_KEY_HEX": "<32-byte-hex-ed25519-seed>",
"LEDGERPROOF_KEY_ID": "default"
}
}
}
}Streamable HTTP
Start the server (npx @ledgerproof/mcp-server --http --port 3000), then point
the client at the URL:
{
"mcpServers": {
"ledgerproof": {
"type": "streamable-http",
"url": "http://127.0.0.1:3000/mcp"
}
}
}Over Streamable HTTP, call ledgerproof_hash_artifact first and pass the result
to ledgerproof_issue_receipt as precomputed_sha256 — raw payloads are
rejected on this transport by design.
License
Apache-2.0
Available Tools
4 toolsledgerproof_check_anchorCheck Bitcoin anchor statusARead-onlyIdempotent
Check whether a receipt's daily Merkle root has been anchored to Bitcoin yet. Returns anchor_status ('pending' or 'anchored') and, when anchored, the Bitcoin txid, block height/hash, and Merkle inclusion proof. Agents should poll this with the receipt's sequence after issuance until anchor_status becomes 'anchored' (the anchor is batched daily, so this can take time).
| Name | Required | Description | Default |
|---|---|---|---|
| sequence | Yes | Sequence number returned by ledgerproof_issue_receipt. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate idempotent and read-only behavior. The description adds important behavioral context: returns anchor_status, txid, block info, and proof when anchored; notes that anchoring is batched daily so polling may take time. No contradictions.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, well-structured. The first sentence states the core purpose, the second lists return fields, and the third provides usage guidance. No unnecessary words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple check tool with one input and no output schema, the description covers input, output fields, and polling behavior. It explains what to expect and gives temporal context (daily batching). Complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema has 100% description coverage for the single parameter 'sequence', explaining it is returned by ledgerproof_issue_receipt. The description mentions 'receipt's sequence' but adds no new semantics beyond referencing the same concept.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: checking whether a receipt's daily Merkle root is anchored to Bitcoin. It uses specific verbs ('check') and identifies the resource ('anchor status of receipt'). Distinguishes from sibling tools by focusing on the check operation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit guidance on when to use the tool: after issuance, and recommends polling until status changes. Mentions daily batching, implying patience. Does not explicitly list when not to use or alternative tools, but the context is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ledgerproof_hash_artifactHash an artifact (SHA-256)ARead-onlyIdempotent
Compute the SHA-256 (hex) of a payload using the SDK's hashing. PRIVACY: use this to obtain a precomputed hash so raw payloads never leave the machine — then pass the hash to ledgerproof_issue_receipt as precomputed_sha256. Over Streamable HTTP, issue_receipt REQUIRES precomputed_sha256 and rejects raw payloads, so hash locally first.
| Name | Required | Description | Default |
|---|---|---|---|
| payload | Yes | The content to hash (UTF-8 text). Returned only as a hash. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds context beyond annotations: local operation, privacy benefit, and that hash is returned instead of raw payload.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three concise sentences front-loading the core function, then usage and context with no wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Complete for a simple hashing tool: explains purpose, privacy, integration requirement, and the single parameter is fully documented.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema already describes payload parameter well; description adds that hash is SHA-256 hex and its integration with issue_receipt, providing extra value.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it computes SHA-256 hash of a payload, distinguishing it from sibling tools that handle receipts and anchors.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly describes when to use (to obtain precomputed hash for ledgerproof_issue_receipt) and why it's required over Streamable HTTP.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ledgerproof_issue_receiptIssue an Article-50 transparency receiptA
Produce an EU AI Act Article 50 transparency record for a piece of AI-generated content and register it with LedgerProof. Provide EXACTLY ONE of artifact (the raw content; hashed locally, never uploaded) or precomputed_sha256 (a SHA-256 hex you computed yourself), plus the AI-system and deployer metadata. Mirrors the SDK's publishAiArticle50. Returns {sequence, entry_hash, verify_url, anchor_status}. anchor_status is ALWAYS 'pending' on issuance because Bitcoin anchoring is asynchronous (a daily Merkle root is written to an OP_RETURN, which costs a Bitcoin tx fee) — poll ledgerproof_check_anchor until it becomes 'anchored'. Do not issue on loose triggers.
| Name | Required | Description | Default |
|---|---|---|---|
| artifact | No | Raw AI-generated content (text). Hashed locally with SHA-256; the bytes are never sent to the LedgerProof API. Mutually exclusive with precomputed_sha256. Rejected over Streamable HTTP. | |
| precomputed_sha256 | No | SHA-256 (hex) of the artifact, computed by the caller (e.g. via ledgerproof_hash_artifact). Keeps raw payloads off the wire. Mutually exclusive with artifact. Required over Streamable HTTP. | |
| artifact_content_type | No | MIME type of the artifact, e.g. text/plain, image/png. | text/plain |
| artifact_bytes | No | Byte length of the artifact. Used with precomputed_sha256 since the raw bytes are unavailable to the server. | |
| aiSystemId | Yes | Identifier of the AI system, e.g. 'openai/gpt-4o'. | |
| deployerName | Yes | Legal name of the deployer organization (not an email/person). | |
| contentCategory | Yes | Article-50 content category. | |
| aiSystemVersion | No | Version of the AI system, if known. | |
| supervisoryAuthority | No | Relevant supervisory authority, if applicable. | |
| generationType | No | How the content was produced. | |
| sourceContentHash | No | SHA-256 of source content for manipulated/assisted media. | |
| perceptualHash | No | Perceptual hash (algorithm, value, bits) for media. | |
| transparencyMarker | No | Transparency marker label (defaults to LPR-EU-AI-ACT-50). | |
| isPublicInterest | No | Whether the content is in the public interest. | |
| enforcementDate | No | Article-50 enforcement date (defaults to 2026-08-02). | |
| profileVersion | No | LPR profile version (defaults to EU-AI-ACT-50-v1.1). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description discloses critical behavioral traits beyond annotations: the anchor_status is always 'pending' first due to asynchronous Bitcoin anchoring, and it instructs users to poll ledgerproof_check_anchor. It also notes that the artifact is hashed locally and never uploaded. There is no contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single paragraph of six sentences, front-loaded with the core action. Every sentence provides essential information (purpose, parameter rules, async behavior, caution). No redundant or extraneous content.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given 16 parameters, 3 required, no output schema, the description covers the return fields (sequence, entry_hash, verify_url, anchor_status) and explains the asynchronous nature. It references the SDK and provides guidance on polling. This is sufficient for the complexity of the tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so baseline is 3. The description adds meaning beyond schema by explaining the mutual exclusivity of artifact and precomputed_sha256, the context for artifact_bytes, and the difference in usage over Streamable HTTP. These clarifications elevate the score.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states that the tool produces an EU AI Act Article 50 transparency record and registers it with LedgerProof. It uses specific verbs ('Produce... and register') and distinguishes itself from siblings like ledgerproof_check_anchor and ledgerproof_verify_receipt by focusing on issuance.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explains when to use the tool (issuing a receipt) and provides conditional guidance such as 'Provide EXACTLY ONE of artifact or precomputed_sha256' and 'Required over Streamable HTTP'. It also cautions 'Do not issue on loose triggers.' However, it does not explicitly state when not to use this tool versus alternatives, though the sibling tools are distinct enough.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ledgerproof_verify_receiptVerify a transparency receiptARead-only
Verify a LedgerProof receipt. Provide EITHER {sequence} (looks up the chain entry from the public verifier) OR {transparent_statement} (a SCITT Transparent Statement bundle, verified with the trust-minimized §7 algorithm: issuer COSE_Sign1 signature, RFC 9162 inclusion proof, Transparency-Service receipt signature, and an independent Bitcoin OP_RETURN check). For a Transparent Statement, returns {issuerSignatureValid, inclusionProofValid, receiptSignatureValid, bitcoinConfirmed, valid, recomputedRoot}. The Transparency-Service PUBLIC key (for the receipt signature) is loaded from LEDGERPROOF_TS_PUBLIC_KEY_HEX or fetched from {apiBase}/v1/scitt/ts-key; the Bitcoin txid is taken from the statement wrapper, the txid arg, or a /v1/scitt anchor lookup. SCITT verification requires the SDK's scitt module to be present in the installed build.
| Name | Required | Description | Default |
|---|---|---|---|
| sequence | No | Sequence number of a receipt to verify via the API. | |
| transparent_statement | No | A SCITT Transparent Statement (COSE_Sign1 with attached COSE Receipts) in SERIALIZED form: a base64/base64url or hex string, or a wrapper object { transparent_statement: <string>, txid? }. Verified locally (a fully decoded COSE object is not accepted). | |
| txid | No | Bitcoin transaction id holding the daily-root OP_RETURN, if known. Used for the §7 step-5 witness when not embedded in the statement. | |
| issuer_public_key_hex | No | Issuer (publisher) Ed25519 PUBLIC key as 64 hex chars, to verify the Signed Statement signature (step 1). If omitted, the issuer key embedded/kid-resolved in the statement is used if available. | |
| bitcoin_check | No | For a Transparent Statement, also confirm the daily root in a Bitcoin OP_RETURN via a public source. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description discloses detailed behavioral traits beyond annotations: the §7 algorithm steps, key loading from environment or API, optional Bitcoin check, and dependency on the SDK's scitt module. Annotations indicate readOnlyHint and openWorldHint, and the description adds substantial context without contradiction.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is verbose but well-structured: it opens with the core purpose, then explains modes, return values, and key loading. Every sentence adds value, but some details (e.g., 'SCITT verification requires the SDK's scitt module') could be more concise. Still, it is effective and not wasteful.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the complexity (5 parameters, no output schema, multi-mode behavior), the description is remarkably complete. It explains return fields for transparent_statement, key resolution, optional parameters (txid, issuer_public_key_hex), and dependencies, leaving little ambiguity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Every parameter has a detailed description in the input schema, and the tool description adds further context (e.g., 'looks up the chain entry from the public verifier' for sequence, 'base64/base64url or hex string' for transparent_statement). Schema coverage is 100%, and the description enriches understanding.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: 'Verify a LedgerProof receipt.' It distinguishes between two operational modes (sequence vs transparent_statement) and explains what each does. It is distinct from sibling tools (check_anchor, hash_artifact, issue_receipt) by focusing on verification.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit guidance on when to use each mode: provide sequence for API-based chain entry lookup, or transparent_statement for local verification with the §7 algorithm. It does not explicitly exclude alternatives but gives enough context for an agent to decide.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
4 tool updates
v0.1.1- First observed
ledgerproof_check_anchor - First observed
ledgerproof_hash_artifact - First observed
ledgerproof_issue_receipt - First observed
ledgerproof_verify_receipt
TDQS
Scored across 4 tools
Each tool has a clearly distinct purpose: hashing content, issuing a receipt, checking Bitcoin anchoring, and verifying a receipt. There is no overlap in functionality.
All tool names follow the consistent pattern 'ledgerproof_verb_noun' using snake_case. Verbs and nouns are clear and match the tool's action (hash_artifact, issue_receipt, check_anchor, verify_receipt).
Four tools is well-scoped for the domain of managing AI-generated content receipts. Each tool covers a necessary step in the workflow without unnecessary extras.
The tool set covers the full lifecycle: hash content (hash_artifact), issue receipt (issue_receipt), check anchoring status (check_anchor), and verify receipt (verify_receipt). No obvious gaps for the intended purpose.
Maintenance
Related MCP Connectors
Agent Content Watermark MCP — dedicated EU AI Act Article 50(2) GenAI watermarking. Visible +
AI governance MCP server for EU AI Act compliance and jurisdiction verification
Deterministic AI liability attribution with Bitcoin-anchored proof certificates.
Prove you made it first. Blockchain Timestamp creative work via Claude or any MCP-enabled AI Agent.
1
Related MCP Servers
- AlicenseAqualityDmaintenanceDocument verification MCP server enabling AI agents to verify file authenticity by computing SHA-256 fingerprints locally and checking Bitcoin-anchored proofs via OpenTimestamps.55 npmMIT
- FlicenseAqualityCmaintenanceMCP server that auto-emits tamper-evident receipts for every tool call, enabling EU AI Act Article 12 compliance with signed, chain-linked receipts.1-
- AlicenseAqualityDmaintenanceEnables AI agents to certify their creations with verifiable, timestamped proof anchored to Bitcoin, and to verify certificates.3MIT
- AlicenseNot gradedqualityDmaintenanceEnables EU AI Act Article 50(2) compliant watermarking of AI-generated content using C2PA manifest envelopes.MIT