Skip to content

Commit 701db26

Browse files
Initial commit
0 parents  commit 701db26

File tree

8 files changed

+1741
-0
lines changed

8 files changed

+1741
-0
lines changed

.gitignore

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
# Byte-compiled / optimized / DLL files
2+
__pycache__/
3+
*.py[cod]
4+
*$py.class
5+
6+
# C extensions
7+
*.so
8+
9+
# Distribution / packaging
10+
.Python
11+
build/
12+
develop-eggs/
13+
dist/
14+
downloads/
15+
eggs/
16+
.eggs/
17+
lib/
18+
lib64/
19+
parts/
20+
sdist/
21+
var/
22+
wheels/
23+
share/python-wheels/
24+
*.egg-info/
25+
.installed.cfg
26+
*.egg
27+
MANIFEST
28+
29+
# PyInstaller
30+
# Usually these files are written by a python script from a template
31+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
32+
*.manifest
33+
*.spec
34+
35+
# Installer logs
36+
pip-log.txt
37+
pip-delete-this-directory.txt
38+
39+
# Unit test / coverage reports
40+
htmlcov/
41+
.tox/
42+
.nox/
43+
.coverage
44+
.coverage.*
45+
.cache
46+
nosetests.xml
47+
coverage.xml
48+
*.cover
49+
*.py,cover
50+
.hypothesis/
51+
.pytest_cache/
52+
cover/
53+
54+
# Translations
55+
*.mo
56+
*.pot
57+
58+
# Django stuff:
59+
*.log
60+
local_settings.py
61+
db.sqlite3
62+
db.sqlite3-journal
63+
64+
# Flask stuff:
65+
instance/
66+
.webassets-cache
67+
68+
# Scrapy stuff:
69+
.scrapy
70+
71+
# Sphinx documentation
72+
docs/_build/
73+
74+
# PyBuilder
75+
.pybuilder/
76+
target/
77+
78+
# Jupyter Notebook
79+
.ipynb_checkpoints
80+
81+
# IPython
82+
profile_default/
83+
ipython_config.py
84+
85+
# pyenv
86+
# For a library or package, you might want to ignore these files since the code is
87+
# intended to run in multiple environments; otherwise, check them in:
88+
# .python-version
89+
90+
# pipenv
91+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
93+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
94+
# install all needed dependencies.
95+
#Pipfile.lock
96+
97+
# poetry
98+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
99+
# This is especially recommended for binary packages to ensure reproducibility, and is more
100+
# commonly ignored for libraries.
101+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
102+
#poetry.lock
103+
104+
# pdm
105+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
106+
#pdm.lock
107+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
108+
# in version control.
109+
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
110+
.pdm.toml
111+
.pdm-python
112+
.pdm-build/
113+
114+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
115+
__pypackages__/
116+
117+
# Celery stuff
118+
celerybeat-schedule
119+
celerybeat.pid
120+
121+
# SageMath parsed files
122+
*.sage.py
123+
124+
# Environments
125+
.env
126+
.venv
127+
env/
128+
venv/
129+
ENV/
130+
env.bak/
131+
venv.bak/
132+
133+
# Spyder project settings
134+
.spyderproject
135+
.spyproject
136+
137+
# Rope project settings
138+
.ropeproject
139+
140+
# mkdocs documentation
141+
/site
142+
143+
# mypy
144+
.mypy_cache/
145+
.dmypy.json
146+
dmypy.json
147+
148+
# Pyre type checker
149+
.pyre/
150+
151+
# pytype static type analyzer
152+
.pytype/
153+
154+
# Cython debug symbols
155+
cython_debug/
156+
157+
# PyCharm
158+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
159+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
160+
# and can be added to the global gitignore or merged into this file. For a more nuclear
161+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
162+
#.idea/

.python-version

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
3.10

README.md

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# mcp-server-qdrant: A Qdrant MCP server
2+
3+
> The [Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction) is an open protocol that enables seamless integration between LLM applications and external data sources and tools. Whether you’re building an AI-powered IDE, enhancing a chat interface, or creating custom AI workflows, MCP provides a standardized way to connect LLMs with the context they need.
4+
5+
This repository is an example of how to create a MCP server for [Qdrant](https://qdrant.tech/), a vector search engine.
6+
7+
## Overview
8+
9+
A basic Model Context Protocol server for keeping and retrieving memories in the Qdrant vector search engine.
10+
It acts as a semantic memory layer on top of the Qdrant database.
11+
12+
## Components
13+
14+
### Tools
15+
16+
1. `qdrant-store-memory`
17+
- Store a memory in the Qdrant database
18+
- Input:
19+
- `information` (string): Memory to store
20+
- Returns: Confirmation message
21+
2. `qdrant-find-memories`
22+
- Retrieve a memory from the Qdrant database
23+
- Input:
24+
- `query` (string): Query to retrieve a memory
25+
- Returns: Memories stored in the Qdrant database as separate messages
26+
27+
## Installation
28+
29+
### Using uv (recommended)
30+
31+
When using [`uv`](https://docs.astral.sh/uv/) no specific installation is needed to directly run *mcp-server-qdrant*.
32+
33+
```shell
34+
uv run mcp-server-qdrant \
35+
--qdrant-url "http://localhost:6333" \
36+
--qdrant-api-key "your_api_key" \
37+
--collection-name "my_collection" \
38+
--fastembed-model-name "sentence-transformers/all-MiniLM-L6-v2"
39+
```
40+
41+
## Usage with Claude Desktop
42+
43+
To use this server with the Claude Desktop app, add the following configuration to the "mcpServers" section of your `claude_desktop_config.json`:
44+
45+
```json
46+
{
47+
"qdrant": {
48+
"command": "uvx",
49+
"args": [
50+
"mcp-server-qdrant",
51+
"--qdrant-url",
52+
"http://localhost:6333",
53+
"--qdrant-api-key",
54+
"your_api_key",
55+
"--collection-name",
56+
"your_collection_name"
57+
]
58+
}
59+
}
60+
```
61+
62+
Replace `http://localhost:6333`, `your_api_key` and `your_collection_name` with your Qdrant server URL, Qdrant API key
63+
and collection name, respectively. The use of API key is optional, but recommended for security reasons, and depends on
64+
the Qdrant server configuration.
65+
66+
This MCP server will automatically create a collection with the specified name if it doesn't exist.
67+
68+
By default, the server will use the `sentence-transformers/all-MiniLM-L6-v2` embedding model to encode memories.
69+
For the time being, only [FastEmbed](https://qdrant.github.io/fastembed/) models are supported, and you can change it
70+
by passing the `--fastembed-model-name` argument to the server.
71+
72+
### Environment Variables
73+
74+
The configuration of the server can be also done using environment variables:
75+
76+
- `QDRANT_URL`: URL of the Qdrant server
77+
- `QDRANT_API_KEY`: API key for the Qdrant server
78+
- `COLLECTION_NAME`: Name of the collection to use
79+
- `FASTEMBED_MODEL_NAME`: Name of the FastEmbed model to use
80+
81+
## License
82+
83+
This MCP server is licensed under the MIT License. This means you are free to use, modify, and distribute the software,
84+
subject to the terms and conditions of the MIT License. For more details, please see the LICENSE file in the project
85+
repository.

pyproject.toml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
[project]
2+
name = "mcp-server-qdrant"
3+
version = "0.5.1"
4+
description = "MCP server for retrieving context from a Qdrant vector database"
5+
readme = "README.md"
6+
requires-python = ">=3.10"
7+
dependencies = [
8+
"mcp>=0.9.1",
9+
"qdrant-client[fastembed]>=1.12.0",
10+
]
11+
12+
[build-system]
13+
requires = ["hatchling"]
14+
build-backend = "hatchling.build"
15+
16+
[tool.uv]
17+
dev-dependencies = ["pyright>=1.1.389", "pytest>=8.3.3", "ruff>=0.8.0"]
18+
19+
[project.scripts]
20+
mcp-server-qdrant = "mcp_server_qdrant:main"

src/mcp_server_qdrant/__init__.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from . import server
2+
3+
4+
def main():
5+
"""Main entry point for the package."""
6+
server.main()
7+
8+
9+
# Optionally expose other important items at package level
10+
__all__ = ["main", "server"]

src/mcp_server_qdrant/qdrant.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
from typing import Optional
2+
from qdrant_client import AsyncQdrantClient, models
3+
4+
5+
class QdrantConnector:
6+
"""
7+
Encapsulates the connection to a Qdrant server and all the methods to interact with it.
8+
:param qdrant_url: The URL of the Qdrant server.
9+
:param qdrant_api_key: The API key to use for the Qdrant server.
10+
:param collection_name: The name of the collection to use.
11+
:param fastembed_model_name: The name of the FastEmbed model to use.
12+
"""
13+
14+
def __init__(
15+
self,
16+
qdrant_url: str,
17+
qdrant_api_key: Optional[str],
18+
collection_name: str,
19+
fastembed_model_name: str,
20+
):
21+
self._qdrant_url = qdrant_url.rstrip("/")
22+
self._qdrant_api_key = qdrant_api_key
23+
self._collection_name = collection_name
24+
self._fastembed_model_name = fastembed_model_name
25+
# For the time being, FastEmbed models are the only supported ones.
26+
# A list of all available models can be found here:
27+
# https://qdrant.github.io/fastembed/examples/Supported_Models/
28+
self._client = AsyncQdrantClient(qdrant_url, api_key=qdrant_api_key)
29+
self._client.set_model(fastembed_model_name)
30+
31+
async def store_memory(self, information: str):
32+
"""
33+
Store a memory in the Qdrant collection.
34+
:param information: The information to store.
35+
"""
36+
await self._client.add(
37+
self._collection_name,
38+
documents=[information],
39+
)
40+
41+
async def find_memories(self, query: str) -> list[str]:
42+
"""
43+
Find memories in the Qdrant collection.
44+
:param query: The query to use for the search.
45+
:return: A list of memories found.
46+
"""
47+
search_results = await self._client.query(
48+
self._collection_name,
49+
query_text=query,
50+
limit=10,
51+
)
52+
return [result.document for result in search_results]

0 commit comments

Comments
 (0)