semantic-code-mcp
MCP server for semantic code search using AST-aware chunking and vector embeddings. Works with any AI coding tool that supports MCP.
The Problem
Traditional search tools like grep, ripgrep, and ag match text patterns exactly. When developers ask conceptual questions like "How is authentication handled?" or "Where do we process payments?", these tools require knowing exact function names or code patterns. This leads to:
- Overwhelming results: Thousands of lines containing search terms, most irrelevant
- Naming convention blindness: "authenticateUser", "login", "validateSession", and "handleAuth" are the same conceptโgrep doesn't know that
- Lost context: Results show isolated lines without surrounding code structure
AI coding tools inherit these limitations. Claude Code relies on grep/ripgrep for code searchโno semantic understanding, just string matching. Aider uses repo maps with graph ranking to select relevant code, but still depends on structural analysis rather than meaning. These approaches work on smaller codebases but struggle at scale, burning tokens on irrelevant results or missing conceptually related code.
The Solution
Semantic search understands code by meaning, not just text. It can answer "How is user authentication implemented?" by understanding conceptual relationshipsโregardless of function names or file locations.
Using local embeddings and vector search, it bridges the gap between text search limitations and LLM context constraints, providing more accurate results for navigating large codebases.
Features
- Semantic search - Find code by meaning, not just keywords
- Context graph - Understand how code connects (calls, imports, inheritance) with graph-enhanced search
- Session memory - Track agent exploration state across multi-turn conversations
- AST-aware chunking - Tree-sitter WASM for cross-platform parsing, no native compilation required
- Local embeddings - ONNX Runtime with nomic-embed-code (768 dims, 8K context)
- Hybrid search - Vector similarity + BM25 keyword matching
- Cross-encoder reranking - Higher precision with transformer reranking
- Incremental indexing - MD5 hashing for change detection, only re-index modified files
- File watching - Live updates as you code
- Lazy indexing - Index builds on first search, not on startup
- GPU support - CUDA auto-detection for 10-50x faster indexing
Installation
OpenCode
Add to ~/.config/opencode/opencode.json:
{
"mcp": {
"semantic-code": {
"type": "local",
"command": ["npx", "@smallthinkingmachines/semantic-code-mcp"],
"enabled": true
}
}
}
Claude Code
Add to ~/.claude.json or project .mcp.json:
{
"mcpServers": {
"semantic-code": {
"command": "npx",
"args": ["@smallthinkingmachines/semantic-code-mcp"]
}
}
}
VS Code
Add to .vscode/mcp.json (workspace) or run MCP: Add Server command:
{
"servers": {
"semantic-code": {
"command": "npx",
"args": ["-y", "@smallthinkingmachines/semantic-code-mcp"]
}
}
}
Specifying a Directory
The server indexes your current working directory by default. To index a specific directory, add it as an argument:
# OpenCode: ["npx", "@smallthinkingmachines/semantic-code-mcp", "/path/to/project"]
# VS Code: "args": ["-y", "@smallthinkingmachines/semantic-code-mcp", "/path/to/project"]
# Claude: "args": ["@smallthinkingmachines/semantic-code-mcp", "/path/to/project"]
First Run
On first search, the server will:
- Download models (~400MB) - embedding and reranking models are cached in
~/.cache/semantic-code-mcp/ - Index your codebase - parses and embeds all supported files (progress shown in logs)
Subsequent searches use the cached models and index. The index updates automatically when files change.
Tool: semantic_search
Search code semantically using natural language queries.
Parameters
Example
semantic_search({
query: "authentication middleware that validates JWT tokens",
path: "src/",
limit: 5
})
Architecture
MCP Server
โโโ Chunker (web-tree-sitter) โ AST-aware code splitting (WASM, cross-platform)
โโโ Embedder (ONNX local) โ nomic-embed-code, 768 dims
โโโ Vector DB (LanceDB) โ Serverless, hybrid search
โโโ Context Graph (SQLite) โ Structural relationships + session memory
โโโ File Watcher (chokidar) โ Incremental updates
โโโ Hybrid Search โ BM25 + vector + reranking
Context Graph (Opt-in)
The context graph adds structural awareness on top of semantic search. Enable it with:
SEMANTIC_CODE_GRAPH_ENABLED=true
When enabled, the server extracts structural relationships (calls, imports, extends, implements) from the AST during indexing and stores them in a SQLite graph. This powers three additional tools.
Tool: context_query
Semantic search + graph neighborhood expansion. Returns search results enriched with structural context.
context_query({
query: "payment processing",
depth: 2,
session_id: "debug-checkout"
})
Returns each search result plus its graph neighbors โ callers, callees, imports, and inheritance โ without reading additional files.
Tool: graph_annotate
Leave notes on code nodes and create links between related chunks.
Tool: session_summary
View exploration state: visited nodes, frontier, annotations, reasoning log, and graph stats.
Graph Configuration
The graph degrades gracefully โ if SQLite initialization fails, semantic search continues to work without graph features.
Supported Languages
- TypeScript / JavaScript (including TSX/JSX)
- Python
- Go
- Rust
- Java
- C / C++
- C#
Other languages fall back to line-based chunking.
Configuration
Environment Variables
Default Ignore Patterns
The following patterns are ignored by default:
**/node_modules/**
**/.git/**
**/dist/**
**/build/**
**/.next/**
**/coverage/**
**/__pycache__/**
**/venv/**
**/.venv/**
**/target/** (Rust)
**/vendor/** (Go)
**/*.min.js
**/*.bundle.js
**/*.map
**/package-lock.json
**/yarn.lock
**/pnpm-lock.yaml
**/.semantic-code/**
Security
The server includes protection against common attack vectors:
- SQL Injection: All filter inputs are validated against a strict whitelist
- Path Traversal: Search paths are validated to stay within the root directory
- Input Validation: IDs and patterns are validated before database operations
Invalid inputs throw typed errors (InvalidFilterError, PathTraversalError, InvalidIdError) that can be caught and handled appropriately.
Storage
- Index location:
.semantic-code/index/(add to.gitignore) - Graph database:
.semantic-code/index/graph.db(SQLite, created when graph is enabled) - Model cache:
~/.cache/semantic-code-mcp/ - Estimated size: 3GB codebase โ ~1.5GB index (with float16)
Documentation
- Deployment Guide - Production deployment, Docker, performance tuning
- Troubleshooting Guide - Common issues and solutions
- Architecture Overview - Internal design and data flow
Development
# Install dependencies
yarn install
# Build
yarn build
# Run in development
yarn dev
# Run tests
yarn test
# Run specific test suites
yarn test -- tests/integration/ # Integration tests
yarn test -- tests/edge-cases/ # Edge case tests
yarn test -- tests/performance/ # Performance benchmarks
Project Structure
semantic-code-mcp/
โโโ src/
โ โโโ index.ts # MCP server entry point
โ โโโ chunker/
โ โ โโโ index.ts # AST-aware chunker + edge extraction
โ โ โโโ languages.ts # Language configs with WASM paths
โ โ โโโ wasm-loader.ts # WASM grammar loader with caching
โ โโโ embedder/
โ โ โโโ index.ts # ONNX embedding generation
โ โ โโโ model.ts # Model download & loading
โ โโโ graph/
โ โ โโโ index.ts # SQLite graph store (nodes, edges, BFS)
โ โ โโโ config.ts # Graph configuration from env vars
โ โ โโโ extractor.ts # Edge resolution (raw edges โ graph edges)
โ โ โโโ schema.ts # SQLite DDL for graph tables
โ โ โโโ session.ts # In-memory session manager
โ โ โโโ types.ts # GraphNode, GraphEdge, RawEdge types
โ โโโ store/
โ โ โโโ index.ts # LanceDB integration
โ โโโ search/
โ โ โโโ index.ts # Hybrid search orchestration
โ โ โโโ reranker.ts # Cross-encoder reranking
โ โโโ watcher/
โ โ โโโ index.ts # File watcher + incremental indexing
โ โโโ tools/
โ โ โโโ semantic-search.ts # semantic_search tool
โ โ โโโ context-query.ts # context_query tool (search + graph)
โ โ โโโ graph-annotate.ts # graph_annotate tool
โ โ โโโ session-summary.ts # session_summary tool
โ โโโ utils/
โ โโโ logger.ts # Structured logging
โ โโโ validation.ts # Shared ID validation
โ โโโ ...
โโโ grammars/ # Pre-built WASM parsers
โโโ scripts/
โ โโโ copy-grammars.js # Build script for WASM files
โโโ package.json
โโโ tsconfig.json
โโโ README.md
Appendix
Nix Users
Due to Nix's PATH isolation, npx may not find the binary. Install to a fixed location instead:
npm install --prefix ~/.local/share/semantic-code-mcp @smallthinkingmachines/semantic-code-mcp
Then use in your MCP config (replace YOUR_USERNAME):
{
"mcpServers": {
"semantic-code": {
"command": "node",
"args": ["/home/YOUR_USERNAME/.local/share/semantic-code-mcp/node_modules/@smallthinkingmachines/semantic-code-mcp/dist/index.js"]
}
}
}