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 tableCREATETABLEembeddings(idINTEGERPRIMARYKEY,symbol_idINTEGER,embeddingBLOB,FOREIGNKEY(symbol_id)REFERENCESsymbols(id));// Query by similaritySELECTsymbols.*FROMsymbolsWHEREsymbol_idIN(SELECTsymbol_idFROMembeddingsWHEREvector_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