AgentStack
MCP verified MIT Self-run

Trail Spec

mcp-timoncool-trail-spec · by timoncool

TRAIL — Tracking Records Across Isolated Logs. An open protocol for cross-MCP content tracking and deduplication.

No reviews yet
0 installs
10 views
0.0% view→install

Install

$ agentstack add mcp-timoncool-trail-spec

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Trail Spec? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

An open protocol for cross-MCP server content tracking and deduplication. Spec (EN) · Spec (RU) · Examples · README на русском


The Problem

You have multiple MCP servers — one fetches content, another posts to Telegram, a third cross-posts to a social network. Each server is isolated by design. No server sees the others.

Now answer these questions:

  • Was this image already posted to Telegram?
  • Did the social network post succeed or fail?
  • Where did the pipeline break yesterday at 3am?

You can't. There's no standard way to track content across isolated MCP servers.

TRAIL solves this.

How It Works

                    LLM Orchestrator (Claude, GPT, etc.)
                   /          |            \
                  /           |             \
         ┌──────────┐  ┌──────────┐  ┌──────────┐
         │ Civitai  │  │ Telegram │  │ Facebook │
         │   MCP    │  │   MCP    │  │   MCP    │
         └────┬─────┘  └────┬─────┘  └────┬─────┘
              │              │              │
         trail.jsonl    trail.jsonl    trail.jsonl

Each server keeps its own trail.jsonl — an append-only log with a shared schema. The orchestrator reads all logs and connects the dots using a universal Content ID (content_id).

One pipeline run across three servers:

# Civitai trail.jsonl
{"version":2,"timestamp":"2026-04-05T14:07:00Z","content_id":"civitai:image:12345","action":"selected","requester":"daily-post","trace_id":"run-001"}

# Telegram trail.jsonl
{"version":2,"timestamp":"2026-04-05T14:07:05Z","content_id":"civitai:image:12345","action":"posted","requester":"daily-post","trace_id":"run-001","details":{"platform":"telegram","platform_id":"42"}}

# Facebook trail.jsonl
{"version":2,"timestamp":"2026-04-05T14:07:30Z","content_id":"civitai:image:12345","action":"posted","requester":"daily-post","trace_id":"run-001","details":{"platform":"facebook","platform_id":"99"}}

The orchestrator sees: civitai:image:12345 → selected → posted to Telegram (#42) → posted to Facebook (#99). Full pipeline traced via trace_id.

Key Features

  • Zero shared state — no database, no message bus, no inter-server communication
  • Append-only JSONL — atomic writes, no corruption risk, trivially parseable
  • Self-documenting — readable field names: content_id, action, requester, timestamp, version
  • Universal Content IDsource:type:id format traces content across any number of servers
  • Trace correlation — optional trace_id links entries across servers into one pipeline trace
  • 15 standard actionsfetched, selected, posted, failed, skipped, retrying, transformed, moderated, expired, delivered, delegated, received, evaluated, guarded, acknowledged
  • Multi-agent patterns — delegation, evaluation, guardrails, and human-in-the-loop via standard actions and caused_by chains
  • Standard toolsget_trail, mark_trail, get_trail_stats — same API everywhere
  • Standardized details — error types, cost tracking, content metadata, platform IDs, guardrail results, evaluation scores
  • Auto-logging — publishing tools log automatically when content_id and requester are passed
  • 3 conformance levels — Basic (5 fields + 2 tools), Standard (+ tracing, auto-logging, discovery), Full (+ causality chains, OTel export, all 15 actions)
  • Zero dependencies — stdlib only, no external packages
  • OTel-native mappingcaused_byparentSpanId, serverservice.name, full span tree in any OTel backend

Quick Start

Python

from trail import Trail

trail = Trail("./data")

# Log an event
await trail.append(
    content_id="civitai:image:12345",
    action="posted",
    requester="daily-post",
    details={"platform": "telegram", "platform_id": "42"},
    trace_id="run-001"
)

# Query the trail
entries, total = await trail.query(content_id="civitai:image:12345")

# Check if already posted
if await trail.is_used("civitai:image:12345"):
    print("Already posted, skipping")

# Get pipeline stats
stats = await trail.stats(requester="daily-post")
print(f"Posted: {stats['by_action'].get('posted', 0)}")

TypeScript

import { Trail } from "./trail";

const trail = new Trail("./data");

// Log an event
await trail.append("civitai:image:12345", "posted", "daily-post", {
  details: { platform: "telegram", platform_id: "42" },
  trace_id: "run-001",
});

// Query the trail
const { entries, total } = await trail.query({ content_id: "civitai:image:12345" });

// Check if already posted
if (await trail.isUsed("civitai:image:12345")) {
  console.log("Already posted, skipping");
}

// Get pipeline stats
const stats = await trail.stats("daily-post");
console.log(`Posted: ${stats.by_action.posted ?? 0}`);

Entry Schema

{"version":2,"timestamp":"2026-04-05T14:07:00.123Z","content_id":"civitai:image:12345","action":"posted","requester":"daily-post","server":"telegram-mcp","trace_id":"run-001","details":{"platform":"telegram","platform_id":"42"}}

| Field | Type | Required | Description | |-------|------|:--------:|-------------| | version | int | yes | Protocol version (2) | | timestamp | string | yes | ISO 8601 timestamp (UTC, milliseconds) | | content_id | string | yes | Content ID: source:type:id | | action | string | yes | Action performed (see below) | | requester | string | yes | Workflow/task ID that initiated this | | details | object | no | Platform-specific data with [standard sub-fields](SPEC.md#details-field) | | trace_id | string | no | Groups entries across servers into one trace | | server | string | no | MCP server that wrote this entry (auto-set) | | entry_id | string | no | Unique entry identifier (for causality chains) | | caused_by | string | no | entry_id of the causing entry (maps to OTel parentSpanId) | | tags | string[] | no | Free-form labels for filtering |

Standard Actions

| Action | When | |--------|------| | fetched | Content retrieved from source (candidate list) | | selected | Chosen from candidates by the orchestrator | | posted | Successfully published | | failed | Publish attempt failed (details.error has structured error info) | | skipped | Intentionally not used (details.reason explains why) | | retrying | Scheduling retry after failure (details.attempt = attempt number) | | transformed | Content modified (resize, transcode, translate) | | moderated | Passed or failed moderation (details.result: "pass" / "reject") | | expired | Content no longer eligible (TTL, source removed) | | delivered | Delivery confirmed by platform (webhook, read receipt) | | delegated | Task delegated to another agent/server (details.delegate_to, details.delegation_reason) | | received | Content received from another agent/server (details.received_from) | | evaluated | Quality/relevance scored (details.score: 0.0–1.0, details.evaluator) | | guarded | Guardrail check (details.guardrail, details.passed, details.reason) | | acknowledged | Human-in-the-loop approval (details.acknowledged_by, details.decision) |

Standard Tools

Every TRAIL-compatible MCP server exposes:

| Tool | Purpose | |------|---------| | get_trail(content_id?, action?, requester?, trace_id?, tags?, since?, limit?, offset?) | Query the log with filters. Returns {entries, total} | | mark_trail(content_id, action, requester, details?, trace_id?, tags?) | Write an entry explicitly | | get_trail_stats(requester?, since?) | Summary statistics (counts by action, unique content IDs, date range) |

Publishing tools (send_photo, publish_post, etc.) accept optional content_id + requester + trace_id for automatic logging.

Standardized Details

TRAIL defines standard sub-fields in details for cross-server consistency:

{
  "details": {
    "platform": "telegram",
    "platform_id": "42",
    "url": "https://t.me/channel/42",
    "error": {"type": "rate_limit", "message": "429", "retry_after": 60},
    "cost": {"tokens_in": 150, "tokens_out": 50, "usd": 0.003},
    "content": {"type": "image", "width": 1024, "height": 1024, "model": "Flux.1"},
    "duration_ms": 1200,
    "delegate_to": "optimizer-mcp",
    "score": 0.92,
    "evaluator": "llm-judge",
    "guardrail": "nsfw-filter",
    "passed": true,
    "acknowledged_by": "editor@company.com",
    "decision": "approve"
  }
}

See [SPEC.md — Details Field](SPEC.md#details-field) for the full specification.

Deduplication

The orchestrator handles deduplication, not the servers:

1. Before fetching  → get_trail(requester="daily-post", since="...") on source
2. Before posting   → get_trail(content_id="civitai:image:12345", action="posted") on destination
3. If already posted → skip

Servers MAY offer convenience filters (e.g., exclude_used=true) that use the trail internally.

Discovery

Servers advertise TRAIL support via capabilities:

{
  "capabilities": {
    "trail": {
      "version": 2,
      "server": "telegram-mcp",
      "conformance": "standard",
      "actions": ["fetched", "selected", "posted", "failed", "skipped", "guarded"],
      "auto_log_tools": ["send_photo", "send_message", "publish_post"],
      "supports": {
        "trace_id": true,
        "entry_id": true,
        "caused_by": true,
        "tags": true,
        "server_field": true
      },
      "retention_days": 90
    }
  }
}

Adopting TRAIL in Your MCP Server

Basic (Level 0) — deduplication and simple tracking:

  1. Copy [trail.py](examples/python/trail.py) or [trail.ts](examples/typescript/trail.ts) into your project
  2. Add get_trail and mark_trail tools
  3. Done

Standard (Level 1) — production pipelines:

  1. Set server name in Trail constructor
  2. Add get_trail_stats tool
  3. Add content_id + requester + trace_id params to publishing tools
  4. Advertise TRAIL in capabilities with "conformance": "standard"

Full (Level 2) — multi-agent observability:

  1. Enable entry_id auto-generation and caused_by support
  2. Implement all 15 standard actions
  3. Add OTel export capability

Full specification: [SPEC.md](SPEC.md) | [SPEC.ru.md](SPEC.ru.md)

Why Not...

| Alternative | Why TRAIL is better for content tracking | |---|---| | Shared database | Creates coupling, deployment complexity, single point of failure. MCP servers are isolated by design. | | Message queue | Overkill. The LLM orchestrator already mediates all servers — it IS the message bus. | | OpenTelemetry | Traces tool calls, not content semantics. Doesn't know what was published where. TRAIL has an [OTel bridge](SPEC.md#opentelemetry-bridge) for combining both. | | IETF AAT | Compliance-focused (hash chains, ECDSA signatures). TRAIL is developer-first — lightweight and zero-dependency. | | Langfuse / LangSmith | LLM observability platforms — trace API calls, not content lifecycle. Require cloud/self-hosted backend. | | Google A2A | Agent-to-agent communication protocol, not a content tracking log. Different layer. | | Agent Protocol | Defines agent API, not a logging format. Tasks/Steps, not content semantics. | | ActivityPub | Designed for social federation, not AI tool orchestration. Massive overhead. |

FAQ

Q: Why readable field names instead of short ones? A: A protocol for decades must be self-documenting. content_id is clear on first sight. The overhead is ~15 KB/year at typical rates — negligible.

Q: Do I need all the optional fields? A: No. The five required fields are the whole protocol. Optional fields unlock advanced features when you need them.

Q: Orchestrator crashes mid-pipeline? A: Use trace_id to find all entries for that run. The last entry's action shows where to resume.

Q: What are conformance levels? A: Three tiers — Basic (5 fields + 2 tools), Standard (+ tracing, server, auto-logging), Full (+ causality chains, all 15 actions, OTel export). Start at Basic.

Q: Multi-agent pipelines? A: delegated/received action pairs + caused_by chains + server field. The orchestrator reconstructs the full DAG. See [SPEC.md — Multi-Agent Patterns](SPEC.md#multi-agent-patterns).

Prior Art

We searched extensively for existing solutions. As of April 2026, no cross-MCP content tracking protocol exists:

  • MCP Spec — no server-to-server communication by design
  • CA-MCP (arXiv 2601.11595) — shared context store for transient state, not persistent content logs
  • lokryn/mcp-log — JSONL audit logging for operations (SOC2/HIPAA), not content tracking
  • IBM ContextForge — gateway proxy with OTel tracing, not content semantics
  • OpenTelemetry GenAI — semantic conventions for LLM calls (Development status), not content lifecycle
  • IETF AAT (draft-sharif-agent-audit-trail) — compliance-focused audit trail with hash chains, no content semantics
  • Google A2A — agent-to-agent communication protocol with traceability extension, not a logging format
  • Langfuse / LangSmith / Arize Phoenix — LLM observability platforms, trace API calls not content
  • Agent Protocol (agentprotocol.ai) — REST API for interacting with agents, not a log format

TRAIL fills a unique gap: lightweight, zero-dependency content tracking with multi-agent support — no other protocol combines content semantics (content_id), zero shared state, and agent patterns (delegation, evaluation, guardrails).

MCP Servers Implementing TRAIL

| Server | Description | Language | |--------|-------------|----------| | civitai-mcp-ultimate | Civitai API — models, images, videos, prompts | Python | | telegram-api-mcp | Telegram Bot API v9.6 — full coverage | TypeScript |

Implementing TRAIL in your server? Open a PR to add it here.


Other Projects by @timoncool

| Project | Description | |---------|-------------| | ACE-Step Studio | AI music studio — songs, vocals, covers, videos | | VideoSOS | AI video production in the browser | | Bulka | Live-coding music platform | | GitLife | Your life in weeks — interactive calendar | | ScreenSavy.com | Ambient screen generator |


Support the Author

I build open-source software and do AI research. Most of what I create is free and available to everyone. Your donations help me keep creating without worrying about where the next meal comes from =)

All donation methods | dalink.to/nerualdreming | boosty.to/neuro_art

  • BTC: 1E7dHL22RpyhJGVpcvKdbyZgksSYkYeEBC
  • ETH (ERC20): 0xb5db65adf478983186d4897ba92fe2c25c594a0c
  • USDT (TRC20): TQST9Lp2TjK6FiVkn4fwfGUee7NmkxEE7C

Star History


MIT License · Made with Claude Code

Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.