Skip to content

smallthinkingmachines/semantic-code-mcp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

49 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

semantic-code-mcp

npm version License: MIT

MCP server for semantic code search using AST-aware chunking and vector embeddings. Works with any AI coding tool that supports MCP.

GitHub | npm

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:

  1. Download models (~400MB) - embedding and reranking models are cached in ~/.cache/semantic-code-mcp/
  2. 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

Parameter Type Required Description
query string Yes Natural language query describing what you're looking for
path string No Directory path to scope the search
limit number No Maximum results (default: 10, max: 50)
file_pattern string No Glob pattern to filter files (e.g., ".ts", "**/.py")

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.

Parameter Type Required Description
query string Yes Natural language query
path string No Directory to scope the search
limit number No Maximum results (default: 10)
file_pattern string No Glob pattern to filter files
depth number No Graph traversal depth (1-3, default: 1)
edge_kinds string[] No Edge types to follow: calls, imports, extends, implements, exports, agent_linked
session_id string No Session ID for exploration tracking
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.

Parameter Type Required Description
session_id string Yes Session ID
node_id string Yes Chunk ID to annotate
note string No Note to attach
link_to string[] No Chunk IDs to create agent_linked edges to
reasoning string No Reasoning log entry

Tool: session_summary

View exploration state: visited nodes, frontier, annotations, reasoning log, and graph stats.

Parameter Type Required Description
session_id string Yes Session ID to summarize

Graph Configuration

Variable Description Default
SEMANTIC_CODE_GRAPH_ENABLED Enable the context graph false
SEMANTIC_CODE_GRAPH_DEPTH Default BFS traversal depth (1-5) 2
SEMANTIC_CODE_SESSION_TTL Session TTL in seconds 3600
SEMANTIC_CODE_EDGE_KINDS Comma-separated edge types to follow all types

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

Variable Description Default
SEMANTIC_CODE_ROOT Root directory to index Current working directory
SEMANTIC_CODE_INDEX Custom index storage location .semantic-code/index/
SEMANTIC_CODE_GRAPH_ENABLED Enable context graph false
SEMANTIC_CODE_GRAPH_DEPTH Default graph traversal depth (1-5) 2
SEMANTIC_CODE_SESSION_TTL Session TTL in seconds 3600
SEMANTIC_CODE_EDGE_KINDS Edge types to follow (comma-separated) all types

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

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"]
    }
  }
}

About

πŸ’½ MCP server for semantic code search using AST-aware chunking and vector embeddings.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors