skimsearch
Integrates with OpenAI-compatible chat and embeddings APIs to power semantic search, ask mode, and optional vector storage.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@skimsearchsearch my indexed repo for where the late fee is calculated"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
skimsearch
Coding agents burn tokens when they grep a monorepo and paste the dump back into the prompt. A wall of unrelated files crowds out the few lines that matter. skimsearch indexes the tree once, then answers with a short deck of ranked snippets that fit a token budget.
What skimsearch does
Index.
skimsearch indexfolds code and docs into skim cards. A card is one function, class, heading, or window, with its path and line range. Cards live in a compact SQLite file at.skimsearch/index.sqlite. SQLite FTS5 (BM25) ranks them offline.Search.
skimsearch searchreturns the best cards, trimmed so the whole deck stays inside a token budget. The default mode is lexical and does not call the network.Ask.
--mode semanticasks an OpenAI-compatible model to turn a question into a few lexical probes, then searches locally.--mode askdoes that and returns a short answer that cites only the cards it used. Optional--embedstores vectors when the provider implementsPOST /embeddings.
Agents spend tokens on the deck, not on a full-tree dump.
Related MCP server: code-memory-rs
Quickstart
Requires Python 3.10+.
python -m venv .venv
source .venv/bin/activate
pip install -e .
skimsearch index examples/acme-billing
skimsearch search "where is the late fee calculated" --path examples/acme-billingA lexical search stays on disk. On the sample project the deck looks like this:
skimsearch mode=lexical cards=4 tokens=322/700
1. src/billing/invoices.py:17-28 function apply_late_fee (python, score 1.71)
def apply_late_fee(invoice: dict, as_of: date) -> dict:
"""The late fee is calculated from the subtotal after the grace window."""
if invoice.get("settled"):
return invoice
overdue = (as_of - invoice["due"]).days
if overdue <= GRACE_DAYS:
return invoice
fee = round(invoice["subtotal"] * LATE_FEE_RATE, 2)
updated = dict(invoice)
updated["late_fee"] = fee
updated["total"] = round(invoice["subtotal"] + fee, 2)
return updated
2. docs/billing.md:3-5 heading Late fees (markdown, score 1.50)
## Late fees
A fee of 1.5 percent is added after a three-day grace period. The late fee is calculated from the invoice subtotal.Each card is a rank, a path:start-end locator, the symbol, and a trimmed body. The whole deck stops at the token budget.
LLM-assisted search uses the configured provider:
export ATMOROUTER_API_KEY=ar-your-key-here
skimsearch search "where is the late fee calculated" --path examples/acme-billing --mode askMCP, for Cursor or Claude Code:
skimsearch serve /absolute/path/to/reposerve builds an index first when the project does not have one yet.
Smoke tests run offline:
pip install -e ".[dev]"
pytest -qDefault LLM: AtmoRouter
Semantic and ask modes call an OpenAI-compatible chat API. The default base URL is AtmoRouter, a cheap AI API gateway and an OpenRouter alternative. One ar- key reaches the catalogue. Point SKIMSEARCH_BASE_URL at any other OpenAI-compatible endpoint when you want a different provider. Powered by AtmoRouter.
AtmoRouter also accepts the Anthropic Messages API. Set SKIMSEARCH_API_STYLE=anthropic and skimsearch posts to {SKIMSEARCH_BASE_URL}/messages (the default base already includes /v1). Chat completions stay on {SKIMSEARCH_BASE_URL}/chat/completions.
curl "$SKIMSEARCH_BASE_URL/models" -H "Authorization: Bearer $ATMOROUTER_API_KEY"The default model is atmo/deepseek-v4.1-flash. Set SKIMSEARCH_MODEL to any id your key can call.
Configuration
Copy .env.example to .env in the project you index, or export the variables in the shell. Values already set in the environment win over .env.
Variable | Default | Role |
| unset | Preferred API key. AtmoRouter keys look like |
| unset | Alias used when |
| unset | Alias used when the two keys above are unset. |
|
| OpenAI-compatible base URL, including |
| unset | Used when |
|
| Chat model id. |
|
|
|
|
| Token budget for one deck. |
|
| Token cap for a single card before the budget cuts it. |
|
| HTTP timeout in seconds. |
| unset | Embedding model for |
index skips dependency folders, build output, lockfiles, and secret files (.env, keys, .pem). It also reads .gitignore. A .skimignore file uses the same pattern syntax and is applied after .gitignore, so a negation such as !dist/ puts a path back into the index. The sample project ignores vendor/ with its own .gitignore and ships a fake .env that the built-in rules leave out of the index.
skimsearch index . # create or update .skimsearch/index.sqlite
skimsearch index . --force # rebuild
skimsearch index . --embed # also store /embeddings vectors
skimsearch search "session ttl" -C . --budget 500
skimsearch search "session ttl" --mode semantic
skimsearch search "session ttl" --mode ask --format json
skimsearch status .
skimsearch serve .search from a subdirectory finds an index in a parent directory. index always writes the index into the directory you name.
Cursor and Claude Code
Index the repo, then register the stdio server. Both clients use the same command.
Cursor (.cursor/mcp.json):
{
"mcpServers": {
"skimsearch": {
"command": "skimsearch",
"args": ["serve", "/absolute/path/to/repo"],
"env": {
"ATMOROUTER_API_KEY": "ar-your-key-here",
"SKIMSEARCH_BASE_URL": "https://atmorouter.dev/v1"
}
}
}
}Claude Code (.mcp.json in the project, or the user MCP config):
{
"mcpServers": {
"skimsearch": {
"command": "skimsearch",
"args": ["serve", "/absolute/path/to/repo"],
"env": {
"ATMOROUTER_API_KEY": "ar-your-key-here"
}
}
}
}Tools:
skim_search—query, optionalmode(lexical,semantic,ask),budget,limit,formatskim_status— index stats and the configured provider
lexical is the right default for a tight loop. Use ask when the question is phrased in prose and you want a short grounded answer plus the cards that support it.
License
MIT. See LICENSE.
This server cannot be deployed
Maintenance
Related MCP Connectors
Code intelligence for coding agents: semantic, AST, graph, and full-text search. 279+ languages.
Search indexed code, trace dependencies, assess change impact, and recall repository memory.
Code intelligence for LLMs. Analyze, search, and retrieve code from any public git repository.
Ask a codebase what calls what: search, blast radius, paths between symbols, and diffs.
Related MCP Servers
- AlicenseAqualityDmaintenanceProvides semantic code search over codebases using local embeddings with natural language queries. Supports hybrid search, file watching, and respects .gitignore.1121 PyPI6MIT
- FlicenseNot gradedqualityDmaintenanceEnables local semantic code search across repositories using natural language, with AST-aware chunking and hybrid vector/FTS5 retrieval.-
- AlicenseNot gradedqualityDmaintenanceEnables AI agents to search and ask questions about a local codebase with citations, using BM25 and optional embeddings, all offline.1 npm1MIT
- AlicenseAqualityBmaintenanceEnables semantic and keyword search over a local codebase by chunking source files along function and class boundaries, embedding them offline, and fusing vector and BM25 results. Runs entirely on your machine in a single SQLite file, so AI coding agents can find relevant code with no API keys, telemetry, or cloud calls.713 npmMIT