MCP server for context-window observability: capture and query exactly what an LLM agent saw at every step.
Project description
ctx-capture
See exactly what your LLM agent saw, at any step, byte-for-byte.
An MCP server for context-window observability. It captures the exact model input at every step of an agent run — including what a tool actually returned versus what got inserted into the next call after truncation — and lets any MCP client query it directly.
Agent failures are usually context failures, not reasoning failures: a tool result got truncated before it reached the model, a token budget overflowed and the framework quietly cut messages from the middle, a retry duplicated a call the model never saw resolve. Answering "what did the model actually see at step 12" today means archaeology across app logs, framework debug output, and provider dashboards. ctx-capture exists so that question has a direct answer.
Features
- Byte-exact per-step capture — the exact provider-native message array as sent, not a reshaped/normalized approximation.
- Pre- and post-truncation tool results —
result_as_returnedvs.result_as_inserted, so truncation is detectable, not just guessed at. - Two capture paths: OpenAI-compatible
chat.completionsclients and Anthropic's Messages API, both duck-typed (no hard SDK dependency) and both gated by the same fidelity test. - 5 MCP tools + 2 resources —
list_traces,get_step_context,diff_step_contexts,find_context_anomalies,get_token_accounting, plustrace://resources for browsing clients. All 5 tools declareoutputSchemaand returnstructuredContent. - Size-capped, paginated responses — every tool response is bounded (default 50 KB); an
oversized payload gets a
resource_uripointer instead of ever blowing up a client's context. - SQLite by default, zero external dependency —
pip install ctx-capturegives you a working MCP server with nothing else to stand up. - CI-blocking fidelity test — the schema's acceptance test, not an optional check: captured
messagesmust be byte-identical, after canonical JSON serialization, to what actually left application code.
Setup
pip install ctx-capture
# or, without installing: uvx ctx-capture --db my_agent.db
Run the server (SQLite-backed, zero config):
python -m ctx_capture.mcp --db my_agent.db
Point an MCP client at it — e.g. Claude Desktop's claude_desktop_config.json:
{
"mcpServers": {
"ctx-capture": {
"command": "ctx-capture",
"args": ["--db", "/absolute/path/to/my_agent.db"]
}
}
}
Instrument your agent — a few lines, either capture path:
from ctx_capture.capture import TraceRecorder
from ctx_capture.storage import SQLiteTraceRepository
recorder = TraceRecorder(agent_name="my-agent")
# OpenAI-compatible client — call sites unchanged
client = recorder.wrap_client(my_openai_compatible_client)
# ...or an Anthropic client — call sites unchanged
client = recorder.wrap_anthropic_client(my_anthropic_client)
recorder.begin_step()
response = client.chat.completions.create(model="...", messages=messages) # or client.messages.create(...)
recorder.end_step()
SQLiteTraceRepository("my_agent.db").save(recorder.trace)
Then, from your MCP client: "list recent traces for my-agent" or "show me exactly what the model
saw at step 12" — the client calls list_traces / get_step_context for you.
For a shared/remote deployment: ctx-capture --transport http --port 8000 --bearer-token <token> (see docs/DESIGN.md § Transport for why stdio is the default and HTTP
is opt-in).
Tool reference
| Tool | Answers |
|---|---|
list_traces(agent_name?, since?, until?, has_anomalies?, tags?, limit?, cursor?) |
"What traces have been captured?" — cursor-paginated. |
get_step_context(trace_id, step_index, max_bytes?, cursor?) |
"What did the model see at step N, exactly?" — the byte-exact reconstructed input. |
diff_step_contexts(trace_id, step_a, step_b) |
"What changed in the model's context between two steps?" |
find_context_anomalies(trace_id, types?) |
"Where did something go wrong?" — truncations, budget overflows, dropped messages, tool-result mismatches. |
get_token_accounting(trace_id, group_by?) |
"Where did the tokens/cost go?" — grouped by step, tool, or role. |
Plus 2 resources for browsing clients: trace://{trace_id} (metadata + step index) and
trace://{trace_id}/step/{step_index} (full, unpaginated step detail).
The fidelity test
The project's one non-negotiable test, CI-blocking forever
(tests/test_fidelity.py,
tests/test_fidelity_anthropic.py): capture a running agent's
model input, reconstruct it from storage, and assert the reconstructed messages array is
byte-identical, after canonical JSON serialization, to what an independent observation point
saw actually leave application code. If this test can't pass, the schema has failed at the one
thing it exists to do.
Capture overhead is measured, not assumed: ~0.017ms added per instrumented model call
(in-process benchmark, wrapper only — see docs/RESULTS.md, reproduce with
python scripts/bench_overhead.py).
ctx-capture vs. Langfuse / LangSmith
| ctx-capture | Langfuse / LangSmith | |
|---|---|---|
| Core question | "What did the model see, byte-for-byte, at step N?" | "What happened across this run?" |
| Fidelity | Provider-native messages captured verbatim; tool results captured both pre- and post-truncation | Traces are typically reshaped for display; framework-level truncation is usually invisible |
| Interface | MCP tools/resources — built for an agent or MCP client to query directly | Web dashboard + SDK — built for a human browsing a UI |
| Evals | Not a goal (see Non-goals) | Core feature |
| Dashboards/UI | None — MCP clients are the UI | Mature, first-class |
| Multi-agent trace stitching | Not in v1 | Yes |
| Storage | SQLite (zero-dep) or Postgres, self-hosted | Hosted or self-hosted, Postgres-backed service |
Use Langfuse/LangSmith for broad observability, evals, cost dashboards, and team-wide trace review. Use ctx-capture when you need to prove, precisely, what one model call actually saw — usually while debugging a specific failure, from inside an MCP-capable client.
Non-goals
- No dashboards/UI — MCP clients are the UI; we're not rebuilding Langfuse's trace viewer.
- No eval features — evals are a mature, separate category with a different workflow.
- No multi-agent trace stitching in v1 — single-agent step fidelity first.
- No prompt management — that's a build-time concern; this is runtime observability.
See docs/DESIGN.md § Non-goals for the reasoning behind each.
Schema stability
Every trace is written with a pinned schema_version. Within a major version, changes are
additive-only — new optional fields, never a repurposed or removed one — so any 1.x reader
can read any 1.x trace. A breaking change requires a major version bump and a migration script;
servers refuse (not silently coerce) traces with an unsupported major version. See
docs/DESIGN.md § The schema for the full schema and versioning rationale.
Roadmap
- OTel span-ingestion adapter — an additive way to bring in traces from OTel GenAI instrumentation, without making it the primary (lower-fidelity) capture path.
- Redaction hook — an opt-in
redact(message) -> messagehook at capture time. Not yet built; until it is, treat captured trace data as sensitive by default (it faithfully contains whatever the agent saw, PII/secrets included). - Postgres backend — the
TraceRepositoryinterface is ready for it; the implementation isn't written yet. - OAuth for HTTP transport — the current HTTP auth is a static bearer token, which is the minimum viable gate, not the final answer for multi-tenant deployments.
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ctx_capture-0.2.0.tar.gz.
File metadata
- Download URL: ctx_capture-0.2.0.tar.gz
- Upload date:
- Size: 28.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3d061ac20956e7d1af2351753c48c9de48b92ea369e4a6ae7f2e558166fa2c87
|
|
| MD5 |
0b4071db47bd161e1391586ba15825df
|
|
| BLAKE2b-256 |
8cad1e60a487a881a94e67a0b02e312159e2b757c808655affc9945792d58b26
|
Provenance
The following attestation bundles were made for ctx_capture-0.2.0.tar.gz:
Publisher:
release.yml on SathvikNayak123/ctx-capture
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ctx_capture-0.2.0.tar.gz -
Subject digest:
3d061ac20956e7d1af2351753c48c9de48b92ea369e4a6ae7f2e558166fa2c87 - Sigstore transparency entry: 2172518955
- Sigstore integration time:
-
Permalink:
SathvikNayak123/ctx-capture@ab4c28a3bac850c8a2dbc4353bffb51e9cd473f7 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/SathvikNayak123
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@ab4c28a3bac850c8a2dbc4353bffb51e9cd473f7 -
Trigger Event:
push
-
Statement type:
File details
Details for the file ctx_capture-0.2.0-py3-none-any.whl.
File metadata
- Download URL: ctx_capture-0.2.0-py3-none-any.whl
- Upload date:
- Size: 24.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dff003c00910be660e502e0a7102f805d6072eaf85f02e0659df80d70937386c
|
|
| MD5 |
fcb9ae7283880b8f29b61053b83a685a
|
|
| BLAKE2b-256 |
87b4aa8c56d49ac7888fa7bc56f111af2eea95cb06be5c27f2cfd1928bd2c30f
|
Provenance
The following attestation bundles were made for ctx_capture-0.2.0-py3-none-any.whl:
Publisher:
release.yml on SathvikNayak123/ctx-capture
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ctx_capture-0.2.0-py3-none-any.whl -
Subject digest:
dff003c00910be660e502e0a7102f805d6072eaf85f02e0659df80d70937386c - Sigstore transparency entry: 2172518974
- Sigstore integration time:
-
Permalink:
SathvikNayak123/ctx-capture@ab4c28a3bac850c8a2dbc4353bffb51e9cd473f7 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/SathvikNayak123
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@ab4c28a3bac850c8a2dbc4353bffb51e9cd473f7 -
Trigger Event:
push
-
Statement type: