A powerful, production-ready Model Context Protocol (MCP) server for fast code indexing and intelligent search across multi-language codebases. Built with Node.js, SQLite + FTS5, and designed for high performance.
- ๐ Full-Text Search - Fast content search across all files using SQLite FTS5
- ๐ฏ Symbol Lookup - Find functions, classes, variables, and their definitions
- ๐ Code Context - Intelligent ranking combining file matches and symbol search
- ๐๏ธ File Watching - Automatic re-indexing on file changes
- ๐ Multi-Language Support - JavaScript/TypeScript, Python, PHP (extensible)
- โก Performance Optimized - Batch inserts, prepared statements, proper indexing
- ๐๏ธ Structured Output - Clean JSON responses for integration
- ๐ Scalable - Handles 10,000+ files efficiently
- Runtime: Node.js (ESM)
- Database: SQLite with FTS5 + WAL mode
- Parsing:
- JavaScript/TypeScript: @babel/parser (full AST)
- Python: Regex-based extraction
- PHP: Regex-based extraction
- File Watching: chokidar
- MCP: @modelcontextprotocol/sdk
- HTTP: Express (optional alternative server)
cd code-index-mcp
npm installnpm run index /path/to/your/projectOr from the project directory:
npm run indexOptions:
-vor--verbose- Show all indexed files--clear- Clear the index before indexing
Example with verbose output:
npm run index /path/to/project -vnpm run serverThe server will start in stdio mode (compatible with Claude Code).
Alternative: HTTP mode
node mcp/server.js http 3000Server will be available at http://localhost:3000/mcp
In another terminal:
npm run watch /path/to/your/projectThe watcher will automatically re-index files as they change.
Check index statistics:
npm run index statsClear the entire index:
npm run index clearThe server exposes 8 powerful tools:
Full-text search across all indexed file content.
Input:
{
"query": "function handleClick",
"limit": 20
}Output:
[
{
"path": "src/components/Button.tsx",
"language": "typescript",
"snippet": "function handleClick(event) {\n // handle click\n}",
"content_length": 1024
}
]Find symbol definitions (functions, classes, variables) by name.
Input:
{
"name": "handleClick",
"limit": 50
}Output:
[
{
"name": "handleClick",
"type": "function",
"path": "src/components/Button.tsx",
"language": "typescript",
"line": 45,
"column": 10,
"scope": "Button"
}
]Retrieve full file content with line numbers.
Input:
{
"path": "src/main.js"
}Output:
{
"path": "src/main.js",
"language": "javascript",
"size": 2048,
"lines": 100,
"content": [
{ "line_number": 1, "content": "import React from 'react'" },
{ "line_number": 2, "content": "" }
]
}Get comprehensive context combining file and symbol matches.
Input:
{
"query": "authentication handler",
"limit": 30
}Output:
{
"query": "authentication handler",
"result_count": 5,
"results": [
{
"type": "file_match",
"path": "src/auth/handler.ts",
"language": "typescript",
"snippet": "export function authenticateUser(credentials) { ... }"
},
{
"type": "symbol_match",
"name": "authenticateUser",
"symbol_type": "function",
"path": "src/auth/handler.ts",
"language": "typescript",
"line": 42,
"scope": null
}
]
}Get database statistics.
Output:
{
"indexed_files": 1250,
"total_symbols": 8500,
"total_imports": 3200,
"database_size_mb": "25.5"
}List all indexed files with optional language filter.
Input:
{
"language": "typescript",
"limit": 100
}Output:
{
"count": 50,
"files": [
{
"path": "src/components/Button.tsx",
"language": "typescript",
"file_size": 2048
}
]
}Get all imports from a specific file.
Input:
{
"path": "src/main.ts"
}Output:
{
"path": "src/main.ts",
"import_count": 12,
"imports": [
{
"import_path": "react",
"import_name": "React",
"import_type": "import"
}
]
}Find files that import or depend on a specific file.
Input:
{
"path": "src/utils/helpers.ts",
"limit": 50
}Output:
{
"target_path": "src/utils/helpers.ts",
"dependent_count": 8,
"dependents": [
{
"path": "src/components/Button.tsx",
"language": "typescript",
"import_name": "{ formatDate }"
}
]
}Start server in HTTP mode:
node mcp/server.js http 3000Test search:
curl -X POST http://localhost:3000/mcp \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "search_code",
"arguments": {
"query": "function",
"limit": 10
}
}
}'Test symbol search:
curl -X POST http://localhost:3000/mcp \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "find_symbol",
"arguments": {
"name": "handleClick"
}
}
}'Get stats:
curl -X POST http://localhost:3000/mcp \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "get_stats",
"arguments": {}
}
}'The MCP server is fully compatible with Claude Code. To use with Claude Code:
- Configure Claude Code to connect to this MCP server
- Run the server in stdio mode:
npm run server - Claude will have access to all code search tools
Metadata about indexed files:
id- Primary keypath- Unique file path (relative)language- Programming languagelast_modified- Unix timestampfile_size- File size in bytes
Full-text search index of file contents:
content- File contentpath- File pathfile_id- Reference to files table
Extracted code symbols:
id- Primary keyfile_id- Reference to filename- Symbol nametype- Type (function, class, variable, method, etc.)line- Line numbercolumn- Column numberscope- Parent scope (e.g., class name)
Import/require statements:
id- Primary keyfile_id- Reference to fileimport_path- Path being importedimport_name- Name imported asimport_type- Type (import, require, use, etc.)
- FTS5 Tokenizer - Optimized for code search patterns
- Prepared Statements - All queries use prepared statements
- Batch Inserts - Processes 100 files per batch
- WAL Mode - SQLite write-ahead logging for concurrency
- Proper Indexing - Indexes on frequently queried columns
- File Exclusion - Skips node_modules, .git, build folders
- Modification Checks - Only re-indexes changed files
The system is designed to be extended with:
-
Vector Embeddings - Add semantic search with embeddings
- Store embeddings in a new
embeddingstable - Use vector similarity search
- Store embeddings in a new
-
Dependency Graph - Build a full dependency graph
- Add
dependenciestable tracking imports - Query transitive dependencies
- Add
-
AI Summarization - Automatic code summarization
- Summarize functions/classes
- Generate documentation
-
Language Support - Easy to add new languages
- Implement parser in
indexer/parser.js - Add to
detectLanguagemapping
- Implement parser in
// Add embeddings table
CREATE TABLE embeddings (
id INTEGER PRIMARY KEY,
symbol_id INTEGER,
embedding BLOB,
FOREIGN KEY (symbol_id) REFERENCES symbols(id)
);
// Query by similarity
SELECT symbols.* FROM symbols
WHERE symbol_id IN (
SELECT symbol_id FROM embeddings
WHERE vector_similarity(embedding, query_embedding) > 0.8
);code-index-mcp/
โโโ db/
โ โโโ schema.sql # Database schema
โโโ indexer/
โ โโโ indexer.js # Main indexing engine
โ โโโ parser.js # AST parsers (JS, Python, PHP)
โโโ mcp/
โ โโโ server.js # MCP server (stdio & HTTP)
โ โโโ tools.js # Tool implementations
โโโ watcher/
โ โโโ watcher.js # File watcher with debouncing
โโโ utils/
โ โโโ file.js # File utilities
โโโ package.json
โโโ README.md
# Verify the database was created
ls -la code-index.db
# Recreate from scratch
npm run clean && npm run index- Ensure files were indexed:
npm run index stats - Check file was indexed with correct language
- Try different search terms
- Ensure watcher is running:
npm run watch - Check file is in supported language (.js, .ts, .py, .php)
- Verify file is not in excluded directory (node_modules, .git, etc.)
- Increase batch size in
indexer.js - Use SQLite pragma optimizations (already configured)
- Consider filtering to specific directories in glob patterns
MIT
This is a complete, production-ready implementation. Feel free to extend it with:
- Additional language parsers
- Vector embeddings
- Dependency graph analysis
- Custom indexing strategies
For issues or questions:
- Check the troubleshooting section
- Review the database schema in
db/schema.sql - Check MCP tool documentation above