Skip to content

stubbies/litos-mcp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Litos MCP

A local MCP server that helps coding agents find code with fewer tokens. Instead of grepping the repo or reading whole files, agents search a structural skeleton index (symbols, kinds, scopes, line ranges) and read only the slices they need.

What is this?

Litos MCP indexes your repository into a small SQLite database (.lcn_cache.db) at the project root. It extracts definitions—functions, types, classes, interfaces—not full source bodies. Agents query that index through MCP tools, get back compact JSON hits (~10 results by default), then pull targeted line ranges.

It runs as a single Go binary over stdio inside Cursor, Claude Code, and other MCP hosts. Everything stays on your machine: no cloud API, no embeddings service, no telemetry.

Why use it?

  • Fewer tokens — Search returns paths and line numbers, not matching lines or entire files. Reads are capped (500 lines / 512KB per call).
  • Faster discovery — FTS5 keyword search over symbols beats scrolling large grep dumps for “where is X implemented?”
  • Stays fresh — On serve, the index hydrates at startup, watches the repo for saves (fsnotify), and rechecks staleness before search. Normal edits do not require manual reindex.
  • Private and offline — Local cache only; respects .gitignore and common skip dirs (node_modules, .git, build outputs).
  • Optional depth — Install Universal Ctags for broad multi-language symbol extraction, or use the built-in regex indexer for Go, TS/JS, and Python.

How it works

  1. litos-mcp init (or auto-init on first serve) crawls indexable source files, extracts symbols, and writes .lcn_cache.db with an FTS5 search index.
  2. litos-mcp serve starts the MCP server, hydrates any drift since last run, and watches the filesystem for changes while you work.
  3. The agent calls search_code_skeleton with keywords (e.g. "jwt verification", "payment handler").
  4. For promising hits, the agent calls read_file_lines with the returned file_path, start_line, and end_line.

Example search hit (no source body—just structure):

[{
  "file_path": "src/billing/billing.go",
  "symbol": "ProcessPayment",
  "kind": "function",
  "start_line": 56,
  "end_line": 69,
  "scope": "BillingService",
  "matched_in": "symbol"
}]

After large tree changes (git pull, branch switch), call reindex_index or run litos-mcp init again. Check sync state anytime via the litos://index/status MCP resource.

What it is not

  • Not semantic / embedding search — Keyword and structural FTS over symbol metadata, not “find code similar to this paragraph.”
  • Not a grep replacement — Use grep when you need literal matches in comments, strings, configs, or exact regex patterns litos does not index.
  • Not a hosted service — You install the binary and wire it into Cursor, Claude Code, or another MCP host.

Install

go install github.com/stubbies/litos-mcp/cmd/litos-mcp@latest

Or build from source:

git clone https://github.com/stubbies/litos-mcp.git
cd litos-mcp
go build -o bin/litos-mcp ./cmd/litos-mcp

Optional: install Universal Ctags for richer symbol extraction across many languages. Without it, litos-mcp falls back to built-in regex heuristics for Go, TypeScript/JavaScript, and Python only (.go, .ts, .tsx, .js, .jsx, .mjs, .cjs, .py, .pyw). Run litos-mcp version to see which indexer your install will use (indexer: ctags available … vs regex fallback).

Language support

Mode Indexed extensions
Regex fallback (no ctags) .go, .ts, .tsx, .js, .jsx, .mjs, .cjs, .py, .pyw
Universal Ctags All crawl-eligible source extensions (Go, TS/JS, Python, Rust, Java/Kotlin, C/C++, C#, Ruby, PHP, Swift, Scala, Vue, Svelte, shell, SQL, Protobuf, and more)

Crawl discovers many file types, but the regex indexer only extracts symbols from the extensions in the first row. With ctags installed, the full crawl set is indexed.

Quick start

  1. Index your repo (creates .lcn_cache.db beside the repo root):

    cd /path/to/your/project
    litos-mcp init

    Example output:

    files=842 symbols=3912 indexer=regex elapsed_ms=1204 db_bytes=524288
    
  2. Wire into your MCP host

    Cursor

    Copy .cursor/mcp.json (or merge into your existing MCP config):

    {
      "mcpServers": {
        "litos-mcp": {
          "command": "/path/to/litos-mcp",
          "args": ["serve"],
          "cwd": "${workspaceFolder}"
        }
      }
    }

    cwd must be the workspace root so the server resolves the same repo root as init.

    Claude Code

    Create .mcp.json in the project you want indexed (your app repo, not necessarily litos-mcp itself). Claude Code ignores cwd in MCP config; litos uses CLAUDE_PROJECT_DIR automatically.

    {
      "mcpServers": {
        "litos-mcp": {
          "type": "stdio",
          "command": "litos-mcp",
          "args": ["serve"]
        }
      }
    }

    Use litos-mcp on your PATH, or substitute an absolute path (e.g. $(go env GOPATH)/bin/litos-mcp or ./bin/litos-mcp).

    Alternative CLI:

    claude mcp add --scope project litos-mcp -- litos-mcp serve

    Restart Claude Code after config changes. Verify with /mcp or claude mcp list. First-time project-scoped servers may require approval in the UI.

  3. Use the MCP tools in agent sessions:

    • search_code_skeleton — find symbols by keyword (returns JSON hits with file path, line ranges, and matched_in; optional match_mode: and or or)
    • read_file_lines — read a bounded, line-numbered slice after search confirms the target
    • reindex_index — full index rebuild after large changes (e.g. git pull); normal saves sync automatically
    • litos://index/status (MCP resource) — JSON sync status: file/symbol counts, indexer, reconcile_needed
    • code_discovery_workflow (MCP prompt) — onboarding text for agents: search first, read narrowly

litos-mcp serve auto-runs init when the cache is missing, then hydrates the index on startup (stat pass + boot crawl) and keeps it fresh with a filesystem watcher for debounced per-file updates. Search calls run a lightweight staleness check before FTS.

Commands

Command Description
litos-mcp init [--root PATH] Build or refresh .lcn_cache.db
litos-mcp serve MCP stdio server + boot hydration + fsnotify sync
litos-mcp version Print binary, Go, indexer, and FTS5 status

Agent workflow

  1. Call search_code_skeleton(query="payment middleware") for structural hits (~10 results by default).
  2. Call read_file_lines(file_path, start_line, end_line) only for confirmed ranges from search results.
  3. Prefer these tools over grep or reading entire files when litos-mcp is available.

The MCP server exposes a code_discovery_workflow prompt with the same guidance. In Cursor, invoke it from the MCP prompts picker or reference it when onboarding agents to the repo.

Claude Code (recommended)

Add CLAUDE.md at the project root with the same discovery workflow (search → read slices → grep fallback). The MCP prompt code_discovery_workflow is available in Claude Code when the server is connected.

After edits, wait for fsnotify debounce (~300ms) or run a second search; use reindex_index after git pull.

Cursor rule (recommended)

Add .cursor/rules/litos-code-discovery.mdc so agents default to litos tools in this workspace:

---
description: Prefer litos-mcp structural search over grep and whole-file reads
alwaysApply: true
---

# Code discovery with litos-mcp

When litos-mcp is connected (search_code_skeleton, read_file_lines):

1. Start with search_code_skeleton using functional keywords from the task.
2. Read only the line ranges returned by search via read_file_lines.
3. Do not use grep, ripgrep, or Read on entire source files for discovery when litos tools are available.
4. Use grep or full-file reads only as a fallback when litos returns no hits or you need exact regex matches.

Refine search queries using symbol names, kinds, scopes, and matched_in from prior hits.

Cache and privacy

  • .lcn_cache.db lives at the repository root, is gitignored, and can be deleted anytime; init or serve rebuilds it.
  • Indexing skips paths covered by .gitignore, .git/info/exclude, and built-in skip rules (e.g. node_modules, .git, common build dirs).
  • No source code is sent to external services—only your local agent reads files through MCP after you connect the server.

Development

# Run tests (includes fixture golden metrics, token/size/latency thresholds)
go test ./...

# Search benchmark + regression guard (2× baseline in testdata/metrics.json)
go test -bench=BenchmarkFixtureSearch -benchtime=100ms ./internal/testutil/...

# Dogfood litos-mcp in this repo with Claude Code
go build -o ./litos-mcp ./cmd/litos-mcp
# then point .mcp.json command at ./litos-mcp or $(pwd)/litos-mcp

Fixture repo: testdata/fixture-repo/ with expectations in testdata/metrics.json.

License

MIT — see LICENSE.

About

MCP server that indexes repo symbols locally (SQLite/FTS5) so coding agents search structure first and read only the lines they need.

Topics

Resources

License

Stars

Watchers

Forks

Contributors

Languages