code-search
Enables semantic code search across indexed code folders using vector embeddings, with support for multiple embedding providers and automatic file watching. Provides an admin UI and integrates with MCP clients for natural language code queries.
README
Code Search MCP Server
An MCP (Model Context Protocol) server for semantic code search using vector embeddings. Index your code folders and perform semantic searches to find code by meaning, not just keywords.
Features
- Multi-folder support: Index multiple code folders simultaneously
- Semantic search: Find code by meaning, not just keywords
- Continuous file watching: Automatically re-indexes files when they change
- Multiple embedding providers: OpenAI, Ollama, Gemini, Mistral, Bedrock, OpenRouter
- Admin UI: Web dashboard to monitor queries and indexing progress
- 35+ language support: JavaScript, TypeScript, Python, Rust, Go, and more
- Embedding cache: SQLite-based caching to avoid redundant API calls
- LSP enrichment: Type signatures and documentation via Language Server Protocol
- Hierarchical context: Parent class/module context included in embeddings
Prerequisites
Required:
- Node.js 18+
- Qdrant vector database (local or cloud)
- An embedding provider (Ollama for local, or API keys for cloud providers)
Optional (for LSP enrichment):
# TypeScript/JavaScript LSP (improves search quality for TS/JS/TSX/JSX)
npm install -g typescript-language-server typescript
# C# LSP (improves search quality for .cs files)
dotnet tool install --global csharp-ls
Installation
# Clone the repository
git clone https://github.com/amolchanov/mcp-code-search.git
cd mcp-code-search
# Install dependencies
npm install
# Download tree-sitter WASM files
npm run download-wasm
# Build the project
npm run build
Running the Server
The server can run in two modes:
Mode 1: Stdio (for CLI integration)
Used when integrating with Claude CLI, Copilot, or other MCP clients:
# Run directly (waits for JSON-RPC input on stdin)
node dist/index.js
# Or with auto-indexing of specific folders
node dist/index.js --index /path/to/project1 --index /path/to/project2
In stdio mode, the server communicates via stdin/stdout using the MCP protocol. This is what Claude CLI uses when you add it as an MCP server.
Mode 2: SSE with Admin UI (for web dashboard)
Used for the web-based admin interface:
# Start with default port 3100
node dist/index.js --sse
# Or specify a custom port
node dist/index.js --sse --port 8080
# With system tray icon (Windows/macOS)
node dist/index.js --sse --tray
# With auto-indexing
node dist/index.js --sse --index /path/to/project
Then open: http://localhost:3100/admin
Mode 3: Running with PM2 (Auto-Restart on Crash)
For production use, run the server with PM2 for automatic restart if it crashes:
# Install PM2 globally (one-time)
npm install -g pm2
# Start the server with PM2
npm run pm2:start
# View logs
npm run pm2:logs
# Check status
npm run pm2:status
# Stop the server
npm run pm2:stop
# Restart the server
npm run pm2:restart
PM2 will automatically restart the server if it crashes (up to 10 times). Logs are saved to logs/output.log and logs/error.log.
Command Line Options
| Option | Description |
|---|---|
--sse |
Run in SSE mode with HTTP server and Admin UI |
--port <number> |
HTTP port for SSE mode (default: 3100) |
--tray |
Show system tray icon (SSE mode only) |
--index <path> |
Auto-index a folder on startup (can be repeated) |
Architecture: Single Server Model
When multiple MCP clients (e.g., multiple Copilot CLI windows) connect simultaneously, the server uses a client-server architecture to prevent database corruption:
┌─────────────────────────────────────────────────┐
│ SSE Server (Daemon) │
│ • Handles ALL indexing and database writes │
│ • HTTP API at localhost:3100 │
│ • Admin UI for monitoring │
└─────────────────────────────────────────────────┘
↑ HTTP
┌───────────┼───────────┐
┌────┴────┐ ┌────┴────┐ ┌───┴─────┐
│ stdio │ │ stdio │ │ stdio │
│ client │ │ client │ │ client │
└─────────┘ └─────────┘ └─────────┘
↑ ↑ ↑
Copilot 1 Copilot 2 Copilot 3
How it works:
- Each stdio instance (spawned by Copilot/Claude CLI) is a lightweight client
- Clients proxy all tool calls to the central SSE server via HTTP
- The SSE server auto-starts if not running when a client connects
- All database writes (SQLite caches, Qdrant) go through the single server
- This prevents corruption from concurrent writes
Key benefits:
- No database locking issues with multiple CLI windows
- Single indexing process per repository
- Shared embedding cache across all clients
- Consistent state visible in Admin UI
Setting Up Prerequisites
Installing Docker (Required for Qdrant)
If you don't have Docker installed:
Windows/macOS:
- Download Docker Desktop from docker.com
- Install and start Docker Desktop
- Verify installation:
docker --version
Linux:
# Ubuntu/Debian
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker $USER # Add your user to docker group
# Log out and back in for group changes to take effect
Running Qdrant (Required)
Qdrant is the vector database that stores code embeddings. Choose one option:
Option A: Docker (Recommended)
Start Qdrant container:
# Run in foreground (stops when terminal closes)
docker run -p 6333:6333 qdrant/qdrant
# OR run in background (keeps running)
docker run -d -p 6333:6333 -v qdrant_storage:/qdrant/storage --name qdrant qdrant/qdrant
# Check if running
docker ps | grep qdrant
# Stop the container
docker stop qdrant
# Restart the container
docker start qdrant
# View logs
docker logs qdrant
Verify Qdrant is running:
curl http://localhost:6333/collections
# Should return: {"result":{"collections":[]}, ...}
Option B: Local Installation
Follow the Qdrant installation guide for native installation.
Running Ollama (Optional - for Local Embeddings)
Ollama provides free local embeddings without API costs. Alternatively, you can use OpenAI, Gemini, Mistral, or Bedrock.
Option A: Native Installation (Recommended)
Download and Install:
- Windows/macOS/Linux: Download from ollama.ai
- Follow the installer instructions
Pull the embedding model:
# Recommended model for code (8192 token context)
ollama pull nomic-embed-text
# Verify model is downloaded
ollama list
# Test the model
ollama run nomic-embed-text
Option B: Docker
# Run Ollama in Docker
docker run -d -v ollama:/root/.ollama -p 11434:11434 --name ollama ollama/ollama
# Pull the embedding model
docker exec ollama ollama pull nomic-embed-text
# Verify
docker exec ollama ollama list
Start/Stop Ollama:
# Native installation - Ollama runs as a service automatically
# Check status
curl http://localhost:11434/api/tags
# Docker
docker start ollama
docker stop ollama
Verify Everything is Running
Before starting the MCP server, check:
# Check Qdrant
curl http://localhost:6333/collections
# Check Ollama (if using)
curl http://localhost:11434/api/tags
Integration with Claude Code CLI
Step 1: Add MCP Server Configuration
Recommended: Use the Claude CLI command:
# Add to current project (creates .mcp.json in project root)
claude mcp add code-search -s project -- node /path/to/code-search-mcp/dist/index.js
# Or add globally for all projects (user-level config)
claude mcp add code-search -s user -- node /path/to/code-search-mcp/dist/index.js
Windows example:
claude mcp add code-search -s project -- node C:/repos/code-search-mcp/dist/index.js
Verify the server is connected:
claude mcp list
# Should show: code-search: node ... - ✓ Connected
Alternative: Manual JSON configuration
Add to .mcp.json in your project root:
{
"mcpServers": {
"code-search": {
"type": "stdio",
"command": "node",
"args": ["/path/to/code-search-mcp/dist/index.js"],
"env": {}
}
}
}
Step 2: Add Instructions for Claude Code
Option A: Use the MCP tool (recommended)
Once connected, ask Claude to run:
Use the get_instructions tool to get the code-search instructions, then add them to my CLAUDE.md file.
Or via CLI:
# The get_instructions tool returns markdown content for CLAUDE.md
# Format options: "claude" (default), "copilot", "generic"
Option B: Copy manually
# Copy to global instructions
cp examples/CLAUDE.md ~/.claude/CLAUDE.md
# Or append to existing instructions
cat examples/CLAUDE.md >> ~/.claude/CLAUDE.md
See examples/CLAUDE.md for the full instructions template.
Key points:
- Prefer
mcp__code-search__searchover built-inGrepandGlobfor finding code - Use natural language queries: "authentication middleware that validates JWT tokens"
- Fall back to
Greponly for exact string/regex matches
Integration with GitHub Copilot CLI
Step 1: Add MCP Server Configuration
You can configure the server globally (for all repos) or per-repository:
Option A: Global Configuration (All Repositories)
Add this to your global Copilot CLI MCP settings file:
Location: ~/.copilot/mcp-config.json (create if it doesn't exist)
Windows: C:\Users\<username>\.copilot\mcp-config.json
{
"mcpServers": {
"code-search": {
"type": "local",
"command": "node",
"args": ["/path/to/code-search-mcp/dist/index.js"],
"tools": ["*"]
}
}
}
Windows example:
{
"mcpServers": {
"code-search": {
"type": "local",
"command": "node",
"args": ["c:/repos/mcp-code-search/dist/index.js"],
"tools": ["*"]
}
}
}
Option B: Repository-Specific Configuration
Add .copilot/mcp-config.json to your repository root:
# In your project repository
mkdir -p .copilot
touch .copilot/mcp-config.json
Add the same configuration:
{
"mcpServers": {
"code-search": {
"type": "local",
"command": "node",
"args": ["/path/to/code-search-mcp/dist/index.js"],
"tools": ["*"]
}
}
}
Note:
- Repository-specific config takes precedence over global config
- Don't commit
.copilot/mcp-config.jsonto version control (add to.gitignore) - If you already have MCP servers configured, add the
code-searchentry to the existingmcpServersobject
Step 2: Add Instructions for Copilot
Copy the example instructions to your Copilot instructions file:
See examples/COPILOT.md for the full instructions template.
Key points:
- Prefer semantic search over grep for finding code
- Use descriptive natural language queries
- Search before implementing to find existing patterns
Admin UI Features
The Admin UI is available when running in SSE mode (see Running the Server):
node dist/index.js --sse
# Then open: http://localhost:3100/admin
Folders Tab:
- View all indexed folders with status
- Add new folders via path input
- Remove folders (deletes indexed data)
- Reindex folders (useful after upgrading to get new features)
Queries Tab:
- Query history with expandable results
- Timeline or per-folder view
- Clear query logs
Ingestion Tab:
- Real-time indexing progress
- File counts and error tracking
Services Tab:
- Ollama status and controls (start/stop)
- LSP enrichment status
Settings Tab:
- Embedding cache statistics
- Cache warming controls
- File watcher configuration
Configuration
Use the configure tool to set up the server after connecting.
Ollama (Local, Free)
{
"qdrantUrl": "http://localhost:6333",
"embedderProvider": "ollama",
"ollamaBaseUrl": "http://localhost:11434",
"modelId": "nomic-embed-text:latest"
}
OpenAI
{
"embedderProvider": "openai",
"openAiApiKey": "sk-...",
"modelId": "text-embedding-3-small"
}
Other Providers
Supported: gemini, mistral, bedrock, openrouter, openai-compatible
Per-Folder Embedding Models
You can configure different embedding models for different folders via the Admin UI. This is useful when:
- Some projects need higher quality embeddings (use larger models)
- Some projects need faster indexing (use smaller models)
- Testing different models for comparison
Supported models and their context sizes:
| Model | Provider | Context (tokens) |
|---|---|---|
nomic-embed-text |
Ollama | 8192 |
mxbai-embed-large |
Ollama | 512 |
text-embedding-3-small |
OpenAI | 8191 |
text-embedding-3-large |
OpenAI | 8191 |
text-embedding-ada-002 |
OpenAI | 8191 |
mistral-embed |
Mistral | 8192 |
voyage-code-2 |
Voyage | 16000 |
voyage-code-3 |
Voyage | 32000 |
gemma2 |
Ollama | 8192 |
snowflake-arctic-embed |
Ollama | 8192 |
Note: For code indexing, models with larger context (8192+ tokens) are recommended to avoid truncation of large functions/classes.
Available Tools Reference
Management
| Tool | Description |
|---|---|
add_folder |
Add a folder to be indexed |
remove_folder |
Remove a folder from indexing |
list_folders |
List all indexed folders |
clear_index |
Clear/rebuild index |
reindex_folder |
Reindex a folder (clears and rebuilds) |
pause_indexing |
Pause indexing for a folder |
resume_indexing |
Resume paused indexing |
reenrich_folder |
Re-enrich folder with LSP (for folders indexed without LSP) |
Search
| Tool | Description |
|---|---|
search |
Perform semantic code search |
Search Parameters:
query(required): Natural language search queryfolderPath: Filter to specific folderfileTypes: Filter by extensions (e.g.,[".ts", ".js"])minScore: Minimum similarity (0-1)maxResults: Max results to return
Status
| Tool | Description |
|---|---|
get_status |
Get indexing status |
get_errors |
Get error reports |
configure |
Update server configuration |
get_instructions |
Get AI assistant instructions (for CLAUDE.md, etc.) |
CLI Usage Examples
# From Claude CLI, you can use these tools directly:
# "search for authentication middleware"
# "add folder /path/to/project"
# "pause indexing for project-name"
# "reindex the api folder"
Supported Languages
JavaScript, TypeScript, TSX, JSX, Python, Rust, Go, C, C++, C#, Java, Ruby, PHP, Swift, Kotlin, Scala, Elixir, Erlang, Haskell, OCaml, Lua, Perl, R, Julia, Dart, Vue, Svelte, HTML, CSS, SCSS, SQL, GraphQL, Markdown, JSON, YAML, TOML, XML, Bash, PowerShell, Dockerfile, Terraform, Solidity, Zig, Nim, and more.
Ignoring Files
The server respects .gitignore files in indexed folders. You can also create a .cs-mcp-ignore file with additional patterns to exclude.
Always ignored directories:
node_modules,.git,dist,build,.next,.cache,coverage,.venv,vendor,target, etc.
Data Storage
All server data is stored in a platform-appropriate application data folder:
| Platform | Location |
|---|---|
| Windows | %LOCALAPPDATA%\code-search |
| macOS | ~/Library/Application Support/code-search |
| Linux | ~/.local/share/code-search (or $XDG_DATA_HOME/code-search) |
Folder contents:
code-search/
├── config.json # Server configuration
├── folders.json # Indexed folder registry
├── embedding-cache.db # SQLite embedding cache
├── lsp-cache.db # LSP enrichment cache
├── queries/ # Query logs (daily JSONL files)
│ └── queries-YYYY-MM-DD.jsonl
└── cache/ # Per-folder file hash cache
└── {folder-id}.json
Notes:
- Query logs are automatically cleaned up after 1 day
- Both stdio (Claude CLI) and SSE (Admin UI) servers share the same data
- Embedding cache persists across restarts to avoid redundant API calls
Advanced Features
Embedding Cache
The server caches computed embeddings in SQLite to avoid redundant API calls. When re-indexing or updating files:
- Unchanged code chunks reuse cached embeddings
- Only new/modified code requires embedding API calls
- Cache is keyed by content hash and model ID
The cache auto-warms from existing Qdrant data on startup.
LSP Enrichment (Optional)
Enable Language Server Protocol integration to enrich code chunks with type information before embedding:
{
"lspEnabled": true,
"lspTimeout": 5000,
"lspMaxConcurrentRequests": 5,
"lspUseOmniSharp": false
}
Benefits:
- Type signatures improve semantic matching
- Documentation/JSDoc included in embeddings
- Better results for type-related queries
Prerequisites:
- TypeScript/JavaScript:
npm install -g typescript-language-server typescript - C#:
dotnet tool install --global csharp-ls(or setlspUseOmniSharp: truefor OmniSharp)
Hierarchical Context
Code chunks automatically include parent context from the AST:
- Class name for methods
- Module name for functions
- Namespace for nested types
- Parent function for nested functions
This helps queries like "authentication method in UserService" match more accurately.
Git Worktree Support
The server automatically detects git worktrees and optimizes indexing:
How it works:
- When you add a worktree folder, the server detects it's a worktree
- The base repository is automatically discovered and indexed (if not already)
- Both repos are indexed, but the embedding cache deduplicates shared code
- Admin UI shows worktree relationships with "worktree" and "base repo" badges
Benefits:
- No duplicate embedding API calls for shared code (same content = cached embedding)
- Clear visualization of repo relationships in admin UI
- Automatic cleanup detection for deleted worktrees
Important: Keep your base repository checked out to the main/master branch for best results. The index reflects whatever is on disk, not a specific git branch.
Orphaned folder cleanup: If you delete a worktree from disk, the server marks it as "orphaned" on next startup. Use the Cleanup button in the admin UI to remove orphaned indexes.
Reindexing After Upgrade
When upgrading to a version with new enrichment features (LSP, hierarchical context), you need to reindex existing folders to take advantage of the improvements:
- Open Admin UI at
http://localhost:3100/admin - Go to the Folders tab
- Click Reindex on each folder
This clears the existing index and re-indexes all files with the new enrichment features.
Future Improvements
See FUTURE-IMPROVEMENTS.md for planned enhancements including:
- LLM re-ranking for improved relevance
- Multi-level code summaries
- Graph-based relationship tracking
- Hybrid BM25 + vector search
Troubleshooting
Claude CLI: "Failed to connect" Error
Symptom: claude mcp list shows code-search: ... - ✗ Failed to connect
Solutions:
-
Verify the server can start manually:
node /path/to/code-search-mcp/dist/index.jsShould output:
[CodeSearch] Server running on stdio -
Check if Qdrant is running:
curl http://localhost:6333/collectionsIf not running, start it:
docker run -p 6333:6333 qdrant/qdrant -
Check if Ollama is running (if using Ollama embeddings):
curl http://localhost:11434/api/tagsIf not running, start Ollama and ensure the model is pulled:
ollama pull nomic-embed-text -
Wrong config file location:
- Claude CLI reads
.mcp.jsonfrom the project root, NOT.claude/mcp.json - Use
claude mcp addcommand to ensure correct placement - Run
claude mcp listto verify registration
- Claude CLI reads
-
SSE vs stdio mode conflict:
- If running the Admin UI in SSE mode (
--sseflag), Claude CLI cannot connect - Stop the SSE server before using stdio mode with Claude CLI
- Or run two separate instances (different ports)
- If running the Admin UI in SSE mode (
-
Rebuild after code changes:
npm run build
Indexing Stuck or Not Progressing
-
Check for errors in server output:
- Run manually to see logs:
node dist/index.js - Look for embedding API errors (context length, rate limits)
- Run manually to see logs:
-
Embedding model context limits:
mxbai-embed-large: 512 tokens (small, may truncate code)nomic-embed-text: 8192 tokens (recommended for code)- Large code chunks are automatically truncated with a warning
-
Pause and resume indexing:
- Use Admin UI or MCP tools to pause/resume
- Check
get_errorsfor specific file failures
LSP Enrichment Not Working
-
Check LSP server is installed:
# TypeScript/JavaScript typescript-language-server --version # C# csharp-ls --version -
Enable LSP in config:
{ "lspEnabled": true } -
Check LSP status in Admin UI: Services tab shows LSP server status
Search Returns Poor Results
- Reindex with LSP enabled for better type information
- Use descriptive queries: "function that validates user email" instead of "validate"
- Check folder is fully indexed: Use
get_statusor Admin UI - Try different embedding model: Some models work better for code
Windows Path Issues
-
Use forward slashes in JSON config:
"args": ["C:/repos/code-search/dist/index.js"]Not backslashes:
"C:\\repos\\..."(can cause escaping issues) -
Avoid spaces in paths or ensure proper quoting
Port Already in Use (SSE Mode)
# Find what's using port 3100
netstat -ano | findstr :3100 # Windows
lsof -i :3100 # macOS/Linux
# Use a different port
node dist/index.js --sse --port 3101
Qdrant Connection Refused
-
Check Docker is running:
docker ps | grep qdrant -
Restart Qdrant container:
docker restart $(docker ps -q --filter ancestor=qdrant/qdrant) # Or start fresh: docker run -d -p 6333:6333 -v qdrant_storage:/qdrant/storage qdrant/qdrant -
Check firewall/antivirus isn't blocking port 6333
Memory Issues with Large Repositories
-
Increase Node.js memory limit:
node --max-old-space-size=4096 dist/index.js -
Index folders incrementally instead of all at once
-
Use
.cs-mcp-ignoreto exclude large generated files or vendor directories
Embedding API Rate Limits
- Use Ollama for local embeddings (no rate limits)
- Pause and resume indexing to spread out API calls
- Check provider dashboard for rate limit details
- The embedding cache prevents redundant calls on re-indexing
License
MIT License - see LICENSE file.
Third-Party Licenses
See THIRD-PARTY-LICENSES.md for dependency licenses.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。