C2PA Content Credentials MCP server for EU AI Act Article 50 compliance.
Project description
c2pa-watermark-mcp
C2PA Content Credentials MCP server — embed and verify machine-readable provenance for AI-generated assets, ahead of the EU AI Act Article 50 deadline (2 December 2026).
Why this exists
EU AI Act Article 50 (Regulation (EU) 2024/1689) requires that AI-generated
content be machine-readable + detectable as AI-generated. The
c2pa.ai_generated assertion is the C2PA spec's mandated way to do that.
The deadline is 2 December 2026 — about 6 months out. Companies that ship user-facing generative tools without C2PA support face fines up to €35M or 7% of global turnover.
This MCP wraps the official c2pa-python
SDK (≥0.9.0) as an MCP server so agents can attach C2PA manifests at
generation time and verify provenance at runtime. A pure-stdlib HMAC
fallback is included for environments where c2pa-python's native deps
won't install (Vercel serverless, CI sandboxes, etc.).
Features
- 3 MCP tools —
sign_asset,verify_asset,status - EU AI Act Article 50 ready — auto-injects
c2pa.ai_generatedassertion - Pure-stdlib fallback — works without c2pa-python's native deps
- HMAC-SHA256 signatures — tamper-evident manifests
- Optional X.509 chain — via
c2pa-python[evm]extra - Vercel-deployable — see
c2pa-watermark-vercelsibling repo
Tools
| Tool | Purpose | Tier |
|---|---|---|
sign_asset |
Embed a C2PA manifest into an asset, HMAC-signed | Pro |
verify_asset |
Verify a manifest against its asset bytes | Free |
status |
Report server health + native SDK availability | Free |
install
# Core (HMAC fallback, no native deps)
pip install c2pa-watermark-mcp
# With full c2pa-python (X.509 chain)
pip install 'c2pa-watermark-mcp[c2pa]'
# For local development
git clone https://github.com/CSOAI-ORG/c2pa-watermark-mcp
cd c2pa-watermark-mcp
pip install -e .[dev]
usage
Sign an asset (Pro tier)
from c2pa_watermark_mcp import sign_asset, verify_asset, status
# Server health
print(status())
# → {'server': 'c2pa-watermark-mcp', 'c2pa_python_available': False, ...}
# Sign an asset
with open("output.png", "rb") as f:
asset = f.read()
key = b"my-hmac-key-32-bytes-long-aaaaaa"
result = sign_asset(
asset_bytes=asset,
asset_mime="image/png",
claim_generator="MEOK-SDXL/1.0",
signing_key=key,
ai_generated=True,
assertions=[
{"label": "c2pa.training", "value": {"model": "sdxl-1.0", "dataset": "internal"}},
],
)
print(result["manifest_id"])
# Verify
verdict = verify_asset(asset, result["manifest"], key)
print(verdict) # {'valid': True, 'reasons': [], ...}
Run as MCP server (stdio)
c2pa-watermark-mcp
# or with full c2pa-python
pip install 'c2pa-watermark-mcp[c2pa]'
c2pa-watermark-mcp
Run via Docker
docker build -t c2pa-watermark-mcp .
docker compose up -d
# status endpoint on http://localhost:8000
Deployment to Vercel
See the companion repo c2pa-watermark-vercel
for a serverless wrapper exposing /sign, /verify, /status routes.
Architecture
┌─────────────────────────────────────────────────────────────┐
│ c2pa-watermark-mcp │
├─────────────────────────────────────────────────────────────┤
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ sign_asset │ │verify_asset │ │ status │ │
│ │ (HMAC + │ │ (HMAC + │ │ (health + │ │
│ │ c2pa.io) │ │ tamper) │ │ capability)│ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │ │ │ │
│ └────────────────┴────────────────┘ │
│ │ │
│ ┌──────┴──────┐ │
│ │ HMAC-SHA256 │ (always available) │
│ │ + c2pa.io │ (if c2pa-python installed)│
│ └──────┬──────┘ │
│ │ │
│ ┌─────────────┐ ┌──────┴──────┐ ┌─────────────┐ │
│ │ manifest │ │ signing │ │ AI-Act │ │
│ │ generator │ │ keys │ │ assertions │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────┘
Why we auto-inject c2pa.ai_generated
The C2PA spec defines this as the standard way to disclose AI-generated content. EU AI Act Article 50 says AI content must be "machine-readable and detectable as AI-generated" — the spec's answer is exactly this assertion. Skipping the auto-inject would be a compliance violation waiting to happen.
FAQ
Q: Does this need c2pa-python? A: No. The pure-stdlib HMAC-SHA256 fallback is fully functional for tamper-evident manifests. Install c2pa-python only if you need the full X.509 chain.
Q: Can I sign an asset that's not a PNG/JPEG?
A: Yes. The asset_mime parameter is just metadata; the HMAC is over
the bytes themselves. Works for video, audio, PDFs, etc.
Q: How do I rotate the signing key?
A: Generate a new key, deploy with both OLD_KEY and NEW_KEY, re-sign
all manifests with NEW_KEY, then drop OLD_KEY after expiry. This
package supports key rotation via the signing_key constructor arg.
Q: Is this production-ready? A: Yes for tamper-evidence (HMAC). For full X.509 C2PA chain + cryptographic non-repudiation, install c2pa-python ≥ 0.9.0.
License
MIT © MEOK AI Labs / CSOAI-ORG
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file c2pa_watermark_mcp-0.1.0.tar.gz.
File metadata
- Download URL: c2pa_watermark_mcp-0.1.0.tar.gz
- Upload date:
- Size: 9.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fbd729e350c37af3babe0c51112ac25e0223f5aeac1f87169871f4b2ac80d61c
|
|
| MD5 |
efe56c7483a154124a2193c248a7bcff
|
|
| BLAKE2b-256 |
043c596b3a97091f71df16d2a026612c479d86bb508614e366eb8432d6f6b378
|
File details
Details for the file c2pa_watermark_mcp-0.1.0-py3-none-any.whl.
File metadata
- Download URL: c2pa_watermark_mcp-0.1.0-py3-none-any.whl
- Upload date:
- Size: 8.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c3007e4d192d49daa925682e91080f5b7841937084a84713b0548b983a5af989
|
|
| MD5 |
c9eb0e8228f5c84949f4db6ad9f24d96
|
|
| BLAKE2b-256 |
0a013483896d64863ef6923c652456da3cdeee73c06422770b93f2151f31e3cd
|