diff --git a/content/doap/solr-mcp.rdf b/content/doap/solr-mcp.rdf new file mode 100644 index 000000000..40faa36a2 --- /dev/null +++ b/content/doap/solr-mcp.rdf @@ -0,0 +1,52 @@ + + + + + + 2025-10-26 + + Apache Solr MCP Server + + + Model Context Protocol server for Apache Solr + + + + Java + + + + + + + + + + + + Apache Solr Team + + + + + + diff --git a/content/pages/mcp/clients/claude-code.md b/content/pages/mcp/clients/claude-code.md new file mode 100644 index 000000000..4d6340d18 --- /dev/null +++ b/content/pages/mcp/clients/claude-code.md @@ -0,0 +1,90 @@ +Title: Claude Code +URL: mcp/clients/claude-code.html +save_as: mcp/clients/claude-code.html +template: mcp/client + +[Claude Code](https://docs.anthropic.com/en/docs/claude-code) is Anthropic's CLI tool for Claude. It supports MCP servers via the `claude mcp add` command or a `.mcp.json` project file. + +*** + +## STDIO Mode (Recommended) ## + +### CLI ### + +```bash +# JAR +claude mcp add --transport stdio \ + -e SOLR_URL=http://localhost:8983/solr/ \ + solr-mcp -- java -jar /absolute/path/to/solr-mcp-1.0.0-SNAPSHOT.jar + +# Docker (local image — build first with ./gradlew jibDockerBuild) +claude mcp add --transport stdio solr-mcp -- \ + docker run -i --rm -e SOLR_URL=http://host.docker.internal:8983/solr/ \ + solr-mcp:latest +``` + +### `.mcp.json` ### + +Add to your project root: + +**JAR:** + +```json +{ + "mcpServers": { + "solr-mcp": { + "type": "stdio", + "command": "java", + "args": ["-jar", "/absolute/path/to/solr-mcp-1.0.0-SNAPSHOT.jar"], + "env": { "SOLR_URL": "http://localhost:8983/solr/" } + } + } +} +``` + +**Docker (local image):** + +```json +{ + "mcpServers": { + "solr-mcp": { + "type": "stdio", + "command": "docker", + "args": ["run", "-i", "--rm", + "-e", "SOLR_URL=http://host.docker.internal:8983/solr/", + "solr-mcp:latest"] + } + } +} +``` + +*** + +## HTTP Mode ## + +Start the server first (see [Running the Server](https://github.com/apache/solr-mcp#running-the-server)), then: + +### CLI ### + +```bash +claude mcp add --transport http solr-mcp http://localhost:8080/mcp +``` + +### `.mcp.json` ### + +```json +{ + "mcpServers": { + "solr-mcp": { + "type": "http", + "url": "http://localhost:8080/mcp" + } + } +} +``` + +### Secured HTTP (OAuth2) ### + +Claude Code detects the OAuth2 challenge from the server and initiates the authorization flow automatically. The configuration is the same as unsecured HTTP. + +See [Security](/mcp/security.html) for server-side OAuth2 setup. diff --git a/content/pages/mcp/clients/claude-desktop.md b/content/pages/mcp/clients/claude-desktop.md new file mode 100644 index 000000000..e849131d0 --- /dev/null +++ b/content/pages/mcp/clients/claude-desktop.md @@ -0,0 +1,110 @@ +Title: Claude Desktop +URL: mcp/clients/claude-desktop.html +save_as: mcp/clients/claude-desktop.html +template: mcp/client + +[Claude Desktop](https://claude.ai/download) is Anthropic's desktop application for Claude. It supports MCP servers via STDIO and HTTP transports. + +### Configuration File + +* **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json` +* **Windows**: `%APPDATA%\Claude\claude_desktop_config.json` + +Restart Claude Desktop after any configuration change. + +*** + +## STDIO Mode (Recommended) ## + +STDIO mode communicates via stdin/stdout. This is the simplest setup for local use. + +### JAR ### + +Requires Java 25+ and a [built JAR](https://github.com/apache/solr-mcp#running-the-server) (`./gradlew build`). + +```json +{ + "mcpServers": { + "solr-mcp": { + "command": "java", + "args": ["-jar", "/absolute/path/to/solr-mcp-1.0.0-SNAPSHOT.jar"], + "env": { + "SOLR_URL": "http://localhost:8983/solr/" + } + } + } +} +``` + +### Docker (local image) ### + +Build the image first: `./gradlew jibDockerBuild` + +```json +{ + "mcpServers": { + "solr-mcp": { + "command": "docker", + "args": ["run", "-i", "--rm", + "-e", "SOLR_URL=http://host.docker.internal:8983/solr/", + "solr-mcp:latest"] + } + } +} +``` + +**Linux users**: add `"--add-host=host.docker.internal:host-gateway"` to the `args` array. + +*** + +## HTTP Mode ## + +HTTP mode connects to a running MCP server via REST endpoints. Start the server first, then configure Claude Desktop to connect using `mcp-remote`. + +### Start the Server ### + +```bash +# JAR +PROFILES=http java -jar build/libs/solr-mcp-1.0.0-SNAPSHOT.jar + +# Or Gradle +PROFILES=http ./gradlew bootRun + +# Or Docker (local image) +docker run -p 8080:8080 --rm \ + -e PROFILES=http \ + -e SOLR_URL=http://host.docker.internal:8983/solr/ \ + solr-mcp:latest +``` + +### Configure Claude Desktop ### + +```json +{ + "mcpServers": { + "solr-mcp": { + "command": "npx", + "args": ["mcp-remote", "http://localhost:8080/mcp"] + } + } +} +``` + +### Secured HTTP (OAuth2) ### + +When OAuth2 is enabled on the server, `mcp-remote` handles the authorization flow automatically—it discovers the authorization server and opens a browser for consent. + +```json +{ + "mcpServers": { + "solr-mcp": { + "command": "npx", + "args": ["mcp-remote", "http://localhost:8080/mcp", "--allow-http"] + } + } +} +``` + +The `--allow-http` flag is needed for `http://` URLs (development). Omit it in production with HTTPS. + +See [Security](/mcp/security.html) for server-side OAuth2 setup. diff --git a/content/pages/mcp/clients/cursor.md b/content/pages/mcp/clients/cursor.md new file mode 100644 index 000000000..e07a37497 --- /dev/null +++ b/content/pages/mcp/clients/cursor.md @@ -0,0 +1,73 @@ +Title: Cursor +URL: mcp/clients/cursor.html +save_as: mcp/clients/cursor.html +template: mcp/client + +[Cursor](https://cursor.sh/) supports MCP servers natively via project configuration files or the Cursor Settings UI. + +*** + +## STDIO Mode (Recommended) ## + +### Project Configuration (`.cursor/mcp.json`) ### + +Create `.cursor/mcp.json` in your project root: + +**JAR:** + +```json +{ + "mcpServers": { + "solr-mcp": { + "command": "java", + "args": ["-jar", "/absolute/path/to/solr-mcp-1.0.0-SNAPSHOT.jar"], + "env": { "SOLR_URL": "http://localhost:8983/solr/" } + } + } +} +``` + +**Docker (local image — build first with `./gradlew jibDockerBuild`):** + +```json +{ + "mcpServers": { + "solr-mcp": { + "command": "docker", + "args": ["run", "-i", "--rm", + "-e", "SOLR_URL=http://host.docker.internal:8983/solr/", + "solr-mcp:latest"] + } + } +} +``` + +### Cursor Settings UI ### + +1. Open **Cursor Settings** (gear icon or Cmd+, / Ctrl+,) +2. Navigate to **Features** > **MCP Servers** +3. Click **Add New MCP Server** +4. Enter: + * **Name**: `solr-mcp` + * **Type**: `command` + * **Command**: `java -jar /absolute/path/to/solr-mcp-1.0.0-SNAPSHOT.jar` + +*** + +## HTTP Mode ## + +Start the server first (see [Running the Server](https://github.com/apache/solr-mcp#running-the-server)), then: + +```json +{ + "mcpServers": { + "solr-mcp": { + "url": "http://localhost:8080/mcp" + } + } +} +``` + +The configuration is the same for secured and unsecured HTTP. Cursor handles the MCP OAuth2 flow automatically. + +See the [Cursor MCP documentation](https://docs.cursor.com/context/model-context-protocol) for the latest configuration format. diff --git a/content/pages/mcp/clients/jetbrains.md b/content/pages/mcp/clients/jetbrains.md new file mode 100644 index 000000000..44887de93 --- /dev/null +++ b/content/pages/mcp/clients/jetbrains.md @@ -0,0 +1,76 @@ +Title: JetBrains IDEs +URL: mcp/clients/jetbrains.html +save_as: mcp/clients/jetbrains.html +template: mcp/client + +[JetBrains IDEs](https://www.jetbrains.com/) (IntelliJ IDEA, WebStorm, PyCharm, etc.) support MCP servers through the AI Assistant plugin. + +*** + +## STDIO Mode (Recommended) ## + +### Project Configuration (`.junie/mcp.json`) ### + +Create `.junie/mcp.json` in your project root: + +**JAR:** + +```json +{ + "mcpServers": { + "solr-mcp": { + "command": "java", + "args": ["-jar", "/absolute/path/to/solr-mcp-1.0.0-SNAPSHOT.jar"], + "env": { "SOLR_URL": "http://localhost:8983/solr/" } + } + } +} +``` + +**Docker (local image — build first with `./gradlew jibDockerBuild`):** + +```json +{ + "mcpServers": { + "solr-mcp": { + "command": "docker", + "args": ["run", "-i", "--rm", + "-e", "SOLR_URL=http://host.docker.internal:8983/solr/", + "solr-mcp:latest"] + } + } +} +``` + +### IDE Settings ### + +1. Open **Settings** (Cmd+, / Ctrl+Alt+S) +2. Navigate to **Tools** > **AI Assistant** > **MCP Servers** +3. Click **Add** (`+`) +4. Configure: + * **Name**: `solr-mcp` + * **Transport**: `STDIO` + * **Command**: `java` + * **Arguments**: `-jar /absolute/path/to/solr-mcp-1.0.0-SNAPSHOT.jar` + +*** + +## HTTP Mode ## + +Start the server first (see [Running the Server](https://github.com/apache/solr-mcp#running-the-server)), then: + +```json +{ + "mcpServers": { + "solr-mcp": { + "url": "http://localhost:8080/mcp" + } + } +} +``` + +Or in IDE Settings, select **SSE** transport and enter `http://localhost:8080/mcp` as the URL. + +The configuration is the same for secured and unsecured HTTP. JetBrains IDEs handle the MCP OAuth2 flow automatically. + +MCP support requires the AI Assistant plugin. See the [JetBrains MCP documentation](https://www.jetbrains.com/help/idea/model-context-protocol.html) for the latest configuration format. diff --git a/content/pages/mcp/clients/mcp-inspector.md b/content/pages/mcp/clients/mcp-inspector.md new file mode 100644 index 000000000..6e4402bd7 --- /dev/null +++ b/content/pages/mcp/clients/mcp-inspector.md @@ -0,0 +1,57 @@ +Title: MCP Inspector +URL: mcp/clients/mcp-inspector.html +save_as: mcp/clients/mcp-inspector.html +template: mcp/client + +The [MCP Inspector](https://github.com/modelcontextprotocol/inspector) is a web-based tool for testing and debugging MCP servers. It lets you browse available tools, invoke them interactively, and inspect responses. + +### Install ### + +```bash +npx @modelcontextprotocol/inspector +``` + +This starts the Inspector UI at `http://localhost:6274`. + +*** + +## STDIO Mode ## + +1. In MCP Inspector, select **STDIO** transport +2. **Command**: `java` +3. **Arguments**: `-jar /absolute/path/to/solr-mcp-1.0.0-SNAPSHOT.jar` +4. Click **Connect** + +*** + +## HTTP Mode ## + +1. Start the server in HTTP mode: + + # JAR + PROFILES=http java -jar build/libs/solr-mcp-1.0.0-SNAPSHOT.jar + + # Or Gradle + PROFILES=http ./gradlew bootRun + + # Or Docker (local image — build first with ./gradlew jibDockerBuild) + docker run -p 8080:8080 --rm \ + -e PROFILES=http \ + -e SOLR_URL=http://host.docker.internal:8983/solr/ \ + solr-mcp:latest + +2. In MCP Inspector, enter: `http://localhost:8080/mcp` +3. Click **Connect** + +*** + +## OAuth2 ## + +When OAuth2 is enabled on the server, configure the Inspector's OAuth settings before connecting: + +1. Click the **OAuth** settings in the Inspector +2. Enter your provider's Authorization URL, Token URL, Client ID, and Redirect URI (`http://localhost:6274/oauth/callback`) +3. Complete the OAuth flow +4. The Inspector will include the Bearer token in all subsequent requests + +See [Security](/mcp/security.html) for server-side OAuth2 setup with Auth0 and Keycloak. diff --git a/content/pages/mcp/clients/vs-code.md b/content/pages/mcp/clients/vs-code.md new file mode 100644 index 000000000..148ae56d8 --- /dev/null +++ b/content/pages/mcp/clients/vs-code.md @@ -0,0 +1,85 @@ +Title: VS Code / GitHub Copilot +URL: mcp/clients/vs-code.html +save_as: mcp/clients/vs-code.html +template: mcp/client + +[VS Code](https://code.visualstudio.com/) supports MCP servers through built-in MCP support (VS Code 1.99+). Solr MCP tools are available in GitHub Copilot Chat when using Agent mode. + +*** + +## STDIO Mode (Recommended) ## + +### Workspace Configuration (`.vscode/mcp.json`) ### + +Create `.vscode/mcp.json` in your project root: + +**JAR:** + +```json +{ + "servers": { + "solr-mcp": { + "type": "stdio", + "command": "java", + "args": ["-jar", "/absolute/path/to/solr-mcp-1.0.0-SNAPSHOT.jar"], + "env": { "SOLR_URL": "http://localhost:8983/solr/" } + } + } +} +``` + +**Docker (local image — build first with `./gradlew jibDockerBuild`):** + +```json +{ + "servers": { + "solr-mcp": { + "type": "stdio", + "command": "docker", + "args": ["run", "-i", "--rm", + "-e", "SOLR_URL=http://host.docker.internal:8983/solr/", + "solr-mcp:latest"] + } + } +} +``` + +### User Settings (`settings.json`) ### + +Open VS Code Settings (JSON) and add: + +```json +{ + "mcp": { + "servers": { + "solr-mcp": { + "type": "stdio", + "command": "java", + "args": ["-jar", "/absolute/path/to/solr-mcp-1.0.0-SNAPSHOT.jar"], + "env": { "SOLR_URL": "http://localhost:8983/solr/" } + } + } + } +} +``` + +*** + +## HTTP Mode ## + +Start the server first (see [Running the Server](https://github.com/apache/solr-mcp#running-the-server)), then: + +```json +{ + "servers": { + "solr-mcp": { + "type": "sse", + "url": "http://localhost:8080/mcp" + } + } +} +``` + +The configuration is the same for secured and unsecured HTTP. VS Code handles the MCP OAuth2 flow automatically. + +See the [VS Code MCP documentation](https://code.visualstudio.com/docs/copilot/chat/mcp-servers) for the latest configuration format. diff --git a/content/pages/mcp/community.md b/content/pages/mcp/community.md new file mode 100644 index 000000000..e2e5b9a22 --- /dev/null +++ b/content/pages/mcp/community.md @@ -0,0 +1,42 @@ +Title: Community +URL: mcp/community.html +save_as: mcp/community.html +template: mcp/community + +## Support ## + +The Solr MCP community provides user support for free through the [users mailing list](#mailing-lists-chat) and [slack channels](#slack). + +## Mailing Lists & Chat ## + +The Solr MCP server shares mailing lists with its parent project, Apache Solr. +Available lists can be [found here]({filename}/pages/community.md#mailing-lists-chat). + +#### Slack #### + +* The project's main Slack channel is `#solr-mcp` in the `the-asf` organization. + Link: + +## Issue tracker ## + +The Solr MCP Server uses [Github issues](https://github.com/apache/solr-mcp/issues) in its repository for issue tracking. + +## How To Contribute ## + +Looking to contribute to the Solr MCP Server? Read the [CONTRIBUTING.md](https://github.com/apache/solr-mcp/blob/main/CONTRIBUTING.md) instructions and join us. + +## Code of Conduct ## + +For a large and diverse community like ours to be friendly, welcoming and respectful, we recognize the need for some guidelines. The project follows [Apache's Code of Conduct statement](https://www.apache.org/foundation/policies/conduct). Please take some time to read and understand it. + +If you feel there has been a violation of this code, please point out your concerns publicly in a friendly and matter of fact manner. Nonverbal communication is prone to misinterpretation and misunderstanding. Everyone has bad days and sometimes says things they regret later. Someone else's communication style may clash with yours, but the difference can be amicably resolved. After pointing out your concerns please be generous upon receiving an apology. + +Should there be repeated instances of code of conduct violations, or if there is an obvious and severe violation, the Solr PMC may become involved. + +### The Apache Way + +As an Apache project we strive to follow [The Apache Way](http://theapacheway.com/). If you are new to the community or to open source in general, you may benefit from understanding our core values as a community, and why we operate the way we do. + +## Version Control ## + +The project's Git repository is found at https://github.com/apache/solr-mcp or the mirror at https://gitbox.apache.org/repos/asf/solr-mcp.git diff --git a/content/pages/mcp/downloads.md b/content/pages/mcp/downloads.md new file mode 100644 index 000000000..8e59896a6 --- /dev/null +++ b/content/pages/mcp/downloads.md @@ -0,0 +1,5 @@ +Title: Downloads +URL: mcp/downloads.html +save_as: mcp/downloads.html +template: mcp/downloads + diff --git a/content/pages/mcp/features.md b/content/pages/mcp/features.md new file mode 100644 index 000000000..6e96e5ecf --- /dev/null +++ b/content/pages/mcp/features.md @@ -0,0 +1,4 @@ +Title: Features +URL: mcp/features.html +save_as: mcp/features.html +template: mcp/features diff --git a/content/pages/mcp/index.md b/content/pages/mcp/index.md new file mode 100644 index 000000000..b9d9a795c --- /dev/null +++ b/content/pages/mcp/index.md @@ -0,0 +1,4 @@ +Title: Welcome +URL: mcp/index.html +save_as: mcp/index.html +template: mcp/index diff --git a/content/pages/mcp/observability.md b/content/pages/mcp/observability.md new file mode 100644 index 000000000..46da40be5 --- /dev/null +++ b/content/pages/mcp/observability.md @@ -0,0 +1,114 @@ +Title: Observability +URL: mcp/observability.html +save_as: mcp/observability.html +template: mcp/observability + +## Overview ## + +When running in **HTTP mode**, the Solr MCP Server exports telemetry data via OpenTelemetry to the **LGTM stack** (Loki, Grafana, Tempo, Mimir) for full observability. + +| Signal | Backend | What it shows | +|--------|---------|---------------| +| **Traces** | Tempo | Distributed traces for every MCP tool invocation, Solr query, and HTTP request | +| **Metrics** | Mimir/Prometheus | JVM stats, HTTP request rates, Solr query latencies, cache hit ratios | +| **Logs** | Loki | Structured application logs correlated with trace IDs | + +Every MCP tool invocation creates a trace span: search, indexing (JSON, CSV, XML), collection operations (list, stats, health, create), and schema retrieval. All incoming HTTP requests and outgoing Solr calls are automatically traced. + +*** + +## Setup ## + +### Start the LGTM Stack ### + +The project's `compose.yaml` includes a Grafana OTEL LGTM all-in-one container: + +```bash +docker compose up -d +``` + +This starts: + +| Service | URL | Purpose | +|---------|-----|---------| +| Grafana | http://localhost:3000 | Dashboards and exploration (no auth required) | +| OTLP gRPC | localhost:4317 | Trace/metric/log ingestion (gRPC) | +| OTLP HTTP | localhost:4318 | Trace/metric/log ingestion (HTTP) | + +### Run the Server with Observability ### + +```bash +PROFILES=http ./gradlew bootRun +``` + +The server auto-configures OTLP export when the LGTM stack is running. Default configuration: + +```properties +management.tracing.sampling.probability=1.0 # 100% sampling (dev) +otel.exporter.otlp.endpoint=http://localhost:4317 +otel.exporter.otlp.protocol=grpc +``` + +*** + +## Grafana ## + +Open [http://localhost:3000](http://localhost:3000) and click **Explore** in the left sidebar. + +### View Traces (Tempo) ### + +1. Select **Tempo** as the data source +2. Use TraceQL to search: + + {.service.name="solr-mcp"} + +3. Click on a trace to see the span waterfall—each MCP tool invocation, Solr query, and HTTP request is a separate span + +### View Logs (Loki) ### + +1. Select **Loki** as the data source +2. Use LogQL to search: + + {service_name="solr-mcp"} |= "search" + +3. Logs are automatically correlated with trace IDs—click a log line to jump to its trace + +### View Metrics (Prometheus) ### + +1. Select **Prometheus** as the data source +2. Example queries: + + # HTTP request rate + rate(http_server_requests_seconds_count[5m]) + + # JVM memory usage + jvm_memory_used_bytes + + # Request latency (p99) + histogram_quantile(0.99, rate(http_server_requests_seconds_bucket[5m])) + +*** + +## Actuator Endpoints ## + +The following health and metrics endpoints are exposed in HTTP mode: + +```bash +curl http://localhost:8080/actuator/health # Health check +curl http://localhost:8080/actuator/info # Build info +curl http://localhost:8080/actuator/metrics # Available metrics +curl http://localhost:8080/actuator/prometheus # Prometheus scrape endpoint +curl http://localhost:8080/actuator/loggers # Logger levels +``` + +*** + +## Production Configuration ## + +For production, reduce the sampling rate and configure the OTLP endpoint for your collector: + +```bash +export OTEL_SAMPLING_PROBABILITY=0.1 # 10% sampling +export OTEL_TRACES_URL=https://otel-collector.example.com:4317 +PROFILES=http java -jar build/libs/solr-mcp-1.0.0-SNAPSHOT.jar +``` diff --git a/content/pages/mcp/quick-start.md b/content/pages/mcp/quick-start.md new file mode 100644 index 000000000..e4ccfa494 --- /dev/null +++ b/content/pages/mcp/quick-start.md @@ -0,0 +1,129 @@ +Title: Quick Start +URL: mcp/quick-start.html +save_as: mcp/quick-start.html +template: mcp/quick-start + +## Prerequisites ## + +* Java 25+ ([Eclipse Temurin](https://adoptium.net/) recommended) +* [Docker](https://docs.docker.com/get-docker/) and Docker Compose +* An MCP client — this guide uses [Claude Desktop](https://claude.ai/download), but any MCP-compatible client works. See [Adding to AI Clients](/mcp/clients/claude-desktop.html) for other options. + +## Start Solr with Sample Data ## + +Clone the repository and start Solr in SolrCloud mode: + +```bash +git clone https://github.com/apache/solr-mcp.git +cd solr-mcp +docker compose up -d +``` + +This starts Solr with ZooKeeper and creates two sample collections pre-loaded with data: + +* **films** — 1,100+ movie records with titles, directors, genres, and release dates +* **books** — empty collection ready for indexing + +Wait ~30 seconds for Solr to fully initialize. Verify at [http://localhost:8983/solr/](http://localhost:8983/solr/). + +## Build the Server ## + +```bash +./gradlew build +``` + +This produces `build/libs/solr-mcp-1.0.0-SNAPSHOT.jar`. + +## Configure Your MCP Client ## + +Add the following to your Claude Desktop configuration file: + +* **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json` +* **Windows**: `%APPDATA%\Claude\claude_desktop_config.json` + +```json +{ + "mcpServers": { + "solr-mcp": { + "command": "java", + "args": ["-jar", "/absolute/path/to/solr-mcp/build/libs/solr-mcp-1.0.0-SNAPSHOT.jar"], + "env": { "SOLR_URL": "http://localhost:8983/solr/" } + } + } +} +``` + +Restart Claude Desktop after saving. + +**Alternatively**, you can use a local Docker image: + +```bash +./gradlew jibDockerBuild +``` + +Then configure Claude Desktop with: + +```json +{ + "mcpServers": { + "solr-mcp": { + "command": "docker", + "args": ["run", "-i", "--rm", + "-e", "SOLR_URL=http://host.docker.internal:8983/solr/", + "solr-mcp:latest"] + } + } +} +``` + +**Linux users**: add `"--add-host=host.docker.internal:host-gateway"` to the args array. + +## Native Image (experimental) ## + +Opt-in GraalVM native image builds are available for both **STDIO** and **HTTP** transports. Native binaries start in milliseconds and use substantially less memory than the JVM image. Spring AOT bakes a profile-specific bean graph at build time, so each native image is single-transport — pick the one that matches your client. + +```bash +# Build the native STDIO image +./gradlew bootBuildImage -Pnative +# Produces: solr-mcp:1.0.0-SNAPSHOT-native-stdio (also tagged :latest-native-stdio) + +# Build the native HTTP image +./gradlew bootBuildImage -Pnative -Pprofile=http +# Produces: solr-mcp:1.0.0-SNAPSHOT-native-http (also tagged :latest-native-http) +``` + +Configure Claude Desktop with the native STDIO image: + +```json +{ + "mcpServers": { + "solr-mcp": { + "command": "docker", + "args": ["run", "-i", "--rm", + "-e", "SOLR_URL=http://host.docker.internal:8983/solr/", + "solr-mcp:latest-native-stdio"] + } + } +} +``` + +For dual-transport support from a single image (e.g. switch between modes via `PROFILES` env var without rebuilding), use the JVM Jib image above. The JVM image trades startup time and memory footprint for transport flexibility. + +## Try It Out ## + +Open Claude Desktop and try these prompts: + +* *"Search the films collection for movies directed by Steven Spielberg"* +* *"What collections are available in Solr?"* +* *"Show me the schema for the films collection"* +* *"Find all sci-fi movies released after 2000 and show the genre breakdown"* +* *"Index this JSON into the books collection: [{"id": "1", "title": "The Great Gatsby", "author": "F. Scott Fitzgerald"}]"* + +*** + +## Next Steps ## + +* **[Adding to AI Clients](/mcp/clients/claude-desktop.html)** — configure Claude Code, VS Code, Cursor, JetBrains, or MCP Inspector +* **[Features](/mcp/features.html)** — explore all available tools and resources +* **[Security](/mcp/security.html)** — set up OAuth2 authentication for HTTP mode +* **[Observability](/mcp/observability.html)** — enable tracing, metrics, and logging diff --git a/content/pages/mcp/resources.md b/content/pages/mcp/resources.md new file mode 100644 index 000000000..ae7b1a483 --- /dev/null +++ b/content/pages/mcp/resources.md @@ -0,0 +1,47 @@ +Title: Resources +URL: mcp/resources.html +save_as: mcp/resources.html +template: mcp/resources + +## Guides ## + +* **[Quick Start](/mcp/quick-start.html)** — get from zero to a working AI + Solr integration in under 2 minutes +* **[Security (OAuth2)](/mcp/security.html)** — Auth0 and Keycloak setup for HTTP mode +* **[Observability](/mcp/observability.html)** — traces, metrics, and logs via the LGTM stack + +## Documentation ## + +* [README](https://github.com/apache/solr-mcp#readme) — quick start, client configurations, and usage overview +* [CONTRIBUTING](https://github.com/apache/solr-mcp/blob/main/CONTRIBUTING.md) — pull request process and commit conventions +* [Architecture](https://github.com/apache/solr-mcp/blob/main/docs/development/ARCHITECTURE.md) — project structure and design decisions +* [Development Guide](https://github.com/apache/solr-mcp/blob/main/docs/development/DEVELOPMENT.md) — build system, testing, and IDE setup +* [Auth0 Setup](https://github.com/apache/solr-mcp/blob/main/docs/development/AUTH0_SETUP.md) — detailed OAuth2 setup with Auth0 +* [Keycloak Setup](https://github.com/apache/solr-mcp/blob/main/docs/development/keycloak.md) — detailed OAuth2 setup with Keycloak + +*** + +## References ## + +### MCP Protocol ### + +* [Model Context Protocol Specification](https://spec.modelcontextprotocol.io/) +* [MCP GitHub Organization](https://github.com/modelcontextprotocol) +* [MCP Inspector](https://github.com/modelcontextprotocol/inspector) + +### Spring AI MCP ### + +* [Spring AI MCP Server (Spring Boot)](https://docs.spring.io/spring-ai/reference/api/mcp/mcp-server-boot.html) +* [Spring AI MCP Project](https://spring.io/projects/spring-ai) +* [Spring AI Community MCP Security](https://github.com/spring-ai-community/mcp-security) + +### Apache Solr ### + +* [Apache Solr Documentation](https://solr.apache.org/guide/) +* [SolrJ Client Library](https://solr.apache.org/guide/solr/latest/deployment-guide/solrj.html) + +### Tools and Libraries ### + +* [Jib (Docker image builder)](https://github.com/GoogleContainerTools/jib) +* [Testcontainers](https://www.testcontainers.org/) +* [OpenTelemetry](https://opentelemetry.io/) +* [Grafana LGTM Stack](https://github.com/grafana/docker-otel-lgtm) diff --git a/content/pages/mcp/security.md b/content/pages/mcp/security.md new file mode 100644 index 000000000..978a81eb9 --- /dev/null +++ b/content/pages/mcp/security.md @@ -0,0 +1,175 @@ +Title: Security +URL: mcp/security.html +save_as: mcp/security.html +template: mcp/security + +## Overview ## + +When running in HTTP mode, the Solr MCP Server supports **OAuth2 authentication** with JWT token validation. Security is **disabled by default** and must be explicitly enabled. + +* **Protocol**: OAuth2 Resource Server with JWT validation +* **Supported providers**: Auth0, Keycloak, Okta, or any OAuth2/OIDC provider +* **STDIO mode**: Security is not applicable (OS-level process isolation) +* **HTTP mode**: Optional, enabled with `SECURITY_ENABLED=true` + +### Enable Security ### + +```bash +export PROFILES=http +export SECURITY_ENABLED=true +export OAUTH2_ISSUER_URI=https://your-provider.example.com/ +./gradlew bootRun +``` + +Or with Docker (local image — build first with `./gradlew jibDockerBuild`): + +```bash +docker run -p 8080:8080 --rm \ + -e PROFILES=http \ + -e SECURITY_ENABLED=true \ + -e OAUTH2_ISSUER_URI=https://your-provider.example.com/ \ + -e SOLR_URL=http://host.docker.internal:8983/solr/ \ + solr-mcp:latest +``` + +*** + +## Auth0 ## + +### 1. Create Auth0 Application ### + +1. Go to [Auth0 Dashboard](https://manage.auth0.com/) > **Applications** > **Create Application** +2. Name: `Solr MCP Server` +3. Type: **Machine to Machine Applications** +4. Note your **Domain**, **Client ID**, and **Client Secret** + +### 2. Create Auth0 API ### + +1. Navigate to **Applications** > **APIs** > **Create API** +2. Name: `Solr MCP API` +3. Identifier (audience): `https://solr-mcp-api` +4. Signing Algorithm: **RS256** + +### 3. Configure Callback URLs ### + +In your application settings, add to **Allowed Callback URLs**: + + http://localhost:6274/oauth/callback,http://localhost:3334/oauth/callback,http://localhost:8080/login/oauth2/code/auth0 + +Each callback URL serves a different client: + +* `http://localhost:6274/oauth/callback` — MCP Inspector +* `http://localhost:3334/oauth/callback` — `mcp-remote` (Claude Desktop, VS Code, Cursor, JetBrains in HTTP mode) +* `http://localhost:8080/login/oauth2/code/auth0` — Direct server OAuth2 code flow + +### 4. Run the Server ### + +```bash +export PROFILES=http +export SECURITY_ENABLED=true +export OAUTH2_ISSUER_URI=https://your-tenant.auth0.com/ +./gradlew bootRun +``` + +### 5. Get an Access Token ### + +```bash +curl --request POST \ + --url https://your-tenant.auth0.com/oauth/token \ + --header 'content-type: application/json' \ + --data '{ + "client_id": "YOUR_CLIENT_ID", + "client_secret": "YOUR_CLIENT_SECRET", + "audience": "https://solr-mcp-api", + "grant_type": "client_credentials" + }' +``` + +Or use the convenience script: + +```bash +./scripts/get-auth0-token.sh \ + --domain your-tenant.auth0.com \ + --client-id YOUR_CLIENT_ID \ + --client-secret YOUR_CLIENT_SECRET \ + --audience https://solr-mcp-api +``` + +### 6. Use the Token ### + +```bash +curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \ + http://localhost:8080/mcp +``` + +For the full step-by-step guide, see [Auth0 Setup Guide](https://github.com/apache/solr-mcp/blob/main/docs/development/AUTH0_SETUP.md). + +*** + +## Keycloak ## + +### 1. Start Keycloak ### + +```bash +docker run -d --name keycloak \ + -p 8180:8080 \ + -e KC_BOOTSTRAP_ADMIN_USERNAME=admin \ + -e KC_BOOTSTRAP_ADMIN_PASSWORD=admin \ + quay.io/keycloak/keycloak:26.0 start-dev +``` + +Access the admin console at `http://localhost:8180` (login: `admin` / `admin`). + +### 2. Create Realm and Client ### + +1. Create realm: `solr-mcp` +2. Create client: + * Client ID: `solr-mcp-client` + * Client type: OpenID Connect + * Client authentication: OFF (public client) + * Valid redirect URIs: `http://localhost:6274/*`, `http://localhost:3334/*`, `http://localhost:8080/*` + * Web origins: `*` + +### 3. Create Test User ### + +1. Navigate to **Users** > **Add user** +2. Username: `testuser`, Email verified: ON +3. Set password in **Credentials** tab + +### 4. Run the Server ### + +```bash +export PROFILES=http +export SECURITY_ENABLED=true +export OAUTH2_ISSUER_URI=http://localhost:8180/realms/solr-mcp +./gradlew bootRun +``` + +### 5. Get a Token ### + +```bash +curl -X POST "http://localhost:8180/realms/solr-mcp/protocol/openid-connect/token" \ + -H "Content-Type: application/x-www-form-urlencoded" \ + -d "client_id=solr-mcp-client" \ + -d "username=testuser" \ + -d "password=yourpassword" \ + -d "grant_type=password" +``` + +For the full guide including role-based access control and production deployment, see [Keycloak Setup Guide](https://github.com/apache/solr-mcp/blob/main/docs/development/keycloak.md). + +*** + +## How OAuth2 Works with MCP Clients ## + +When a client connects to a secured Solr MCP Server: + +1. Client connects to `/mcp` +2. Server responds with `401` + OAuth2 metadata +3. Client discovers the authorization server from `/.well-known/oauth-authorization-server` +4. Client opens a browser for login/consent +5. Client receives an authorization code, exchanges it for an access token (JWT) +6. Client attaches the Bearer token to all subsequent MCP requests +7. Server validates the JWT with the OAuth2 provider + +Most MCP clients handle this flow transparently—the configuration is the same for secured and unsecured HTTP servers. See the individual [client setup pages](/mcp/clients/claude-desktop.html) for details. diff --git a/pelicanconf.py b/pelicanconf.py index ee0c7925f..2559ddec1 100755 --- a/pelicanconf.py +++ b/pelicanconf.py @@ -18,6 +18,10 @@ SOLR_OPERATOR_LATEST_RELEASE_DATE = datetime(2025, 3, 25) SOLR_OPERATOR_PREVIOUS_MAJOR_RELEASE = 'v0.8.1' +SOLR_MCP_LATEST_RELEASE = 'v1.0.0' +#SOLR_MCP_LATEST_RELEASE_DATE = datetime(2025, 3, 25) +#SOLR_MCP_PREVIOUS_MAJOR_RELEASE = 'v0.8.1' + # This string will be appended to all unversioned css and js resources to prevent caching surprises on edits. # The theme's htaccess file also sets a cache-control header with longer lifetime, if the v=XXXX query string is added. STATIC_RESOURCE_SUFFIX = "?v=%s" % dirhash('themes/solr/static', 'sha1')[-8:] diff --git a/themes/solr/static/css/mcp.css b/themes/solr/static/css/mcp.css new file mode 100644 index 000000000..cf97fd65c --- /dev/null +++ b/themes/solr/static/css/mcp.css @@ -0,0 +1,1033 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +*/ +html, body { + font-family: 'Helvetica Neue', sans-serif; /* substitute for proxima nova */ + color: #333; +} + +body { + overflow-x:hidden; + pointer-events: none; +} + +body > * { + pointer-events: auto; +} + +.alignleft { + float: left; +} + +.alignright { + float: right; +} + +.container { + padding: 40px 0; +} + +code, pre { + font-family: Menlo, Consolas,"Liberation Mono",Courier,monospace; + color:#4F504D; +} + +code { + font-weight: 500; +} + +/* + * Elements + */ +:focus { + outline: 0; +} + +.offset { + position: relative; + top: -150px; + padding-top: 150px; + margin-bottom: -130px; + z-index: -1000; +} + +.offset-medium { + position: relative; + top: -115px; + padding-top: 115px; + padding-bottom: 0px; + margin-bottom: -115px; + z-index: -1000; +} + +.offset-small { + position: relative; + top: -56px; + padding-top: 112px; + margin-bottom: -56px; + z-index: -1000; +} + +.btn1{ + border: 1px solid #d1d3d4; + background-color:inherit; + text-transform: uppercase; + color:#000; + padding: 0.7em 1em; + font-weight: 500; + margin: 0; +} +.btn1:hover, .btn1:focus { + color:#ff833d; + background:inherit; +} + +div.centered { + text-align: center; + padding-top: 32px; +} + +a.btn, button { + border: 1px solid #d1d3d4; + background-color:inherit; + text-transform: uppercase; + color:#000; + padding: 0.7em 1em; + font-weight: 500; + margin: 0; +} + +a.btn:hover, a.btn:focus, +button:hover, button:focus { + color:#ff833d; + background:inherit; +} + +a.btn.white, +button.white { + color:#fff; +} + +a.btn.white, +button.white:hover { + color:#262130; + background:#fff; +} + +/* + * Header + */ + +.header-section { + position: fixed; + z-index: 999; + min-width: 100%; + background:#2d7a3e; +} + +.header-fill { + padding-top: 90px; +} + +.top-bar, .top-bar .name { + background:#2d7a3e; + height: 90px; +} + +.top-bar .name .logo { + height: 100%; + position:relative; + left: 15px; + padding: 20px 0 25px 0; +} + +.top-bar-section ul li, .top-bar-section li:not(.has-form) a:not(.button) { + background: #2d7a3e; +} + +.top-bar-section li:not(.has-form) a:not(.btn):hover { + background:inherit; + color: #25202f; +} + +.top-bar-section .navigation a.selected { + color: #25202f; +} + +.top-bar-section li:not(.has-form) a.btn:hover, .top-bar-section li:not(.has-form) a.btn:focus { + background:#fff; + color: #25202f; +} + +.top-bar-section ul li>a, +.top-bar-section ul li>a.btn, +.top-bar.shrink.expanded .top-bar-section ul li>a, +.top-bar.shrink.expanded .top-bar-section ul li>a.btn { + padding: 0 10px !important; + transition: all 0.1s ease; + text-transform:uppercase; + font-size:0.92rem; +} + +.top-bar-section ul li>a.btn { + margin: 0; + background-color: transparent; + text-align:left; +} + +.top-bar.expanded .toggle-topbar a { + color:#fff; +} + +.top-bar.expanded .top-bar-section li:not(.has-form) a:not(.btn):hover { + background:#fff; +} + +/* full-width nav styles */ +@media only screen and (min-width: 47.5em) { + .top-bar-section .navigation { + margin: 20px 20px 20px 0; + } + .top-bar .name .logo { + left: 15px; + } + .top-bar .btn { + padding-top: .65rem; + padding-bottom: .55rem; + top: 2px; + text-align:center; + border: 1px solid #fff; + } + .top-bar .btn:hover { + background:#fff; + } +} + +/* shrink header styles */ +.top-bar.shrink, .top-bar.shrink .name, .top-bar.expanded .name { + height: 55px; +} + +.top-bar.shrink.expanded { + height:auto; +} + +.top-bar.shrink .name .logo, .top-bar.expanded .name .logo { + padding: 10px 0 15px 0; +} + +.top-bar.shrink .top-bar-section ul li>a, .top-bar.shrink .top-bar-section ul li>a.btn { + font-size: 0.8em; +} + +.top-bar.shrink .top-bar-section li:not(.has-form) a:not(.button) { + line-height: 35px; +} + +.top-bar.shrink .navigation { + margin: 10px 15px 10px 0; +} + +.top-bar.shrink.expanded .navigation { + margin: 0; +} + +.top-bar.shrink.expanded .top-bar-section li:not(.has-form) a:not(.button) { + line-height: 1.6; +} + +.top-bar.shrink .button { + padding: 10px 20px; +} + +/* + * Global + */ +h1, h2, h3, h4, h5 { + font-family: 'Raleway', 'Helvetica Neue', sans-serif; + font-weight:300; +} + +h1 { + margin-bottom: 20px; + color: #2d7a3e; +} + +h2 { + margin-bottom: 0.8em; + color: #2d7a3e; +} + +h3 { + color: #666; +} + +h4 { + color: #666; +} + +h5 { + color: #999; +} + +p { + line-height: 1.8em; + color:#262130; +} + +.button { + background-color: #ff833d; + text-transform: uppercase; +} + +.button:hover, +.button:focus, +.button:active { + background-color: #ff5c00; +} + +.annotation { + color: #262130; + text-transform: uppercase; + margin-bottom: 0.8em; + font-weight:400; +} + +/* + * PAGES + */ + +.homepage h1.red { + color: #2d7a3e;; +} + +.page h1, .page h2, .page h3 { + font-family: 'Raleway', 'Helvetica Neue', sans-serif; + color: #262130; +} + +.page h1, .subnav h1 , h1.news { + font-weight:300; +} + +.subnav h1 , h1.news { + margin-bottom: 30px; +} + +.subnav h1 , h1.news { + line-height:0.8; +} + +.page h1 small, .subnav h1 small, h1.news small { + font-size:0.4em; + color:#333; +} + +.page h2, .page h3 { + font-weight:500; +} + +.page h2 { + font-size:1.5em; +} + +.page h3 { + font-size:1.4em; +} + +.page p, .page ul li, .page ol li { + color:#333; +} + +.page a { + color: #2d7a3e; +} + +.page .date { + color: #2d7a3e; + text-transform:uppercase; + font-weight:500; +} + +#resources { + text-align:center; +} + +pre { + white-space:pre-wrap; + overflow:hidden; +} + +/* + * Alternate styles (green sections) + */ +.alternate .annotation { + color: #2d7a3e; +} + +.alternate h1 { + font-weight: 100; + color: #212121; +} + +.alternate h2 { + font-weight: 300; +} + +hr { + margin-bottom: 2em; + color:#e4e2dd; +} + +/* + * Small styles + */ + +.small h1 { + font-size: 2em; +} + +.small h2 { + font-size: 1.6em; +} + +.small h3 { + font-size: 1.4em; +} + +.small h4 { + font-size: 1.2em; +} + +.small h5 { + font-size: 1em; +} + +.small p { + font-size: 0.9em; +} + +/* + * Section styles + */ +section { + padding: 40px 0; + color: #333; + text-align:center; +} + +.artifacthub-widget > section { + padding: 0; +} + +section.gray { + background-color: #f9f8f8; +} + +section.orange { + background-color: #2d7a3e; + color: #fff; + padding:60px 0 80px 0; + text-align:center; + position:relative; +} + +section.orange .annotation { + color:#fff; +} + +section.orange h1 { + color: inherit; +} + +section.orange h2 { + color: inherit; +} + +section.orange p { + color:#fff; + font-weight: 300; + font-size: 1.1em; +} + +section.orange .down-arrow { + position: absolute; + left: 50%; +} + +section.orange .down-arrow .red { + color: #ff833c; +} + +section.orange .down-arrow a { + color:#fff; +} + +section.orange.full-width { + margin-left: -100%; + margin-right: -100%; + margin-bottom: 2em; +} + + +/* + * Hero + */ +.hero { + background-color: #262130; + color: #fff; + position:relative; + padding: 100px 0; +} + +.hero h1, +.hero p { + color: #fff; +} + +.hero p { + margin-bottom: 40px; + font-weight: 300; + font-size: 1.1em; +} + +.hero .button { + background-color: #305cb3; +} + +.hero .button:hover, +.hero .button:focus, +.hero .button:active { + background-color: #0045cd; +} + +.hero .down-arrow { + position: absolute; + bottom: -80px; + left: 50%; +} + +.hero .down-arrow .red { + color: #2d7a3e; +} + +.hero .down-arrow a { + color:#fff; +} + +.security { + background-color: #FFBF78; + padding-top: 10px; + padding-bottom: 0px; + display: none; +} + +.security a { + color: #262130; +} + +.topnews { + background-color: #59BD81; + padding-top: 15px; + padding-bottom: 0px; + display: none; +} + +.topnews .row p a { + color: #262130; + font-size: larger; +} + +.topnews-operator { + background-color: #59BD81; + padding-top: 15px; + padding-bottom: 0px; + display: none; +} + +.topnews-operator .row p a { + color: #262130; + font-size: larger; +} + +/* + * Footer + */ +footer { + background-color: #262130; + color: #f9f8f8; + padding: 40px 0 20px 0; +} + +footer h4 { + padding-bottom:15px; + text-transform:uppercase; + font-size: 1em; +} + +footer h4, footer ul li a, .page footer ul li a { + color: #f9f8f8; + font-family: 'Raleway', 'Helvetica Neue', sans-serif; +} + +footer ul li a, .page footer ul li a { + font-weight:300; + font-size:0.9em; +} + +footer ul { + list-style: none; + margin-left: 0; +} + +footer .copyright { + padding: 50px 0 40px 0; +} + +footer .copyright p { + color: #bbb; + font-size:0.7em; + text-align:center; +} + +/* + * Gray/white section styles + */ + +.white h1 { + line-height:0.8; +} + +.gray .annotation { + color: #262130; + font-size: 1em; +} + +.gray h1 { + color: #2d7a3e; + line-height:0.8; +} + +.gray .box h3 { + color:#000; + font-size:1.4em; + margin-bottom:20px; +} + +.gray .box p { + font-size: 0.9em; + line-height: 1.3em; + color:#333; +} + +.gray .box button { + font-size: 0.75em; + margin-bottom: 0; +} + +.gray .box button:hover { + background-color:inherit; + color:#ff833d; +} + +.gray .box:hover { + background:#fff; + border: 1px solid #333; + cursor:pointer; +} + +.gray .box:hover button { + color:#ff833d; +} + +.gray .box .img { + height:120px; +} + +.gray .box .img img { + height:95px; +} + +.full-width .gray .box { + padding:0; + border:none; +} + +.full-width .gray .box:hover { + border:none; + cursor:default; + background:inherit; +} + +/* box variants */ +.col-4 .box { + margin: 15px; + padding: 5px 5px 15px 5px; + border: solid 1px transparent +} + +.col-4 .box .title { + height: 70px; +} + +.col-3 .box { + margin: 15px; + padding: 20px 20px 30px 20px; + border: solid 1px transparent +} + +.col-3 .box .title { + height: 70px; +} + +[class*="block-grid-"] { + display: flex; + padding: 0; + margin:0; + flex-wrap: wrap; + justify-content: center; +} + +/* + * Solr books + */ +.books { + margin:40px 0; + +} + +.books > div{ + padding-left: 5px; +} + +.powered{ + line-height: 99px; + height: 99px; +} +.powered div{ + line-height: 99px; + height: 99px; + padding-right: 10px; +} + +.powered img{ + vertical-align: middle; + display: inline; +} + +/* + * Slider + * TODO: Not in use + */ +.slider-prev { + left:-25px; + color:#ffa16b; +} + +.slider-next { + right:-25px; + color:#ffa16b; +} + +.slider-prev, .slider-next { + position: absolute; + display: block; + height: 20px; + width: 20px; + cursor: pointer; + top: 50%; + margin-top: -10px; +} + +/* + * FEATURES PAGE + */ +section.list { + padding:80px 0; +} + +section.list { + text-align:left; +} + +section.list ul li { + font-family: 'Raleway', 'Helvetica Neue', sans-serif; + font-weight:300; + color: #333; + font-size: 1.2em; + padding-right:20px; +} + +section.list ul li p { + font-family: 'Helvetica Neue', sans-serif; + font-weight:300; + color: #A13016; + margin-top: 10px; + font-size: 0.8em; +} + +section.list ul li ul { + padding-top: 10px; +} + +section.list ul li ul li { + font-family: 'Helvetica Neue', sans-serif; + font-weight:300; + color: #A13016; + margin-top: 2px; + font-size: 0.96em; +} + + +.anchor-fixed { + top: 57px; + z-index: 1000; + position: fixed; +} + +/* + * Subnav style pages + */ +.sub-nav { + display:inline-block; + margin-bottom:0; +} + +.sub-nav-container { + height: 100px; + width: 1000px; + margin: 0 auto; +} + +.sub-nav-border { + padding: 20px 0; + background: white; + border-top: 1px solid #e4e2dd; + border-bottom: 1px solid #e4e2dd; + margin: 0 auto 30px auto; +} + +.sub-nav dd { + margin-bottom: 0; +} + +.sub-nav dd a { + padding-right: 30px; + padding-left: 15px; + border-right:1px solid #e4e2dd; + position: relative; + z-index: 2000; +} + +.codehilite { + margin: 10px 0; + background-color: #EEEEEE; + padding-top: 5px; + padding-bottom: 5px; + padding-left: 15px; +} + +pre { + line-height:1.5; +} + +ul.breadcrumbs { + background-color:transparent; + border: none; +} + +/* + * Sidebar + */ + +.side-nav { + padding:25px; + border:1px solid #e4e2dd; + margin-bottom:40px; +} + +ul.side-nav > li { + border-top:1px solid #e4e2dd; + padding:10px 0 10px 10px; + margin:0; +} + +.page .side-nav li a { + color:#25202f; + font-weight:300; + font-size: 1.3em; +} + +.page .side-nav li a.active { + color:#2d7a3e; +} + +.page .side-nav li a:hover { + color:#2d7a3e; +} + +#search form, #search fieldset { + border:none; + padding:0; + margin:0; +} + +.search-box { + display: inline-block; + padding-right: 1em; + position: relative; + width: 150px; + height: 42px; +} + +#search input[type="search"] { + font-family: 'Raleway', 'Helvetica Neue', sans-serif; + font-weight:300; + height: 28px; + width: 135px; + font-size: 12px; + border: none; + box-shadow: none; + position: absolute; + top: 8px; + left: 0px; + padding-right: 26px; +} + +#search input[type="search"]:focus { + background-color: #f9f9f9; +} + +.search-button { + position:absolute; + height:23px; + width:23px; + background-color: transparent !important; + line-height: 23px !important; + padding: 0 !important; + top: 10px; + right: 17px; + margin:0; +} + +.search-button img { + padding:0; + line-height:23px; + margin:0; +} + +.nested-nav { + +} + +ul.breadcrumbs { + margin:0; + padding:0; +} + +ul.breadcrumbs a { + text-transform:none; + font-size:1.2em; +} + +.tutorials .orange { + margin-top: 40px; + margin-bottom:40px; +} + +.float-right { + float: right; +} + +img.float-right { + margin: 5px 0px 10px 10px; +} + + +.poweredby .list ul{ + list-style-type: none; +} + +.wrappable-btn { + border: 1px solid #d1d3d4; + background-color: inherit; + text-transform: uppercase; + color: #000; + padding: 0.25em 0.75em 0.05em 0.47em; + font-weight: 500; + margin: 0; + display: inline-block; + vertical-align: middle; +} +.wrappable-btn:hover, .wrappable-btn:focus { + color: #ff833d; + background: inherit; +} + +.ref-guide-badge { + background-color: #2d7a3e; + color: #fff; + display: inline-block; + text-align: center; + font-size: 0.6em; + line-height: 1.1; + font-weight: 500; + vertical-align: middle; + padding: 1px 2px; + margin: 0em 0.50em 0.30em -0.40em; +} +.wrappable-btn:hover .ref-guide-badge, .wrappable-btn:focus .ref-guide-badge { + background-color: #ff833d; +} + +ul li div.box div.img img.resizeable-solr-logo { + max-width:243px; + max-height:123px; + height:auto; + width: 100%; + border:2px solid #CCC +} + +ul li div.box h3.fixed-wrap-point-logo-title { + padding-left:9px; + padding-right:8px; +} + +section h3.asset-download { + text-align: left; + padding-top: 10px; +} + +ul li div.box div.img.logo-container { + padding: 20px; + height: auto; + width: auto; +} +ul li div.box div.img.logo-container.black-background { + background-color:#000; +} +ul li div.box div.img.logo-container.white-background { + background-color:#fff; +} +ul li div.box div.img.logo-container.orange-background { + background-color:#2d7a3e; +} +.full-width .gray .box.logo-box { + position: relative; + border: 1px solid #CCC; +} diff --git a/themes/solr/templates/_header.html b/themes/solr/templates/_header.html index b9ae4ae45..3c52bd820 100644 --- a/themes/solr/templates/_header.html +++ b/themes/solr/templates/_header.html @@ -31,6 +31,9 @@
  • Solr Operator
  • +
  • + MCP +
  • + + + +{% include "mcp/_css.html" %} + + + + +{% include "_javascript.html" %} diff --git a/themes/solr/templates/mcp/_header.html b/themes/solr/templates/mcp/_header.html new file mode 100644 index 000000000..0f0b16dc9 --- /dev/null +++ b/themes/solr/templates/mcp/_header.html @@ -0,0 +1,40 @@ +
    +
    + +
    +
    + +
    diff --git a/themes/solr/templates/mcp/base.html b/themes/solr/templates/mcp/base.html new file mode 100644 index 000000000..da0b928a7 --- /dev/null +++ b/themes/solr/templates/mcp/base.html @@ -0,0 +1,46 @@ + + + + {% include "mcp/_head.html" %} + {% block title %}{{ page.title }}{% endblock %} - Apache Solr MCP Server + {% block css %}{% endblock %} + + {% block metakeys %} + + {% endblock %} + {% block ogmeta %} + + + + + + + {% endblock %} + + {% block favicon %} + + + {% endblock %} + {% block rss %}{% endblock %} + {% block javascript %}{% endblock %} + {% include "_matomo.html" %} + + + + {% include "mcp/_header.html" %} + + {% block solr_security_warning %} + {% endblock %} + {% block hero_header %} + {% endblock %} + {% block content %} + {% endblock %} + + + {% include "_last_scripts.html" %} + + diff --git a/themes/solr/templates/mcp/client.html b/themes/solr/templates/mcp/client.html new file mode 100644 index 000000000..52c825397 --- /dev/null +++ b/themes/solr/templates/mcp/client.html @@ -0,0 +1,26 @@ +{% extends "mcp/page.html" %} + +{% block content_inner %} +
    + + +

    {{ page.title }}

    + +

    + All clients: + Claude Desktop · + Claude Code · + VS Code / Copilot · + Cursor · + JetBrains · + MCP Inspector +

    + + {{ page.content }} +
    +{% endblock content_inner %} diff --git a/themes/solr/templates/mcp/community.html b/themes/solr/templates/mcp/community.html new file mode 100644 index 000000000..d20e29389 --- /dev/null +++ b/themes/solr/templates/mcp/community.html @@ -0,0 +1,12 @@ +{% extends "mcp/subnav.html" %} + +{% block subnav_title %}Community{% endblock %} +{% block subnav_subtitle %}Join the active community of Solr MCP Server contributors.{% endblock %} +{% block subnav_nav_items %} +
    Support
    +
    Lists/Chat
    +
    Issues
    +
    Contributing
    +
    Code of Conduct
    +
    Version Control
    +{% endblock %} diff --git a/themes/solr/templates/mcp/downloads.html b/themes/solr/templates/mcp/downloads.html new file mode 100644 index 000000000..a093066e9 --- /dev/null +++ b/themes/solr/templates/mcp/downloads.html @@ -0,0 +1,20 @@ +{% extends "mcp/page.html" %} + +{% block content_inner %} +
    + + +

    {{ page.title }} + +

    + {{ page.content }} +

    This project has not made any official releases yet. See the README for instructions on building from source.

    +
    +{% endblock content_inner %} diff --git a/themes/solr/templates/mcp/features.html b/themes/solr/templates/mcp/features.html new file mode 100644 index 000000000..f6950d4a4 --- /dev/null +++ b/themes/solr/templates/mcp/features.html @@ -0,0 +1,194 @@ +{% extends "mcp/fullwidth.html" %} + +{% block fullwidth_title %}

    Features

    {% endblock %} + +{% block hero_header_inner %} +
    +
    + Apache Solr MCP Server {{ SOLR_MCP_LATEST_RELEASE }} +
    +

    Powerful MCP Tools for Solr

    +

    + 9 tools and 2 resources that let AI assistants search, index, and manage your Solr collections through natural language. +

    +
    +
    +{% endblock %} + +{% block content_inner %} + +
    +
    +
    +
    MCP Tools
    +

    Tool Reference

    +

    Each tool is callable by any MCP-compatible AI client. The AI translates natural language into the right tool calls automatically.

    +
    +
    + +
    +
    + + + + + + + + + + +
    ToolDescription
    searchFull-text search with filtering, faceting, sorting, and pagination. Accepts query strings, filter queries, facet fields, sort clauses, start offset, and row count.
    + +

    Indexing

    + + + + + + + + + + + + + + + + +
    ToolDescription
    index-json-documentsIndex documents from a JSON array string. Handles batch processing (1,000 per batch), field name sanitization, and automatic commits.
    index-csv-documentsIndex documents from a CSV string. First row is used as headers. Same batch processing and field normalization.
    index-xml-documentsIndex documents from a Solr XML string (<add><doc>...).
    + +

    Collections

    + + + + + + + + + + + + + + + + + + + + +
    ToolDescription
    list-collectionsList all available Solr collections in the cluster.
    get-collection-statsComprehensive metrics: index stats, query performance, cache hit ratios, handler throughput.
    check-healthHealth check returning status, document count, and responsiveness.
    create-collectionCreate a new collection with configurable shards, replicas, and configset. Defaults: _default configset, 1 shard, 1 replica.
    + +

    Schema

    + + + + + + + + +
    ToolDescription
    get-schemaRetrieve the complete schema definition: field definitions, field types, dynamic fields, copy fields, unique key, and schema attributes.
    + +
    +
    +
    + +
    +
    +
    +
    MCP Resources
    +

    Read-Only Data

    +

    MCP Resources provide data that clients can access directly without calling a tool. The schema resource supports autocompletion for collection names.

    +
    +
    + +
    +
    + + + + + + + + + + + + +
    Resource URIDescription
    solr://collectionsList of all Solr collections available in the cluster.
    solr://{collection}/schemaSchema definition for a specific collection. Supports autocompletion—MCP clients can query for available collection names.
    +
    +
    +
    + +
    +
    +
    +
    Platform
    +

    Enterprise-Ready Infrastructure

    +
    +
    +
    +
      +
    • +
      +
      +
      +

      STDIO & HTTP Transports

      +

      STDIO for local AI clients (Claude Desktop). HTTP for remote access, multi-client, and MCP Inspector.

      +
      +
      +
    • +
    • +
      +
      +
      +

      OAuth2 Security

      +

      JWT validation with Auth0, Keycloak, or any OAuth2/OIDC provider. Setup guide →

      +
      +
      +
    • +
    • +
      +
      +
      +

      Observability

      +

      OpenTelemetry traces, Prometheus metrics, structured logs via LGTM stack. Learn more →

      +
      +
      +
    • +
    +
    +
    + +
    +
    +
    +
    Configuration
    +

    Environment Variables

    +
    +
    + +
    +
    + + + + + + + + + + +
    VariableDescriptionDefault
    SOLR_URLSolr base URLhttp://localhost:8983/solr/
    PROFILESTransport mode: stdio or httpstdio
    SECURITY_ENABLEDEnable OAuth2 authentication (HTTP only)false
    OAUTH2_ISSUER_URIOAuth2 issuer URL (Auth0, Keycloak, Okta)
    OTEL_SAMPLING_PROBABILITYTracing sampling rate (0.0–1.0)1.0
    OTEL_TRACES_URLOTLP collector endpointhttp://localhost:4317
    +
    +
    +
    + +{{ super() }} +{% endblock content_inner %} diff --git a/themes/solr/templates/mcp/fullwidth.html b/themes/solr/templates/mcp/fullwidth.html new file mode 100644 index 000000000..e326919d4 --- /dev/null +++ b/themes/solr/templates/mcp/fullwidth.html @@ -0,0 +1,24 @@ +{% extends "mcp/base.html" %} + +{% block hero_header %} +
    +
    + {% block hero_header_inner %} +
    +
    + Apache Solr MCP Server {{ SOLR_MCP_LATEST_RELEASE }} +
    +

    + The Apache Solr MCP Server gives your LLM super powers in managing Solr clusters. +

    + +
    +
    + {% endblock hero_header_inner %} +
    +
    +{% endblock hero_header %} + +{% block content %} +{% block content_inner %}{{ page.content }}{% endblock %} +{% endblock %} diff --git a/themes/solr/templates/mcp/index.html b/themes/solr/templates/mcp/index.html new file mode 100644 index 000000000..d9ce9233a --- /dev/null +++ b/themes/solr/templates/mcp/index.html @@ -0,0 +1,182 @@ +{% extends "mcp/fullwidth.html" %} + +{% block bodyclass %}homepage{% endblock %} + +{% block solr_security_warning %} +{% set latest_sec_articles = (articles | selectattr("category.name", "eq", "solr/security") | list)[:1] %} +{% if (latest_sec_articles | length) > 0 %} +{% set latest_sec_date = latest_sec_articles[0].date | strftime("%Y-%m-%d") %} +
    + +
    +{% endif %} +{% endblock %} + +{% block content_inner %} +
    + +
    +
    +
    +
    + Apache Solr MCP Server +
    +

    Give AI Assistants Solr Superpowers

    +

    + A standards-compliant Model Context Protocol server that brings powerful search, indexing, and collection management capabilities to Claude and other LLM assistants. Built with Spring AI, backed by SolrJ, and ready to deploy anywhere. +

    +
    + Get Started on GitHub +
    +
    +
    +
    + +
    +
    +
    +
    + Why Use Solr MCP Server? +
    +

    Empower Your AI with Enterprise Search

    +

    + Integrate Apache Solr directly into your AI workflows. Execute complex searches, manage indexes, and analyze your data—all through natural language with an AI assistant. +

    +
    +
    +
    +
      +
    • +
      +
      +
      +

      Powerful Search

      +
      +

      Complex queries, filtering, faceting, and pagination through a natural language interface

      +
      +
    • +
    • +
      +
      +
      +

      Flexible Indexing

      +
      +

      Index documents in JSON, CSV, or XML formats with automatic field name normalization

      +
      +
    • +
    • +
      +
      +
      +

      Standards-Based

      +
      +

      Implements the Model Context Protocol specification for seamless AI integration

      +
      +
    • +
    • +
      +
      +
      +

      Multi-Collection

      +
      +

      Manage and query multiple Solr collections and schemas through a unified interface

      +
      +
    • +
    • +
      +
      +
      +

      Easy Deployment

      +
      +

      Deploy as a Docker container, Spring Boot application, or via HTTP/STDIO transports

      +
      +
    • +
    • +
      +
      +
      +

      Enterprise Ready

      +
      +

      Built on proven technologies with comprehensive error handling and logging

      +
      +
    • +
    +
    +
    + +
    +
    +
    +
    + Next Steps +
    +

    Explore the Solr MCP Server

    +
    +
    + +
    + +
    +
    +
    +

    + The Apache Software Foundation +

    +

    + The Apache Software Foundation provides support for the Apache community of open-source software projects. The Apache projects are defined by collaborative consensus based processes, an open, pragmatic software license and a desire to create high quality software that leads the way in its field. Apache Lucene, Apache Solr, Apache PyLucene, Apache Open Relevance Project and their respective logos are trademarks of The Apache Software Foundation. All other marks mentioned may be trademarks or registered trademarks of their respective owners. +

    +
    +

    + +

    +
    +
    +
    +{% endblock content_inner %} diff --git a/themes/solr/templates/mcp/observability.html b/themes/solr/templates/mcp/observability.html new file mode 100644 index 000000000..b25c07628 --- /dev/null +++ b/themes/solr/templates/mcp/observability.html @@ -0,0 +1,11 @@ +{% extends "mcp/subnav.html" %} + +{% block subnav_title %}Observability{% endblock %} +{% block subnav_subtitle %}Traces, metrics, and logs for the Solr MCP Server via the LGTM stack.{% endblock %} +{% block subnav_nav_items %} +
    Overview
    +
    Setup
    +
    Grafana
    +
    Actuator
    +
    Production
    +{% endblock %} diff --git a/themes/solr/templates/mcp/page.html b/themes/solr/templates/mcp/page.html new file mode 100644 index 000000000..845fadbb9 --- /dev/null +++ b/themes/solr/templates/mcp/page.html @@ -0,0 +1,11 @@ +{% extends "mcp/base.html" %} + +{% block content %} +
    + {% block subnav %} + {% endblock %} +
    + {% block content_inner %}{{ page.content }}{% endblock %} +
    +
    +{% endblock %} diff --git a/themes/solr/templates/mcp/quick-start.html b/themes/solr/templates/mcp/quick-start.html new file mode 100644 index 000000000..3b6e1ab77 --- /dev/null +++ b/themes/solr/templates/mcp/quick-start.html @@ -0,0 +1,10 @@ +{% extends "mcp/subnav.html" %} + +{% block subnav_title %}Quick Start{% endblock %} +{% block subnav_subtitle %}Get from zero to a working AI + Solr integration in under 2 minutes.{% endblock %} +{% block subnav_nav_items %} +
    Prerequisites
    +
    Start Solr
    +
    Configure Client
    +
    Try It
    +{% endblock %} diff --git a/themes/solr/templates/mcp/resources.html b/themes/solr/templates/mcp/resources.html new file mode 100644 index 000000000..6b71a8ff8 --- /dev/null +++ b/themes/solr/templates/mcp/resources.html @@ -0,0 +1,9 @@ +{% extends "mcp/subnav.html" %} + +{% block subnav_title %}Resources{% endblock %} +{% block subnav_subtitle %}Documentation, guides, and references for the Solr MCP Server.{% endblock %} +{% block subnav_nav_items %} +
    Guides
    +
    Documentation
    +
    References
    +{% endblock %} diff --git a/themes/solr/templates/mcp/security.html b/themes/solr/templates/mcp/security.html new file mode 100644 index 000000000..00f5e9dae --- /dev/null +++ b/themes/solr/templates/mcp/security.html @@ -0,0 +1,10 @@ +{% extends "mcp/subnav.html" %} + +{% block subnav_title %}Security{% endblock %} +{% block subnav_subtitle %}OAuth2 authentication for the Solr MCP Server in HTTP mode.{% endblock %} +{% block subnav_nav_items %} +
    Overview
    +
    Auth0
    +
    Keycloak
    +
    How It Works
    +{% endblock %} diff --git a/themes/solr/templates/mcp/subnav.html b/themes/solr/templates/mcp/subnav.html new file mode 100644 index 000000000..76e81656f --- /dev/null +++ b/themes/solr/templates/mcp/subnav.html @@ -0,0 +1,20 @@ +{% extends "mcp/page.html" %} + +{% block subnav %} +
    +
    +

    {% block subnav_title %}{% endblock %}
    + {% block subnav_subtitle %}{% endblock %}

    +
    +
    + +{% endblock %}