mcp-trace-inspector 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,22 @@
1
+ name: ci
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: ubuntu-latest
11
+ strategy:
12
+ matrix:
13
+ python-version: ["3.11", "3.12"]
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+ - uses: actions/setup-python@v5
17
+ with:
18
+ python-version: ${{ matrix.python-version }}
19
+ - name: Install
20
+ run: pip install -e ".[dev]"
21
+ - name: Test
22
+ run: pytest -q
@@ -0,0 +1,43 @@
1
+ name: publish-pypi
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ release:
6
+ types: [published]
7
+
8
+ permissions:
9
+ contents: read
10
+ id-token: write
11
+
12
+ jobs:
13
+ publish:
14
+ runs-on: ubuntu-latest
15
+ environment: pypi
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+ - uses: actions/setup-python@v5
19
+ with:
20
+ python-version: "3.12"
21
+ - name: Build distributions
22
+ run: |
23
+ python -m pip install --upgrade build
24
+ python -m build
25
+ - name: Publish to PyPI with trusted publishing
26
+ uses: pypa/gh-action-pypi-publish@release/v1
27
+
28
+ publish-mcp:
29
+ needs: publish
30
+ if: github.event_name == 'release'
31
+ runs-on: ubuntu-latest
32
+ steps:
33
+ - uses: actions/checkout@v4
34
+ with:
35
+ ref: ${{ github.event.release.tag_name }}
36
+ - name: Install mcp-publisher
37
+ run: |
38
+ curl -fsSL "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz" | tar xz mcp-publisher
39
+ chmod +x mcp-publisher
40
+ - name: Authenticate to MCP Registry
41
+ run: ./mcp-publisher login github-oidc
42
+ - name: Publish server metadata
43
+ run: ./mcp-publisher publish
@@ -0,0 +1,13 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ .venv/
5
+ venv/
6
+ build/
7
+ dist/
8
+ .pytest_cache/
9
+ .coverage
10
+ htmlcov/
11
+ traces/
12
+ runs.jsonl
13
+ .env
@@ -0,0 +1,19 @@
1
+ # Contributing to mcp-trace-inspector
2
+
3
+ ## Development setup
4
+
5
+ ```bash
6
+ uv venv
7
+ uv pip install -e ".[dev]"
8
+ pytest -q
9
+ ```
10
+
11
+ The core query engine is dependency-light and should remain pure. Server tests exercise the MCP 2.x protocol adapter as well as the core functions.
12
+
13
+ ## Pull requests
14
+
15
+ - Add a deterministic fixture for new query behavior.
16
+ - Test the tool through `MCPServer.call_tool`, not only by calling the underlying function.
17
+ - Keep tool descriptions phrased as when-to-use prompts.
18
+ - Preserve trace-id prefix support and compact output defaults.
19
+ - Update the README's tool table and limitations when behavior changes.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Abhishek Ash
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,157 @@
1
+ Metadata-Version: 2.5
2
+ Name: mcp-trace-inspector
3
+ Version: 0.3.0
4
+ Summary: Agent observability MCP server for querying OpenTelemetry traces, failures, tool health, security evidence, and regressions.
5
+ Project-URL: Homepage, https://github.com/abhishekash/mcp-trace-inspector
6
+ Project-URL: Repository, https://github.com/abhishekash/mcp-trace-inspector
7
+ Project-URL: Issues, https://github.com/abhishekash/mcp-trace-inspector/issues
8
+ Author-email: Abhishek Ash <ash.abhishek@gmail.com>
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: agent-evals,ai-agents,mcp,model-context-protocol,observability,opentelemetry
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Requires-Python: >=3.11
18
+ Requires-Dist: mcp>=2.0.0
19
+ Provides-Extra: dev
20
+ Requires-Dist: pytest>=8; extra == 'dev'
21
+ Description-Content-Type: text/markdown
22
+
23
+ # mcp-trace-inspector
24
+
25
+ <!-- mcp-name: io.github.abhishekash/mcp-trace-inspector -->
26
+
27
+ [![CI](https://github.com/abhishekash/mcp-trace-inspector/actions/workflows/ci.yml/badge.svg)](https://github.com/abhishekash/mcp-trace-inspector/actions/workflows/ci.yml) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
28
+
29
+ mcp-trace-inspector is a small, local-first stdio MCP server for querying JSONL
30
+ OpenTelemetry spans emitted by agent runs. It exposes focused queries for
31
+ run summaries, tool failures, approvals, activity, and comparisons instead of
32
+ requiring an application-specific dashboard.
33
+
34
+ It pairs with [agent-harness](https://github.com/abhishekash/agent-harness),
35
+ but the reader is format-simple: any JSONL of OTel-shaped spans works. The
36
+ project's concrete origin was a shell-boundary regression: the harness blocked
37
+ `cat ../outside.txt`, but the old trace recorded only that `run_shell` was
38
+ called, not the returned diagnostic. mcp-trace-inspector and the harness now preserve and
39
+ query that bounded error.
40
+
41
+ ## AI-native use cases
42
+
43
+ | Question during an agent run | MCP tool | Evidence returned |
44
+ |---|---|---|
45
+ | "Why did yesterday's run stall?" | `list_runs` → `slowest_spans` | Run IDs and the longest model or tool spans. |
46
+ | "Did the agent act after I denied the write?" | `approval_log` → `span_tree` | The recorded decision and subsequent execution path. |
47
+ | "How many model tokens did this run use?" | `token_usage` → `span_tree` | Run-level usage totals and the span tree for context. |
48
+ | "Which tool is failing or timing out?" | `failure_report` / `tool_stats` | Redacted diagnostics, error rates, denials, and p95 latency. |
49
+ | "Who/what was allowed to act?" | `security_audit` | Caller, tenant, server provenance, risk, and missing-evidence findings. |
50
+ | "What is happening in the run right now?" | `recent_activity` | Cursor-based polling of newly written spans. |
51
+ | "Did this model/version regress?" | `compare_runs` | Cost, latency, tokens, tool calls, and failure deltas. |
52
+
53
+ The tools read stored traces and can poll files being written, but they do not push events or infer intent from the final answer. Start with the [installation and user guide](docs/user-guide.md), then see the [real trace fixture](examples/example_trace.jsonl) and the [tool descriptions](src/mcp_trace/server.py) for the query contract.
54
+
55
+ ## Install & run
56
+
57
+ ```bash
58
+ uvx mcp-trace-inspector --trace-dir ./traces
59
+ # or, for local development:
60
+ git clone https://github.com/abhishekash/mcp-trace-inspector
61
+ cd mcp-trace-inspector && uv pip install -e .
62
+ mcp-trace-inspector --trace-dir ./traces
63
+ ```
64
+
65
+ ## Client configuration
66
+
67
+ **Claude Desktop** (`claude_desktop_config.json`):
68
+
69
+ ```json
70
+ {
71
+ "mcpServers": {
72
+ "agent-traces": {
73
+ "command": "uvx",
74
+ "args": ["mcp-trace-inspector", "--trace-dir", "/path/to/traces"]
75
+ }
76
+ }
77
+ }
78
+ ```
79
+
80
+ **pi** (`~/.pi/agent/settings.json`):
81
+
82
+ ```json
83
+ {
84
+ "mcpServers": {
85
+ "agent-traces": {
86
+ "command": "uvx",
87
+ "args": ["mcp-trace-inspector", "--trace-dir", "/path/to/traces"]
88
+ }
89
+ }
90
+ }
91
+ ```
92
+
93
+ **agent-harness** (mounted as gated tools):
94
+
95
+ ```bash
96
+ harness run "Why was my last run slow?" --mcp "uvx mcp-trace-inspector --trace-dir ./traces"
97
+ ```
98
+
99
+ ## Tools
100
+
101
+ | Tool | Use it when |
102
+ |---|---|
103
+ | `list_runs` | Starting out — recent runs with task, model, duration, cost, decision counts |
104
+ | `run_summary` | One run at a glance (accepts trace-id prefix) |
105
+ | `span_tree` | "What did the agent actually do?" — nested shape of the run |
106
+ | `slowest_spans` | "Why was it slow?" — top-k spans by duration |
107
+ | `approval_log` | HITL audit — every approve/deny/**edit**, who decided, and *the rationale* |
108
+ | `token_usage` | Cost questions — aggregated across runs or per-run |
109
+ | `search_spans` | Find spans by tool name, file path, "denied", … |
110
+ | `failure_report` | Find actionable, bounded, redacted errors and failed tool calls. |
111
+ | `tool_stats` | Rank tools by volume, error rate, denials, and latency. |
112
+ | `security_audit` | Audit caller identity, tenant, server provenance, risk, and approval evidence. |
113
+ | `recent_activity` | Poll new spans with a cursor while a run is active. |
114
+ | `compare_runs` | Compare selected traces for regressions across models or versions. |
115
+
116
+ Tool descriptions are written as prompts (when-to-use, not just what-it-does) — descriptions are the interface for agent-called tools.
117
+
118
+ ## Example session (real fixture trace)
119
+
120
+ ```
121
+ > list_runs
122
+ [{ "trace_id": "f920798dd255…", "task": "Summarize the workspace's notes…",
123
+ "tool_calls": 4, "human_decisions": 2, "stopped_reason": "completed" }]
124
+
125
+ > approval_log
126
+ [{ "tool": "write_file", "decision": "approve", "approver": "auto", … },
127
+ { "tool": "run_shell", "decision": "approve", "approver": "auto", … }]
128
+ ```
129
+
130
+ ## Design
131
+
132
+ ```
133
+ traces/*.jsonl ──▶ mcp_trace.core (pure query functions, zero deps)
134
+ │
135
+ mcp_trace.server (thin MCPServer adapter, mcp 2.x)
136
+ │
137
+ stdio (NDJSON JSON-RPC)
138
+ ```
139
+
140
+ - **core/server split**: all logic is pure functions over parsed spans; the MCP layer only parses args and JSON-encodes results. Tests hit both layers.
141
+ - **trace_id prefixes**: agents fumble full 32-char hex ids; every tool accepts prefixes.
142
+ - **bounded output**: diagnostics are truncated and obvious credentials are redacted before query results leave the server.
143
+ - **honest cost totals**: `token_usage` returns `cost_known: false` and a null cost when any producer marks pricing as unavailable; unknown pricing is never presented as `$0`.
144
+ - **cursor polling**: `recent_activity` makes the snapshot reader useful while a run is still writing spans.
145
+ - The demo fixture ([`examples/example_trace.jsonl`](examples/example_trace.jsonl)) is a *real* agent-harness run, not hand-written.
146
+
147
+ ## Honest limitations
148
+
149
+ - stdio transport only (Streamable HTTP plus authenticated remote access is the next transport boundary)
150
+ - live polling re-reads snapshots; it is not a push subscription
151
+ - security audit can only report identity/provenance that the trace producer records
152
+ - read-only tools; trace mutation (annotations) is roadmap
153
+ - The Python query and server modules are available as `mcp_trace`; older import and command aliases remain for existing clients.
154
+
155
+ ## License
156
+
157
+ MIT
@@ -0,0 +1,135 @@
1
+ # mcp-trace-inspector
2
+
3
+ <!-- mcp-name: io.github.abhishekash/mcp-trace-inspector -->
4
+
5
+ [![CI](https://github.com/abhishekash/mcp-trace-inspector/actions/workflows/ci.yml/badge.svg)](https://github.com/abhishekash/mcp-trace-inspector/actions/workflows/ci.yml) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
6
+
7
+ mcp-trace-inspector is a small, local-first stdio MCP server for querying JSONL
8
+ OpenTelemetry spans emitted by agent runs. It exposes focused queries for
9
+ run summaries, tool failures, approvals, activity, and comparisons instead of
10
+ requiring an application-specific dashboard.
11
+
12
+ It pairs with [agent-harness](https://github.com/abhishekash/agent-harness),
13
+ but the reader is format-simple: any JSONL of OTel-shaped spans works. The
14
+ project's concrete origin was a shell-boundary regression: the harness blocked
15
+ `cat ../outside.txt`, but the old trace recorded only that `run_shell` was
16
+ called, not the returned diagnostic. mcp-trace-inspector and the harness now preserve and
17
+ query that bounded error.
18
+
19
+ ## AI-native use cases
20
+
21
+ | Question during an agent run | MCP tool | Evidence returned |
22
+ |---|---|---|
23
+ | "Why did yesterday's run stall?" | `list_runs` → `slowest_spans` | Run IDs and the longest model or tool spans. |
24
+ | "Did the agent act after I denied the write?" | `approval_log` → `span_tree` | The recorded decision and subsequent execution path. |
25
+ | "How many model tokens did this run use?" | `token_usage` → `span_tree` | Run-level usage totals and the span tree for context. |
26
+ | "Which tool is failing or timing out?" | `failure_report` / `tool_stats` | Redacted diagnostics, error rates, denials, and p95 latency. |
27
+ | "Who/what was allowed to act?" | `security_audit` | Caller, tenant, server provenance, risk, and missing-evidence findings. |
28
+ | "What is happening in the run right now?" | `recent_activity` | Cursor-based polling of newly written spans. |
29
+ | "Did this model/version regress?" | `compare_runs` | Cost, latency, tokens, tool calls, and failure deltas. |
30
+
31
+ The tools read stored traces and can poll files being written, but they do not push events or infer intent from the final answer. Start with the [installation and user guide](docs/user-guide.md), then see the [real trace fixture](examples/example_trace.jsonl) and the [tool descriptions](src/mcp_trace/server.py) for the query contract.
32
+
33
+ ## Install & run
34
+
35
+ ```bash
36
+ uvx mcp-trace-inspector --trace-dir ./traces
37
+ # or, for local development:
38
+ git clone https://github.com/abhishekash/mcp-trace-inspector
39
+ cd mcp-trace-inspector && uv pip install -e .
40
+ mcp-trace-inspector --trace-dir ./traces
41
+ ```
42
+
43
+ ## Client configuration
44
+
45
+ **Claude Desktop** (`claude_desktop_config.json`):
46
+
47
+ ```json
48
+ {
49
+ "mcpServers": {
50
+ "agent-traces": {
51
+ "command": "uvx",
52
+ "args": ["mcp-trace-inspector", "--trace-dir", "/path/to/traces"]
53
+ }
54
+ }
55
+ }
56
+ ```
57
+
58
+ **pi** (`~/.pi/agent/settings.json`):
59
+
60
+ ```json
61
+ {
62
+ "mcpServers": {
63
+ "agent-traces": {
64
+ "command": "uvx",
65
+ "args": ["mcp-trace-inspector", "--trace-dir", "/path/to/traces"]
66
+ }
67
+ }
68
+ }
69
+ ```
70
+
71
+ **agent-harness** (mounted as gated tools):
72
+
73
+ ```bash
74
+ harness run "Why was my last run slow?" --mcp "uvx mcp-trace-inspector --trace-dir ./traces"
75
+ ```
76
+
77
+ ## Tools
78
+
79
+ | Tool | Use it when |
80
+ |---|---|
81
+ | `list_runs` | Starting out — recent runs with task, model, duration, cost, decision counts |
82
+ | `run_summary` | One run at a glance (accepts trace-id prefix) |
83
+ | `span_tree` | "What did the agent actually do?" — nested shape of the run |
84
+ | `slowest_spans` | "Why was it slow?" — top-k spans by duration |
85
+ | `approval_log` | HITL audit — every approve/deny/**edit**, who decided, and *the rationale* |
86
+ | `token_usage` | Cost questions — aggregated across runs or per-run |
87
+ | `search_spans` | Find spans by tool name, file path, "denied", … |
88
+ | `failure_report` | Find actionable, bounded, redacted errors and failed tool calls. |
89
+ | `tool_stats` | Rank tools by volume, error rate, denials, and latency. |
90
+ | `security_audit` | Audit caller identity, tenant, server provenance, risk, and approval evidence. |
91
+ | `recent_activity` | Poll new spans with a cursor while a run is active. |
92
+ | `compare_runs` | Compare selected traces for regressions across models or versions. |
93
+
94
+ Tool descriptions are written as prompts (when-to-use, not just what-it-does) — descriptions are the interface for agent-called tools.
95
+
96
+ ## Example session (real fixture trace)
97
+
98
+ ```
99
+ > list_runs
100
+ [{ "trace_id": "f920798dd255…", "task": "Summarize the workspace's notes…",
101
+ "tool_calls": 4, "human_decisions": 2, "stopped_reason": "completed" }]
102
+
103
+ > approval_log
104
+ [{ "tool": "write_file", "decision": "approve", "approver": "auto", … },
105
+ { "tool": "run_shell", "decision": "approve", "approver": "auto", … }]
106
+ ```
107
+
108
+ ## Design
109
+
110
+ ```
111
+ traces/*.jsonl ──▶ mcp_trace.core (pure query functions, zero deps)
112
+ │
113
+ mcp_trace.server (thin MCPServer adapter, mcp 2.x)
114
+ │
115
+ stdio (NDJSON JSON-RPC)
116
+ ```
117
+
118
+ - **core/server split**: all logic is pure functions over parsed spans; the MCP layer only parses args and JSON-encodes results. Tests hit both layers.
119
+ - **trace_id prefixes**: agents fumble full 32-char hex ids; every tool accepts prefixes.
120
+ - **bounded output**: diagnostics are truncated and obvious credentials are redacted before query results leave the server.
121
+ - **honest cost totals**: `token_usage` returns `cost_known: false` and a null cost when any producer marks pricing as unavailable; unknown pricing is never presented as `$0`.
122
+ - **cursor polling**: `recent_activity` makes the snapshot reader useful while a run is still writing spans.
123
+ - The demo fixture ([`examples/example_trace.jsonl`](examples/example_trace.jsonl)) is a *real* agent-harness run, not hand-written.
124
+
125
+ ## Honest limitations
126
+
127
+ - stdio transport only (Streamable HTTP plus authenticated remote access is the next transport boundary)
128
+ - live polling re-reads snapshots; it is not a push subscription
129
+ - security audit can only report identity/provenance that the trace producer records
130
+ - read-only tools; trace mutation (annotations) is roadmap
131
+ - The Python query and server modules are available as `mcp_trace`; older import and command aliases remain for existing clients.
132
+
133
+ ## License
134
+
135
+ MIT
@@ -0,0 +1,204 @@
1
+ # mcp-trace-inspector user guide
2
+
3
+ mcp-trace-inspector lets an MCP client ask questions about an agent's recorded traces.
4
+ Point it at a directory of JSONL span records, connect it to an MCP client, and
5
+ ask about a run's tool calls, failures, approvals, timing, or token usage.
6
+
7
+ ## What it helps with
8
+
9
+ Use mcp-trace-inspector when you want to:
10
+
11
+ - Find a slow model or tool call without reading every trace line.
12
+ - See recorded tool failures and bounded diagnostic messages.
13
+ - Review approval decisions, including denials and edited calls.
14
+ - Compare recorded latency, tokens, tool calls, and failures across runs.
15
+ - Keep traces on your own machine and query them from an MCP-capable client.
16
+
17
+ mcp-trace-inspector is a read-only trace viewer. It does not run, change, retry, or stop
18
+ the agent being observed. Live activity is returned by polling the trace files;
19
+ there is no push stream. Results describe evidence in the traces. Missing
20
+ identity or approval fields mean the producer did not record that evidence;
21
+ they do not prove a person or policy authorized an action.
22
+
23
+ ## Requirements
24
+
25
+ - Python 3.11 or newer.
26
+ - An MCP client that can launch a local stdio server.
27
+ - JSONL traces in the project's OTel-shaped span format. The reader expects each
28
+ line to contain a span with `trace_id`, `span_id`, `name`,
29
+ `start_unix_nano`, `end_unix_nano`, `attributes`, and, where available,
30
+ `parent_span_id`, `status`, and `events`. Tool, model, and approval details
31
+ depend on the attributes your trace producer records.
32
+
33
+ The bundled example trace works immediately. Other producers may need an
34
+ export adapter to map their OTel export format into these JSONL span records.
35
+
36
+ ## Install and start
37
+
38
+ The simplest option is `uvx`, which runs the published package without a
39
+ project checkout:
40
+
41
+ ```bash
42
+ uvx --from mcp-trace-inspector==0.3.0 mcp-trace-inspector --trace-dir /absolute/path/to/traces
43
+ ```
44
+
45
+ The server speaks MCP over standard input and output, so this command waits for
46
+ an MCP client. Its startup message goes to standard error. To use a different
47
+ trace directory, change `/absolute/path/to/traces` to the directory containing
48
+ your `.jsonl` files. Relative paths are resolved from the server's working
49
+ directory.
50
+
51
+ For a local development install:
52
+
53
+ ```bash
54
+ git clone https://github.com/abhishekash/mcp-trace-inspector.git
55
+ cd mcp-trace-inspector
56
+ uv pip install -e .
57
+ mcp-trace-inspector --trace-dir /absolute/path/to/traces
58
+ ```
59
+
60
+ You can also set `MCP_TRACE_DIR` and omit `--trace-dir`:
61
+
62
+ ```bash
63
+ MCP_TRACE_DIR=/absolute/path/to/traces uvx --from mcp-trace-inspector==0.3.0 mcp-trace-inspector
64
+ ```
65
+
66
+ The server is local and read-only. Connecting an MCP client gives that client
67
+ access to trace-derived information, including task text and recorded tool
68
+ diagnostics. Choose a trace directory appropriate for the client that will
69
+ query it.
70
+
71
+ ## Connect an MCP client
72
+
73
+ Configure the client to launch `uvx` with the package and trace directory.
74
+ Restart or reload its MCP connections after saving the configuration.
75
+
76
+ For clients using the `mcpServers` JSON format, the entry looks like this:
77
+
78
+ ```json
79
+ {
80
+ "mcpServers": {
81
+ "mcp-trace-inspector": {
82
+ "command": "uvx",
83
+ "args": [
84
+ "--from",
85
+ "mcp-trace-inspector==0.3.0",
86
+ "mcp-trace-inspector",
87
+ "--trace-dir",
88
+ "/absolute/path/to/traces"
89
+ ]
90
+ }
91
+ }
92
+ }
93
+ ```
94
+
95
+ Use the configuration file and field names documented by your MCP client. For
96
+ example, clients can place MCP server entries in user-level or project-level
97
+ settings. Use an absolute trace path so the server does not depend on the
98
+ client's working directory.
99
+
100
+ With the mcp-trace-inspector repository checked out locally, run the server directly:
101
+
102
+ ```json
103
+ {
104
+ "mcpServers": {
105
+ "mcp-trace-inspector": {
106
+ "command": "/absolute/path/to/mcp-trace-inspector/.venv/bin/mcp-trace-inspector",
107
+ "args": ["--trace-dir", "/absolute/path/to/traces"]
108
+ }
109
+ }
110
+ }
111
+ ```
112
+
113
+ On Windows, use the executable path from your virtual environment, commonly
114
+ `C:\\path\\to\\mcp-trace-inspector\\.venv\\Scripts\\mcp-trace-inspector.exe`.
115
+
116
+ ## First questions to ask
117
+
118
+ Start with `list_runs` to find a recent trace. It returns a shortened trace ID;
119
+ the other tools accept ID prefixes.
120
+
121
+ Try these prompts in your MCP client:
122
+
123
+ ```text
124
+ List the recent runs and tell me which one had a failure.
125
+ For trace <prefix>, show the tool failures and their diagnostics.
126
+ For trace <prefix>, show each approval decision and why it was made.
127
+ For trace <prefix>, what were the three slowest spans?
128
+ Compare traces <prefix-a> and <prefix-b>. Did tokens, latency, or failures change?
129
+ ```
130
+
131
+ The model chooses which tools to call. Ask for the trace IDs and returned
132
+ evidence in its answer so you can check the result against the source data.
133
+
134
+ ## Tool reference
135
+
136
+ | Tool | What it returns | Useful question |
137
+ |---|---|---|
138
+ | `list_runs` | Recent run summaries with shortened trace IDs | “What ran recently?” |
139
+ | `run_summary` | Task, model, duration, calls, tokens, cost, outcome | “What happened in this run?” |
140
+ | `span_tree` | Nested spans, durations, selected attributes, event names | “What was the execution sequence?” |
141
+ | `slowest_spans` | Longest spans across runs or one trace | “Where did this run spend time?” |
142
+ | `approval_log` | Decision, approver, rationale, and whether an edit was recorded | “What did the reviewer approve or deny?” |
143
+ | `token_usage` | Token totals and cost when producer pricing is known | “How much model usage did these runs record?” |
144
+ | `search_spans` | Spans whose names or attributes contain a search phrase | “Find calls involving `write_file`.” |
145
+ | `failure_report` | Bounded, redacted errors and failed calls | “Why did this tool fail?” |
146
+ | `tool_stats` | Call volume, errors, denials, and latency by tool | “Which integration has the most errors?” |
147
+ | `security_audit` | Recorded identity, tenant, server, risk, and approval evidence | “Which provenance fields were recorded?” |
148
+ | `recent_activity` | Newly written spans after a polling cursor | “What new spans appeared?” |
149
+ | `compare_runs` | Per-run metrics and deltas from the first trace | “What changed between these runs?” |
150
+
151
+ ## Connect agent-harness
152
+
153
+ mcp-trace-inspector can run as a stdio MCP server mounted by `agent-harness`:
154
+
155
+ ```bash
156
+ harness run "Inspect the last run and explain its failure" \
157
+ --mcp "uvx --from mcp-trace-inspector==0.3.0 mcp-trace-inspector --trace-dir ./traces" \
158
+ --approve cli
159
+ ```
160
+
161
+ The harness treats mounted MCP tools as execute-risk by default, so its
162
+ interactive approval mode asks before invoking them. Read the harness's MCP
163
+ and approval documentation for its current policy options.
164
+
165
+ ## Troubleshooting
166
+
167
+ **The client says the server is unavailable.** Confirm that `uvx` is installed,
168
+ the package can be fetched, and the configured trace path exists. Reload the
169
+ client's MCP configuration and check its server logs; the server writes its
170
+ startup message to standard error.
171
+
172
+ **No runs appear.** Check that the path points to a directory
173
+ containing `.jsonl` files. The server searches subdirectories. The included
174
+ example is at `examples/example_trace.jsonl` in the repository.
175
+
176
+ **Runs appear, but model or approval details are missing.** The server only
177
+ reports fields present in the trace. Check whether your producer exports model
178
+ names, token counts, cost-known status, tool call spans, and approval events.
179
+ Missing fields are not inferred from the final answer.
180
+
181
+ **The JSONL is rejected.** Each line must be a JSON object representing one
182
+ span with the required trace ID, span ID, name, and start and end timestamps.
183
+ Ask your tracing exporter to produce one span object per line.
184
+
185
+ ## Privacy and limits
186
+
187
+ mcp-trace-inspector processes the files in the configured directory and returns selected
188
+ trace fields to the connected MCP client. Failure messages are bounded and
189
+ credential patterns are redacted, but redaction is not a guarantee that every
190
+ private value is removed. Review trace contents and client access before using
191
+ it with sensitive data.
192
+
193
+ The current server uses local stdio transport. It polls stored files for new
194
+ spans rather than receiving push events. `security_audit` summarizes recorded
195
+ identity and provenance; it does not independently verify them. Cost totals
196
+ are unknown when the trace producer does not provide reliable pricing.
197
+
198
+ ## Example data
199
+
200
+ Try mcp-trace-inspector against the checked-in
201
+ [example trace](../examples/example_trace.jsonl). It contains a run emitted by
202
+ `agent-harness` and can be queried using the tools above.
203
+
204
+ [Back to the README](../README.md)
@@ -0,0 +1,15 @@
1
+ {"trace_id": "f920798dd2558fcb84f9977736432a8b", "span_id": "047527cfe5a06b79", "parent_span_id": "b3870190725e6c0a", "name": "llm.complete", "start_unix_nano": 1791446657381364374, "end_unix_nano": 1791446657381395204, "status": "UNSET", "attributes": {"llm.model": "scripted", "llm.usage.input_tokens": 92, "llm.usage.output_tokens": 9, "llm.cost_usd": 0.0}, "events": []}
2
+ {"trace_id": "f920798dd2558fcb84f9977736432a8b", "span_id": "cf9ec887533385eb", "parent_span_id": "b3870190725e6c0a", "name": "tool.call", "start_unix_nano": 1791446657381557076, "end_unix_nano": 1791446657381753320, "status": "UNSET", "attributes": {"tool.name": "list_dir", "tool.risk": "read", "tool.call_id": "call_1d4b88534934", "tool.duration_ms": 0.17095799557864666}, "events": []}
3
+ {"trace_id": "f920798dd2558fcb84f9977736432a8b", "span_id": "b3870190725e6c0a", "parent_span_id": "aec12b5c51ce2580", "name": "agent.step", "start_unix_nano": 1791446657381336939, "end_unix_nano": 1791446657381830109, "status": "UNSET", "attributes": {"step.index": 1}, "events": []}
4
+ {"trace_id": "f920798dd2558fcb84f9977736432a8b", "span_id": "3a1883f304c6810a", "parent_span_id": "060258fcbbc7b4b2", "name": "llm.complete", "start_unix_nano": 1791446657381913540, "end_unix_nano": 1791446657381938066, "status": "UNSET", "attributes": {"llm.model": "scripted", "llm.usage.input_tokens": 94, "llm.usage.output_tokens": 9, "llm.cost_usd": 0.0}, "events": []}
5
+ {"trace_id": "f920798dd2558fcb84f9977736432a8b", "span_id": "ec96e325ccf2812b", "parent_span_id": "060258fcbbc7b4b2", "name": "tool.call", "start_unix_nano": 1791446657382001356, "end_unix_nano": 1791446657382097431, "status": "UNSET", "attributes": {"tool.name": "read_file", "tool.risk": "read", "tool.call_id": "call_e67e16d926b0", "tool.duration_ms": 0.08226605132222176}, "events": []}
6
+ {"trace_id": "f920798dd2558fcb84f9977736432a8b", "span_id": "060258fcbbc7b4b2", "parent_span_id": "aec12b5c51ce2580", "name": "agent.step", "start_unix_nano": 1791446657381892888, "end_unix_nano": 1791446657382146922, "status": "UNSET", "attributes": {"step.index": 2}, "events": []}
7
+ {"trace_id": "f920798dd2558fcb84f9977736432a8b", "span_id": "b07c48a63a82f767", "parent_span_id": "0bd568f46e01fc65", "name": "llm.complete", "start_unix_nano": 1791446657382220834, "end_unix_nano": 1791446657382241746, "status": "UNSET", "attributes": {"llm.model": "scripted", "llm.usage.input_tokens": 125, "llm.usage.output_tokens": 9, "llm.cost_usd": 0.0}, "events": []}
8
+ {"trace_id": "f920798dd2558fcb84f9977736432a8b", "span_id": "d6bc66fcba6ba958", "parent_span_id": "0bd568f46e01fc65", "name": "tool.call", "start_unix_nano": 1791446657382294447, "end_unix_nano": 1791446657382449645, "status": "UNSET", "attributes": {"tool.name": "write_file", "tool.risk": "write", "tool.call_id": "call_8a5a534020b7", "hitl.required": true, "tool.duration_ms": 0.11282693594694138}, "events": [{"name": "hitl.decision", "time_unix_nano": 1791446657382326440, "attributes": {"hitl.decision": "approve", "hitl.approver": "auto", "hitl.rationale": "auto-approved (unattended run)"}}]}
9
+ {"trace_id": "f920798dd2558fcb84f9977736432a8b", "span_id": "0bd568f46e01fc65", "parent_span_id": "aec12b5c51ce2580", "name": "agent.step", "start_unix_nano": 1791446657382193796, "end_unix_nano": 1791446657382508737, "status": "UNSET", "attributes": {"step.index": 3}, "events": []}
10
+ {"trace_id": "f920798dd2558fcb84f9977736432a8b", "span_id": "70d5591a02be91d6", "parent_span_id": "e83a45284010e5c7", "name": "llm.complete", "start_unix_nano": 1791446657382582514, "end_unix_nano": 1791446657382605733, "status": "UNSET", "attributes": {"llm.model": "scripted", "llm.usage.input_tokens": 132, "llm.usage.output_tokens": 9, "llm.cost_usd": 0.0}, "events": []}
11
+ {"trace_id": "f920798dd2558fcb84f9977736432a8b", "span_id": "0f176ff0f2ed3f5f", "parent_span_id": "e83a45284010e5c7", "name": "tool.call", "start_unix_nano": 1791446657382663037, "end_unix_nano": 1791446657384990883, "status": "UNSET", "attributes": {"tool.name": "run_shell", "tool.risk": "execute", "tool.call_id": "call_9a19cc1b4ead", "hitl.required": true, "tool.duration_ms": 2.2949520498514175}, "events": [{"name": "hitl.decision", "time_unix_nano": 1791446657382685591, "attributes": {"hitl.decision": "approve", "hitl.approver": "auto", "hitl.rationale": "auto-approved (unattended run)"}}]}
12
+ {"trace_id": "f920798dd2558fcb84f9977736432a8b", "span_id": "e83a45284010e5c7", "parent_span_id": "aec12b5c51ce2580", "name": "agent.step", "start_unix_nano": 1791446657382563796, "end_unix_nano": 1791446657385069850, "status": "UNSET", "attributes": {"step.index": 4}, "events": []}
13
+ {"trace_id": "f920798dd2558fcb84f9977736432a8b", "span_id": "7e5dff5291ab7ee6", "parent_span_id": "7523732e099104c7", "name": "llm.complete", "start_unix_nano": 1791446657385145680, "end_unix_nano": 1791446657385168372, "status": "UNSET", "attributes": {"llm.model": "scripted", "llm.usage.input_tokens": 196, "llm.usage.output_tokens": 14, "llm.cost_usd": 0.0}, "events": []}
14
+ {"trace_id": "f920798dd2558fcb84f9977736432a8b", "span_id": "7523732e099104c7", "parent_span_id": "aec12b5c51ce2580", "name": "agent.step", "start_unix_nano": 1791446657385127184, "end_unix_nano": 1791446657385204759, "status": "UNSET", "attributes": {"step.index": 5}, "events": []}
15
+ {"trace_id": "f920798dd2558fcb84f9977736432a8b", "span_id": "aec12b5c51ce2580", "parent_span_id": null, "name": "agent.run", "start_unix_nano": 1791446657381269974, "end_unix_nano": 1791446657385251046, "status": "UNSET", "attributes": {"agent.task": "Summarize the workspace's notes into SUMMARY.md, then verify it with ls", "agent.max_steps": 12, "agent.tools": ["list_dir", "read_file", "run_shell", "write_file"], "agent.skills": [], "llm.model": "scripted", "agent.steps": 5, "agent.stopped_reason": "completed", "agent.usage.input_tokens": 639, "agent.usage.output_tokens": 50, "agent.cost_usd": 0.0, "agent.approvals": 2}, "events": []}