by mjochum64
Provides document search capabilities through Apache Solr, exposing Model Context Protocol (MCP) resources and tools for LLMs to query, filter, sort, and retrieve documents via both MCP and direct HTTP interfaces.
MCP Server For Apache Solr implements an MCP server that wraps Apache Solr’s search engine, allowing large language models (LLMs) and other clients to perform document searches, retrieve specific records, and apply advanced filtering, sorting, and pagination through standardized MCP endpoints.
# Install uv (optional) and dependencies
pip install uv
uv install # or pip install -e .
.env.example to .env and edit SOLR_BASE_URL, SOLR_COLLECTION, and optional authentication variables../start_solr.sh # launches Solr 9.4, creates "documents" collection, loads sample data
python run_server.py --mode mcp
python run_server.py --mode http --port 8765
curl -X POST http://localhost:8765/tool/search -H "Content-Type: application/json" -d '{"query":"*:*","rows":5}'
curl -X POST http://localhost:8765/tool/get_document -H "Content-Type: application/json" -d '{"id":"doc1"}'
solr://search/{query}) and document retrieval (get_document).httpx.pytest and coverage reporting.run_server.py) supporting multiple modes, custom ports, and help output./tool/search, /resource/...) to incorporate powerful full‑text search.Q: Which Python version is required? A: Python 3.11 or newer.
Q: Do I need Docker to run the server?
A: Docker is required only for the bundled Solr development environment. If you have an existing Solr instance, you can point the server to it by editing the .env variables.
Q: How does the server handle MCP 1.6.0 incompatibilities? A: Global variables store the Solr client, and the FastAPI fallback provides a standard HTTP interface because MCP 1.6.0 lacks direct HTTP transport support.
Q: Can I change the listening port?
A: Yes, use --port <number> when starting in HTTP mode or set MCP_SERVER_PORT in the .env file for MCP mode.
Q: Is authentication enforced out of the box? A: JWT fields are present in the configuration template, but authentication is optional and currently scaffolded for future use.
Q: How do I run the test suite?
A: Execute pytest for all tests, pytest -m integration for integration tests (requires a running Solr container), or add --cov=src for coverage.
This project implements a Model Context Protocol (MCP) server that provides document search capabilities through Apache Solr. It allows Large Language Models to search and retrieve documents from Solr collections using the MCP standard.
Version 1.5.0 - edismax Multi-Field Search & OAuth Auto-Refresh. Includes automatic OAuth token management and improved search results. Fully compliant with MCP Spec 2025-06-18. See CHANGELOG.md for details on all changes.
The Model Context Protocol (MCP) is a standardized way for applications to provide context to Large Language Models (LLMs). This project implements an MCP server that exposes Apache Solr's search capabilities to LLMs, allowing them to:
uv package manager (recommended)Install uv (if not already installed):
pip install uv
Install the project dependencies:
uv install
Or with pip:
pip install -e .
Copy the environment template and configure it:
cp .env.example .env
# Edit .env with your Solr connection details
Create and activate a virtual environment (important):
python -m venv .venv
source .venv/bin/activate # On Linux/macOS
# OR
.\.venv\Scripts\activate # On Windows
Note: Always ensure the virtual environment is activated before running the server or client tools. Many connection issues are caused by running commands outside the virtual environment.
This project uses the latest MCP 1.21.0 SDK with full support for the 2025-06-18 specification:
✅ Lifespan Context Manager: Type-safe dependency injection with AppContext dataclass
✅ Streamable HTTP Transport: Native HTTP support without external workarounds
✅ Tool Annotations: Enhanced metadata (readOnlyHint, title, description)
✅ Context-Based Logging: Direct client communication via ctx.info/debug/warning/error
✅ Modern Decorators: @app.tool() and @app.resource() patterns
The project has been fully modernized from MCP 1.6.0. Key changes:
ctx.request_context.lifespan_context)@asynccontextmanager patternMCP 1.21.0 includes native Streamable HTTP transport support. Start the server with HTTP transport:
# Run with native Streamable HTTP transport
python src/server/mcp_server.py --http
# Or use the convenience wrapper
python run_server.py --mode http
The server will be available at http://127.0.0.1:8000 with full MCP protocol support over HTTP.
The FastAPI-based HTTP server (src/server/http_server.py) is still available for backwards compatibility:
python run_server.py --mode http-legacy
Note: The legacy HTTP server is no longer required with MCP 1.21.0 and may be deprecated in future versions. Use native Streamable HTTP transport for new integrations.
The project includes a Docker Compose setup with Apache Solr and sample documents for development and testing:
# Start the Solr container with sample data
./start_solr.sh
# Access the Solr Admin UI
open http://localhost:8983/solr/
This will:
The MCP server supports OAuth 2.1 authentication using Keycloak. This is required for production deployments with the MCP 2025-06-18 specification.
Quick Setup (Automated):
# Start Keycloak and PostgreSQL containers
docker-compose up -d keycloak
# Wait for Keycloak to be ready (~60 seconds)
# Then run the automated setup script
./setup-keycloak.sh
# Test the OAuth flow
./test-keycloak.sh <CLIENT_SECRET>
The automated setup script will:
.env fileManual Setup:
For step-by-step manual configuration through the Keycloak web UI, see docs/KEYCLOAK_SETUP_GUIDE.md.
Documentation:
OAuth Implementation Status: ✅ Fully implemented and tested (14 unit tests + 10 integration tests). OAuth can be enabled by setting ENABLE_OAUTH=true in your .env file.
You can run the MCP server using the provided wrapper script which supports different modes:
# Show help and available options
python run_server.py --mode help
# Run the MCP protocol server (for LLM integration)
python run_server.py --mode mcp
# Run the HTTP API server (for direct HTTP access)
python run_server.py --mode http
# Specify a custom port
python run_server.py --mode http --port 9000
For development with MCP Inspector GUI:
# MCP development environment with inspector GUI
mcp dev src/server/mcp_server.py
For Claude Desktop integration:
# Install the MCP server for Claude Desktop
mcp install src/server/mcp_server.py --name "Solr Search"
The server exposes the following MCP endpoints:
solr://search/{query} - Basic search functionalitysearch - Advanced search with filtering, sorting, pagination, faceting, and highlightingget_document - Retrieve specific documents by ID# Example of using the search tool from an MCP client
result = await session.call_tool(
"search",
arguments={
"query": "machine learning",
"filter_query": "category:technology",
"sort": "date desc",
"rows": 5,
"start": 0
}
)
# Example of using faceted search to explore data
result = await session.call_tool(
"search",
arguments={
"query": "*:*",
"rows": 10,
"facet_fields": ["category", "author"]
}
)
# Response includes facet_counts with aggregated counts per field value
# e.g., {"category": ["programming", 3, "technology", 3, ...]}
# Example of using highlighting to show where search terms appear
result = await session.call_tool(
"search",
arguments={
"query": "title:machine",
"rows": 10,
"highlight_fields": ["title", "content"]
}
)
# Response includes highlighting with <em> tags around matched terms
# e.g., {"doc2": {"title": ["<em>Machine</em> Learning Basics"], ...}}
When OAuth is enabled (ENABLE_OAUTH=true), all tool calls require a valid access token:
# Step 1: Get access token from Keycloak
import httpx
async with httpx.AsyncClient() as client:
response = await client.post(
"http://localhost:8080/realms/solr-mcp/protocol/openid-connect/token",
headers={"Content-Type": "application/x-www-form-urlencoded"},
data={
"client_id": "solr-search-server",
"client_secret": "your-client-secret",
"username": "testuser",
"password": "testpassword",
"grant_type": "password",
"scope": "solr:search solr:read",
},
)
token_data = response.json()
access_token = token_data["access_token"]
# Step 2: Use the token in tool calls
result = await session.call_tool(
"search",
arguments={
"query": "machine learning",
"rows": 10,
"access_token": access_token # Include the token
}
)
OAuth Features:
solr:search, solr:read, solr:write, solr:admin)For local development without OAuth, simply set ENABLE_OAUTH=false in your .env file.
# Example of retrieving a document by ID
document = await session.call_tool(
"get_document",
arguments={
"id": "doc123",
"fields": ["title", "content", "author"]
}
)
The following environment variables can be configured in your .env file:
# MCP Server Configuration
MCP_SERVER_NAME=Solr Search
MCP_SERVER_PORT=8765
# Apache Solr Configuration
SOLR_BASE_URL=http://localhost:8983/solr
SOLR_COLLECTION=documents
SOLR_USERNAME=
SOLR_PASSWORD=
# Authentication (for future use)
JWT_SECRET_KEY=your_jwt_secret_key
JWT_ALGORITHM=HS256
JWT_EXPIRATION_MINUTES=1440 # 24 hours
# Logging
LOG_LEVEL=INFO
There are several ways to test and interact with the MCP Solr server:
This is the most convenient method for testing and debugging:
# Start the server with the inspector
mcp dev src/server/mcp_server.py
Then open http://127.0.0.1:6274 in your browser to access the MCP Inspector.
Using the Resource:
solr://search/{query} in the sidebar{query} with your search term (e.g., *:* for all documents)Using the Search Tool:
{
"query": "*:*",
"filter_query": "category:technology",
"sort": "id asc",
"rows": 5,
"start": 0
}
Using Faceted Search:
{
"query": "*:*",
"rows": 10,
"facet_fields": ["category", "author"]
}
facet_counts with aggregated data per fieldUsing Highlighting:
{
"query": "title:machine",
"rows": 10,
"highlight_fields": ["title", "content"]
}
highlighting with <em> tags around matched terms{
"id": "doc1",
"fields": ["title", "content", "author"]
}
You can create a simple Python client to test the server:
import asyncio
from mcp.client import MCPClient
async def test_solr_search():
# Connect to the MCP server
async with MCPClient(url="http://localhost:8765") as client:
# Get server info to verify connection
server_info = await client.get_server_info()
print("Connected to MCP server:", server_info.name)
# Execute a search
search_result = await client.call_tool(
"search",
arguments={
"query": "*:*",
"filter_query": None,
"sort": "id asc",
"rows": 5,
"start": 0
}
)
print("Search results:", search_result)
# If documents were found, retrieve the first one
if "response" in search_result and search_result["response"]["numFound"] > 0:
doc_id = search_result["response"]["docs"][0]["id"]
document = await client.call_tool(
"get_document",
arguments={
"id": doc_id,
"fields": ["title", "content"]
}
)
print(f"Document with ID {doc_id}:", document)
if __name__ == "__main__":
asyncio.run(test_solr_search())
Save this as test_solr_client.py and run:
python test_solr_client.py
You can also test with curl or any HTTP client. Note that the MCP server expects specific request formats:
# Testing search tool with curl
curl -X POST http://localhost:8765/tool/search \
-H "Content-Type: application/json" \
-d '{"query": "*:*", "rows": 5}'
# Retrieving a document with curl
curl -X POST http://localhost:8765/tool/get_document \
-H "Content-Type: application/json" \
-d '{"id": "doc1"}'
# Using the resource endpoint
curl -G http://localhost:8765/resource/solr%3A%2F%2Fsearch%2F%2A%3A%2A \
--data-urlencode "query=*:*"
If you can access the MCP Inspector but not connect with other clients:
Check CORS settings:
Verify network access:
Check for authentication requirements:
Inspect request format:
Use the debug server mode:
MCP_DEBUG=1 python run_server.py --mode mcp
To integrate the MCP server into external tools (e.g., Claude Desktop, VSCode Dev Containers, custom tool runners), use the following configuration:
"solr-search": {
"command": "/home/mjochum/miniconda3/bin/uv",
"args": [
"run",
"--project",
"/home/mjochum/projekte/mcp-solr-search",
"--with",
"mcp[cli]>=1.21.0",
"mcp",
"run",
"/home/mjochum/projekte/mcp-solr-search/src/server/mcp_server.py"
]
}
Important:
uv command and the server file/home/mjochum/... → your home directory)--project argument ensures the correct dependencies are loaded# Run all tests (unit and integration)
pytest
# Run only unit tests
pytest tests/test_server.py
# Run only integration tests (requires running Solr)
pytest tests/test_integration_server.py -m integration
# Run with coverage
pytest --cov=src
Integration tests will automatically skip if the Solr server is not available, so they're safe to run even without a running Docker environment.
/src
server.py # Main MCP server implementation
/tests
test_server.py # Unit tests with mocked Solr responses
test_integration_server.py # Integration tests with real Solr
/docker
/solr
load_sample_data.py # Script to load sample documents
/configsets
/documents
/conf
schema.xml # Solr schema definition
solrconfig.xml # Solr configuration
stopwords.txt # Stopwords for text analysis
docker-compose.yml # Docker Compose configuration for Solr
start_solr.sh # Script to start Solr and load data
.env.example # Environment variables template
pyproject.toml # Project configuration
PLANNING.md # Project planning document
TASK.md # Project tasks and progress tracking
CHANGELOG.md # Documentation of project changes
README.md # This file
This project follows Semantic Versioning. For the versions available, see the CHANGELOG.md file for details on what has changed in each version.
git checkout -b feature-namegit commit -am 'Add some feature'git push origin feature-nameThis project is licensed under the MIT License.
Please log in to share your review and rating for this MCP.
Explore related MCPs that share similar capabilities and solve comparable challenges
by exa-labs
Provides real-time web search capabilities to AI assistants via a Model Context Protocol server, enabling safe and controlled access to the Exa AI Search API.
by perplexityai
Enables Claude and other MCP‑compatible applications to perform real‑time web searches through the Perplexity (Sonar) API without leaving the MCP ecosystem.
by MicrosoftDocs
Provides semantic search and fetch capabilities for Microsoft official documentation, returning content in markdown format via a lightweight streamable HTTP transport for AI agents and development tools.
by elastic
Enables natural‑language interaction with Elasticsearch indices via the Model Context Protocol, exposing tools for listing indices, fetching mappings, performing searches, running ES|QL queries, and retrieving shard information.
by graphlit
Enables integration between MCP clients and the Graphlit platform, providing ingestion, extraction, retrieval, and RAG capabilities across a wide range of data sources and connectors.
by ihor-sokoliuk
Provides web search capabilities via the SearXNG API, exposing them through an MCP server for seamless integration with AI agents and tools.
by mamertofabian
Fast cross‑platform file searching leveraging the Everything SDK on Windows, Spotlight on macOS, and locate/plocate on Linux.
by spences10
Provides unified access to multiple search engines, AI response tools, and content processing services through a single Model Context Protocol server.
by cr7258
Provides Elasticsearch and OpenSearch interaction via Model Context Protocol, enabling document search, index management, cluster monitoring, and alias operations.