Skip to content

INEcodes/Claude-Micro-Manager

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Claude Code Tool Tracker

Tracks every tool call Claude Code makes — captured by a PostToolUse HTTP hook, stored via FastAPI + SQLite, visualized in a live React dashboard, and queryable from inside Claude Code with /toolstats through an embedded MCP server. A Stop hook also prints a compact per-turn stats note automatically after each response (CLI + VS Code extension).

Architecture

Claude Code ──PostToolUse HTTP hook──▶ FastAPI /ingest/tool-event ──▶ DB (SQLite)
                                              │
                          ┌───────────────────┼────────────────────┐
                          ▼                   ▼                    ▼
                 REST /api/* + WS /ws    MCP server /mcp      shared aggregation
                          │              (mounted in the         service
                          ▼               same FastAPI app)
                 React dashboard         Claude Code connects
                 (charts + live feed)    via `claude mcp add`

Key design points:

  • Capture is a Claude Code hook, not the MCP server. An MCP server only runs when Claude calls one of its tools; it cannot observe tool calls. The four hooks (SessionStart, PreToolUse, PostToolUse, Stop) POST each event to the backend; the MCP server is a read-only query interface. The Stop hook targets /hooks/turn-summary, which also returns a per-turn stats note (see below).
  • Per-turn note after each response. The Stop hook's endpoint returns a Claude Code systemMessage summarizing the tools used in the just-finished turn plus running session totals. It is shown to you only — never fed back into the model — so there is no extra turn and no token cost, and it stays silent on tool-less turns. (Claude Code has no inline artifact panel; for a visual, keep the dashboard open.)
  • Fail-open by construction. Claude Code treats HTTP-hook connection failures, timeouts, and non-2xx responses as non-blocking — a down backend never stalls a session. The capture endpoint returns empty 2xx bodies so tracker output is never injected into the conversation; the Stop note endpoint returns only a user-facing systemMessage and falls back to an empty 2xx on any error. WebSocket broadcasts are fire-and-forget so a stuck dashboard can't delay a hook response.
  • One aggregation service (backend/app/aggregation.py) feeds the REST API, the WebSocket feed, and the MCP tools — the dashboard and /toolstats always agree.

Setup

Prerequisites: Python 3.12+, uv, Node 22+, Claude Code.

cd backend
cp .env.example .env      # edit TOOLTRACKER_TOKEN (default: dev-token)
uv sync
uv run uvicorn app.main:app --port 8000

Health check: curl http://localhost:8000/health

2. Install the capture hook

Merge the hooks block from hooks/settings.snippet.json into .claude/settings.json (team-wide) or .claude/settings.local.json (personal). The snippet reads the token from the environment Claude Code launches from:

setx TOOLTRACKER_TOKEN "dev-token"    # Windows; then restart the terminal
export TOOLTRACKER_TOKEN=dev-token    # macOS/Linux (add to shell profile)

Restart Claude Code — hooks are read at session start. From then on every tool call lands in the DB in real time. See hooks/README.md for details.

3. Frontend dashboard (http://localhost:5173)

cd frontend
npm install
npm run dev

Summary cards, calls-per-tool chart, timeline (minute/hour/day), most-touched files, a sessions table (click a row to filter everything to that session, including a session-detail panel), and a WebSocket live feed of tool calls as they happen.

4. Register the MCP server + /toolstats

claude mcp add --transport http tooltracker http://localhost:8000/mcp \
  --header "Authorization: Bearer $TOOLTRACKER_TOKEN"
claude mcp list    # → tooltracker: http://localhost:8000/mcp (HTTP) - ✓ Connected

Then type /toolstats in Claude Code (command file: .claude/commands/toolstats.md) for an inline overview of the current session. The MCP tools — get_session_summary, get_tool_stats, list_recent_calls, get_most_touched_files — are read-only and require the same bearer token.

API reference

Endpoint Description
POST /ingest/tool-event Hook ingestion (bearer token required)
POST /hooks/turn-summary Stop-hook per-turn note; returns a systemMessage (bearer token required)
GET /api/stats?session= Overview counters + per-tool stats
GET /api/sessions Recent sessions
GET /api/sessions/{id} Full session summary
GET /api/events?tool=&session=&limit= Recent tool calls
GET /api/files?session= Most-touched files
GET /api/timeline?bucket=minute|hour|day&session= Calls over time
WS /ws Live event push
/mcp MCP streamable-HTTP endpoint (bearer token required)

Docker

TOOLTRACKER_TOKEN=your-token docker compose up --build

Backend on :8000 (SQLite on a named volume), dashboard on :5173. The hook and claude mcp add URLs stay the same. (Compose files are provided but were authored on a machine without a running Docker daemon — expect to smoke-test the first build.)

Deploying to Railway (two services)

Both services deploy from this one repo — create two Railway services and point each at its own subdirectory.

Backend service

  1. Railway → New service → GitHub repo, pick this repo, and in Settings → Source set Root Directory to backend. Railway builds backend/Dockerfile and picks up backend/railway.json (healthcheck on /health).

  2. Settings → Networking → Generate Domain, target port 8000 (the container honors Railway's PORT if injected and falls back to 8000).

  3. Attach a Volume mounted at /data — the image already stores SQLite at sqlite:////data/tooltracker.db, so events survive redeploys. (Or use Postgres instead, see below.)

  4. Variables:

    Variable Value
    TOOLTRACKER_TOKEN a long random secret (not dev-token)
    CORS_ORIGINS your frontend URL, e.g. https://<frontend>.up.railway.app (comma-separate to also allow http://localhost:5173)
  5. Verify: https://<backend>.up.railway.app/health{"status":"ok",...}.

Frontend service

  1. Second service from the same repo, Root Directory frontend.
  2. Variables: VITE_API_URL=https://<backend>.up.railway.app (no trailing slash). This is baked in at build time — changing it requires a redeploy, and it must be set before the first build.
  3. Settings → Networking → Generate Domain, target port 80.
  4. Open the domain — the dashboard should load, and the WebSocket live feed connects over wss:// automatically.

Deploy the backend first so its domain exists when you set VITE_API_URL and CORS_ORIGINS. If you generated domains in the other order, just update the two variables and redeploy.

Using it after deployment

Everything that pointed at http://localhost:8000 now points at the Railway backend URL:

  1. Capture hook — in your .claude/settings.json (from hooks/settings.snippet.json) replace all four occurrences of http://localhost:8000/ingest/tool-event with https://<backend>.up.railway.app/ingest/tool-event, set the matching token in the shell Claude Code launches from (setx TOOLTRACKER_TOKEN "<your-token>" on Windows, then open a new terminal), and restart Claude Code.

  2. Dashboard — open https://<frontend>.up.railway.app. Run any Claude Code session with the hook installed and calls appear in the live feed.

  3. /toolstats via MCP

    claude mcp add --transport http tooltracker https://<backend>.up.railway.app/mcp \
      --header "Authorization: Bearer <your-token>"

Operational notes:

  • Disable App Sleeping on the backend service — hooks fail open by design, so events fired while the service wakes up are silently dropped.
  • The dashboard and REST /api/* are public. Ingest and MCP require the bearer token, but anyone with the URLs can read your tool-call metadata (file paths, commands). Keep the URLs private, or ask for auth on the read API before sharing them.
  • SQLite + volume means one replica only. Scale by switching to Postgres: add a Railway Postgres service, run uv add "psycopg[binary]" in backend/, and set DATABASE_URL on the backend service to the Postgres URL with the scheme rewritten to postgresql+psycopg:// (Railway hands out postgresql://).

Swapping SQLite for Postgres

The storage layer is deliberately portable: no SQLite-specific SQL anywhere (aggregations are plain SQLAlchemy; timeline bucketing happens in Python).

cd backend
uv add "psycopg[binary]"

Set DATABASE_URL=postgresql+psycopg://user:pass@host:5432/tooltracker in backend/.env (or the container environment) and restart. Tables are created on startup. For production you'd add Alembic migrations instead of create_all, but nothing else changes.

Repo layout

backend/
  app/main.py          FastAPI app, MCP mount, combined lifespan, /mcp auth
  app/ingest.py        POST /ingest/tool-event (capture hook events)
  app/hooks_display.py POST /hooks/turn-summary (Stop-hook per-turn note)
  app/aggregation.py   shared stats service (REST + MCP + WS all use it)
  app/api.py           REST /api/*
  app/ws.py            WebSocket broadcaster
  app/mcp_server.py    FastMCP query tools
  app/models.py        SQLModel tables (ToolEvent, Session)
  app/db.py, config.py, auth.py
frontend/              Vite + React + TS dashboard (TanStack Query, Recharts)
hooks/                 settings.snippet.json + install docs
.claude/commands/      /toolstats slash command

Troubleshooting

  • No events arriving? Hooks are snapshotted at session start — restart Claude Code after installing the snippet. Then check the backend log and that TOOLTRACKER_TOKEN in the hook environment matches backend/.env (a mismatch 401s silently by design — capture must never break a session).
  • /mcp returns 401? The claude mcp add registration must include the Authorization: Bearer <token> header.
  • /toolstats says "not connected"? Start the backend, then check claude mcp list.
  • Dashboard empty but backend up? The dev server proxies nothing — the browser calls http://localhost:8000 directly; make sure that port isn't blocked and CORS origin (default http://localhost:5173) matches.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages