Custom tool descriptions (#29)

* Allow setting up the tool descriptions with env variables

* Document the env variables as a table in README

* Link settings.py in README.md

* Allow to choose transport protocol: stdio or sse

* Fix metadata handling in Cursor

* Improve README to cover more cases

* Add info about Cursor rules

* Fix Github note type
This commit is contained in:
Kacper Łukawski
2025-03-11 21:05:39 +01:00
committed by GitHub
parent 41bab919be
commit 5878cc1267
5 changed files with 208 additions and 50 deletions

View File

@@ -1,9 +1,24 @@
from mcp_server_qdrant.server import mcp
import argparse
def main():
"""
Main entry point for the mcp-server-qdrant script defined
in pyproject.toml. It runs the MCP server.
in pyproject.toml. It runs the MCP server with a specific transport
protocol.
"""
mcp.run()
# Parse the command-line arguments to determine the transport protocol.
parser = argparse.ArgumentParser(description="mcp-server-qdrant")
parser.add_argument(
"--transport",
choices=["stdio", "sse"],
default="stdio",
)
args = parser.parse_args()
# Import is done here to make sure environment variables are loaded
# only after we make the changes.
from mcp_server_qdrant.server import mcp
mcp.run(transport=args.transport)

View File

@@ -1,14 +1,18 @@
import json
import logging
from contextlib import asynccontextmanager
from typing import AsyncIterator, List, Optional
from typing import AsyncIterator, List
from mcp.server import Server
from mcp.server.fastmcp import Context, FastMCP
from mcp_server_qdrant.embeddings.factory import create_embedding_provider
from mcp_server_qdrant.qdrant import Entry, Metadata, QdrantConnector
from mcp_server_qdrant.settings import EmbeddingProviderSettings, QdrantSettings
from mcp_server_qdrant.settings import (
EmbeddingProviderSettings,
QdrantSettings,
ToolSettings,
)
logger = logging.getLogger(__name__)
@@ -54,20 +58,26 @@ async def server_lifespan(server: Server) -> AsyncIterator[dict]: # noqa
pass
# FastMCP is an alternative interface for declaring the capabilities
# of the server. Its API is based on FastAPI.
mcp = FastMCP("mcp-server-qdrant", lifespan=server_lifespan)
# Load the tool settings from the env variables, if they are set,
# or use the default values otherwise.
tool_settings = ToolSettings()
@mcp.tool(
name="qdrant-store",
description=(
"Keep the memory for later use, when you are asked to remember something."
),
)
@mcp.tool(name="qdrant-store", description=tool_settings.tool_store_description)
async def store(
ctx: Context, information: str, metadata: Optional[Metadata] = None
ctx: Context,
information: str,
# The `metadata` parameter is defined as non-optional, but it can be None.
# If we set it to be optional, some of the MCP clients, like Cursor, cannot
# handle the optional parameter correctly.
metadata: Metadata = None,
) -> str:
"""
Store a memory in Qdrant.
Store some information in Qdrant.
:param ctx: The context for the request.
:param information: The information to store.
:param metadata: JSON metadata to store with the information, optional.
@@ -82,15 +92,7 @@ async def store(
return f"Remembered: {information}"
@mcp.tool(
name="qdrant-find",
description=(
"Look up memories in Qdrant. Use this tool when you need to: \n"
" - Find memories by their content \n"
" - Access memories for further analysis \n"
" - Get some personal information about the user"
),
)
@mcp.tool(name="qdrant-find", description=tool_settings.tool_find_description)
async def find(ctx: Context, query: str) -> List[str]:
"""
Find memories in Qdrant.
@@ -98,15 +100,15 @@ async def find(ctx: Context, query: str) -> List[str]:
:param query: The query to use for the search.
:return: A list of entries found.
"""
await ctx.debug(f"Finding points for query {query}")
await ctx.debug(f"Finding results for query {query}")
qdrant_connector: QdrantConnector = ctx.request_context.lifespan_context[
"qdrant_connector"
]
entries = await qdrant_connector.search(query)
if not entries:
return [f"No memories found for the query '{query}'"]
return [f"No information found for the query '{query}'"]
content = [
f"Memories for the query '{query}'",
f"Results for the query '{query}'",
]
for entry in entries:
# Format the metadata as a JSON string and produce XML-like output

View File

@@ -5,6 +5,31 @@ from pydantic_settings import BaseSettings
from mcp_server_qdrant.embeddings.types import EmbeddingProviderType
DEFAULT_TOOL_STORE_DESCRIPTION = (
"Keep the memory for later use, when you are asked to remember something."
)
DEFAULT_TOOL_FIND_DESCRIPTION = (
"Look up memories in Qdrant. Use this tool when you need to: \n"
" - Find memories by their content \n"
" - Access memories for further analysis \n"
" - Get some personal information about the user"
)
class ToolSettings(BaseSettings):
"""
Configuration for all the tools.
"""
tool_store_description: str = Field(
default=DEFAULT_TOOL_STORE_DESCRIPTION,
validation_alias="TOOL_STORE_DESCRIPTION",
)
tool_find_description: str = Field(
default=DEFAULT_TOOL_FIND_DESCRIPTION,
validation_alias="TOOL_FIND_DESCRIPTION",
)
class EmbeddingProviderSettings(BaseSettings):
"""