
C2PA in Ableton: Making AI Music Provenance Visible Inside Your DAW
In May 2026 I shipped an MCP for reading C2PA manifests in music. This post is the follow-up: the same reader, now inside Ableton Live as an open-source Max for Live device.
Key takeaways
- Google Lyria signs every generated MP3 with a C2PA manifest, but Ableton has no way to display that information today.
- A Max for Live device + local FastAPI server makes the manifest visible the moment you click a clip.
- All in one repo — Python HTTP server + Max for Live device. One clone, one install, no cloud round-trip.
- Read-side only — the harder problem (signing the DAW project, attributing the training corpus) is next.
In May 2026 I shipped a Claude MCP for reading C2PA manifests in music files. This post is the follow-up: the same reader, now inside Ableton Live as an open-source Max for Live device.
This is the fourth article in my Max for Live series. It builds directly on the M4L → FastAPI pattern I wrote about in January 2026, with one change: the API runs on your laptop, not in the cloud.
The problem
Google Lyria signs every MP3 it generates with a C2PA manifest. The manifest records who made the file, what model produced it, whether it is AI-generated, what watermarks were applied (Lyria adds SynthID), and who signed the claim. The data is there. Producers cannot see it.
You drop a Lyria stem onto an audio track. Ableton shows you the waveform. It does not show you that the file is AI-generated, who signed it, or what the manifest says about the source. To find out, you have to leave the DAW, run c2patool on the file, and read raw JSON.
Andrew Melchior — Massive Attack's CTO, advising the UK DCMS on AI and the Copyright Act — framed the bigger gap in a reply on LinkedIn to my MCP announcement:
C2PA now tells you a machine generated this track. It doesn't tell you whose work trained the machine.
Training-corpus provenance is the hard problem. This article is about the easier half — making the output manifest visible at the point a producer is actually working.
The fix
A Max for Live device. Click a clip → see the manifest summary. That is the whole product.
Under the hood, the device borrows a pattern I already shipped: a Max for Live js object reads the Live Object Model, then routes the work to a Node for Max HTTP client. I wrote about this exact shape in January 2026. The only change here is where the HTTP server lives.
Architecture in one diagram
flowchart TB
subgraph Ableton["Ableton Live"]
device["MTL_C2PA_Ableton_PoC.amxd"]
livepi["LiveAPI observer<br/>(detail_clip)"]
js["c2pa_reader.js"]
node["c2pa_node.js<br/>(Node for Max)"]
ui["UI textedit<br/>summary display"]
device --> livepi --> js --> node --> ui
end
subgraph LocalServer["mtl-c2pa-http (127.0.0.1:8765)"]
fastapi["FastAPI app"]
summary["/summary"]
verify["/verify"]
scan["/scan"]
info["/info"]
fastapi --> summary
fastapi --> verify
fastapi --> scan
fastapi --> info
end
subgraph PythonPkg["mtl_c2pa_server (in this repo)"]
c2pamod["c2pa.py (parser)"]
reader["c2pa-python Reader<br/>(Rust binding)"]
c2pamod --> reader
end
node -->|POST /summary| fastapi
fastapi -->|import| c2pamod
launchd["launchd plist<br/>auto-start on login"]
launchd -.->|spawn| fastapi
Three sentences:
- A LiveAPI observer in the
jsobject watcheslive_set view detail_clip. When the selection changes, it pulls the clip'sfile_path. - The path flows into a Node for Max script, which
POSTs it tohttp://127.0.0.1:8765/summary. - The local FastAPI server is shipped in this same repo as the device — a small Python package (
mtl_c2pa_server) that wraps the officialc2pa-pythonRust binding. One clone, onepoetry install.
Selection-to-display, end to end
sequenceDiagram
actor User
participant Live as Ableton Live
participant Device as M4L Device
participant Reader as c2pa_reader.js
participant Node as c2pa_node.js
participant HTTP as mtl-c2pa-http :8765
participant Lib as c2pa-python
User->>Live: click audio clip
Live->>Device: detail_clip changed
Device->>Reader: observer fires
Reader->>Live: get detail_clip.file_path
Live-->>Reader: /path/to/lyria.mp3
Reader->>Node: outlet "fetch" path
Node->>HTTP: POST /summary {path}
HTTP->>Lib: Reader(mime, stream).json()
Lib-->>HTTP: manifest store
HTTP-->>Node: summary JSON
Node->>Device: outlet "result" json
Device-->>User: display summary
The manual "Refresh" button short-circuits the observer and triggers the same POST /summary call. Same pipeline, different trigger source.
Why local, not cloud, not CLI
I considered three options. Local won.
Simplest, but Python startup costs ~300 ms. On every clip selection. You feel it.
Right for generation, wrong for reading. You'd upload audio just to inspect a local file.
Keeps c2pa-python warm. Loopback only. Reuses the MCP parser without changes.
c2pa-python directly. Self-contained in this repo — one clone, one install, no separate dependency on the sibling MCP server.A persistent local FastAPI server keeps c2pa-python warm in memory, runs on loopback only (no external attack surface), and reuses the existing MCP parser without changes.
What you see
For a Lyria-signed MP3, the device shows the same shape the MCP produces:
{
"file": "/Users/you/Music/Sovereign_Ascent.mp3",
"generator": {"name": "Google C2PA Core Generator Library"},
"is_ai_generated": true,
"actions": [
{"action": "c2pa.created", "description": "Created by Google Generative AI."},
{"action": "c2pa.edited", "description": "Applied imperceptible SynthID watermark."}
],
"watermarks": [
{"description": "Applied imperceptible SynthID watermark."}
],
"signature_issuer": "Google LLC",
"validation": "valid"
}
For an unsigned audio clip you get {"error": "No C2PA manifest found"}. For a MIDI clip, {"info": "MIDI clip — no C2PA manifest applicable"}. The Refresh button re-runs the lookup manually.
What this doesn't solve
This is read-side only. The device tells you the C2PA truth that is already in the file. It does not sign anything. It does not tell you what corpus trained the model. Andrew's point still stands.
The C2PA community is working on the harder problem. There is an active conversation in the C2PA group about capturing provenance during DAW work — signing the project at bounce time, attributing the samples and MIDI sources that went in. That is the generation side. I would like to help build it next.
Install and try it
You need Ableton Live with Max for Live (Live Suite, or Standard plus the M4L add-on), and macOS for the auto-start script.
# 1. Clone and install (one-time)
git clone https://github.com/musictechlab/mtl-c2pa-ableton.git
cd mtl-c2pa-ableton && poetry install
# 2. Auto-start on login (macOS)
bash install/install.sh
# 3. Verify
curl http://127.0.0.1:8765/health
# {"status":"ok"}
# 4. Drop the device on a track
# Drag device/MTL_C2PA_Ableton_PoC.amxd onto any audio track in Live.
That's it. Click a Lyria clip — see the manifest. Full setup detail in the repo README.
Roadmap
Generation-side device next. The plan is a Max for Live effect that signs the project at bounce time and emits a C2PA manifest describing the session's ingredients — samples, MIDI sources, plugin chain. I would like input from the C2PA community before settling on the assertion shape.
If you are interested in the broader open-source MCP family I have shipped:
Read and write ID3, FLAC, and Vorbis tags from Claude — siblings on the metadata layer.
Complementary provenance: VHC says a human made this; C2PA says how it was made.
Natural-language queries over Bandcamp revenue CSVs from Claude.
Adjacent metadata extraction — going below the LiveAPI layer.
Try it, break it, send feedback
The device is MIT-licensed. Repo: musictechlab/mtl-c2pa-ableton. Issues and PRs welcome. If you build something on top of the local HTTP server (a Logic plugin, a REAPER script, a standalone viewer), tell me — same pattern works for any DAW that can shell out to localhost.
Need help integrating C2PA into your music workflow?
Adding provenance to your distribution pipeline, AI music platform, DAW plugin, or rights workflow? I have been there.
drop me a line — no sales pitch, just honest engineering advice.
FAQ
Why a local HTTP server instead of a CLI shell-out or a cloud API?
Python startup takes about 300 ms, which you feel on every clip click. A persistent local server keeps c2pa-python warm in memory. Cloud would mean uploading audio to a server just to inspect a file the user already has on disk — wrong shape for reading, right shape for generation.
Does the device work without the Max for Live add-on?
No. You need Ableton Live Suite (which includes Max for Live), or Ableton Live Standard with the Max for Live add-on. The device is a .amxd file — it cannot run as a stock VST or AU plugin.
Does the device upload my audio anywhere?
No. The FastAPI server binds to 127.0.0.1 only — loopback. No external network access. The Node for Max HTTP client only ever talks to your own machine. You can verify with lsof -i :8765 while the server runs.
What happens with MIDI clips or recorded audio that has no source file?
The device returns a structured info message: MIDI clip — no C2PA manifest applicable, or audio clip has no file path (recorded in session?). It never crashes the device, never blocks Live.
Will this device tell me whose work trained the model that generated my Lyria stem?
No, and that is the next problem the C2PA community is working on. This device surfaces the output manifest — what Google Lyria declared about the file. Training-corpus attribution requires upstream provenance on the training data itself, which almost no major dataset is C2PA-signed today.
Building a YouTube Video Research Pipeline with Whisper and Claude
How I built a CLI tool that downloads YouTube videos, transcribes them with Whisper, and generates structured market intelligence using Claude — all with one command.
C2PA in Music: A Claude MCP for Reading Content Provenance
C2PA is the open standard for content provenance, and it just landed in music files. I open-sourced an MCP server so you can read these manifests inside Claude Code.