Skip to content

tl-mcp: persistent HTTP daemon, expanded hooks, MCP tools, cache, pi + codex support#14

Open
carlkibler wants to merge 12 commits intoedimuj:mainfrom
carlkibler:tl-mcp
Open

tl-mcp: persistent HTTP daemon, expanded hooks, MCP tools, cache, pi + codex support#14
carlkibler wants to merge 12 commits intoedimuj:mainfrom
carlkibler:tl-mcp

Conversation

@carlkibler
Copy link
Copy Markdown

Summary

This branch adds a persistent HTTP daemon mode to tl-mcp, expands hook coverage for Claude Code, Codex, and the Pi coding agent, and improves MCP tool surface and performance.

Rebased onto upstream main (v0.39.4) — all 396 tests pass.


tl-mcp: Persistent HTTP daemon (bin/tl-mcp.mjs)

Upstream's tl-mcp is 48 lines of stdio-only. This adds a full daemon layer:

  • tl-mcp start / stop / status — detached background daemon on port 3742, PID/port files in ~/.tokenlean/
  • tl-mcp serve — foreground HTTP server (StreamableHTTPServerTransport)
  • tl-mcp install-service — generates and installs a launchd plist (macOS) or systemd user unit (Linux), ready to run
  • tl-mcp --session-daemon — auto-spawns an HTTP sidecar for the session lifetime; cleans up on exit
  • --idle-timeout N — auto-shutdown after N minutes of inactivity
  • Prefers a manually-started daemon over launchd/systemd when both exist
  • Single McpServer instance per daemon (was rebuilt per HTTP request)

Agent config after tl-mcp start:

{ "mcpServers": { "tokenlean": { "type": "http", "url": "http://127.0.0.1:3742/mcp" } } }

tl-hook: Expanded patterns + Codex fix + Pi support (bin/tl-hook.mjs, src/pi-extension.ts)

Codex format fix — hooks were returning {"decision":"allow"} (wrong format); Codex uses the same hookSpecificOutput schema as Claude Code. Fixed. Codex auto-detected from transcript_path in payload when env vars aren't set.

New Bash patterns caught:

Pattern Nudge
git log/diff/show (no truncation flags) tl-diff / tl-history
ls -R/la, tree tl-structure / Glob
sed -i, awk > file Edit tool
cat > file, echo >>, tee Write tool
Read on JSON/YAML > 50KB tl-snippet

Persuasive messages — large file nudges now include size and estimated savings: "[tl] 47KB — tl-symbols + tl-snippet saves ~40KB".

Per-category TTL dedup: 5 min (high-impact), 15 min (medium), 30 min (informational).

Pi coding agenttl-hook install pi writes ~/.pi/agent/extensions/tokenlean-hook.ts. Uses pi-specific tool names in messages (grep tool, find tool, read tool). Pi detected via PI_CODING_AGENT env var.


MCP tool surface: 8 → 12 tools (src/mcp-tools.mjs)

New tool Purpose
tl_structure Project overview with token estimates; replaces ls -R
tl_audit Mid-session token waste analysis with savings breakdown
tl_deps File dependency tree without reading implementations
tl_exports Public API surface of a module or directory

Result cache (src/mcp-cache.mjs)

256-entry LRU, 60s TTL, keyed on sha1(tool + sorted args + file mtimes). Active in HTTP daemon mode; opt-out with TL_MCP_CACHE=0.

Measured: repeated tl_symbols call — 205ms → 0ms (cache hit).


tl-audit: MCP namespace support (src/audit-analyze.mjs)

tl-audit --savings now counts namespaced MCP tool calls (mcp__tokenlean__tl_symbols) as tokenlean usage. Also fixes Claude session discovery for symlinked project dirs. Includes new tests.


Test plan

  • npm test — 396 tests, all passing
  • tl-mcp start && tl-mcp status — daemon starts on port 3742
  • tl-mcp stop — daemon stops cleanly
  • tl-mcp install-service | bash — installs launchd/systemd service
  • MCP call tl_structure via agent — returns project tree
  • MCP call tl_audit — returns session token analysis
  • echo '{"tool_name":"Bash","tool_input":{"command":"git log"},...}' | tl-hook run — returns git-verbose nudge
  • Same with transcript_path containing /.codex/ — confirms codex detection
  • tl-hook install pi — installs extension to ~/.pi/agent/extensions/
  • tl-audit --savings on a session with MCP usage — counts mcp__tokenlean__* calls

🤖 Generated with Claude Code

carlkibler and others added 12 commits April 28, 2026 17:29
- Add bin/tl-mcp.mjs with stdio, serve, start, stop, status subcommands
- Add src/mcp-tools.mjs exposing symbols, snippet, run, impact, browse,
  tail, guard, diff as MCP tools (ported from upstream 0.34.1)
- HTTP mode uses StreamableHTTP stateless transport on port 3742
- Daemon (start/stop/status) writes PID+port to ~/.tokenlean/
- Add @modelcontextprotocol/sdk and zod dependencies
- Register tl-mcp in package.json bin section

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…docs

- status: TCP probe on port instead of PID-file-only check — works with
  launchd, systemd, or tl-mcp start regardless of how it was started
- stop: on macOS, unloads launchd agent if plist exists; falls back to PID file
- start: skips spawn if port already alive (handles launchd-managed case)
- install-service: prints ready-to-run launchd (macOS) or systemd (Linux)
  setup commands, with agent config snippet at the end
- buildServer: reads version from package.json instead of hardcoding
- README: add MCP Server section with quick start, persistent daemon for
  macOS and Linux, per-agent config examples, and MCP tools table
- README: add Codex to hooks install examples in both integration + workflows sections

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add pi install/uninstall/status handlers (extension at ~/.pi/agent/extensions/)
- Detect PI_CODING_AGENT env var for pi hook format
- Use pi-specific tool names in nudges: grep/find/read instead of Grep/Glob/Read
- Add src/pi-extension.ts template (TypeScript, copies on install)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Missing patterns added:
- git log/diff/show without truncation flags → tl-diff / tl-history
- ls -R/la, tree → tl-structure / Glob
- sed -i, awk > file → Edit tool
- cat > file, echo >>, tee → Write tool
- large JSON/YAML reads (>50KB) → tl-snippet

Persuasive nudges:
- Large file read now includes size + estimated savings (85%)
- cat read includes file size when checkable
- Per-category TTL: 5min (high-impact), 15min (medium), 30min (informational)

Codex format fix:
- Remove broken {"decision":"allow"} format for codex
- Both Claude Code and Codex now use hookSpecificOutput format
- Detect codex from transcript_path (/.codex/) when env vars absent

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add tl_structure, tl_audit, tl_deps, tl_exports.

tl_structure: project overview with token estimates; replaces ls -R patterns
tl_audit: mid-session token waste analysis with savings breakdown
tl_deps: file dependency tree without reading implementation
tl_exports: public API surface of a module or directory

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
src/mcp-cache.mjs: 256-entry LRU cache, 60s TTL, keyed on
  sha1(tool + sorted args + file mtimes). Opt-out: TL_MCP_CACHE=0.

mcp-tools.mjs: wrap dispatchTool with cache lookup; only cache
  successful results.

tl-mcp.mjs: build McpServer once per daemon lifecycle (was per-request),
  reuse across HTTP requests with fresh per-request transport.

Measured: tl_symbols cold 205ms → cached 0ms (205x for repeated calls).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds GIT_VERBOSE_PATTERNS, LS_TREE_PATTERNS, WRITE_VIA_BASH_PATTERNS,
SED_AWK_EDIT_PATTERNS, plus grep/find/ls-tree/git-verbose/sed-awk/write-via-bash
nudges and large JSON/YAML detection to the centralised policy module.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant