qdrant-mcp
MCP server that gives AI coding agents persistent, semantic memory via Qdrant vector search.
Built for Claude Code but works with any MCP-compatible client.
"How does the price sync work?"
┌─ codebase ──────── sync-prices.ts (function syncFromAPI)
├─ documentation ─── API reference: POST /products/sync
├─ business_rules ── "Manual discounts override synced prices"
└─ decisions ─────── ADR-007: Pull model chosen over webhooks
Key Features
Workspace-aware search — detects uncommitted changes via git status. Modified files return fresh content from disk, not stale embeddings. New files are discovered even before their first commit.
4 knowledge collections — code, documentation, business rules, architectural decisions. Search one or all at once.
Content-hashed indexing — only re-embeds chunks that actually changed. Full reindex of a large project takes seconds, not minutes.
Incremental by default — git post-commit hook triggers indexing of changed files in the background. Zero manual effort after setup.
Architecture
┌────────────────────────────────────────────────────────┐
│ Claude Code Agent │
│ │ │
│ MCP Protocol │
└────────────────────────┬───────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────┐
│ qdrant-mcp (this server) │
│ │
│ Tools: │
│ search_codebase search_docs search_business │
│ search_decisions search_all reindex │
│ │
│ Workspace-Aware Layer: │
│ ┌──────────────┐ ┌───────────────┐ ┌───────────────┐ │
│ │WorkspaceState│→│FreshContent │→│NewFiles │ │
│ │ git status │ │Resolver │ │Matcher │ │
│ │ dirty/new/del│ │ disk override │ │ path+keyword │ │
│ └──────────────┘ └───────────────┘ └───────────────┘ │
└────────────────────────┬───────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────┐
│ Qdrant (Docker) │
│ │
│ ┌──────────┐ ┌──────────────┐ ┌────────────────────┐ │
│ │ codebase │ │documentation │ │ business_rules │ │
│ └──────────┘ └──────────────┘ └────────────────────┘ │
│ ┌──────────────────┐ │
│ │ decisions │ │
│ └──────────────────┘ │
└────────────────────────────────────────────────────────┘
Quick Start
Prerequisites
- Node.js >= 20
- Docker (for Qdrant)
- OpenAI API key (or Ollama for local embeddings)
Install
git clone https://github.com/dutchakdev/qdrant-mcp.git
cd qdrant-mcp
npm install
npm run build
Configure
cp .env.example .env
Edit .env:
QDRANT_URL=http://localhost:6333
EMBEDDING_PROVIDER=openai
OPENAI_API_KEY=sk-your-key-here
PROJECT_ROOT=/path/to/your/project
Setup (one command)
npm run setup
This will:
- Start Qdrant via Docker Compose
- Create all 4 collections with proper indexes
- Run initial codebase indexing
- Install git post-commit hook
Connect to Claude Code
Add to your .claude/settings.json or claude_desktop_config.json:
{
"mcpServers": {
"project-knowledge": {
"command": "node",
"args": ["/absolute/path/to/qdrant-mcp/dist/index.js"],
"env": {
"PROJECT_ROOT": "/path/to/your/project",
"QDRANT_URL": "http://localhost:6333",
"EMBEDDING_PROVIDER": "openai",
"OPENAI_API_KEY": "sk-..."
}
}
}
}
MCP Tools
| Tool | Description | |------|-------------| | search_codebase | Semantic code search. Filters by language, project. Workspace-aware. | | search_docs | Documentation search across all indexed sources. | | search_business | Business rules and domain logic. Filter by domain. | | search_decisions | Architectural decisions, ADRs, resolved issues. | | search_all | Hybrid search across all collections at once. | | reindex | Trigger re-indexing (full or changed mode). |
How Workspace Awareness Works
The core problem: you edit a file, but Qdrant still has the old embedding. The agent gets stale context.
The solution is a 3-component pipeline that runs on every search:
WorkspaceState — calls git status --porcelain=v2 (cached 2s). Knows which files are modified, new, deleted, or renamed.
FreshContentResolver — if a Qdrant result points to a dirty file, reads the fresh version from disk and replaces the stale content. Tries to extract the same symbol (function/class) via regex for precision.
NewFilesMatcher — discovers relevant new files that Qdrant doesn't know about. Three-phase matching: path tokens → content keywords → (optional) on-the-fly embedding.
Overhead: ~10-30ms per search. Negligible compared to embedding + vector search latency.
See RACE-CONDITIONS.md for the full edge case matrix.
CLI
# One-time setup (Qdrant + collections + initial index + git hook)
npm run setup
# Index changed files (default: since last commit)
npm run index
# Full reindex
npm run index:full
# Watch mode (real-time indexing on file save)
npm run watch
# Show collection stats
npm run status
Embedding Providers
OpenAI (default)
EMBEDDING_PROVIDER=openai
OPENAI_API_KEY=sk-...
OPENAI_EMBEDDING_MODEL=text-embedding-3-small # 1536 dim, ~$0.02/1M tokens
Ollama (local, free)
EMBEDDING_PROVIDER=ollama
OLLAMA_URL=http://localhost:11434
OLLAMA_EMBEDDING_MODEL=nomic-embed-text # 768 dim
Install the model first: ollama pull nomic-embed-text
Project Structure
src/
├── index.ts # MCP server entry point
├── cli.ts # CLI (setup, index, watch, status)
├── config.ts # Environment-based configuration
├── types/
│ └── index.ts # Shared type definitions
├── embeddings/
│ └── provider.ts # OpenAI + Ollama embedding providers
├── qdrant/
│ ├── client.ts # Qdrant client singleton + init
│ └── collections.ts # Collection schemas + setup
├── indexers/
│ └── code-indexer.ts # Code chunking + content-hashed indexing
├── search/
│ └── workspace-aware-search.ts # Main search pipeline
├── workspace/
│ ├── workspace-state.ts # Git status → dirty/new/deleted detection
│ ├── fresh-content-resolver.ts # Stale → fresh content replacement
│ ├── new-files-matcher.ts # New file discovery (path + keyword + embedding)
│ └── index.ts
└── tools/
└── definitions.ts # MCP tool schemas
Customization
Adding new collections
Edit src/qdrant/collections.ts to add a collection, then add a corresponding search tool in src/tools/definitions.ts and handler in src/index.ts.
Indexing non-code content
The documentation and business_rules collections are ready but need custom indexers for your data sources. Create an indexer in src/indexers/ following the CodeIndexer pattern.
Adjusting chunking
The code indexer uses regex-based chunking by default (functions, classes, exports). For more precise AST-based chunking, replace the regex patterns in code-indexer.ts with tree-sitter parsing.
License
MIT











