Skip to main content
Glama

Qdrant MCP Server

by mhalder
README.md14.4 kB
# Qdrant MCP Server [![CI](https://github.com/mhalder/qdrant-mcp-server/actions/workflows/ci.yml/badge.svg)](https://github.com/mhalder/qdrant-mcp-server/actions/workflows/ci.yml) [![codecov](https://codecov.io/gh/mhalder/qdrant-mcp-server/branch/main/graph/badge.svg)](https://codecov.io/gh/mhalder/qdrant-mcp-server) A Model Context Protocol (MCP) server that provides semantic search capabilities using a local Qdrant vector database and OpenAI embeddings. ## Features - **Semantic Search**: Natural language search across your document collections - **Metadata Filtering**: Filter search results by metadata fields using Qdrant's powerful filter syntax - **Local Vector Database**: Runs Qdrant locally via Docker for complete data privacy - **Automatic Embeddings**: Uses OpenAI's embedding models to convert text to vectors - **Rate Limiting**: Intelligent request throttling with exponential backoff to prevent API rate limit errors - **MCP Integration**: Works seamlessly with Claude Code and other MCP clients - **Collection Management**: Create, list, and delete vector collections - **Document Operations**: Add, search, and delete documents with metadata support ## Prerequisites - Node.js 18+ - Docker and Docker Compose - OpenAI API key ## Installation 1. Clone the repository: ```bash git clone <your-repo-url> cd qdrant-mcp-server ``` 2. Install dependencies: ```bash npm install ``` 3. Set up environment variables: ```bash cp .env.example .env ``` Edit `.env` and add your OpenAI API key: ```bash OPENAI_API_KEY=sk-your-api-key-here QDRANT_URL=http://localhost:6333 # Optional: OpenAI Rate Limiting (defaults shown) OPENAI_MAX_REQUESTS_PER_MINUTE=3500 OPENAI_RETRY_ATTEMPTS=3 OPENAI_RETRY_DELAY=1000 ``` 4. Start Qdrant: ```bash docker compose up -d ``` 5. Build the project: ```bash npm run build ``` ## Usage ### Running the Server For development: ```bash npm run dev ``` For production: ```bash node build/index.js ``` ### Claude Code Configuration (Linux) Add this to your Claude Code configuration file at `~/.claude/claude_code_config.json`: ```json { "mcpServers": { "qdrant": { "command": "node", "args": [ "/home/YOUR_USERNAME/projects/active/qdrant-mcp-server/build/index.js" ], "env": { "OPENAI_API_KEY": "sk-your-api-key-here", "QDRANT_URL": "http://localhost:6333" } } } } ``` Replace `YOUR_USERNAME` and the path with your actual username and installation path. Restart Claude Code after making this change. ## Available Tools ### `create_collection` Create a new vector collection. **Parameters:** - `name` (string, required): Collection name - `distance` (string, optional): Distance metric - "Cosine", "Euclid", or "Dot" (default: "Cosine") **Example:** ``` Create a collection named "my-docs" ``` ### `add_documents` Add documents to a collection with automatic embedding generation. **Parameters:** - `collection` (string, required): Collection name - `documents` (array, required): Array of documents with: - `id` (string/number, required): Unique identifier (string IDs are automatically normalized to UUID format) - `text` (string, required): Document text content - `metadata` (object, optional): Additional metadata **Note:** String IDs are automatically normalized to UUID format for Qdrant compatibility. The normalization is deterministic, so the same string ID will always produce the same UUID. **Example:** ``` Add these documents to "my-docs" collection: - id: 1, text: "Introduction to vector databases" - id: 2, text: "Semantic search with embeddings" ``` ### `semantic_search` Search for documents using natural language. **Parameters:** - `collection` (string, required): Collection to search - `query` (string, required): Search query - `limit` (number, optional): Max results (default: 5) - `filter` (object, optional): Metadata filter in Qdrant format **Filter Format:** The filter parameter accepts Qdrant's native filter format for powerful metadata-based filtering: ```json { "must": [{ "key": "category", "match": { "value": "database" } }] } ``` You can also use more complex filters: - **Multiple conditions (AND)**: Use `must` with multiple conditions - **Any condition (OR)**: Use `should` with multiple conditions - **Negation (NOT)**: Use `must_not` with conditions Example with multiple conditions: ```json { "must": [ { "key": "category", "match": { "value": "database" } }, { "key": "level", "match": { "value": "beginner" } } ] } ``` **Examples:** Basic search: ``` Search "my-docs" for information about vector databases ``` With single filter: ``` Search "my-docs" for "vector databases" with filter {"must": [{"key": "category", "match": {"value": "technical"}}]} ``` With multiple filters (AND): ``` Search "knowledge-base" for "machine learning" with filter {"must": [{"key": "category", "match": {"value": "ml"}}, {"key": "level", "match": {"value": "advanced"}}]} ``` ### `list_collections` List all available collections. ### `get_collection_info` Get detailed information about a collection. **Parameters:** - `name` (string, required): Collection name ### `delete_collection` Delete a collection and all its documents. **Parameters:** - `name` (string, required): Collection name ### `delete_documents` Delete specific documents from a collection. **Parameters:** - `collection` (string, required): Collection name - `ids` (array, required): Array of document IDs to delete (string IDs are automatically normalized to UUID format) **Note:** String IDs will be normalized to the same UUID format used when adding documents. ## Available Resources - `qdrant://collections` - List all collections - `qdrant://collection/{name}` - Collection details and statistics ## Project Structure ``` qdrant-mcp-server/ ├── src/ │ ├── index.ts # MCP server implementation │ ├── qdrant/ │ │ └── client.ts # Qdrant client wrapper │ └── embeddings/ │ └── openai.ts # OpenAI embeddings provider ├── docker-compose.yml # Qdrant Docker setup ├── package.json ├── tsconfig.json └── README.md ``` ## Example Workflow 1. **Create a collection:** ``` Create a collection called "knowledge-base" ``` 2. **Add documents:** ``` Add these documents to knowledge-base: - id: "doc1", text: "MCP is a protocol for AI model context", metadata: {"type": "definition", "category": "protocol"} - id: "doc2", text: "Vector databases store embeddings for semantic search", metadata: {"type": "definition", "category": "database"} - id: "doc3", text: "Qdrant provides high-performance vector similarity search", metadata: {"type": "product", "category": "database"} ``` 3. **Search without filters:** ``` Search knowledge-base for "how does semantic search work" ``` 4. **Search with filters:** ``` Search knowledge-base for "vector database" with filter {"must": [{"key": "category", "match": {"value": "database"}}]} ``` 5. **Get collection information:** ``` Get info about "knowledge-base" collection ``` 6. **View all collections:** ``` What collections do I have? ``` ## Configuration Options ### Environment Variables - `OPENAI_API_KEY` (required): Your OpenAI API key - `QDRANT_URL` (optional): Qdrant server URL (default: http://localhost:6333) - `OPENAI_EMBEDDING_MODEL` (optional): Embedding model (default: text-embedding-3-small) - `OPENAI_EMBEDDING_DIMENSIONS` (optional): Custom embedding dimensions - `OPENAI_MAX_REQUESTS_PER_MINUTE` (optional): Maximum OpenAI API requests per minute (default: 3500) - `OPENAI_RETRY_ATTEMPTS` (optional): Number of retry attempts for rate limit errors (default: 3) - `OPENAI_RETRY_DELAY` (optional): Initial retry delay in milliseconds with exponential backoff (default: 1000) ### Embedding Models Available OpenAI models: - `text-embedding-3-small` (1536 dims, faster, cheaper) - `text-embedding-3-large` (3072 dims, higher quality) ## Advanced Features ### Rate Limiting and Error Handling The server implements robust rate limiting to handle OpenAI API limits gracefully: **Features:** - **Request Throttling**: Queues requests to stay within OpenAI's rate limits (configurable, default: 3500 requests/minute) - **Exponential Backoff**: Automatically retries failed requests with increasing delays (1s, 2s, 4s, 8s...) - **Retry-After Header Support**: Respects OpenAI's retry guidance with validation fallback for invalid headers - **Typed Error Handling**: Uses OpenAIError interface for type-safe error detection and handling - **Smart Error Detection**: Identifies rate limit errors (429 status) vs other failures - **User Feedback**: Clear console messages during retry attempts with estimated wait times **Configuration:** ```bash # Adjust for your OpenAI tier (free tier: 500/min, paid tiers: 3500+/min) OPENAI_MAX_REQUESTS_PER_MINUTE=3500 # Retry behavior OPENAI_RETRY_ATTEMPTS=3 # Number of retries before failing OPENAI_RETRY_DELAY=1000 # Initial delay (doubles each retry) ``` **Benefits:** - Prevents failed operations during high-volume usage - Automatic recovery from temporary API issues - Optimized for batch document processing - Works seamlessly with both single and batch embedding operations ### Metadata Filtering The server supports Qdrant's powerful filtering capabilities for refined search results. Filters can be applied to any metadata field stored with your documents. **Supported filter types:** - **Match filters**: Exact value matching for strings, numbers, and booleans - **Logical operators**: `must` (AND), `should` (OR), `must_not` (NOT) - **Range filters**: Greater than, less than, between (for numeric values) - **Nested filters**: Complex boolean expressions See the `semantic_search` tool documentation for filter syntax examples. ## Troubleshooting ### Qdrant connection errors Make sure Qdrant is running: ```bash docker compose ps ``` If not running: ```bash docker compose up -d ``` ### Collection doesn't exist Create the collection first before adding documents: ``` Create a collection named "my-collection" ``` ### OpenAI API errors - Verify your API key is correct in `.env` - Check your OpenAI account has available credits - Ensure you have access to the embedding models ### Rate limit errors The server automatically handles rate limits, but if you see persistent rate limit errors: - Reduce `OPENAI_MAX_REQUESTS_PER_MINUTE` to match your OpenAI tier (free: 500, paid: 3500+) - Increase `OPENAI_RETRY_ATTEMPTS` for more resilient retries - Check your OpenAI dashboard for current usage and limits ### Filter errors If you encounter "Bad Request" errors with filters: - Ensure you're using Qdrant's native filter format - Check that field names match your metadata exactly - Verify the filter structure has proper nesting ## Development ### Development Mode Run in development mode with auto-reload: ```bash npm run dev ``` ### Build Build for production: ```bash npm run build ``` ### Type Checking Run TypeScript type checking without emitting files: ```bash npm run type-check ``` ### Continuous Integration The project uses GitHub Actions for CI/CD: - **Build**: Compiles TypeScript to JavaScript - **Type Check**: Validates TypeScript types with strict mode - **Test**: Runs all 140 unit and functional tests (129 unit + 11 functional) - **Multi-version**: Tests on Node.js 18, 20, and 22 The CI workflow runs on every push and pull request to the main branch. ## Testing The project includes comprehensive unit and integration tests using Vitest. ### Run Tests ```bash # Run all tests npm test # Run tests in watch mode npm test -- --watch # Run tests with UI npm run test:ui # Run tests with coverage npm run test:coverage ``` ### Test Coverage The test suite includes **140 tests** (129 unit + 11 functional) covering: **Unit Tests:** - **QdrantManager** (21 tests): Collection management, point operations, and search functionality - **OpenAIEmbeddings** (25 tests): Embedding generation, batch processing, rate limiting with exponential backoff, Retry-After header validation, and typed error handling - **MCP Server** (19 tests): Tool schemas, resource URI patterns, and MCP protocol compliance **Functional Tests:** - **Live API Integration** (11 tests): Real OpenAI embeddings, production MCP server validation, rate limiting behavior, and end-to-end workflows with 30+ real documents **Coverage Highlights:** - ✅ 100% function coverage across all modules - ✅ Comprehensive rate limiting tests with timing validation - ✅ Typed error handling with OpenAIError interface - ✅ Invalid Retry-After header fallback to exponential backoff - ✅ Real-world validation with live OpenAI API - ✅ Both source and compiled code tested See [`docs/test_report.md`](docs/test_report.md) for detailed test results and coverage analysis. ### Writing Tests Tests are located next to the files they test with a `.test.ts` extension: - `src/qdrant/client.test.ts` - Qdrant client wrapper tests - `src/embeddings/openai.test.ts` - OpenAI embeddings provider tests - `src/index.test.ts` - MCP server integration tests Run tests before committing: ```bash npm test -- --run ``` ## License This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. ## Contributing Contributions are welcome! Please feel free to submit a Pull Request. ### Before Submitting a PR 1. **Run tests**: Ensure all tests pass ```bash npm test -- --run ``` 2. **Type check**: Verify no TypeScript errors ```bash npm run type-check ``` 3. **Build**: Confirm the project builds successfully ```bash npm run build ``` All pull requests will automatically run through CI checks that validate: - TypeScript compilation - Type checking - Test suite (114 tests) - Compatibility with Node.js 18, 20, and 22 ### Note for Repository Owners After forking or cloning, update the CI badge URL in README.md: ```markdown [![CI](https://github.com/mhalder/qdrant-mcp-server/actions/workflows/ci.yml/badge.svg)](https://github.com/mhalder/qdrant-mcp-server/actions/workflows/ci.yml) ``` Replace `YOUR_USERNAME` with your GitHub username or organization name.

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mhalder/qdrant-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server