Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ dependencies = [
"qdrant-client>=1.12.0",
"pydantic>=2.10.6",
"fastmcp>=2.7.0",
"openai>=1.109.1",
]

[build-system]
Expand Down
6 changes: 6 additions & 0 deletions src/mcp_server_qdrant/embeddings/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,11 @@ def create_embedding_provider(settings: EmbeddingProviderSettings) -> EmbeddingP
from mcp_server_qdrant.embeddings.fastembed import FastEmbedProvider

return FastEmbedProvider(settings.model_name)
elif settings.provider_type == EmbeddingProviderType.OAI_COMPAT:
from mcp_server_qdrant.embeddings.oai_compat import OAICompatProvider

return OAICompatProvider(settings.model_name,
settings.oai_compat_endpoint,
settings.oai_compat_api_key)
else:
raise ValueError(f"Unsupported embedding provider: {settings.provider_type}")
48 changes: 48 additions & 0 deletions src/mcp_server_qdrant/embeddings/oai_compat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from mcp_server_qdrant.embeddings.base import EmbeddingProvider
from openai import AsyncOpenAI
import asyncio


class OAICompatProvider(EmbeddingProvider):
def __init__(self, model_name: str, endpoint_url: str, api_key: str, vec_size: int | None = None) -> None:
self.model_name = model_name
self.base_url = endpoint_url
self.key = api_key
self.oai_client = AsyncOpenAI(base_url=self.base_url, api_key=self.key)
self._vec_size = self.fetch_vec_size() if vec_size is None else vec_size

async def embed_documents(self, documents: list[str]) -> list[list[float]]:
response = await self.oai_client.embeddings.create(
input=documents,
model=self.model_name
)
results = [embed.embedding for embed in response.data]
return results

async def embed_query(self, query: str) -> list[float]:
response = await self.oai_client.embeddings.create(
input=query,
model=self.model_name
)
results = response.data[0].embedding
return results

def get_vector_name(self) -> str:
return f"oai_compat-{self.model_name}"

def get_vector_size(self) -> int:
return self._vec_size

def fetch_vec_size(self):
"""Retrieves the embedding vector dimensionality by sending a minimal inference request to the endpoint.
Since the OpenAI-compatible API does not expose model metadata detailing vector dimensions, this method
uses a dummy input to obtain a sample embedding and derives the dimension count from its structure.
To avoid unnecessary latency and cost during initialization, it is recommended to explicitly provide
the vector size via the `vec_size` parameter when the dimension is known."""
try:
loop = asyncio.get_running_loop()
fut = asyncio.run_coroutine_threadsafe(self.embed_query("dummy"), loop)
result = fut.result()
except RuntimeError:
result = asyncio.run(self.embed_query("dummy"))
return len(result)
1 change: 1 addition & 0 deletions src/mcp_server_qdrant/embeddings/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@

class EmbeddingProviderType(Enum):
FASTEMBED = "fastembed"
OAI_COMPAT = "oai_compat"
15 changes: 15 additions & 0 deletions src/mcp_server_qdrant/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,21 @@ class EmbeddingProviderSettings(BaseSettings):
validation_alias="EMBEDDING_MODEL",
)

oai_compat_endpoint: str = Field(
default="https://api.openai.com/v1",
validation_alias="OAI_COMPAT_ENDPOINT"
)

oai_compat_api_key: str = Field(
default="",
validation_alias="OAI_COMPAT_API_KEY"
)

oai_compat_vec_size: int | None = Field(
default=None,
validation_alias="OAI_COMPAT_VEC_SIZE"
)


class FilterableField(BaseModel):
name: str = Field(description="The name of the field payload field to filter on")
Expand Down
Loading