Codebase Semantic Search
БесплатноНе проверенLocal semantic search engine for any codebase. MCP + HTTP + file watcher. Reuses Ollama embeddings + Milvus vector storage.
Описание
Local semantic search engine for any codebase. MCP + HTTP + file watcher. Reuses Ollama embeddings + Milvus vector storage.
README
A local, project-agnostic semantic search engine for any codebase. Drop it into a project, point it at your source dirs, and any agent (Claude Code, GitHub Copilot Chat, OpenCode, Codex) or human can query it by meaning rather than by literal text match.
- Vector DB: Milvus Standalone (Docker)
- Embeddings: Ollama
nomic-embed-text(768-dim, local, fast) - Chunker: AST-aware for TS/JS, heading-based for markdown, sliding window for the rest
- Interfaces: stdio MCP server (for agents, preferred) + HTTP API (for humans / curl debugging)
- Live updates: chokidar file watcher with debounced incremental reindex
TL;DR for agents. Install the package, run
npx codesearch uponce, then register the stdio MCP server with your agent runtime. The agent gets four tools —codebase_semantic_search,codebase_clip,codebase_read_file,codebase_stats— and queries them as part of its normal tool calls. The HTTP API is a fallback for humans only; agents should not shell out tocurl.
Quickstart
# 1. Install as a dev dep
npm install --save-dev codebase-semantic-search
# 2. Bootstrap the engine (writes config + starts Milvus + pulls the
# embedding model + runs an initial reindex if empty + starts the
# file watcher). Idempotent. Blocks in the foreground.
npx codesearch up
Then register the MCP server with your agent runtime (one-time per machine):
Claude Code (~/.claude/mcp.json or per-project .mcp.json):
{
"mcpServers": {
"codebase": {
"command": "npx",
"args": ["-y", "codebase-semantic-search", "mcp"]
}
}
}
GitHub Copilot Chat (.vscode/mcp.json):
{
"servers": {
"codebase-semantic-search": {
"type": "stdio",
"command": "npx",
"args": ["-y", "codebase-semantic-search", "mcp"]
}
}
}
OpenCode (opencode.json):
{
"mcp": {
"codebase-semantic-search": {
"type": "local",
"command": ["npx", "-y", "codebase-semantic-search", "mcp"]
}
}
}
Your agent runtime spawns the MCP server on demand over stdio whenever it
needs to query the index. You do not need to run codesearch mcp
yourself — that's the agent's job. (See "How it fits together" below.)
After registration, the agent has four new tools:
| Tool | Returns |
|---|---|
codebase_semantic_search |
Ranked code chunks matching a natural-language query |
codebase_clip |
Full text of a chunk by its short numeric id (single or batch) |
codebase_read_file |
File slice by line range (sed -n 'A,Bp' semantics) |
codebase_stats |
Chunk count, collection name, embedding model |
If
upfails on first run, it's almost always a missing dep. Runnpx codesearch doctorand follow the fix it prints — usually "Ollama not running" or "Docker compose stack not up."
Requirements
codesearch up shells out to three external things on your machine:
Docker, Ollama, and curl. They must already be installed and reachable
before you run up. The package itself is pure-JS and installs
cleanly via npm on any platform Node 20+ runs on.
| Need | Why | Where |
|---|---|---|
| Node.js ≥ 20 | The engines requirement |
any platform |
Docker + Compose v2 plugin (docker compose …) |
Milvus Standalone stack (Milvus + etcd + MinIO) | uses ~600 MB of images on first pull |
Ollama running on http://127.0.0.1:11434 |
Provides the embedding endpoint. up will throw if it's not reachable — up does not auto-install Ollama (system service requires sudo, out of scope for an npm package) |
see install notes below |
Embedding model (nomic-embed-text, ~270 MB) |
up auto-pulls this once Ollama is running — but the first pull is slow |
managed by up |
curl on your $PATH |
up uses curl to probe Ollama |
shipped on macOS / Linux; modern Windows too |
Verify nothing's missing: npx codesearch doctor (works pre-init, prints one line per dep with status and the fix command if anything fails).
Install Ollama (one-time)
| OS | Command |
|---|---|
| macOS | brew install ollama && brew services start ollama (or just ollama serve in another terminal) |
| Linux | curl -fsSL https://ollama.com/install.sh | sh, then ollama serve |
| Windows | Install from ollama.com/download, then ollama serve |
To prefetch the embedding model (optional — up will do it for you):
ollama pull nomic-embed-text
Footprint
This is a chunky tool. Don't up it on a half-full laptop without expecting:
- Disk — ~600 MB of Docker images + a few GB per project for the Milvus
index volume (
<project>_milvus_data). First time is the biggest. - Ports (defaults) —
19530Milvus gRPC,9091Milvus metrics,9000/9001MinIO API/console,7700HTTP API. (etcd + MinIO are internal dependencies of Milvus — they're reachable between containers on thesearch-networkbridge, not from the host.) All overridable via.codesearchrc.jsonor env vars (MILVUS_PORT,SEARCH_PORT, etc.). - First-run time — ~45s on Apple Silicon (the bundled Milvus image is
multi-arch, so Apple Silicon gets native
linux/arm64execution — no QEMU emulation), plus 30–60s for the initial index build depending on codebase size.
Apple Silicon / ARM64
Native, not emulated. The bundled Milvus image (milvusdb/milvus:v2.5.5)
publishes a multi-arch manifest with both linux/amd64 and linux/arm64
digests. codesearch up automatically forwards your host architecture to
Docker via the UNAME_M env var, so an M-series Mac pulls the native arm64
image and Docker runs it directly — no Rosetta, no QEMU. Startup on M1/M2/M3
is roughly the same as on linux/amd64 (~45s for the stack + index build).
If you'd rather pin the platform yourself (e.g. for CI on a mixed-architecture
runner), set UNAME_M=linux/amd64 (or linux/arm64) in the shell before
running codesearch up and the bundled compose will respect it.
How it fits together
The CLI brings up three runtime components — Milvus, Ollama, the file watcher — and two query surfaces sit on top:
- MCP stdio server (preferred for agents). The agent runtime spawns
npx -y codebase-semantic-search mcpas a child process and talks to it over JSON-RPC. No port, no daemon — the server starts on demand when the agent makes its first tool call and exits when the agent quits. Each MCP process has its own in-memory clip store (the short numeric ids assigned bycodebase_semantic_searchare valid for the lifetime of that process only). - HTTP API (fallback for humans / curl debugging). Run
npx codesearch serve(just HTTP) ornpx codesearch serve:watch(HTTP- file watcher). Listens on
http://localhost:7700. Use this when an agent runtime can't speak MCP, or when you want to poke at the index with curl / Postman / a browser.
- file watcher). Listens on
Both query surfaces read the same Milvus collection, so results are consistent across them. Agents should always prefer the MCP tools — no port collisions in multi-project setups, no long-running server to manage, clean process boundaries.
┌─────────────────────────────────────────────────────────┐
│ Agent (Claude Code, Copilot, …) │
└────────────────────────┬────────────────────────────────┘
│ stdio MCP (preferred) / HTTP fallback
▼
┌─────────────────────────────────────────────────────────┐
│ codesearch (Node.js, TypeScript) │
│ ┌─────────────┐ ┌──────────────┐ ┌────────────────┐ │
│ │ Watcher │ │ HTTP API │ │ MCP Server │ │
│ │ (chokidar) │ │ (express) │ │ (@modelctx/sdk)│ │
│ └──────┬──────┘ └──────┬───────┘ └────────┬───────┘ │
│ └───────────────┼───────────────────┘ │
│ ▼ │
│ ┌────────────────────────────┐ │
│ │ Indexer (mtime-diff) │ │
│ └─────────┬──────────────────┘ │
│ ▼ │
│ ┌────────────────────────────┐ │
│ │ Milvus Standalone :19530 │ │
│ └────────────────────────────┘ │
│ ▲ │
│ │ │
│ ┌───────────────┴──────────────┐ │
│ │ Ollama :11434 (embeddings) │ │
│ └──────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
MCP Server
Spawns a stdio MCP server exposing four tools:
codebase_semantic_search— query the index by meaning. Args:query(natural language),top_k(1–100, default 100),module,language,chunk_type,min_score(absolute quality threshold, 0..1),min_score_diff(relative quality threshold, 0..1, default 0.1, mutually exclusive withmin_score),include(opt-in metadata fields to add to each result),format(response format:"markdown"default or"json"opt-in). Default response is a single markdown document with a# Search: "..."title and per-hit code fences + metadata captions. Passformat: "json"for the structured response. Whenformat: "json", default per-hit fields areid,filePath,symbolName,score,startLine,endLine,content(lean); passinclude: ["chunkType", "module", "language"]to opt in to the metadata fields. The response always echoes whichever quality filter was applied (default or explicit) so callers can see the threshold andmaxScore. Whenincludeis set, response also includesincludedFields.codebase_clip— fetch a clip by its short numeric id from the in-memory store. Args: EITHERid: number(single) ORids: number[](batch). Ids are assigned bycodebase_semantic_searchand are valid for the lifetime of this MCP process (FIFO evict at 10K entries; cleared on restart).codebase_read_file— fetch a slice of a file by line range (sed -n '<start>,<end>p'semantics). Args:filePath(relative to workspace root),startLine(1-indexed inclusive),endLine(1-indexed inclusive). 500 lines per call, 25 MB file cap. Use it to expand the context around a hit returned bycodebase_semantic_searchwithout re-loading the whole file.codebase_stats— chunk count, collection name, embedding model, embedding dimensions.
Typical workflow:
1. codebase_semantic_search(query="how invoices are created") → results[] (each has an id)
2a. codebase_clip(ids=[r.id for r in results]) → full text of each
2b. codebase_read_file(filePath=results[0].filePath, startLine=…, endLine=…) // expand context around one
3. make your edit in the lines you've now seen in full
Agent templates
npx codesearch init (or up, if no config exists yet) wires the
canonical MCP + HTTP reference into your project's agent ecosystem:
.github/instructions/codebase-semantic-search.instructions.md— the canonical reference (full tool list, defaults, response shapes, filters, recovery flow, bootstrap). Auto-loaded into every agent context viaapplyTo: "**". Written once per project.- A slim dual-pointer block into every
.github/agents/*.agent.md(marker-bounded so re-runs are idempotent). Points at the canonical doc above — does NOT duplicate its content. - A slim pointer section in
.github/copilot-instructions.md(created if missing).
The per-agent blocks are intentionally ~15-20 lines each — they point
at the canonical doc rather than duplicating it. With N agent files,
that keeps total agent-ecosystem bloat at N × 20 + 1 × ~300 lines
instead of N × 200.
CLI
| Command | What it does |
|---|---|
codesearch init |
Scaffold .codesearchrc.json + agent file snippets + docker-compose |
codesearch init --port=19531 |
Same, with a Milvus port offset for running multiple codebases in parallel |
codesearch init --search-port=7800 |
Same, with a custom HTTP API port |
codesearch up |
One-shot bootstrap: init (if needed) → Milvus → Ollama model → index (if empty) → dev loop. Idempotent. |
codesearch up --port=19531 |
Same, with a Milvus port offset |
codesearch up --no-index |
Same, but skip the initial reindex |
codesearch up --no-serve |
Same, but stop after bootstrap (no dev loop) |
codesearch down |
Stop Milvus (volumes preserved — index survives) |
codesearch doctor |
Check Ollama, Milvus, embedding model availability |
codesearch index |
Reindex the codebase (incremental by default) |
codesearch index --full |
Drop the collection and rebuild from scratch |
codesearch index --dry-run |
Show what would change without writing |
codesearch serve |
HTTP search server on :7700 (humans / curl fallback) |
codesearch watch |
File watcher only (no HTTP) |
codesearch serve:watch |
HTTP server + watcher in one process |
codesearch mcp |
stdio MCP server (spawned automatically by agent runtimes; rarely run manually) |
codesearch status |
Show collection stats and current config |
All config is overridable via .codesearchrc.json or env vars
(OLLAMA_HOST, MILVUS_HOST, MILVUS_PORT, EMBEDDING_MODEL,
SEARCH_PORT).
The underlying subcommands
up is the recommended entry point, but the granular subcommands are still available for fine-grained control:
npx codesearch init # Scaffold .codesearchrc.json + agent file snippets + docker-compose
npx codesearch doctor # Check Ollama, Milvus, embedding model
npx codesearch index # Reindex the codebase (incremental by default)
npx codesearch index --full # Drop the collection and rebuild from scratch
npx codesearch serve # HTTP search server on :7700 (fallback for humans)
npx codesearch watch # File watcher only (no HTTP)
npx codesearch serve:watch # HTTP server + watcher in one process
npx codesearch mcp # stdio MCP server (spawned automatically by agent runtimes)
npx codesearch status # Show collection stats and current config
npx codesearch up # One-shot bootstrap (init + Milvus + index + dev loop)
npx codesearch down # Stop Milvus (volumes preserved — index survives)
The init command drops:
.codesearchrc.json— project-specific configdocker-compose.search.yml— Milvus + etcd + MinIO.github/instructions/codebase-semantic-search.instructions.md— the canonical MCP + HTTP reference, auto-loaded into every agent context- A slim dual-pointer block appended to every
.github/agents/*.agent.md(with marker comments so re-runs are idempotent) - A slim pointer section in
.github/copilot-instructions.md(created if missing)
Running multiple codebases in parallel
Docker container names are auto-namespaced by the compose project, so two projects no longer collide. To run two stacks side-by-side on the same machine, give the second one a port offset:
# In project A (default ports)
npx codesearch up
# In project B
npx codesearch up --port=19531 --search-port=7800
up forwards the offset to init (if .codesearchrc.json is missing) and sets the matching env vars on the docker compose invocation. Each project gets its own Milvus data volume (<project>_milvus_data), so indexes don't share or overwrite.
For MCP-only setups (no HTTP server running), multi-project is trivially isolated — each agent runtime spawns its own MCP child process per project, with no port to share at all.
HTTP API (humans / curl fallback)
Base URL: http://localhost:7700 (port overridable via SEARCH_PORT).
The HTTP API exposes the same data as the MCP server; it's intended for
humans debugging with curl / Postman, or for tools that can't speak MCP.
POST /search — semantic search by meaning
Minimum viable call:
POST /search
Content-Type: application/json
{
"query": "how does tenant isolation work in mongoose queries"
}
Defaults applied: top_k: 100 and min_score_diff: 0.1 (drop anything more
than 10% below the best match). To override or add filters:
POST /search
Content-Type: application/json
{
"query": "how does tenant isolation work in mongoose queries",
"top_k": 100, // optional, default 100, max 100
"module": "platform", // optional filter
"language": "typescript", // optional filter
"chunk_type": "function", // optional filter
"min_score": 0.7, // optional absolute quality threshold (0..1)
"min_score_diff": 0.1, // optional, default 0.1; mutually exclusive with min_score
"include": ["chunkType", "module", "language"], // optional opt-in metadata
"format": "json" // optional response format; default "markdown"
}
Default response is markdown — a single document with a # Search: "..."
title and one-line summary at the top, then per-hit fenced code blocks
with a metadata caption line beneath each. Code is the primary matter;
metadata is the caption. See "Response format: markdown by default"
below for the shape.
Pass "format": "json" for the structured response. See "JSON response
shape" further down.
Response format: markdown by default
The markdown response is a single document:
# Search: "how invoices are created"
3 results • top_k: 10 • min_score: 0.7 • clip store: 142
---
```typescript
/**
* Clawback transaction — reclaim issued tokens or MPTs from a holder's account.
*
* @see https://xrpl.org/clawback.html
*/
import type { BaseTransactionFields } from '../types/base.js';
...
```
src/transactions/clawback.ts:1-11 • file-header • score: 0.8146 • id: 1
---
```typescript
export class ClawbackTx extends TokenTransaction {
override readonly TransactionType = 'Clawback' as const;
...
}
```
src/transactions/clawback.ts:18-38 • ClawbackTx • score: 0.7353 • id: 2
Structure:
- Header:
# Search: "<query>"followed by a one-line summary (count • top_k • min_score? • min_score_diff? • included? • clip store: N). Each filter only shows when it's actually applied. - Per hit:
- A code fence with the language hint (from the chunker; falls back to
textif unknown). - The full chunk content, pristine.
- A plain-text caption line:
filePath:startLine-endLine•symbolName(when present) •score: N•chunkType: …(whenincluded) •module: …(whenincluded) •id: N.
- A code fence with the language hint (from the chunker; falls back to
- Hits are separated by
---(horizontal rule).
Content-Type: text/markdown; charset=utf-8.
Why markdown: agents and humans read code naturally when it's fenced. Metadata sits below each block as a caption, visually subordinate. JSON preserves typed structure but every field competes for visual weight; markdown gives the code the prominence it deserves and parks metadata in the gutter.
JSON response shape
Pass "format": "json" to opt in. The response envelope stays the same
as before; only the body is structured instead of rendered.
{
"success": true,
"data": {
"query": "...",
"count": 10,
"topK": 10,
"clipStoreSize": 142,
"results": [
{
"id": 42,
"filePath": "server/src/modules/billing/routes.ts",
"symbolName": "createInvoice",
"score": 0.842,
"startLine": 42,
"endLine": 80,
"content": "export async function createInvoice(req, res) { ... }"
}
],
"minScore": 0.7,
"candidatesBeforeFilter": 10,
"includedFields": ["chunkType", "module", "language"]
}
}
Default response per hit is lean — id, filePath, symbolName,
score, startLine, endLine, content. The chunkType, module,
language fields are opt-in via include (see below).
scoreis 0..1 cosine similarity — ≥0.75 = strong, 0.55–0.75 = review, <0.55 = likely noise.idis a short numeric handle assigned at search time. Pass it toGET /clip/:id(or/clips) to fetch the full text without re-encoding the path + line range.clipStoreSizereports the current in-memory clip-store size.minScoreandcandidatesBeforeFilterare echoed only whenmin_scorewas supplied.includedFieldsis echoed only whenincludewas supplied.
include — opt-in metadata fields
{
"include": ["chunkType", "module", "language"] // any subset
}
Allowed values: "chunkType", "module", "language". Unknown value or
wrong type (e.g. a string instead of an array) returns HTTP 400 with the
allowed list. Omit or pass [] for the lean default.
min_score semantics
Quality filter applied after the vector search. The engine asks Milvus
for top_k candidates, then drops anything below min_score. So the
response may contain fewer than top_k results — that's by design (you
asked for "up to top_k results that score ≥ min_score"). With the
default top_k: 100 you're already at the maximum candidate pool;
tighten the query (or use min_score_diff for a relative cutoff)
instead of pushing top_k higher — it can't go above 100.
Recommended bands:
- 0.75+ — strong, relevant matches; safe to act on.
- 0.55–0.75 — worth reviewing; context may help disambiguate.
- < 0.55 — likely noise; widen the query or add filters instead of lowering the threshold.
Validation: min_score must be a finite number in [0, 1]. Out-of-range
or non-numeric values return HTTP 400.
min_score_diff semantics (relative threshold)
Applied by default at 0.1 when the caller doesn't supply either
filter. To disable the default, set min_score_diff: 0 explicitly (keeps
only ties with the top hit). To use a different threshold, pass any value
in [0, 1].
The threshold is computed from the best hit in the result set:
appliedThreshold = max_score - min_score_diff. Drop any hit whose score
is below that. Useful when you don't know the absolute score distribution
in advance — "everything within 0.1 of the best match" is often more
meaningful than "everything above 0.7".
Mutually exclusive with min_score — passing both returns HTTP 400.
The default min_score_diff does NOT count as "provided" for this
check; if you set min_score, the default is ignored.
Response echo when applied:
{
"minScoreDiff": 0.1,
"appliedThreshold": 0.7146,
"maxScore": 0.8146,
"candidatesBeforeFilter": 10
}
Recommended bands:
- 0.05–0.15 — strict; typically keeps 3–8 hits on a sizeable codebase
with
top_k: 100. The default (0.1) sits in the middle of this band. - 0.2–0.3 — lenient; useful when the top match is strong but the semantic space drops off sharply below it.
Validation: min_score_diff must be a finite number in [0, 1].
Out-of-range or non-numeric values return HTTP 400. Threshold is clamped
at 0 if max_score is 0 (pathological).
GET /clip/:id — fetch one clip by its short id
GET /clip/42
Returns: { success, data: { id, filePath, startLine, endLine, totalLines, content } }.
The id is assigned by /search. The underlying (filePath, startLine, endLine) is stored in an in-memory table keyed by id. Use this when
you want the chunk back exactly as the search returned it.
GET /clips?ids=1,2,3 — batch fetch (small batches, curl-friendly)
GET /clips?ids=42,17,99
Accepts both ?ids=1,2,3 (comma-separated) and ?ids=1&ids=2&ids=3
(repeated param). Max 500 ids per request.
POST /clips — batch fetch (large batches)
POST /clips
Content-Type: application/json
{ "ids": [42, 17, 99, 128, 256] }
Same batch cap (500 ids). Use this when the query-string approach gets unwieldy.
Batch response shape (both GET and POST):
{
"success": true,
"data": {
"results": [
{ "id": 42, "success": true, "filePath": "...", "startLine": 1, "endLine": 50, "totalLines": 191, "content": "..." },
{ "id": 99, "success": false, "error": "id not found or expired. Re-run /search to get a fresh id." }
],
"requested": 2,
"succeeded": 1,
"failed": 1,
"clipStoreSize": 142
}
}
Per-item errors do NOT abort the batch — one bad id returns
success: false in its slot, the rest proceed.
POST /read — fetch a file slice by raw line range
Use this when you want to expand a chunk's context (e.g. startLine - 5 to
endLine + 5 to see the surrounding function/class). Semantics match
sed -n '<start>,<end>p' <filePath>.
POST /read
Content-Type: application/json
{
"filePath": "server/src/modules/billing/routes.ts",
"startLine": 42,
"endLine": 95
}
Response: { success, data: { filePath, startLine, endLine, totalLines, rangeRequested, content } }.
Limits shared by /read, /clip/:id, /clips:
- Range cap: 500 lines per call. Chain reads to paginate larger ranges.
- File size cap: 25 MB (HTTP 413 if exceeded). Protects against OOM when an agent points at a huge generated file.
- Path safety:
filePathis resolved relative to the workspace root. Absolute paths and../escapes are rejected with HTTP 403. - Not found: HTTP 404.
Clip store: how ids work
The clip store is a per-process, in-memory Map<id, {filePath, startLine, endLine}>:
- Auto-increment numeric ids (1, 2, 3, …). Short — easier to log, curl, and pass through agent context than encoded base64.
- Dedup on
(filePath, startLine, endLine)— the same chunk always returns the same id across searches. - FIFO eviction at 10K entries — once full, the oldest inserted id is dropped to make room. Long-idle ids may return 404 ("not found or expired").
- Ephemeral — server restart clears the table. Agents mid-session can just re-search; no data loss.
- Per-process — the MCP server has its own table; an HTTP
/searchid is not resolvable by an MCPcodebase_clipcall (they're separate processes). Run a search in the same process that will resolve the ids.
Typical workflow
# 1. search — results carry ids
curl -s http://localhost:7700/search -H "Content-Type: application/json" \
-d '{"query": "how invoices are created", "chunk_type": "function"}'
# 2a. shortcut — fetch by id (recommended for the common case)
curl -s http://localhost:7700/clip/42
# 2b. expand context — fetch by raw filePath + adjusted range
curl -s -X POST http://localhost:7700/read -H "Content-Type: application/json" \
-d '{"filePath": "server/src/modules/billing/routes.ts", "startLine": 38, "endLine": 95}'
Other endpoints
GET /health — liveness check. GET /stats — collection stats (chunk count, etc.).
Project Layout
codebase-semantic-search/
├── package.json # name: codebase-semantic-search, bin: codesearch
├── docker-compose.search.yml
├── src/
│ ├── cli.ts # entry: commander dispatch
│ ├── config.ts # loads .codesearchrc.json + env
│ ├── walker.ts # file system walker + mtime diff
│ ├── chunker.ts # AST-aware chunker (ts-morph)
│ ├── embedder.ts # Ollama client
│ ├── milvus.ts # Milvus client (create/upsert/search/delete)
│ ├── search-server.ts # Express HTTP API (humans / curl fallback)
│ ├── watcher.ts # Chokidar file watcher
│ ├── mcp-server.ts # stdio MCP server (preferred for agents)
│ ├── indexer.ts # reindex library (used by index + watch)
│ ├── clip-store.ts # in-memory store of clip refs (FIFO evict)
│ ├── read-clip.ts # shared file-slice helper (path safety, caps)
│ └── commands/
│ ├── init.ts # scaffold config + agent files + docker-compose
│ ├── doctor.ts # prereq check
│ ├── index.ts # reindex (full or incremental)
│ ├── serve.ts # HTTP server (fallback for humans)
│ ├── watch.ts # file watcher
│ ├── serve-and-watch.ts
│ ├── mcp.ts # stdio MCP server
│ ├── up.ts # one-shot bootstrap (init + Milvus + index + dev loop)
│ ├── down.ts # stop Milvus (volumes preserved)
│ └── status.ts # config + stats
└── templates/ # bundled init templates (written into your project)
├── codesearchrc.json # project config
├── codesearch-instructions.md # canonical MCP + HTTP reference (written to .github/instructions/)
├── copilot-instructions-section.md # slim pointer (appended to .github/copilot-instructions.md)
└── agent-semantic-search-section.md # slim dual-pointer (appended to each .github/agents/*.agent.md)
Why this exists
Grep is literal. Agents reinvent the same utilities because they don't know they exist. Semantic search by meaning fixes that, but the existing OSS options (Qdrant Cloud, hosted vector DBs, custom RAG frameworks) all add infrastructure that doesn't fit a single-dev box.
This package is the local-first version: Milvus in Docker, Ollama for embeddings, chokidar for live updates, MCP for agent integration. ~10 source files, no cloud dependencies, ~50ms per query after a warm cache.
Releasing
This package publishes to npm automatically via GitHub Actions — see
.github/workflows/publish.yml. The
publish is triggered by pushing a v* tag (or via manual dispatch in the
Actions tab).
To cut a release
- Bump
versioninpackage.json(npm version 0.2.0for stable,npm version 0.2.0-beta.1 --preid=betafor a pre-release —npm versionalso commits and tags for you). - Add an entry to
CHANGELOG.mdsummarising what's in the cut. - Push the commit and tag:
git push --follow-tags - CI publishes the version to npm — the dist-tag is auto-derived from
the version:
v0.2.0→latest,v0.2.0-beta.1→beta,v0.2.0-rc.2→rc. A GitHub Release is opened with auto-generated release notes.
CI prerequisites (one-time, on the repo)
The workflow reads an NPM_TOKEN secret from the repo's Actions
settings. Generate it on npmjs.com
(npm tokens docs):
create a granular access token scoped to this repository with
Packages and scopes → Read and write. Paste the value into
Settings → Secrets and variables → Actions → New repository secret
with name NPM_TOKEN. After that, releases are unattended.
License
MIT
Установить Codebase Semantic Search в Claude Desktop, Claude Code, Cursor
unyly install codebase-semantic-searchСтавит в Claude Desktop, Claude Code, Cursor и VS Code — сам разбирается с npx, uvx и сборкой из исходников.
Впервые? Поставь CLI: curl -fsSL https://unyly.org/install | sh
Или настроить вручную
Выполни в терминале:
claude mcp add codebase-semantic-search -- npx -y codebase-semantic-searchFAQ
Codebase Semantic Search MCP бесплатный?
Да, Codebase Semantic Search MCP бесплатный — установка в пару кликов через Unyly без оплаты.
Нужен ли API-ключ для Codebase Semantic Search?
Нет, Codebase Semantic Search работает без API-ключей и переменных окружения.
Codebase Semantic Search — hosted или self-hosted?
Self-hosted: сервер запускается локально на твоей машине командой из раздела установки.
Как установить Codebase Semantic Search в Claude Desktop, Claude Code или Cursor?
Открой Codebase Semantic Search на unyly.org, выбери вкладку своего клиента (Claude Desktop, Claude Code, Cursor) и нажми Install — конфиг сгенерируется автоматически, без правки JSON.
Похожие MCP
GitHub
PRs, issues, code search, CI status
автор: GitHubFilesystem
Secure file operations with configurable access controls.
Memory
Knowledge graph-based persistent memory system.
Template MCP Server
A CLI tool to create a new Model Context Protocol server project with TypeScript support, dual transport options, and an extensible structure
автор: mcpdotdirectCompare Codebase Semantic Search with
Не уверен что выбрать?
Найди свой стек за 60 секунд
Автор?
Embed-бейдж для README
Похожее
Все в категории development
