Give any agent eyes on everything.

A local APM for coding agents. Point Claude, Cursor, or Codex at one MCP, and they inspect traces, SQL, and logs from your running app.

Read docs

An agent that writes code without seeing the running system is guessing. LocalTrace makes every signal, from any SDK, look the same: one local store, one MCP, so any agent can inspect what actually happened.

Agent visibility

The running system, not just the source.

Connect the SDKs you already use and LocalTrace still shows the model a single MCP. It lists traces, pulls SQL, and reads logs only when the investigation needs them.

Without LocalTrace the agent only sees pasted source and a terminal line. With LocalTrace it inspects traces, SQL, and logs over MCP.

Without LocalTrace
The agentsource · pasted
YouPOST /checkout is 500ing. This is the handler:
src/routes/checkout.tspasted
14export async function POST(req) {
15 const cart = await db.cart.findUnique({ where: { id } })
16 const tax = await taxClient.quote(cart)
17 const pay = await stripe.charges.create({ amount })
18 return Response.json({ ok: true })
19}
Three awaits, no try/catch, nothing timed. Could be tax, Stripe, or a null cart.
Paste a log?
Youthis is all it printed
terminalpasted
▲ Next.js 15.2.4POST /api/checkout 500 in 842ms
Still a 500 in 842ms. No stack, no upstream status.
With LocalTrace
The agent1 MCP · compact
YouPOST /checkout is 500ing
MCPhttp://127.0.0.1:4318/mcp
list_facets()
list_traces(since_minutes: 15, status: "error")
get_trace("8f2c…")
POST/checkout842ms500
prismacart.findUnique12ms
httptax.quote611ms503
httpstripe.charges—cancelled
get_trace_sql("8f2c…")
SELECT id, total FROM carts WHERE id = $112ms
get_trace_logs("8f2c…")
errortax upstream 503
Fix taxClient.quote. Repeat.
What you get

The model reasons. LocalTrace handles the rest.

01

Native ingest

OTLP HTTP and gRPC, Sentry envelopes, Datadog traces and metrics. Point the SDK you already have at localhost. No LocalTrace SDK.

02

MCP is the product

Cursor, Claude, Codex, or anything that speaks MCP. Compact payloads, since_minutes, and a playbook in server instructions.

03

See the slow query

One place to open a trace, pull the SQL, and read the correlated logs. The agent does this. You can watch it in the UI if you want.

POST /checkout842ms
prisma findUnique12ms
http tax.quote611ms
http stripe—
04

SQLite on this machine

Traces, logs, and metrics land in one file. No cluster, no account, nothing leaves the box. Wipe and re-ingest when the schema moves.

05

Typed span overviews

SQL, Redis, Mongo, Prisma, S3, tRPC, HTTP. The API classifies the span. The UI and the agent both get type plus payload_path.

06

Same data, every surface

MCP, HTTP API, optional UI. The agent does not need the dashboard. You get one if you want to look.

Why we built it

Your agent should be able to reach the running system in a way that isn't scary. Most setups make you choose between a dashboard the model cannot use, or pasting logs into chat.

LocalTrace doesn't care which SDK you already have. Once telemetry is in that one store, the agent can inspect it the same way every time. That is the whole idea: make the productive path the local path.

Get started

Pick your path.

Docker

any agent

Paste this into any agent. It starts the container — UI, OTLP/HTTP, Sentry, Datadog, and MCP on :4318, gRPC on :4317 — and wires ingest plus MCP.

Help me set up LocalTrace so you can inspect traces, SQL, and logs from the app we're working on.

LocalTrace is a local APM for coding agents. It sits on this machine, ingests OpenTelemetry / Sentry / Datadog (no LocalTrace SDK), stores telemetry in SQLite, and exposes it over MCP at http://127.0.0.1:4318/mcp. The UI at http://localhost:4318 is optional — MCP is the product.

How to run it (Docker, recommended):

docker run --rm -p 4318:4318 -p 4317:4317 \
  -v localtrace-data:/app/data \
  ghcr.io/skaznowiecki/localtrace:0.4.0

Point the app's existing SDK at localhost:

- OpenTelemetry HTTP: OTEL_EXPORTER_OTLP_ENDPOINT=http://127.0.0.1:4318
  and OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
- OpenTelemetry gRPC: OTEL_EXPORTER_OTLP_ENDPOINT=http://127.0.0.1:4317
- Sentry: SENTRY_DSN=http://local@127.0.0.1:4318/1
- Datadog: DD_TRACE_AGENT_URL=http://127.0.0.1:4318

Wire MCP for the client you are running in.

Cursor (.cursor/mcp.json):
{
  "mcpServers": {
    "localtrace": {
      "url": "http://127.0.0.1:4318/mcp"
    }
  }
}

Claude Code (.mcp.json):
{
  "mcpServers": {
    "localtrace": {
      "type": "http",
      "url": "http://127.0.0.1:4318/mcp"
    }
  }
}

Playbook once it's up:
1. list_facets / list_log_facets before inventing filter values
2. Prefer since_minutes over RFC3339 since
3. get_trace is overview (no attributes). get_span for attributes; get_trace_sql / get_trace_spans for typed payloads; get_trace_logs for logs
4. Do not call get_trace in a loop over list_traces
5. Do not attach a raw SQLite MCP — use LocalTrace's server

Docs: https://localtrace.sh/docs

Cursor

.cursor/mcp.json

Paste this into Cursor. It runs LocalTrace, points this app at localhost, and writes Streamable HTTP MCP config.

Help me set up LocalTrace so you can inspect traces, SQL, and logs from the app we're working on.

LocalTrace is a local APM for coding agents. It sits on this machine, ingests OpenTelemetry / Sentry / Datadog (no LocalTrace SDK), stores telemetry in SQLite, and exposes it over MCP at http://127.0.0.1:4318/mcp. The UI at http://localhost:4318 is optional — MCP is the product.

How to run it (Docker, recommended):

docker run --rm -p 4318:4318 -p 4317:4317 \
  -v localtrace-data:/app/data \
  ghcr.io/skaznowiecki/localtrace:0.4.0

Point the app's existing SDK at localhost:

- OpenTelemetry HTTP: OTEL_EXPORTER_OTLP_ENDPOINT=http://127.0.0.1:4318
  and OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
- OpenTelemetry gRPC: OTEL_EXPORTER_OTLP_ENDPOINT=http://127.0.0.1:4317
- Sentry: SENTRY_DSN=http://local@127.0.0.1:4318/1
- Datadog: DD_TRACE_AGENT_URL=http://127.0.0.1:4318

Wire MCP in this Cursor project (.cursor/mcp.json):
{
  "mcpServers": {
    "localtrace": {
      "url": "http://127.0.0.1:4318/mcp"
    }
  }
}

After writing the file, tell me to reload MCP so you can call the tools.

Playbook once it's up:
1. list_facets / list_log_facets before inventing filter values
2. Prefer since_minutes over RFC3339 since
3. get_trace is overview (no attributes). get_span for attributes; get_trace_sql / get_trace_spans for typed payloads; get_trace_logs for logs
4. Do not call get_trace in a loop over list_traces
5. Do not attach a raw SQLite MCP — use LocalTrace's server

Docs: https://localtrace.sh/docs

Claude Code

.mcp.json

Paste this into Claude Code. Same setup, typed HTTP transport in .mcp.json. Then let the agent investigate.

Help me set up LocalTrace so you can inspect traces, SQL, and logs from the app we're working on.

LocalTrace is a local APM for coding agents. It sits on this machine, ingests OpenTelemetry / Sentry / Datadog (no LocalTrace SDK), stores telemetry in SQLite, and exposes it over MCP at http://127.0.0.1:4318/mcp. The UI at http://localhost:4318 is optional — MCP is the product.

How to run it (Docker, recommended):

docker run --rm -p 4318:4318 -p 4317:4317 \
  -v localtrace-data:/app/data \
  ghcr.io/skaznowiecki/localtrace:0.4.0

Point the app's existing SDK at localhost:

- OpenTelemetry HTTP: OTEL_EXPORTER_OTLP_ENDPOINT=http://127.0.0.1:4318
  and OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
- OpenTelemetry gRPC: OTEL_EXPORTER_OTLP_ENDPOINT=http://127.0.0.1:4317
- Sentry: SENTRY_DSN=http://local@127.0.0.1:4318/1
- Datadog: DD_TRACE_AGENT_URL=http://127.0.0.1:4318

Wire MCP in this Claude Code project (.mcp.json). Use typed HTTP transport:
{
  "mcpServers": {
    "localtrace": {
      "type": "http",
      "url": "http://127.0.0.1:4318/mcp"
    }
  }
}

After writing the file, tell me to restart Claude Code or reconnect MCP so you can call the tools.

Playbook once it's up:
1. list_facets / list_log_facets before inventing filter values
2. Prefer since_minutes over RFC3339 since
3. get_trace is overview (no attributes). get_span for attributes; get_trace_sql / get_trace_spans for typed payloads; get_trace_logs for logs
4. Do not call get_trace in a loop over list_traces
5. Do not attach a raw SQLite MCP — use LocalTrace's server

Docs: https://localtrace.sh/docs

FAQ

Do I need a LocalTrace SDK?
No. Point OpenTelemetry, Sentry, or dd-trace at localhost. LocalTrace speaks the protocols your app already emits.
Where does the data live?
SQLite on this machine. Docker volume localtrace-data, or ./data/localtrace.db from source. Nothing is shipped to a cloud. Early and local-only — wipe and re-ingest when the schema changes. That is intentional.
What can call LocalTrace?
Any MCP client (Claude, Cursor, Codex, and others), the HTTP API, or the optional UI at localhost:4318. MCP is the primary interface.
How should an agent investigate a failure?
list_facets first. Prefer since_minutes. get_trace is overview — no attributes. get_span for attributes, get_trace_sql / get_trace_spans for typed payloads, get_trace_logs for logs. Do not loop get_trace over list_traces. Do not attach a raw SQLite MCP.
Is it open source?
Yes. MIT licensed. Run the Docker image, or develop from source with pnpm, Bun, and Just. Same process, one file, two ports.

Give your agent eyes on everything.

or read the docs →