forked from innovacion/searchbox
9.4 KiB
9.4 KiB
AGENTS.md - Guide for Coding Agents
This document provides essential information for coding agents working on the Searchbox MCP (Model Context Protocol) project. It serves as a quick reference to understand the codebase architecture, testing setup, and development workflows.
🏗️ Project Overview
Searchbox is an MCP server that provides vector search capabilities using Qdrant as the backend. It allows AI assistants to perform semantic search operations on document collections through a standardized MCP interface.
Key Components:
- MCP Server: FastMCP-based server exposing semantic search tools
- Vector Engine: Pluggable backend system (currently supports Qdrant)
- Client Interface: High-level API for vector operations
- Models: Pydantic data structures for search operations
📁 Project Structure
qdrant-mcp/
├── src/searchbox/ # Main package (renamed from vector_search_mcp)
│ ├── __init__.py # Package initialization
│ ├── client.py # High-level client interface
│ ├── config.py # Configuration management
│ ├── models.py # Pydantic models and data structures
│ ├── engine/ # Vector database backends
│ │ ├── __init__.py # Engine factory and Backend enum
│ │ ├── base_engine.py # Abstract base engine with generics
│ │ └── qdrant_engine.py # Qdrant implementation
│ └── mcp_server/ # MCP protocol implementation
│ ├── __init__.py # Server entry point
│ └── server.py # FastMCP server setup
├── tests/ # Test suite (97.22% coverage)
│ ├── test_client/ # Client API tests
│ ├── test_engine/ # Engine implementation tests
│ └── test_mcp/ # MCP server integration tests
├── pyproject.toml # Project configuration
└── README.md # Project documentation
🔧 Development Environment
Prerequisites
- Python 3.13+
- UV package manager
- Qdrant (for integration tests)
Setup Commands
# Install dependencies
uv sync --all-extras --dev
# Run tests with coverage
uv run pytest --cov --cov-report=term-missing
# Run linting
uv run ruff check
# Start MCP server
uv run searchbox-mcp
Package Management
- Main deps:
qdrant-client,vault-settings - Optional:
fastmcp(MCP functionality) - Dev deps:
pytest,pytest-cov,pytest-asyncio,ruff,fastembed
🧪 Testing Framework
Test Structure (91 tests, 97.22% coverage)
tests/
├── test_client/ # 14 tests - Client API functionality
├── test_engine/ # 68 tests - Engine implementations & factory
└── test_mcp/ # 9 tests - MCP server integration
Key Test Commands
# Run all tests
uv run pytest
# Run with coverage
uv run pytest --cov --cov-report=html
# Run specific test module
uv run pytest tests/test_client/
# Run integration tests (starts real MCP server)
uv run pytest tests/test_mcp/
Test Patterns
- Unit tests: Mock external dependencies (Qdrant client, settings)
- Integration tests: Use real MCP server with in-memory Qdrant
- Fixtures: Located in
conftest.pyfiles for each test package - Async testing: Uses
pytest-asynciowithasyncio_mode = "auto"
🏛️ Architecture Patterns
1. Generic Engine System
# Base engine uses generics for type safety
class BaseEngine[ResponseType, ConditionType, ChunkType](ABC):
# Abstract methods that subclasses must implement
@abstractmethod
def transform_conditions(self, conditions: list[Condition] | None) -> ConditionType | None: ...
# Template method pattern for semantic search
async def semantic_search(self, embedding, collection, limit, conditions, threshold):
# Orchestrates: transform -> query -> transform
2. Factory Pattern with Caching
@cache # functools.cache for singleton behavior
def get_engine(backend: Backend):
if backend == Backend.QDRANT:
return QdrantEngine()
elif backend == Backend.COSMOS:
raise NotImplementedError("Cosmos engine not implemented yet")
3. Client Facade Pattern
@final
class Client:
"""High-level interface abstracting engine complexity"""
def __init__(self, backend: Backend, collection: str):
self.engine = get_engine(backend) # Factory usage
self.collection = collection
📊 Data Models
Core Models (in models.py)
# Search conditions
class Match(BaseModel): # Exact match filter
class MatchAny(BaseModel): # Any-of match filter
class MatchExclude(BaseModel): # Exclusion filter
# Document data
class ChunkData(BaseModel): # Document content + metadata
class Chunk(BaseModel): # Vector + ChunkData
class SearchRow(BaseModel): # Search result format
Backend-Specific Models
- Qdrant: Uses
qdrant_client.models(PointStruct, Filter, etc.) - Generic: Abstractions in
base_engine.py
🔌 MCP Integration
Server Setup (mcp_server/server.py)
from fastmcp import FastMCP
from ..engine import Backend, get_engine
mcp = FastMCP("Vector Search MCP")
engine = get_engine(Backend.QDRANT)
# Auto-register semantic_search as MCP tool
_ = mcp.tool(engine.semantic_search)
Entry Point (mcp_server/__init__.py)
def run(transport: Transport = "sse"):
"""Start MCP server with specified transport"""
mcp.run(transport=transport)
🎯 Common Development Tasks
Adding a New Vector Backend
- Create engine: Inherit from
BaseEngine[ResponseType, ConditionType, ChunkType] - Implement abstracts:
transform_conditions,transform_response,run_similarity_query, etc. - Update factory: Add new backend to
Backendenum andget_engine() - Add tests: Create test file following existing patterns
- Update docs: Add configuration examples
Modifying Search Functionality
- Models: Extend condition types in
models.py - Base Engine: Update abstract methods if needed
- Implementations: Update concrete engines (
qdrant_engine.py) - Tests: Add test cases for new functionality
Extending MCP Tools
- Server: Add new tools in
mcp_server/server.py - Client: Extend
Clientclass with new methods - Integration: Add MCP integration tests
🐛 Debugging & Troubleshooting
Common Issues
- Import errors: Check if module was renamed from
vector_search_mcptosearchbox - Test failures: Ensure MCP server uses correct script name
searchbox-mcp - Coverage gaps: Focus on branch coverage, not just line coverage
- Async issues: Use
pytest.mark.asynciofor async tests
Debugging Tools
# Verbose test output
uv run pytest -v --tb=long
# Coverage with missing lines
uv run pytest --cov --cov-report=term-missing
# Run single test
uv run pytest tests/path/to/test.py::TestClass::test_method -v
MCP Server Testing
- Integration tests start real server on
http://localhost:8000/sse - Server startup takes ~5 seconds (configured in test fixtures)
- Uses in-memory Qdrant with pre-seeded test data
📋 Code Quality Standards
Linting Configuration (Ruff)
[tool.ruff.lint]
extend-select = ["I", "D", "ERA", "UP", "FURB", "TRY", "PERF"]
ignore = ["D203", "D213"]
- I: Import sorting
- D: Docstring conventions (Google style)
- ERA: Remove commented code
- UP: Python upgrade syntax
- FURB: Refurb suggestions
- TRY: Exception handling
- PERF: Performance
Coverage Standards
- Target: >95% coverage (currently 97.22%)
- Branch coverage: Enabled via
tool.coverage.run.branch = true - Exclusions: Abstract methods, defensive code patterns
- HTML reports: Generated in
htmlcov/directory
Documentation Requirements
- Docstrings: All public classes/methods (Google style)
- Type hints: Full typing for all functions
- Examples: Include usage examples in docstrings
- Generics: Document type parameters clearly
🚀 Deployment & Distribution
Package Configuration
- Name:
searchbox(internal), distributed asvector-search-mcp - Entry point:
searchbox-mcpcommand - Build system:
uv_build - Python requirement:
>=3.13
Dependencies
- Core: Minimal (qdrant-client, vault-settings)
- MCP: Optional extras (
[mcp]) - Dev: Comprehensive testing and linting tools
🔗 Key Files to Understand
Must-read files for new contributors:
src/searchbox/engine/base_engine.py- Core abstractions and patternssrc/searchbox/client.py- Main user-facing APIsrc/searchbox/models.py- Data structures and typestests/conftest.pyfiles - Test configuration and fixturespyproject.toml- Project configuration and dependencies
Reference implementations:
src/searchbox/engine/qdrant_engine.py- Complete backend implementationtests/test_client/test_client.py- Comprehensive testing patternssrc/searchbox/mcp_server/server.py- MCP integration example
This guide should provide sufficient context for any coding agent to quickly understand the project structure, make meaningful contributions, and maintain the high code quality standards established in this codebase.