Provides a standardized audit trail for AI-assisted research workflows by recording tool calls, decisions, and actor attribution.
Also known as Thru-Echoes/TRACE
- Stars
- 26
- Tools
- 17
- Downloads, 30 days
- —
- Latest version
- —
- Last commit
- Nov 14, 2026
- License
- Apache-2.0
What is TRACE MCP?
TRACE provides a standardized audit trail for AI-assisted research workflows by recording tool calls, decisions, and actor attribution. It exposes 17 tools, such as trace_start_session, trace_end_session, trace_log_tool_call.
Summary generated from the project's README
About TRACE MCP server
Researchers and developers who need to document the reasoning behind AI-assisted decisions can use TRACE to create a standardized audit trail. Unlike standard observability tools that only track tool calls, this server records the provenance of decisions, including who proposed a step, whether a human accepted or rejected it, and the rationale behind the choice. It functions as a sidecar to your existing domain MCP servers, meaning the AI client explicitly logs events to TRACE rather than the server intercepting traffic.
Users can manage sessions through an MCP-aware client like Claude Code or Cursor. The server stores data in human-readable, git-diffable JSON files located in a local directory. It supports advanced features like decision confidence measurements and canonical project identity to prevent data merging errors. Because it records rejected alternatives and corrections as first-class events, it provides a complete history of how a workflow evolved, making it suitable for regulated environments requiring strict decision-process documentation.
What you can do with it
- 1Documenting decision provenanceA developer can record whether an AI-proposed methodological change was accepted, revised, or rejected by a human.
- 2Tracking collaborative contributionsUsers can distinguish between ideas that were human-directed with AI execution versus those that were purely AI-directed.
- 3Maintaining research audit trailsResearchers can use the server to ensure their AI-assisted workflows meet regulatory requirements for decision-process documentation.
Written from the project's README. Every use case is checked against a quote from it.
TRACE MCP tools 17
Detected from the READMEtrace_start_sessiontrace_end_sessiontrace_log_tool_calltrace_log_annotationtrace_log_contributiontrace_log_state_changetrace_propose_decisiontrace_resolve_decisiontrace_get_sessiontrace_get_eventstrace_get_decisionstrace_get_decision_chain
| trace_start_session | — | |
| trace_end_session | — | |
| trace_log_tool_call | — | |
| trace_log_annotation | — | |
| trace_log_contribution | — | |
| trace_log_state_change | — | |
| trace_propose_decision | — | |
| trace_resolve_decision | — | |
| trace_get_session | — | |
| trace_get_events | — | |
| trace_get_decisions | — | |
| trace_get_decision_chain | — |
Show all 17 toolsShow fewer tools
trace_searchtrace_exporttrace_list_sessionstrace_project_summarytrace_health_check
| trace_search | — | |
| trace_export | — | |
| trace_list_sessions | — | |
| trace_project_summary | — | |
| trace_health_check | — |
Configuration
TRACE_FLEET_ROOTSTRACE_PROJECT
| Name | Description | |
|---|---|---|
| TRACE_FLEET_ROOTS | — | |
| TRACE_PROJECT | — |
Automated checks
Ran Nov 13, 2026Full report →Passed our automated checks. That is not a security audit: read the code and give the server the narrowest access it needs. How checks work
- Source repository linked and reachablePass
- Open source license (OSI)Pass
- Commit or release in the last yearPass
- Package name not close to a popular packageNot checked
- Remote endpoint uses HTTPSNot checked
- Destructive tools are labelledPass
- No hidden instructions to the modelPass
- No critical advisory in the package or its dependenciesNot checked
README
View on GitHubWhy TRACE?
In the age of AI, how do we know who proposed what in a scientific or coding dev workflow? Was the idea for that methodological decision made by AI or by a human? And when decisions are proposed by AI, are they being accepted, rejected, or iterated on?
What does the solution to this look like?
Every row above is a real event from session trace_20260730_32c108, captured as
the work happened. Note what a diff could not have told you: one decision is
still awaiting resolution because the AI is not permitted to resolve its own
proposal, and the last event retracts an earlier contribution that turned out
to be wrong. Regenerate it from any session with
python3 scripts/make_provenance_animation.py <session.json>.
One sentence from you, fully-scoped session from Claude:
- From inside
TRACE/, ask Claude to start a session and review the manuscript (which is inside sibling dir,TRACE-research/). - Past-session memory makes Claude pivot to that sibling repo before logging anything.
trace_start_sessionruns there, learnings auto-recall, and a five-item task plan emerges.
TRACE: Transparent Recording of AI-assisted Collaboration Experiments
TRACE is an MCP server that provides a standardized audit trail for AI-assisted research workflows. It records tool calls, decisions, annotations, contributions, and actor attribution — who proposed what, who accepted or revised it, and why.
TRACE runs as a sidecar alongside your domain MCP servers. It doesn't proxy or intercept calls — the AI client explicitly logs events to TRACE, creating a complete, human-readable provenance record.
New here? docs/ONBOARDING.md is the map for a developer or a user — the mental model, the attribution rules, project identity, hooked-vs-bare projects, and the dev workflow. docs/WHAT-IS-TRACE.md explains the same thing without assuming a technical background.
Version: 0.5.2.dev0 (unreleased; latest release v0.5.1) | Spec: v0.5.2 | Schema: https://trace-protocol.org/v0.3 | License: Apache 2.0
The schema URI is an identifier (per W3C PROV convention) and is not currently a resolvable URL. The machine-readable JSON Schema lives at
schemas/trace-v0.5.jsonin this repository.
New in 0.5.1 — decision confidence. Additive; every earlier session loads unchanged. A decision may now carry the measurement that motivated it as a typed confidence object — the estimate, an interval and its nominal coverage, the method, the sample size, and digest-bound evidence references — checked on construction, in the published schema, and by trace-mcp validate. It types the measurement only: a producer's own decision rule is preserved beside it under a contract key and never interpreted, because encoding one producer's rule in a generic protocol would refuse every producer with a different one. The release also adds a Streamable HTTP transport, an importer for Gents run timelines, and trace-mcp doctor / fleet-check, which check a deployment rather than the source tree.
New in 0.5.0 — canonical project identity. Additive; every v0.3.x and v0.4.x session loads unchanged. A project is identified by a stable canonical key rather than a free-text label, so case and separator variants of one name stop reading as separate projects, and two genuinely different projects can no longer be merged by a case-insensitive filesystem. A TRACE_PROJECT pin binds one server process to one project, and cross-project reads and writes fail closed. No capture record is ever rewritten — a mislabelled project is repaired by adding an alias.
See CHANGELOG.md for the full entry and for 0.4.x, which added the Proposer Identity Rule, the discovery annotation category, URI-form corrections, and host / parent_event_id on tool calls. Design rationale lives in the ADRs; worked examples in docs/examples.md.
Why decision provenance?
Existing AI observability stacks (LangSmith, Langfuse, OpenTelemetry GenAI semconv) capture call-level traces — what tool an agent called, with what inputs, and what came back. They do not capture decision-level provenance — who proposed each step, whether a human reviewed it, what alternatives were rejected. The cost is visible in practice: in a preliminary rubric audit of agentic-AI deployments in environmental science, analytical decision provenance scored markedly lower than basic workflow description, and several recently-published papers showed discrepancies such as model details that did not match the cited models, or analyses that could not be reproduced from the reported description.
The need is also moving from norm to regulation. The EU AI Act (Articles 12, 19; high-risk obligations deferred by the Digital Omnibus, in force July 2026, to December 2, 2027 for Annex III systems and August 2, 2028 for Annex I products), California SB 942 (Transparency AI Act) (applicable August 2, 2026), Colorado SB 24-205 (effective June 30, 2026), the FDA PCCP final guidance (December 2024), the NIST AI Risk Management Framework, and ISO/IEC 42001:2023 all require some form of decision-process documentation. TRACE is designed so that documentation is a workflow byproduct, not an after-the-fact compilation.
Core concept: the decision chain
Every TRACE decision carries an actor (who proposed, who resolved), a disposition (proposed → accepted / revised / rejected), a rationale, a suggestion_type (proactive / requested / collaborative), and an optional revises_event_id linking to a prior decision. Decisions form a provenance DAG, not a flat log — a future reader can reconstruct who proposed what, why it landed where it did, and how the approach evolved during the session.
Three events from a real corp-sus-report-extractor session: a human-proposed scope decision (evt_002, accepted), an AI-proposed alternative kept for provenance after rejection (evt_003), and a correction annotation linked to the rejection via corrects_event_ids (evt_004). Rejected alternatives and corrections are first-class events — they don't get discarded.
Preliminary deployment results
Between 2026-03-18 and 2026-07-30, TRACE was used across 7 sustained research and development projects:
| Project | Domain | Sessions | Decisions | Contributions | Corrections |
|---|---|---|---|---|---|
| trace-mcp (self-host / meta) | Protocol research | 89 | 132 | 206 | 26 |
| corp-sus-report-extractor | Corporate sustainability disclosure | 54 | 91 | 132 | 18 |
| REAP | Environmental discourse analysis | 38 | 65 | 112 | 18 |
| When-Algorithms-Meet-Artists | Computational art / cultural studies | 31 | 56 | 95 | 5 |
| trace-research | Manuscript / literature synthesis | 30 | 48 | 76 | 18 |
| waggle | Applied agentic tooling | 24 | 31 | 76 | 6 |
| green-narrative | Environmental narrative analysis | 23 | 38 | 40 | 8 |
| Total | 289 | 461 | 737 | 99 |
Decisions: 68% AI-proposed / 32% human-proposed. Of the 344 resolved decisions, 89% accepted, 7% revised, 4% rejected; a further 117 remain in the proposed state, because an AI may not resolve its own proposal and not every proposal gets answered. The acceptance rate is not rubber-stamping — the 23 revisions, 15 rejections, and 99 separately-logged corrections are the active human steering this protocol exists to surface, and each one is an alternative that a commit history would have discarded.
Contributions: 68% human-directed, 24% collaborative, 8% AI-directed; 65% are human-directed and AI-executed. Pure AI-directed-and-executed work is a small minority. The dominant pattern is human direction with AI execution — which existing authorship and attribution norms cannot describe.
What these counts include. Figures were taken on 2026-07-30 from per-session logs in
~/.trace/sessions/, which are not committed here (they contain project-internal content), and cover the seven named projects only. The store also holds meeting-transcription namespaces, throwaway test keys, and short exploratory sessions; those are excluded, since a transcript namespace accumulates thousands of machine-written annotation events and no decisions, and counting them would inflate a raw event total by more than an order of magnitude without adding a single act of provenance. Counts here are the deliberately logged event types. Sessions recorded before v0.5 under the display labelTRACEare counted undertrace-mcp, which is the same project under its canonical key. Reproducible from those logs viatrace_project_summary; an aggregated, de-identified export can be provided on request.
Architecture
AI Client (any MCP-aware client: Claude Code, Cursor, ChatGPT, Codex, ...)
|
+-- connects to: Domain MCP Server(s)
| (corpus search, NLP pipeline, data retrieval, etc.)
| --> does the actual work
|
+-- connects to: TRACE MCP Server (this project)
--> records what happened to JSON files
--> persists learnings across sessions (trace-learn)
Storage model: One self-contained JSON file per session in ~/.trace/sessions/. Files are human-readable (pretty-printed with indent=2), git-diffable, and shareable.
Core stack: Python 3.11+, Pydantic v2, async throughout, zero external dependencies beyond mcp and pydantic (OpenAI optional for LLM-enhanced features).
Quick Start
⚠️ TRACE is not on PyPI. The PyPI package named
trace-mcpis an unrelated project —pip install trace-mcpinstalls someone else's code. Install from a clone of this repository (below), or pointuvx --fromat a local checkout or a pinned VCS source:uvx --from 'git+https://github.com/Thru-Echoes/TRACE.git@v0.5.1' trace-mcp
Install
uv pip install -e ".[dev]"
Configure your MCP client
Add to your project's .mcp.json:
{
"mcpServers": {
"trace": {
"command": "uvx",
"args": [
"--from", "/path/to/TRACE",
"--with", "openai", "--with", "numpy", "--with", "fastembed",
"--refresh-package", "trace-mcp", "trace-mcp"
],
"env": { "TRACE_PROJECT": "your-project-key" }
}
}
}
Using uvx builds the package into an isolated environment, avoiding .venv breakage from Python upgrades. --refresh-package rebuilds TRACE from the source tree on the next server start, without re-resolving the whole dependency set each time.
Two parts of that config are easy to omit and worth keeping:
- The three
--withpackages enable the five trace-learn tools. Without them the server still starts and records provenance, but trace-learn does not load. The dependency-free Jev advisory tool still registers, disabled until explicitly configured. TRACE_PROJECTpins the process to one project. With it set you omitprojectfromtrace_start_session, and cross-project reads and writes fail closed. Without it, passproject="..."explicitly on every session start — an unpinned server rejects the call rather than guessing.
Serve over Streamable HTTP
The config above spawns TRACE as a stdio subprocess, which is what editor-style clients do. A client that instead connects to an endpoint it did not spawn (an agent runtime with an MCP service registry, or any consumer that outlives one editor session) needs the HTTP transport:
trace-mcp --transport streamable-http --port 8765 # serves http://127.0.0.1:8765/mcp
--host (default 127.0.0.1) and --port (default 8765) apply only to this
transport. Plain trace-mcp still serves stdio, and an unknown flag or
transport exits non-zero rather than falling back to stdio while an HTTP
consumer waits on a socket that never opens.
Two things to know before pointing a runtime at it:
- There is no authentication layer. Anything that can reach the port can write to your session store, so keep the bind on loopback unless the host is isolated by other means. A non-loopback bind logs a warning at startup.
- Pass
session_idon every call when more than one client shares the endpoint. The process keeps a single current-session pointer (see Known limitations), so concurrent clients that rely on it interleave into one session. One server instance per consumer avoids the question entirely.
docs/integrations/gents.md
works this through end to end for one such runtime, including what to put in the
agent's prompt so it knows what is worth recording.
docs/integrations/decision-log.md
covers the other importer, trace-mcp import decision-log, which builds a session
from an evaluation gate's decision log — the records that carry a measured
confidence block on each decision.
Install hooks
trace-mcp-init installs the host-side enforcement: hook scripts under .claude/hooks/, registrations merged into .claude/settings.json, and a marker block appended to CLAUDE.md.
trace-mcp-init # auto-detect host (default)
trace-mcp-init --client claude-code # explicit
trace-mcp-init --dry-run # preview, no writes
The Claude Code adapter installs four hooks:
| Hook | Event | Purpose |
|---|---|---|
session-reminder.sh |
SessionStart |
Reminds you to start a TRACE session if one isn't active for the current project. Project detection: .claude/trace.project → CLAUDE.md → git repo basename → cwd basename. |
prompt-reminder.sh |
UserPromptSubmit |
Periodic nudge after several prompts without a session. Per-project rate-limited. |
pretool-guard.sh |
PreToolUse (Edit|Write) |
Warns (or blocks) edits when no TRACE session is active. |
decision-audit.sh |
PostToolUse (mcp__trace__trace_end_session) |
Echoes the session-end attribution audit into the conversation. The matcher is the FULL namespaced tool name — a host matches tool names exactly, so a bare trace_end_session never fires. |
Project detection uses, in order: the .claude/trace.project pin file written by trace-mcp-init, a TRACE project name: "..." line in CLAUDE.md (bold form accepted), the git repository basename, then the current working directory basename. Add the explicit marker if your repo name differs from the project name you want logged.
Codex support is scaffolded as a placeholder; see src/trace_mcp/adapters/codex/README.md for the hook primitives a Codex adapter would need.
Worked examples for logging decisions, corrections, contributions, and decision chains live in docs/examples.md.
Hook environment variables
| Variable | Default | Effect |
|---|---|---|
TRACE_GUARD |
soft |
pretool-guard.sh mode: off (no-op), soft (warn-only), strict (exit 2 to block when no session is active). |
TRACE_PROMPT_MIN_TURNS |
3 |
Minimum prompt turns before prompt-reminder.sh will nudge. |
TRACE_PROMPT_COOLDOWN_SEC |
300 |
Wall-clock cooldown between nudges from prompt-reminder.sh. |
TRACE_RUNTIME_DIR |
~/.trace/runtime |
Per-project nudge state (<project>.state.json). Safe to delete to reset. |
TRACE_SOURCE_PATH |
unset | Override what trace-mcp-init writes into .mcp.json as uvx --from <X>. Set to a local TRACE clone path. Required when running init from an installed wheel — with no override, init fails closed rather than writing the PyPI name trace-mcp, which belongs to an unrelated package (dependency confusion). |
Verify the deployment
A green test suite proves the source tree is correct. It cannot prove that a deployed project is: hook copies drift a release behind, a matcher stops firing, a pin goes missing, a package cache serves a stale build. trace-mcp doctor checks one project directory against the artifacts the installed build actually ships.
trace-mcp doctor # check the current directory
trace-mcp doctor /path/to/proj # check another project
trace-mcp doctor --live # also start the configured server and verify what it serves
trace-mcp doctor --json # machine-readable report (stable check ids)
Exit codes: 0 clean, 1 findings, 2 usage error — a bad path is not an unhealthy project, and diagnostics go to stderr so --json stdout is always a report or empty. What it checks:
| Group | Checks |
|---|---|
config.* |
.mcp.json parses and declares a trace server; launched with uvx; the --from source is something uvx can build (and is not the unrelated PyPI distribution name); the args actually name trace-mcp as the command to run; the three trace-learn --with extras are present; --refresh-package trace-mcp is set. |
hooks.* |
Every shipped hook script is installed, executable, and carries this build's [trace-hooks vX.Y] stamp; no TRACE-stamped leftovers from an older release remain; settings.json parses; every hook is registered under its own host event; the decision-audit hook uses the namespaced matcher that actually fires. |
pin.* |
The pin file, the .mcp.json TRACE_PROJECT env pin, and the CLAUDE.md pin line all exist and canonicalize to one project key. |
live.* |
With --live only: the project's own configured command starts, completes an MCP handshake, reports this build's version, and serves all 23 tools. |
--live is opt-in because it runs the command the project's .mcp.json declares — an action, not an inspection. It is the only check that catches a project whose config, hooks, and pins are all correct while the running server is a stale build; a warm uv cache can serve an old wheel for minutes even with --refresh-package, and the finding names the remedy (uv cache clean trace-mcp, then restart the server).
Sweep every project
trace-mcp fleet-check runs the doctor over every project declaring a TRACE server under the roots you give it, and rolls the failures up by check — the view that turns "23 projects are broken" into "one fix, applied 23 times".
trace-mcp fleet-check ~/code ~/work # sweep these roots
TRACE_FLEET_ROOTS=~/code trace-mcp fleet-check
trace-mcp fleet-check ~/code --json # per-project reports + totals
fleet-check: 1/24 project(s) clean
FAIL /path/to/project (3 finding(s))
hooks.stamp: installed hook version differs from this build's [trace-hooks v0.5] ...
fleet-check: failing checks, most widespread first
23 project(s) pin.trace_project_file
14 project(s) hooks.decision_audit_matcher
No path is compiled in: with no roots and no TRACE_FLEET_ROOTS, the command exits 2 rather than guessing a directory to sweep — a checker that assumes one machine's layout would silently survey nothing on another and report a healthy fleet. The walk is depth-capped, skips dependency and VCS directories, does not follow symlinks, and reports a project once however many roots reach it. A root or .mcp.json that cannot be read is reported and makes the sweep non-clean, since a partial survey is not a clean bill of health.
--live applies the doctor's live probe to every project found — which means running the server command each of those projects declares. Because a sweep reaches directories you never named one by one, the first --live only lists the commands it would run; adding --yes executes them. --max-depth raises the walk limit, and the number of branches left un-descended is reported rather than silently omitted.
A finding is pass, fail, or skip — where skip means not evaluated and always names the upstream check that made evaluation impossible. Exactly one check fails per root cause.
The hook checks describe the Claude Code deployment, which is the only host adapter that installs today. A project set up with --client none has no hooks by construction and reports the hooks.* checks as failures — deliberately: an MCP server without host-side enforcement is a real gap in the audit trail, not a supported configuration to be waved through.
Run a first session
Once configured, TRACE tools are available to the AI client:
You: "Start a TRACE session for our climate NLP analysis"
Claude: -> trace_start_session(project="climate-nlp", ...)
"Session started: trace_20260205_a1b2c3"
"Relevant learnings from past sessions:
- [correction] Always use ml-dev conda env, not base (relevance: 87%)"
You: "Search for adaptation passages in the IPCC corpus"
Claude: -> [calls corpus-search-mcp/search_passages]
-> trace_log_tool_call(server="corpus-search-mcp", ...)
-> trace_propose_decision(description="Focus on chapters 14-17", ...)
You: "Also include chapter 6"
Claude: -> trace_resolve_decision(disposition="revised", ...)
You: "End the session"
Claude: -> trace_end_session(summary="Analyzed 47 passages...")
(learnings auto-extracted and persisted for future sessions)
Available tools (23 total)
TRACE MCP questions
What tools does TRACE MCP provide?
It exposes 17 tools, including trace_start_session, trace_end_session, trace_log_tool_call, trace_log_annotation, trace_log_contribution.
What does TRACE record?
It records tool calls, decisions, annotations, contributions, and actor attribution, including who proposed what and who accepted or revised it.
How does TRACE differ from existing AI observability stacks?
Unlike tools that capture call-level traces, TRACE captures decision-level provenance, such as who proposed a step and what alternatives were rejected.
Where is the session data stored?
Data is stored in self-contained, human-readable, and git-diffable JSON files located in ~/.trace/sessions/.
Is TRACE available on PyPI?
No, the TRACE server is not on PyPI; users should install it from a repository clone or via a pinned VCS source.