MCP Integration
lip mcp exposes the LIP daemon as a Model Context Protocol server. Any MCP-compatible client — Claude Code, CKB, Cursor, or a custom agent — gets live, always-current code intelligence without building its own indexing layer.
Tools
| Tool | Description |
|---|---|
lip_blast_radius | Which files are affected if this symbol changes |
lip_workspace_symbols | Semantic symbol search across the whole repo |
lip_definition | Go-to-definition at (file, line, col) |
lip_references | All call sites for a symbol URI |
lip_hover | Type signature + docs at a position |
lip_document_symbols | All symbols defined in a file |
lip_dead_symbols | Symbols defined but never referenced |
lip_annotation_get | Read a persistent symbol annotation |
lip_annotation_set | Write a persistent symbol annotation |
lip_annotation_workspace_list | All annotations matching a key prefix, workspace-wide |
lip_similar_symbols | Trigram fuzzy-search across all symbol names and docs |
lip_stale_files | Merkle sync probe — which files need re-indexing |
lip_load_slice | Mount a pre-built dependency slice into the daemon graph |
lip_batch_query | Execute multiple queries in one round-trip |
lip_embedding_batch | Compute and cache file embeddings via HTTP endpoint |
lip_nearest | Top-K files most similar to a given file (cosine similarity) |
lip_nearest_by_text | Top-K files most similar to a free-text query |
lip_index_status | Daemon health: indexed count, embedding coverage, last update |
lip_file_status | Per-file indexing status and embedding age |
lip_reindex_files | Force re-index of specific file URIs from disk |
lip_similarity | Pairwise cosine similarity of two stored embeddings |
lip_query_expansion | Expand a query string into related symbol names |
lip_cluster | Group URIs by embedding proximity within a given radius |
lip_export_embeddings | Return raw stored vectors for external pipelines |
All tools are backed by the live LIP daemon — results are always current, never a stale snapshot.
Setup
1. Start the daemon
lip daemon --socket /tmp/lip.sock
2. Start the MCP server
lip mcp --socket /tmp/lip.sock
The MCP server speaks JSON-RPC 2.0 over stdio. Keep it running alongside the daemon, or launch it on demand — it connects to the daemon per-request.
3. Add to your MCP client config
Claude Code (~/.claude/mcp.json or project .mcp.json):
{
"mcpServers": {
"lip": {
"command": "lip",
"args": ["mcp", "--socket", "/tmp/lip.sock"]
}
}
}
CKB (.ckb/config.json):
{
"backends": {
"lip": {
"command": "lip",
"args": ["mcp", "--socket", "/tmp/lip.sock"],
"tools": ["lip_blast_radius", "lip_workspace_symbols", "lip_references"]
}
}
}
Cursor (~/.cursor/mcp.json):
{
"mcpServers": {
"lip": {
"command": "lip",
"args": ["mcp"]
}
}
}
Tool reference
lip_blast_radius
Call before modifying any function, class, or interface to understand the scope of impact.
Input:
{ "symbol_uri": "lip://local/src/auth.rs#AuthService.verifyToken" }
Output:
Blast radius for `AuthService.verifyToken`:
direct dependents: 3
transitive dependents: 12
affected files (12):
file:///src/middleware/auth_guard.rs
file:///src/handlers/login.rs
file:///src/handlers/register.rs
...
lip_workspace_symbols
Semantic symbol search — finds by name across the entire workspace, returns kind, location, and confidence.
Input:
{ "query": "verifyToken", "limit": 20 }
lip_definition
Find where a symbol is defined.
Input:
{ "uri": "file:///src/auth.rs", "line": 42, "col": 10 }
line and col are 0-based, UTF-8 byte offsets.
lip_references
Find all call sites for a symbol.
Input:
{ "symbol_uri": "lip://local/src/auth.rs#AuthService.verifyToken", "limit": 50 }
lip_annotation_set / lip_annotation_get
Persistent annotations on symbols — survive daemon restarts, file changes, and re-indexes. Useful for AI agents to leave notes that persist across sessions.
Set:
{
"symbol_uri": "lip://local/src/payments.rs#processCharge",
"key": "agent:note",
"value": "Uses deprecated Stripe v1 API. Migration tracked in #472.",
"author_id": "agent:claude"
}
Get:
{
"symbol_uri": "lip://local/src/payments.rs#processCharge",
"key": "agent:note"
}
Canonical key prefixes:
| Prefix | Meaning |
|---|---|
lip:fragile | Handle with care — high blast radius or known instability |
lip:do-not-touch | Frozen — do not modify without explicit approval |
lip:{agent-id}-lock | Symbol is claimed by a running agent instance |
team:owner | Owning team or person |
agent:note | AI agent observations (scoped per agent ID) |
lip:agent-lock — worktree collision prevention
When an agent starts working on a symbol it sets a lock annotation so other instances know to skip it:
{
"symbol_uri": "lip://local/src/payments.rs#processCharge",
"key": "lip:nyx-agent-lock",
"value": "{\"worktree\":\"/repo-work\",\"pid\":4821,\"started_at_ms\":1744320000000}",
"author_id": "agent:nyx"
}
Before claiming a symbol, check for the lock. If the value is non-empty, a peer is already working on it — skip and move on.
After finishing, clear the lock by writing an empty value:
{ "symbol_uri": "...", "key": "lip:nyx-agent-lock", "value": "", "author_id": "agent:nyx" }
The lock key is agent-type-specific (lip:nyx-agent-lock, lip:claude-agent-lock, …) so two different agent types can work on the same symbol without blocking each other.
lip_batch_query
Execute multiple queries in a single round-trip. One socket connection instead of N — critical for planning workflows where you need several facts per symbol.
Input:
{
"queries": [
{ "type": "query_blast_radius", "symbol_uri": "lip://local/src/auth.rs#AuthService" },
{ "type": "query_references", "symbol_uri": "lip://local/src/auth.rs#AuthService", "limit": 50 },
{ "type": "annotation_get", "symbol_uri": "lip://local/src/auth.rs#AuthService", "key": "lip:fragile" },
{ "type": "annotation_get", "symbol_uri": "lip://local/src/auth.rs#AuthService", "key": "lip:nyx-agent-lock" }
]
}
Manifest and Delta are not permitted inside a batch; they return an error for that slot without aborting the rest.
Semantic search tools
These tools require LIP_EMBEDDING_URL to be set. See Embeddings & Semantic Search.
lip_embedding_batch
Compute and cache dense embedding vectors for a list of file URIs. Already-cached embeddings are returned without a network call.
Input:
{
"uris": [
"file:///src/auth.rs",
"file:///src/payments.rs",
"file:///src/session.rs"
]
}
Output:
embedded 3/3 files model=nomic-embed-text dims=768
lip_nearest
Find the top_k files most semantically similar to a given file, using pre-computed embedding vectors and cosine similarity.
Input:
{ "uri": "file:///src/auth.rs", "top_k": 5 }
Output:
score=0.9412 file:///src/session.rs
score=0.8871 file:///src/middleware/auth_guard.rs
score=0.8204 file:///src/handlers/login.rs
score=0.7931 file:///src/tokens.rs
score=0.7456 file:///src/crypto.rs
lip_nearest_by_text
Find the top_k files most semantically similar to a free-text query. The daemon embeds the text on the fly and runs cosine search against all stored vectors.
Input:
{ "text": "authentication token validation and session management", "top_k": 5 }
Observability tools
lip_index_status
Report overall daemon health. Useful as a CI pre-flight check.
Input: {} (no arguments)
Output:
indexed=142 pending_embeddings=38 last_updated=1744400123000ms embedding_model=nomic-embed-text
pending_embeddings— files indexed but not yet embedded.last_updated— Unix timestamp (ms) of the most recent file upsert.
lip_file_status
Report the indexing status of a single file.
Input:
{ "uri": "file:///src/auth.rs" }
Output:
file:///src/auth.rs indexed=true has_embedding=true age=42s
age is seconds since the file was last indexed.
v1.6 embedding integration tools
These tools require LIP_EMBEDDING_URL to be set unless otherwise noted.
lip_reindex_files
Force a re-index of specific file URIs from disk. Does not require embeddings — reads each file, detects its language, and updates the symbol graph.
Input:
{ "uris": ["file:///src/auth.rs", "file:///src/session.rs"] }
Use this after out-of-band changes that the daemon’s file watcher didn’t catch (e.g. selective git checkout or CI-generated files). Returns DeltaAck.
lip_similarity
Pairwise cosine similarity of two stored embeddings.
Input:
{ "uri_a": "file:///src/auth.rs", "uri_b": "file:///src/session.rs" }
Output:
score=0.9214
Returns null when either URI has no cached embedding — call lip_embedding_batch first. Accepts both file:// (file embeddings) and lip:// (symbol embeddings) URIs. Safe inside lip_batch_query.
lip_query_expansion
Embed a short query string and return the display names of the nearest symbols — useful before lip_workspace_symbols when the exact symbol name isn’t known.
Input:
{ "query": "token validation", "top_k": 5 }
Output:
verifyToken
validateSession
checkJwt
parseBearer
refreshToken
Requires symbols to have embeddings in the symbol store (populate with lip_embedding_batch using lip:// URIs).
lip_cluster
Group a list of URIs into clusters based on embedding proximity.
Input:
{
"uris": [
"file:///src/auth.rs",
"file:///src/session.rs",
"file:///src/payments.rs",
"file:///src/invoices.rs"
],
"radius": 0.85
}
Output:
Group 1: file:///src/auth.rs file:///src/session.rs
Group 2: file:///src/payments.rs file:///src/invoices.rs
radius is the cosine-similarity threshold. Two URIs land in the same group when their similarity is ≥ the radius. URIs without a cached embedding are silently excluded.
lip_export_embeddings
Return the raw stored embedding vectors for a list of URIs. Useful for passing to external re-ranking, custom clustering, or visualization tools.
Input:
{ "uris": ["file:///src/auth.rs", "file:///src/session.rs"] }
Output:
{
"file:///src/auth.rs": [0.021, -0.044, 0.117, ...],
"file:///src/session.rs": [0.019, -0.051, 0.109, ...]
}
URIs with no cached embedding are omitted from the result. Safe inside lip_batch_query.
How agents should use LIP
Planning a multi-symbol refactor (use batch):
1. lip_workspace_symbols → collect URIs for all symbols you plan to touch
2. lip_batch_query → for each URI: blast_radius + references + annotation_get("lip:fragile")
+ annotation_get("lip:nyx-agent-lock")
— 10 symbols = 1 round-trip, not 40
3. lip_annotation_set → set lip:nyx-agent-lock on each claimed symbol
Before modifying a single symbol:
1. lip_workspace_symbols → find the symbol URI
2. lip_blast_radius → understand scope of change
3. lip_references → see all call sites
4. lip_annotation_get → check for "lip:fragile" or "lip:do-not-touch"
After modifying code (if the change is notable):
lip_annotation_set("agent:note") → leave a note explaining what changed and why
lip_annotation_set("lip:nyx-agent-lock", value="") → release the lock
Finding dead code:
lip_dead_symbols → candidates for safe deletion
lip_blast_radius on each → confirm truly zero dependents
Semantic exploration workflow
# 1. Bootstrap embeddings for the whole workspace (once per session)
lip_embedding_batch(uris=[all_file_uris])
# 2. Find files related to a concept
lip_nearest_by_text("payment processing and fraud detection", top_k=10)
# 3. For each relevant file: check blast radius and ownership
lip_batch_query([
blast_radius(file_uri),
annotation_get(file_uri, "team:owner"),
annotation_get(file_uri, "lip:fragile")
])
# 4. Health check before committing results
lip_index_status() # confirm coverage
lip_file_status(target_uri) # confirm specific file is indexed and fresh
The CKB → LIP mapping
| CKB tool | LIP tool | Notes |
|---|---|---|
analyzeImpact | lip_blast_radius | LIP is always live; CKB needs SCIP refresh |
searchSymbols | lip_workspace_symbols | LIP uses live Tier 1 index |
findReferences | lip_references | Same semantics |
getCallGraph | lip_references + CPG edges | LIP CPG via Tier 2 |
prepareChange | lip_blast_radius + lip_annotation_get | LIP adds annotation check |
batchSearch | lip_query_expansion + lip_workspace_symbols | Expand → search replaces compound text scan |
explore | lip_cluster + lip_nearest_by_text | Group and navigate by semantic proximity |
recentlyRelevant | lip_similarity + lip_export_embeddings | Feed raw vectors into CKB’s re-ranking tier |
With LIP as CKB’s backend, analyzeImpact and prepareChange are always current — no more ckb index needed.