trace_start
Begin a new agent workflow trace. Returns a trace_id to use with subsequent calls. Example: { "name": "My Search Workflow" }. Pass "auto" or leave name blank for an auto-generated name.
namerequired
io.github.dbsectrainerPublished by GitHub account dbsectrainerv1.0.1Updated Nov 4, 2026
Step-by-step observability for MCP agent workflows
Local-first MCP server that lets an assistant record, inspect, compare and export traces of its own agent workflow steps.
Desktop only via STDIO. STDIO servers start a local process, so they need the SourceWeft desktop host.
Follow the launch instructions in the repository.
Local-first, MCP-native observability for agent workflows. Every tool call, prompt transformation, latency, token estimate, and cost estimate is recorded in a local SQLite database — no cloud account, no API key, and no traces leaving your machine.
Built specifically for MCP rather than bolted onto a generic LLM proxy.
Tools · Configuration · HTTP transport · Verification · Known limitations · Contributing
mcp-agent-trace-inspector is an MCP server. Agents call its tools to start a trace,
record each step they take, and finish the trace. Humans then inspect summaries,
compare runs, export a self-contained HTML dashboard, export OTLP/JSON spans, or
stream the compliance audit log.
node:sqlite; traces
survive restarts and never require a service.cl100k_base tokenizer plus a configurable pricing
table; no API calls and no billing-account data.resourceSpans → scopeSpans → spans documents.node:sqlite first became available in Node 22.5.0
behind --experimental-sqlite; it is unflagged from 22.13.0. This project does not
pass the flag.Add the server to your MCP client configuration:
Use a project-specific database:
Then ask your agent to trace its own work:
The summary contains the step count, estimated token total, total recorded latency,
wall-clock duration, cost estimate, and reasoning-chain detection. Tracing is explicit:
the inspector records steps when the agent calls trace_step; it does not intercept
other MCP servers automatically.
Development mode runs TypeScript directly and logs MCP protocol messages on stderr:
HTTP mode is useful for a local team instance or a container. It is stateless:
every POST gets a fresh MCP server and transport, there is no Mcp-Session-Id, and the
endpoint does not offer a server-initiated SSE stream. Send every JSON-RPC message as
its own POST /mcp request.
Initialize the endpoint:
The response is an SSE frame. Call a tool:
Set one or both environment variables before starting the server:
MCP_API_KEY is set, every HTTP request must send X-API-Key: <value>.MCP_JWT_SECRET is set, every HTTP request must send
Authorization: Bearer <HS256 JWT>; exp and nbf claims are checked.--http-host=0.0.0.0 is allowed but the server warns. Put TLS and an authenticating
reverse proxy in front of any non-loopback deployment; do not expose the raw endpoint
to an untrusted network.
When the server is bound to loopback behind a reverse proxy, the proxy must rewrite the
Host header to 127.0.0.1:<port>. The loopback DNS-rebinding guard rejects other
Host values with 403 by design.
The server does not load .env files automatically. Export variables in your
shell or configure them in your MCP client.
See .env.example for a copy-paste template. Never commit real
secrets or database files; both are ignored by .gitignore.
The server exposes 13 tools. Tool annotations mark state-changing tools
(readOnlyHint: false) and destructive retention (destructiveHint: true).
trace_step requires trace_id, tool_name, input (object), and output (object).
token_count must be a non-negative integer; latency_ms must be a finite,
non-negative number. Caller-supplied token counts are used as-is.
export_otel returns a document; it does not push to a collector. Write the
result to a file and submit it with your OTLP tooling, or adapt it in your client.
Non-UUID trace/step IDs are hashed into valid lowercase 32/16-character hex IDs.
trace://{trace_id} with trace metadata,
totals, and step metadata as JSON.analyze-trace accepts trace_id and returns a structured investigation
prompt covering performance, errors, reasoning chains, and optimization opportunities.cl100k_base BPE encoding via gpt-tokenizer.ceil(characters / 4) estimate to keep synchronous step recording bounded.
Pass token_count explicitly if you need an exact count for a large payload.--no-token-count disables automatic counting entirely.--pricing-table merges over those entries, so a custom file can add a model or
override a rate while retaining the defaults.get_trace_summary estimates cost from the aggregate token count using the input
rate. Token counts are not split into input/output categories, so this is an estimate,
not a billing figure.claude-sonnet-4-6. Unknown models report N/A.There are two related mechanisms:
--retention-days=N) deletes traces whose started_at is older
than N days, plus their steps. This is irreversible and applied when the process
starts.set_retention_policy then apply_retention) is held in memory for
the lifetime of the process. It sets archived = 1 on traces older than N days and
deletes archived traces older than 2×N days, along with their steps. The policy is
not persisted across restarts; call set_retention_policy again after a restart.
Archived traces remain queryable until deleted.Rules are persisted in the alert_rules table and evaluated when trace_end runs:
latency — average recorded step latency across all stored traces (ms).error_rate — percentage of steps whose output contains error or isError: true.cost — total recorded tokens × the default input rate ($0.003 / 1K tokens).Metrics are global to the database, not scoped to the just-ended trace. When a rule
fires, the alert is included in the trace_end response (alerts_fired, alerts) and
delivered to configured webhooks. Webhook requests time out after 5 seconds and
failures are logged without failing the tool call. There is no retry or deduplication.
Channel URLs are process configuration, not database rows: pass them to
configure_alerts, or set MCP_SLACK_WEBHOOK / MCP_ALERT_WEBHOOK. Omitting a URL
on a later configure_alerts call preserves the previously configured channel.
Automated checks (no external services required):
npm run verify:e2e starts the built server, exercises all 13 tools against a temp
SQLite database, drives two sequential HTTP requests to prove the stateless transport
works, checks auth/validation failures, and writes machine-readable evidence under
docs/evidence/test-results/. It does not use a mock transport.
Optional MCP Inspector verification:
The dashboard is generated by the real export_dashboard tool from a real trace and
opened in Chrome at desktop and mobile viewport sizes. See
the verification report for the commands,
test results, and per-screenshot workflow associations.
[Desktop dashboard showing the trace timeline, stats, and error row]
[Mobile dashboard with responsive stat cards and card-style step timeline]
[Dashboard with an error step's input expanded]
Traces contain tool inputs and outputs and may include secrets, prompts, or personal data. The inspector stores them locally and does not transmit them except when you configure alert webhooks. Review trace contents before sharing HTML exports.
~/.mcp/traces.db; the audit log is created with mode 0600.127.0.0.1 by default. Configure MCP_API_KEY and/or
MCP_JWT_SECRET before binding to a non-loopback address, and use TLS upstream..env, *.db, *.db-wal, or audit logs.trace_end over database-wide metrics, with
best-effort webhook delivery and no retry/deduplication.set_retention_policy must be called after each
restart; only the CLI startup purge is automatic.node:sqlite is still evolving (release candidate in newer Node releases). Pin a
Node version in production if API stability is required.See CONTRIBUTING.md. Run the full local gate before opening a PR:
Commit messages follow Conventional Commits. One focused change per pull request.
MIT — see LICENSE.
Source: README.md at commit 56e9f5b
Begin a new agent workflow trace. Returns a trace_id to use with subsequent calls. Example: { "name": "My Search Workflow" }. Pass "auto" or leave name blank for an auto-generated name.
namerequiredRecord a single step within a running trace. Captures tool name, input, output, optional token count and latency. Steps cannot be added after trace_end. Example: { "trace_id": "abc-123", "tool_name": "web_search", "input": {"query": "hello"}, "output": {"results": ["a","b"]}, "token_count": 50, "latency_ms": 320 }
inputrequiredoutputrequiredtrace_idrequiredtool_namerequiredlatency_mstoken_countMark a trace as completed and evaluate the currently configured alert rules. Further trace_step calls for this trace are rejected. Example: { "trace_id": "abc-123" }
trace_idrequiredRetrieve a summary of a trace including step count, total tokens, total latency, cost estimate, and reasoning chain detection. Example: { "trace_id": "abc-123", "model": "claude-sonnet-4-6" }
modeltrace_idrequiredList all stored traces with their names, statuses, and timestamps. Example: { "limit": 10 } to get the 10 most recent traces.
limitGenerate a self-contained HTML dashboard for a trace with error highlighting and latency waterfall visualization. Returns the full HTML as a string. Example: { "trace_id": "abc-123" }
trace_idrequiredCompare two traces side by side: step counts, tokens, latency, and step-by-step differences. Example: { "trace_id_a": "abc-123", "trace_id_b": "def-456" }
trace_id_arequiredtrace_id_brequiredExtract only the reasoning/thinking steps from a trace. Returns steps whose tool_name matches reasoning patterns (reason, think, plan, reflect, analyz, consider) or whose input/output content includes the word "think". Example: { "trace_id": "abc-123" }
trace_idrequiredExport trace(s) as an OTLP/JSON document (resourceSpans → scopeSpans → spans) suitable for an OTLP collector or backend. Omit trace_id to export all traces. Example: { "format": "json" } or { "trace_id": "abc-123", "format": "json" }
formatrequiredtrace_idPersist alert rules for latency, error rate, or cost thresholds. Rules are evaluated on trace_end; optional Slack or generic webhooks deliver fired alerts. Example: { "rules": [{"type":"latency","threshold":1000}], "slack_webhook": "https://hooks.slack.com/..." }
rulesrequiredwebhook_urlslack_webhookSet the trace retention policy (how many days to keep traces before archiving). Example: { "retention_days": 30 }
retention_daysrequiredApply the current in-process retention policy: archives traces older than retention_days and deletes archived traces past 2× threshold. Call set_retention_policy first. Example: {}
Takes no parameters.
Export the compliance audit log as JSON or CSV. Example: { "format": "json" } or { "format": "csv", "from_date": "2025-01-01", "to_date": "2025-12-31" }
formatrequiredto_datefrom_date90% of the applicable checks met
How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.
Declare the credential headers in the registry entry, or keep the endpoint answering the probe so its auth can be classified.
Agent / MCP client │ trace_start → trace_step → trace_end ▼MCP Agent Trace Inspector ├── SQLite (~/.mcp/traces.db) ├── JSONL audit log (~/.mcp/trace-inspector-audit.jsonl) └── tools: summaries, diffs, HTML, OTLP/JSON, retention, alerts{ "mcpServers": { "trace-inspector": { "command": "npx", "args": ["-y", "mcp-agent-trace-inspector@latest"] } }}{ "mcpServers": { "trace-inspector": { "command": "npx", "args": [ "-y", "mcp-agent-trace-inspector@latest", "--db=~/traces/my-project.db" ] } }}Start a trace named "test-run" with trace_start.Record a trace_step for each tool you call, including that tool's input and output.Call trace_end when you are done, then call get_trace_summary for the trace.npm cinpm run buildnode dist/index.js --db=~/.mcp/traces.dbnpm run dev -- --db=/tmp/traces.dbnode dist/index.js --db=~/.mcp/traces.db --http-port=3000 --http-host=127.0.0.1# stderr: MCP Agent Trace Inspector HTTP server listening on http://127.0.0.1:3000/mcpcurl -s http://127.0.0.1:3000/mcp \ -H 'Content-Type: application/json' \ -H 'Accept: application/json, text/event-stream' \ -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"1"}}}'curl -s http://127.0.0.1:3000/mcp \ -H 'Content-Type: application/json' \ -H 'Accept: application/json, text/event-stream' \ -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"list_traces","arguments":{}}}'MCP_API_KEY=change-me \MCP_JWT_SECRET=change-me-too \node dist/index.js --http-port=3000 --http-host=127.0.0.1npm cinpm run verify # lint + format check + typecheck + testsnpm test -- --coverage # unit/integration tests + V8 coveragenpm run build # compile to dist/npm run verify:e2e # build, then run real stdio + HTTP MCP processesnpm run screenshots # Chrome/CDP capture of the generated dashboard (set CHROME_PATH if needed)npm run buildnpx @modelcontextprotocol/inspector node dist/index.jsnpm cinpm run verify