qdrant-mcp-ollama
by michal7kw
README.md
# qdrant-mcp-ollama
A [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server for [Qdrant](https://qdrant.tech/) vector database that uses [Ollama](https://ollama.com/) for **GPU-accelerated embeddings**.
## Why not the official mcp-server-qdrant?
The [official Qdrant MCP server](https://github.com/qdrant/mcp-server-qdrant) uses [FastEmbed](https://qdrant.github.io/fastembed/) for embeddings, which:
- **Runs on CPU only** — slow on large codebases, underutilizes modern GPUs
- **Uses a small model** (`all-MiniLM-L6-v2`, 384-dim) — lower quality embeddings
- **Single-process lock** in local mode — only one MCP client can access the database at a time
This server solves all three problems:
| | Official `mcp-server-qdrant` | `qdrant-mcp-ollama` |
|---|---|---|
| Embedding engine | FastEmbed (CPU) | Ollama (GPU) |
| Default model | all-MiniLM-L6-v2 (384-dim, 80MB) | bge-m3 (1024-dim, 1.2GB) |
| Concurrent access | No (local mode) | Yes (Qdrant server) |
| Model flexibility | FastEmbed models only | Any Ollama embedding model |
## Architecture
```
┌──────────────┐ ┌────────────────────┐ ┌─────────────┐
│ MCP Client │────>│ qdrant-mcp-ollama │────>│ Ollama │
│ (Claude Code, │ │ (server.py) │ │ (GPU) │
│ Kilo Code, │<────│ │ └─────────────┘
│ Cursor, etc) │ └────────┬───────────┘
└──────────────┘ │
v
┌────────────────────┐
│ Qdrant Server │
│ (Docker, :6333) │
│ Storage: local │
│ disk / cloud │
└────────────────────┘
```
## Prerequisites
- **[Ollama](https://ollama.com/)** — installed and running with an embedding model pulled
- **[Docker](https://www.docker.com/)** — for running the Qdrant server
- **[uv](https://docs.astral.sh/uv/)** — Python package manager (recommended) or `pip`
## Quick Start
### 1. Pull an embedding model in Ollama
```bash
ollama pull bge-m3
```
### 2. Start the Qdrant server
```bash
docker run -d --name qdrant-server \
-p 6333:6333 -p 6334:6334 \
-v qdrant-storage:/qdrant/storage \
--restart unless-stopped \
qdrant/qdrant:latest
```
### 3. Run the MCP server
```bash
# No install needed — uv downloads dependencies on-the-fly:
QDRANT_URL="http://localhost:6333" \
EMBEDDING_MODEL="bge-m3" \
uv run --with fastmcp --with qdrant-client --with httpx python server.py
```
### 4. Embed a codebase
```bash
uv run --with qdrant-client --with httpx python embed_codebase.py \
/path/to/your/project my-project --preset python
```
### 5. Search from your MCP client
Once configured (see sections below), ask your AI assistant:
> "Search the codebase for authentication logic"
It will use the `qdrant_find` tool to return semantically relevant code chunks.
---
## Setting Up the Qdrant Server
### Option A: Docker (recommended)
Store data on a specific drive (e.g., `E:` on Windows):
```bash
# Create storage directories
mkdir -p E:/qdrant-storage E:/qdrant-snapshots
# Start Qdrant with persistent storage
docker run -d --name qdrant-server \
-p 6333:6333 -p 6334:6334 \
-v E:/qdrant-storage:/qdrant/storage \
-v E:/qdrant-snapshots:/qdrant/snapshots \
--restart unless-stopped \
qdrant/qdrant:latest
```
On Linux/macOS:
```bash
docker run -d --name qdrant-server \
-p 6333:6333 -p 6334:6334 \
-v ~/qdrant-storage:/qdrant/storage \
--restart unless-stopped \
qdrant/qdrant:latest
```
The `--restart unless-stopped` flag ensures Qdrant starts automatically with Docker Desktop.
Verify it's running:
```bash
docker ps --filter name=qdrant-server
# Or open http://localhost:6333/dashboard in your browser
```
### Option B: Qdrant Cloud
Sign up at [cloud.qdrant.io](https://cloud.qdrant.io/) and get your URL and API key. Then set:
```bash
QDRANT_URL="https://your-cluster.cloud.qdrant.io:6333"
QDRANT_API_KEY="your-api-key"
```
> **Note:** The `QDRANT_API_KEY` environment variable is passed through to the Qdrant client automatically.
---
## Embedding a Codebase
The `embed_codebase.py` script scans a directory, chunks source files, and bulk-embeds them into Qdrant using Ollama on GPU.
### Basic usage
```bash
uv run --with qdrant-client --with httpx python embed_codebase.py <directory> <collection-name>
```
### Using extension presets
```bash
# Python project
python embed_codebase.py ./my-api api-backend --preset python
# Full-stack web project
python embed_codebase.py ./my-app frontend --preset web
# R / bioinformatics project
python embed_codebase.py ./analysis bio-analysis --preset r
# Everything
python embed_codebase.py ./mono-repo all-code --preset all
```
### Custom extensions
```bash
python embed_codebase.py ./project my-collection --extensions .py .sql .sh .yaml
```
### Available presets
| Preset | Extensions |
|---|---|
| `python` | `.py` `.pyi` |
| `javascript` | `.js` `.jsx` `.mjs` `.cjs` |
| `typescript` | `.ts` `.tsx` |
| `web` | `.js` `.jsx` `.ts` `.tsx` `.vue` `.svelte` `.html` `.css` `.scss` |
| `r` | `.R` `.r` `.Rmd` `.rmd` |
| `java` | `.java` |
| `csharp` | `.cs` |
| `go` | `.go` |
| `rust` | `.rs` |
| `cpp` | `.cpp` `.hpp` `.cc` `.hh` `.c` `.h` |
| `all` | All common source extensions |
If no `--preset` or `--extensions` is provided, the script auto-detects file types.
### All options
```
usage: embed_codebase.py <directory> <collection> [options]
positional arguments:
directory Path to the codebase directory
collection Qdrant collection name
options:
--extensions EXT [EXT ...] File extensions to include (e.g. .py .ts)
--preset PRESET Use a preset group of extensions
--model MODEL Ollama embedding model (default: bge-m3)
--qdrant-url URL Qdrant server URL (default: http://localhost:6333)
--ollama-url URL Ollama server URL (default: http://localhost:11434)
--chunk-size N Max lines per chunk (default: 80)
--chunk-overlap N Overlap lines between chunks (default: 10)
--batch-size N Upload batch size for Qdrant (default: 500)
--append Append to existing collection instead of replacing
```
### Append mode
By default, re-running the script **replaces** the collection. Use `--append` to add to an existing collection:
```bash
# First embed
python embed_codebase.py ./src main-code --preset typescript
# Add more files later
python embed_codebase.py ./docs main-code --extensions .md --append
```
---
## Multi-Codebase Usage
Use **separate collections** for each codebase to keep search results scoped and relevant:
```bash
# Project A
python embed_codebase.py ~/projects/api-server api-server --preset python
# Project B
python embed_codebase.py ~/projects/web-app web-app --preset web
# Project C
python embed_codebase.py ~/projects/data-pipeline data-pipeline --preset python
```
When configuring the MCP server:
- **Without `COLLECTION_NAME`**: You must specify the collection per query. This is ideal when one MCP server serves multiple projects.
- **With `COLLECTION_NAME`**: A default collection is used automatically. Set this per-project if your MCP client supports project-scoped configuration.
---
## Configuring Claude Code
### Add the MCP server
```bash
claude mcp add qdrant -s user \
-e QDRANT_URL="http://localhost:6333" \
-e OLLAMA_URL="http://localhost:11434" \
-e EMBEDDING_MODEL="bge-m3" \
-- uv run --with fastmcp --with qdrant-client --with httpx \
python /path/to/qdrant-mcp-ollama/server.py
```
Replace `/path/to/qdrant-mcp-ollama/` with the actual path where you cloned this repo.
### With a default collection
If you primarily work on one project:
```bash
claude mcp add qdrant -s user \
-e QDRANT_URL="http://localhost:6333" \
-e OLLAMA_URL="http://localhost:11434" \
-e EMBEDDING_MODEL="bge-m3" \
-e COLLECTION_NAME="my-project" \
-- uv run --with fastmcp --with qdrant-client --with httpx \
python /path/to/qdrant-mcp-ollama/server.py
```
### Verify
```bash
claude mcp list
# Should show: qdrant: ... ✓ Connected
claude mcp get qdrant
# Shows full configuration details
```
### Usage in Claude Code
Once configured, Claude Code can use these tools:
- **`qdrant_store`** — Store information: *"Store this authentication pattern in Qdrant"*
- **`qdrant_find`** — Search: *"Find code related to database migrations"*
For multi-collection setups (no default), specify the collection:
> "Search the `api-server` collection for rate limiting logic"
---
## Configuring Kilo Code (VS Code Extension)
Kilo Code is a VS Code extension with built-in MCP support.
### Option 1: Manual MCP configuration
1. Open Kilo Code settings in VS Code
2. Navigate to MCP Servers configuration
3. Add a new server with:
| Field | Value |
|---|---|
| **Name** | `qdrant` |
| **Command** | `uv` |
| **Arguments** | `run --with fastmcp --with qdrant-client --with httpx python /path/to/server.py` |
4. Set environment variables:
| Variable | Value |
|---|---|
| `QDRANT_URL` | `http://localhost:6333` |
| `OLLAMA_URL` | `http://localhost:11434` |
| `EMBEDDING_MODEL` | `bge-m3` |
| `COLLECTION_NAME` | Your project collection name (e.g., `my-project`) |
### Option 2: VS Code settings.json
Add to your VS Code `settings.json` (`Ctrl+Shift+P` > `Preferences: Open User Settings (JSON)`):
```json
{
"kilocode.mcpServers": {
"qdrant": {
"command": "uv",
"args": [
"run", "--with", "fastmcp", "--with", "qdrant-client", "--with", "httpx",
"python", "/path/to/qdrant-mcp-ollama/server.py"
],
"env": {
"QDRANT_URL": "http://localhost:6333",
"OLLAMA_URL": "http://localhost:11434",
"EMBEDDING_MODEL": "bge-m3",
"COLLECTION_NAME": "my-project"
}
}
}
}
```
### Per-project setup in Kilo Code
For multi-codebase setups, configure Kilo Code at **project scope** (not global) with a project-specific `COLLECTION_NAME`. This way each workspace searches only its own codebase.
---
## Configuring Other MCP Clients
### Cursor / Windsurf
Run the server with SSE transport for remote-capable clients:
```bash
QDRANT_URL="http://localhost:6333" \
OLLAMA_URL="http://localhost:11434" \
EMBEDDING_MODEL="bge-m3" \
FASTMCP_PORT=8000 \
uv run --with fastmcp --with qdrant-client --with httpx \
python server.py --transport sse
```
Then in Cursor/Windsurf MCP settings, connect to: `http://localhost:8000/sse`
### Generic MCP client (stdio)
The default transport is `stdio`. Any MCP client that supports stdio can use this server by running:
```bash
uv run --with fastmcp --with qdrant-client --with httpx python server.py
```
---
## Configuration Reference
### MCP Server Environment Variables
| Variable | Description | Default |
|---|---|---|
| `QDRANT_URL` | Qdrant server URL | `http://localhost:6333` |
| `QDRANT_API_KEY` | API key for Qdrant Cloud | None |
| `OLLAMA_URL` | Ollama server URL | `http://localhost:11434` |
| `EMBEDDING_MODEL` | Ollama embedding model name | `bge-m3` |
| `COLLECTION_NAME` | Default collection (empty = must specify per call) | *(empty)* |
### Choosing an Embedding Model
All models below are available via `ollama pull <model>`:
| Model | Dimensions | Size | Speed | Quality | Best for |
|---|---|---|---|---|---|
| `bge-m3` | 1024 | 1.2 GB | Moderate | High | General purpose, multilingual |
| `nomic-embed-text` | 768 | 274 MB | Fast | Good | Lightweight, English-focused |
| `mxbai-embed-large` | 1024 | 670 MB | Moderate | High | English, high quality |
| `snowflake-arctic-embed2` | 1024 | 1.2 GB | Moderate | Very High | Best quality, English |
| `all-minilm` | 384 | 46 MB | Very Fast | Fair | Minimal resources |
**Recommendation:** Start with `bge-m3`. It handles code well, supports multilingual content (comments in any language), and balances quality with speed.
> **Important:** The embedding model used to index a collection **must match** the model used for queries. If you re-embed with a different model, delete and recreate the collection.
### GPU Utilization
Larger models use more GPU. If your GPU is underutilized:
- Switch from `nomic-embed-text` (274 MB) to `bge-m3` (1.2 GB) or larger
- The embedding script sends all texts in a single batch to maximize GPU saturation
- For individual queries (via `qdrant_find`), GPU spikes are brief and normal — embedding a single query takes milliseconds
Check GPU usage: `nvidia-smi` (NVIDIA) or `rocm-smi` (AMD)
---
## MCP Tools
### `qdrant_store`
Store information in the Qdrant database.
| Parameter | Type | Required | Description |
|---|---|---|---|
| `information` | string | Yes | Text to store and make searchable |
| `collection_name` | string | If no default set | Target collection |
| `metadata` | dict | No | Optional metadata to attach |
### `qdrant_find`
Search for relevant information using semantic similarity.
| Parameter | Type | Required | Description |
|---|---|---|---|
| `query` | string | Yes | Natural language search query |
| `collection_name` | string | If no default set | Collection to search |
| `top_k` | int | No | Max results to return (default: 5) |
---
## Troubleshooting
### "Connection closed" / MCP server won't start
- **Is Ollama running?** Check with `ollama list`. Start it with `ollama serve` if needed.
- **Is the embedding model pulled?** Run `ollama pull bge-m3`.
- **Is Qdrant running?** Check with `docker ps --filter name=qdrant-server`.
### "Collection does not exist"
The collection is created by the embedding script or on first `qdrant_store` call. Either:
- Run `embed_codebase.py` to index your codebase first
- Or store something with `qdrant_store` to auto-create the collection
### Dimension mismatch errors
This happens when the collection was created with one embedding model but you're querying with another. Fix:
1. Delete the collection: visit `http://localhost:6333/dashboard`
2. Re-embed with the correct model
3. Ensure `EMBEDDING_MODEL` in the MCP server config matches what you used for embedding
### "Storage folder is already accessed by another instance"
This error comes from the **official** `mcp-server-qdrant` using local mode (`QDRANT_LOCAL_PATH`). This project avoids that by connecting to a Qdrant server via URL. Make sure you're not running both servers pointing to the same local path.
### Slow embedding / low GPU utilization
- Use a larger model: `bge-m3` (1.2 GB) instead of `nomic-embed-text` (274 MB)
- The embedding script sends all texts in one batch — if you have thousands of chunks, this maximizes GPU usage
- For very large codebases (10,000+ files), consider splitting into multiple runs per directory
---
## License
Apache License 2.0 — see [LICENSE](LICENSE).
TDQS
B3.2/5.0
Scored across 2 tools
Disambiguation5/5
The two tools, qdrant_store and qdrant_find, have entirely distinct purposes—one writes data, the other retrieves it. There is zero ambiguity between them.
Naming Consistency5/5
Both tools follow a consistent 'qdrant_<verb>' pattern, using clear action verbs (store, find). The naming is predictable and uniform.
Tool Count3/5
With only two tools, the server feels thin for what is typically a database domain, but it is not an extreme mismatch. It sits at the borderline of adequacy.
Completeness2/5
The server only provides store and find, lacking any management operations like delete, update, or list. For a database, this is a significant gap that will limit workflow coverage.
Maintenance
ActivityInactive
ResponsivenessNo issues