From 37c8e64ebc1b922aa1b50b066bff3e1be0b8b582 Mon Sep 17 00:00:00 2001 From: adityamparikh Date: Fri, 27 Mar 2026 22:33:17 -0400 Subject: [PATCH 1/2] Add Solr MCP Server tutorial to reference guide Adds a comprehensive user guide for the Solr MCP Server covering quick start, MCP client integration (Claude Desktop, Claude Code, VS Code, Cursor, JetBrains), STDIO and HTTP transport modes, OAuth2 security with Auth0 and Keycloak, observability with the LGTM stack, building from source, and debugging with MCP Inspector. Signed-off-by: adityamparikh Co-Authored-By: Claude Opus 4.6 Signed-off-by: adityamparikh --- .../getting-started/getting-started-nav.adoc | 1 + .../pages/tutorial-solr-mcp.adoc | 1392 +++++++++++++++++ 2 files changed, 1393 insertions(+) create mode 100644 solr/solr-ref-guide/modules/getting-started/pages/tutorial-solr-mcp.adoc diff --git a/solr/solr-ref-guide/modules/getting-started/getting-started-nav.adoc b/solr/solr-ref-guide/modules/getting-started/getting-started-nav.adoc index 095f679f93b6..03436f75d2e2 100644 --- a/solr/solr-ref-guide/modules/getting-started/getting-started-nav.adoc +++ b/solr/solr-ref-guide/modules/getting-started/getting-started-nav.adoc @@ -35,6 +35,7 @@ ** xref:tutorial-solrcloud.adoc[] ** xref:tutorial-opennlp.adoc[] ** xref:tutorial-aws.adoc[] +** xref:tutorial-solr-mcp.adoc[] * xref:solr-admin-ui.adoc[] * xref:about-this-guide.adoc[] diff --git a/solr/solr-ref-guide/modules/getting-started/pages/tutorial-solr-mcp.adoc b/solr/solr-ref-guide/modules/getting-started/pages/tutorial-solr-mcp.adoc new file mode 100644 index 000000000000..cae763711550 --- /dev/null +++ b/solr/solr-ref-guide/modules/getting-started/pages/tutorial-solr-mcp.adoc @@ -0,0 +1,1392 @@ += Solr MCP Server -- User Guide +:toc: left +:toclevels: 3 +:sectnums: +:sectnumlevels: 3 +:experimental: +:icons: font +:source-highlighter: rouge +:imagesdir: ../images +// 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. + +Search, index, and manage https://solr.apache.org/[Apache Solr] collections using *natural language* -- no need to hand-craft Solr queries, build filter expressions, or memorize the admin API. + +Instead of writing: + +[,text] +---- +q=title:"star wars" AND genre_s:"sci-fi"&fq=year_i:[2000 TO *]&facet=true&facet.field=genre_s&sort=score desc&rows=10 +---- + +Just ask your AI assistant: + +> _"Find sci-fi movies with 'star wars' in the title released after 2000, show me the genre breakdown, and sort by relevance."_ + +The Solr MCP Server makes this possible by exposing Solr operations -- searching, indexing, collection management, and schema introspection -- as tools that any MCP-compatible AI client can invoke. + +== Quick Start + +Get from zero to a working Claude + Solr integration in under 2 minutes. + +=== Prerequisites + +* https://docs.docker.com/get-docker/[Docker] and Docker Compose +* An MCP client (e.g., https://claude.ai/download[Claude Desktop]) + +=== Step 1: Start Solr with Sample Data + +[,console] +---- +$ git clone https://github.com/apache/solr-mcp.git +$ cd solr-mcp +$ docker compose up -d +---- + +This starts Solr in SolrCloud mode 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/. + +=== Step 2: 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": "docker", + "args": ["run", "-i", "--rm", + "-e", "SOLR_URL=http://host.docker.internal:8983/solr/", + "ghcr.io/apache/solr-mcp:latest"] + } + } +} +---- + +Restart Claude Desktop. + +=== Step 3: Try It Out + +Ask Claude: + +* _"Search the films collection for movies directed by Steven Spielberg"_ +* _"What collections are available in Solr?"_ +* _"Show me the schema for the films collection"_ +* _"Index this JSON into the books collection: [{"id": "1", "title": "The Great Gatsby", "author": "F. Scott Fitzgerald"}]"_ + +image::claude-stdio.png[Claude Desktop STDIO] + +== Overview + +=== What is MCP? + +The https://spec.modelcontextprotocol.io/[Model Context Protocol (MCP)] is an open standard that lets AI assistants -- like Claude, GitHub Copilot, and Cursor -- call external *tools* and read external *resources* in a structured way. +Think of it as a USB-C port for AI: one protocol, many capabilities. + +=== Why MCP for Solr? + +Apache Solr is a powerful search platform, but using it effectively requires knowledge of its query syntax, filter queries, facet parameters, schema design, and admin APIs. +This creates a barrier for users who know _what_ they want to find but not _how_ to express it in Solr's language. + +MCP removes that barrier. +With the Solr MCP Server, an AI assistant can: + +* *Search* -- translate natural language questions into optimized Solr queries with filters, facets, sorting, and pagination +* *Index* -- accept data in any format (JSON, CSV, XML) and handle batch processing, field name sanitization, and commits +* *Manage* -- create collections, check health, inspect schemas, and view statistics -- all through conversation +* *Learn the schema* -- read collection schemas to craft better queries without the user needing to know field names or types + +The user focuses on intent; the AI handles the Solr details. + +=== Architecture + +.... +┌──────────────────────┐ ┌──────────────────────┐ ┌──────────────────┐ +│ │ │ │ │ │ +│ MCP Clients │ │ Solr MCP Server │ │ Apache Solr │ +│ │ │ │ │ │ +│ · Claude Desktop │◄─────►│ Tools: │◄─────►│ Collections │ +│ · Claude Code │ STDIO │ search │ SolrJ │ Documents │ +│ · GitHub Copilot │ or │ index-json/csv/xml │ │ Schema │ +│ · Cursor │ HTTP │ list-collections │ │ │ +│ · JetBrains AI │ │ get-collection-stats│ │ │ +│ · MCP Inspector │ │ check-health │ │ │ +│ │ │ create-collection │ │ │ +│ │ │ get-schema │ │ │ +└──────────────────────┘ └──────────────────────┘ └──────────────────┘ + │ + │ OTLP (optional) + ▼ + ┌──────────────────────┐ + │ LGTM Stack │ + │ Grafana · Tempo │ + │ Loki · Mimir │ + └──────────────────────┘ +.... + +=== Transport Modes + +[cols="1,2,2",options="header"] +|=== +| |STDIO |HTTP +|*How it works* |Communicates via stdin/stdout |REST endpoints on port 8080 +|*Best for* |Claude Desktop, local AI clients |MCP Inspector, remote access, multi-client +|*Security* |OS-level process isolation |OAuth2 (Auth0, Keycloak, Okta) +|*Observability* |Not available |OpenTelemetry, Prometheus, Grafana +|*Network exposure* |None |Requires firewall / TLS in production +|=== + +== Features + +=== Collections + +Manage and monitor your Solr collections. + +[cols="1,3",options="header"] +|=== +|Tool |Description +|`list-collections` |List all available Solr collections +|`get-collection-stats` |Get comprehensive metrics: index stats, query performance, cache hit ratios, handler throughput +|`check-health` |Health check -- returns status, document count, and responsiveness +|`create-collection` |Create a new collection with configurable shards, replicas, and configset (defaults: `_default`, 1 shard, 1 replica) +|=== + +*Example prompts:* + +* "List all Solr collections" +* "How many documents are in the films collection?" +* "Is the books collection healthy?" +* "Create a new collection called products" + +=== Indexing + +Index documents in three formats. +The server handles batch processing, field name sanitization, and automatic commits. + +[cols="1,3",options="header"] +|=== +|Tool |Description +|`index-json-documents` |Index documents from a JSON array string +|`index-csv-documents` |Index documents from a CSV string (first row = headers) +|`index-xml-documents` |Index documents from an XML string +|=== + +==== JSON Example + +[,json] +---- +[ + {"id": "1", "title": "The Great Gatsby", "author": "F. Scott Fitzgerald", "year_i": 1925}, + {"id": "2", "title": "To Kill a Mockingbird", "author": "Harper Lee", "year_i": 1960} +] +---- + +==== CSV Example + +[,csv] +---- +id,title,author,year_i +1,The Great Gatsby,F. Scott Fitzgerald,1925 +2,To Kill a Mockingbird,Harper Lee,1960 +---- + +==== XML Example + +[,xml] +---- + + + 1 + The Great Gatsby + F. Scott Fitzgerald + + +---- + +*Batch processing:* Documents are indexed in batches of 1,000 with per-document retry fallback on errors. +Field names are automatically sanitized for Solr compatibility. + +=== Searching + +Full-text search with filtering, faceting, sorting, and pagination. + +[cols="1,3",options="header"] +|=== +|Tool |Description +|`search` |Search a Solr collection with query, filters, facets, sorting, and pagination +|=== + +==== Parameters + +[cols="1,3,1",options="header"] +|=== +|Parameter |Description |Required +|`collection` |Solr collection to query |Yes +|`query` |Solr query string (`q` parameter). Defaults to `\*:*` |No +|`filterQueries` |Filter queries (`fq` parameter) |No +|`facetFields` |Fields to facet on |No +|`sortClauses` |Sort clauses (list of `\{item, order}` maps) |No +|`start` |Pagination offset |No +|`rows` |Number of results to return |No +|=== + +==== Dynamic Field Suffixes + +Solr's schemaless mode uses field name suffixes to indicate types: + +[cols="1,2,2",options="header"] +|=== +|Suffix |Type |Example +|`_s` |String (exact match) |`genre_s:"fantasy"` +|`_t` |Text (tokenized) |`description_t:"adventure"` +|`_i` |Integer |`year_i:1925` +|`_l` |Long |`population_l:1000000` +|`_f` |Float |`rating_f:4.5` +|`_d` |Double |`price_d:29.99` +|`_dt` |Date |`published_dt:"2024-01-01T00:00:00Z"` +|`_b` |Boolean |`inStock_b:true` +|=== + +*Example prompts:* + +* "Search films for movies with 'war' in the title" +* "Find all fantasy books sorted by price ascending" +* "Search films and facet by genre_s" +* "Show me the top 5 most recent films" + +==== Response Format + +[,json] +---- +{ + "numFound": 42, + "start": 0, + "maxScore": 1.5, + "documents": [ + {"id": "1", "title": "Star Wars", "genre_s": "sci-fi"} + ], + "facets": { + "genre_s": {"sci-fi": 12, "drama": 8, "comedy": 6} + } +} +---- + +=== Schema + +Retrieve the complete schema definition for any collection. + +[cols="1,3",options="header"] +|=== +|Tool |Description +|`get-schema` |Retrieve field definitions, field types, dynamic fields, copy fields, unique key, and schema attributes +|=== + +=== MCP Resources + +MCP Resources provide read-only data that clients can access directly (without calling a tool). + +[cols="2,3",options="header"] +|=== +|Resource URI |Description +|`solr://collections` |List of all Solr collections in the cluster +|`solr://\{collection}/schema` |Schema definition for a specific collection (supports autocompletion) +|=== + +The `solr://\{collection}/schema` resource supports *autocompletion* -- MCP clients can query for available collection names when building the URI. + +image::mcp-inspector-list-resources.png[MCP Inspector Resources] + +image::mcp-inspector-resource-completion.png[MCP Inspector Resource Autocompletion] + +== Usage + +=== STDIO Mode (Default) + +STDIO mode communicates via standard input/output streams. +This is the recommended mode for local AI client integrations like Claude Desktop. + +==== Docker (Recommended) + +[,console] +---- +$ docker run -i --rm \ + -e SOLR_URL=http://host.docker.internal:8983/solr/ \ + ghcr.io/apache/solr-mcp:latest +---- + +*Linux users* -- add `--add-host=host.docker.internal:host-gateway` to connect to Solr on the host machine: + +[,console] +---- +$ docker run -i --rm \ + --add-host=host.docker.internal:host-gateway \ + -e SOLR_URL=http://host.docker.internal:8983/solr/ \ + ghcr.io/apache/solr-mcp:latest +---- + +==== JAR (Build from Source) + +[,console] +---- +$ ./gradlew build +$ java -jar build/libs/solr-mcp-1.0.0-SNAPSHOT.jar +---- + +==== Gradle (Development) + +[,console] +---- +$ ./gradlew bootRun +---- + +[[http-mode]] +=== HTTP Mode + +HTTP mode starts a web server on port 8080 with REST endpoints. +Use this for MCP Inspector, remote access, or multi-client scenarios. + +==== Docker + +[,console] +---- +$ docker run -p 8080:8080 --rm \ + -e PROFILES=http \ + -e SOLR_URL=http://host.docker.internal:8983/solr/ \ + ghcr.io/apache/solr-mcp:latest +---- + +==== JAR (Build from Source) + +[,console] +---- +$ ./gradlew build +$ PROFILES=http java -jar build/libs/solr-mcp-1.0.0-SNAPSHOT.jar +---- + +==== Gradle (Development) + +[,console] +---- +$ PROFILES=http ./gradlew bootRun +---- + +The MCP endpoint is available at `http://localhost:8080/mcp`. + +Verify the server is running: + +[,console] +---- +$ curl http://localhost:8080/actuator/health +---- + +=== Configuration Reference + +[cols="2,3,2",options="header"] +|=== +|Variable |Description |Default +|`SOLR_URL` |Solr base URL |`http://localhost:8983/solr/` +|`PROFILES` |Transport mode: `stdio` or `http` |`stdio` +|`SECURITY_ENABLED` |Enable OAuth2 authentication (HTTP only) |`false` +|`OAUTH2_ISSUER_URI` |OAuth2 issuer URL (Auth0, Keycloak, Okta) |-- +|`OTEL_SAMPLING_PROBABILITY` |Tracing sampling rate (0.0--1.0) |`1.0` +|`OTEL_TRACES_URL` |OTLP collector endpoint |`http://localhost:4317` +|=== + +[[mcp-client-integration]] +== MCP Client Integration + +Configure the Solr MCP Server with your preferred AI client. +Each section below shows the configuration for STDIO, HTTP, and *secured HTTP* (OAuth2) modes. + +NOTE: *Secured HTTP prerequisite:* Before connecting clients to a secured server, start the server with OAuth2 enabled as described in <>. +You'll need your OAuth2 provider's authorization URL, token URL, and client credentials. + +[[claude-desktop]] +=== Claude Desktop + +Edit your Claude Desktop configuration file: + +* *macOS*: `~/Library/Application Support/Claude/claude_desktop_config.json` +* *Windows*: `%APPDATA%\Claude\claude_desktop_config.json` + +==== STDIO Mode with Docker + +[,json] +---- +{ + "mcpServers": { + "solr-mcp": { + "command": "docker", + "args": ["run", "-i", "--rm", + "-e", "SOLR_URL=http://host.docker.internal:8983/solr/", + "ghcr.io/apache/solr-mcp:latest"] + } + } +} +---- + +==== STDIO Mode with 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/" + } + } + } +} +---- + +==== HTTP Mode (via mcp-remote) + +First start the server in HTTP mode (see <>), then configure Claude Desktop to connect via `mcp-remote`: + +[,json] +---- +{ + "mcpServers": { + "solr-mcp": { + "command": "npx", + "args": ["mcp-remote", "http://localhost:8080/mcp"] + } + } +} +---- + +==== Secured HTTP Mode (OAuth2 via mcp-remote) + +When OAuth2 is enabled on the server, `mcp-remote` handles the full OAuth2 authorization flow automatically. +It discovers the authorization server from the MCP server's metadata and opens a browser for user consent. + +[,json] +---- +{ + "mcpServers": { + "solr-mcp": { + "command": "npx", + "args": [ + "mcp-remote", + "http://localhost:8080/mcp", + "--allow-http" + ] + } + } +} +---- + +[NOTE] +==== +*How it works:* When `mcp-remote` connects to a secured server, the server responds with an OAuth2 challenge. `mcp-remote` then: + +. Discovers the authorization server from the server's `/.well-known/oauth-authorization-server` endpoint +. Opens your browser for login/consent +. Receives the authorization code via a local callback (default: `http://localhost:3334/oauth/callback`) +. Exchanges it for an access token and attaches it to all subsequent MCP requests + +The `--allow-http` flag is needed when the MCP server is running on `http://` (development). +In production with HTTPS, omit this flag. +==== + +Restart Claude Desktop after any configuration change. + +image::claude-stdio.png[Claude Desktop STDIO] + +[[claude-code]] +=== Claude Code + +==== STDIO Mode -- CLI + +[,console] +---- +$ # Docker +$ claude mcp add --transport stdio solr-mcp -- \ + docker run -i --rm -e SOLR_URL=http://host.docker.internal:8983/solr/ \ + ghcr.io/apache/solr-mcp:latest + +$ # 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 +---- + +==== STDIO Mode -- `.mcp.json` + +Add to your project root: + +[,json] +---- +{ + "mcpServers": { + "solr-mcp": { + "type": "stdio", + "command": "docker", + "args": ["run", "-i", "--rm", + "-e", "SOLR_URL=http://host.docker.internal:8983/solr/", + "ghcr.io/apache/solr-mcp:latest"] + } + } +} +---- + +==== HTTP Mode -- CLI + +Start the server first, then: + +[,console] +---- +$ claude mcp add --transport http solr-mcp http://localhost:8080/mcp +---- + +==== HTTP Mode -- `.mcp.json` + +[,json] +---- +{ + "mcpServers": { + "solr-mcp": { + "type": "http", + "url": "http://localhost:8080/mcp" + } + } +} +---- + +==== Secured HTTP Mode (OAuth2) + +Claude Code supports OAuth2-secured MCP servers. +When connecting to a secured server, Claude Code handles the OAuth2 flow automatically -- it opens a browser for authentication and manages token lifecycle. + +*CLI:* + +[,console] +---- +$ claude mcp add --transport http solr-mcp http://localhost:8080/mcp +---- + +*`.mcp.json`:* + +[,json] +---- +{ + "mcpServers": { + "solr-mcp": { + "type": "http", + "url": "http://localhost:8080/mcp" + } + } +} +---- + +TIP: The configuration is the same as unsecured HTTP -- Claude Code detects the OAuth2 challenge from the server and initiates the authorization flow automatically. + +[[github-copilot-vs-code]] +=== GitHub Copilot / VS Code + +VS Code supports MCP servers through the built-in MCP support (available in VS Code 1.99+). + +==== Workspace Configuration (`.vscode/mcp.json`) + +Create `.vscode/mcp.json` in your project root: + +*STDIO Mode:* + +[,json] +---- +{ + "servers": { + "solr-mcp": { + "type": "stdio", + "command": "docker", + "args": ["run", "-i", "--rm", + "-e", "SOLR_URL=http://host.docker.internal:8983/solr/", + "ghcr.io/apache/solr-mcp:latest"] + } + } +} +---- + +*HTTP Mode (unsecured and secured):* + +[,json] +---- +{ + "servers": { + "solr-mcp": { + "type": "sse", + "url": "http://localhost:8080/mcp" + } + } +} +---- + +TIP: The configuration is the same for secured and unsecured HTTP. +VS Code handles the MCP OAuth2 flow automatically -- when connecting to a secured server, a browser window opens for authentication and the token is managed transparently. + +==== User Settings (`settings.json`) + +Open VS Code Settings (JSON) and add: + +[,json] +---- +{ + "mcp": { + "servers": { + "solr-mcp": { + "type": "stdio", + "command": "docker", + "args": ["run", "-i", "--rm", + "-e", "SOLR_URL=http://host.docker.internal:8983/solr/", + "ghcr.io/apache/solr-mcp:latest"] + } + } + } +} +---- + +After adding the configuration, the Solr MCP tools will be available to GitHub Copilot Chat in Agent mode. + +NOTE: MCP support in VS Code and Copilot is evolving. Check the https://code.visualstudio.com/docs/copilot/chat/mcp-servers[VS Code MCP documentation] for the latest configuration format. + +[[cursor]] +=== Cursor + +Cursor supports MCP servers natively. +Configure via Cursor Settings or a project-level config file. + +==== Cursor Settings UI + +. Open *Cursor Settings* (gear icon or kbd:[Cmd+,] / kbd:[Ctrl+,]) +. Navigate to *Features* > *MCP Servers* +. Click *Add New MCP Server* +. Enter: +** *Name*: `solr-mcp` +** *Type*: `command` (for STDIO) or `sse` (for HTTP) +** *Command*: `docker run -i --rm -e SOLR_URL=http://host.docker.internal:8983/solr/ ghcr.io/apache/solr-mcp:latest` + +==== Project Configuration (`.cursor/mcp.json`) + +Create `.cursor/mcp.json` in your project root: + +*STDIO Mode:* + +[,json] +---- +{ + "mcpServers": { + "solr-mcp": { + "command": "docker", + "args": ["run", "-i", "--rm", + "-e", "SOLR_URL=http://host.docker.internal:8983/solr/", + "ghcr.io/apache/solr-mcp:latest"] + } + } +} +---- + +*HTTP Mode (unsecured and secured):* + +[,json] +---- +{ + "mcpServers": { + "solr-mcp": { + "url": "http://localhost:8080/mcp" + } + } +} +---- + +TIP: The configuration is the same for secured and unsecured HTTP. +Cursor handles the MCP OAuth2 authorization flow automatically -- it opens a browser for authentication and manages access tokens transparently. + +NOTE: MCP support in Cursor is evolving. Check the https://docs.cursor.com/context/model-context-protocol[Cursor MCP documentation] for the latest configuration format. + +[[jetbrains-ides]] +=== JetBrains IDEs + +JetBrains IDEs (IntelliJ IDEA, WebStorm, PyCharm, etc.) support MCP servers through the AI Assistant plugin. + +==== IDE Settings + +. Open *Settings* (kbd:[Cmd+,] / kbd:[Ctrl+Alt+S]) +. Navigate to *Tools* > *AI Assistant* > *MCP Servers* +. Click *Add* (`+`) +. Configure: +** *Name*: `solr-mcp` +** *Transport*: `STDIO` +** *Command*: `docker` +** *Arguments*: `run -i --rm -e SOLR_URL=http://host.docker.internal:8983/solr/ ghcr.io/apache/solr-mcp:latest` + +For HTTP mode, select *SSE* transport and enter `http://localhost:8080/mcp` as the URL. + +==== Project Configuration + +Create a `.junie/mcp.json` file in your project root: + +*STDIO Mode:* + +[,json] +---- +{ + "mcpServers": { + "solr-mcp": { + "command": "docker", + "args": ["run", "-i", "--rm", + "-e", "SOLR_URL=http://host.docker.internal:8983/solr/", + "ghcr.io/apache/solr-mcp:latest"] + } + } +} +---- + +*HTTP Mode (unsecured and secured):* + +[,json] +---- +{ + "mcpServers": { + "solr-mcp": { + "url": "http://localhost:8080/mcp" + } + } +} +---- + +TIP: The configuration is the same for secured and unsecured HTTP. +JetBrains IDEs handle the MCP OAuth2 authorization flow automatically -- the IDE opens a browser for authentication and manages the token lifecycle. + +NOTE: MCP support in JetBrains IDEs requires the AI Assistant plugin. Check the https://www.jetbrains.com/help/idea/model-context-protocol.html[JetBrains MCP documentation] for the latest configuration format. + +=== How MCP OAuth2 Works with Clients + +When a client connects to a secured Solr MCP Server, the following flow occurs: + +.... +MCP Client Solr MCP Server OAuth2 Provider + │ │ (Auth0 / Keycloak) + │ │ │ + │── Connect to /mcp ──────────►│ │ + │◄── 401 + OAuth2 metadata ────│ │ + │ │ │ + │── Discover auth server ─────────────────────────────────► │ + │◄── Authorization endpoint ────────────────────────────── │ + │ │ │ + │── Open browser for login ───────────────────────────────► │ + │◄── Authorization code ────────────────────────────────── │ + │ │ │ + │── Exchange code for token ──────────────────────────────► │ + │◄── Access token (JWT) ────────────────────────────────── │ + │ │ │ + │── MCP request + Bearer ─────►│ │ + │ │── Validate JWT ──────────► │ + │ │◄── Valid ──────────────── │ + │◄── MCP response ─────────────│ │ +.... + +The server exposes its OAuth2 metadata at `/.well-known/oauth-authorization-server`, which the client uses to discover authorization and token endpoints. +Most MCP clients handle this flow transparently -- the URL configuration is the same for both secured and unsecured HTTP servers. + +[[security-http-mode]] +== Security (HTTP Mode) + +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. + +=== Overview + +* *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 + +[,console] +---- +$ export PROFILES=http +$ export SECURITY_ENABLED=true +$ export OAUTH2_ISSUER_URI=https://your-provider.example.com/ +$ ./gradlew bootRun +---- + +Or with Docker: + +[,console] +---- +$ 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/ \ + ghcr.io/apache/solr-mcp:latest +---- + +=== Auth0 + +==== 1. Create Auth0 Application + +. Go to https://manage.auth0.com/[Auth0 Dashboard] > *Applications* > *Create Application* +. Name: `Solr MCP Server` +. Type: *Machine to Machine Applications* +. Note your *Domain*, *Client ID*, and *Client Secret* + +==== 2. Create Auth0 API + +. Navigate to *Applications* > *APIs* > *Create API* +. Name: `Solr MCP API` +. Identifier (audience): `https://solr-mcp-api` +. Signing Algorithm: *RS256* + +==== 3. Configure Callback URLs + +In your application settings, add to *Allowed Callback URLs*: + +[,text] +---- +http://localhost:6274/oauth/callback,http://localhost:3334/oauth/callback,http://localhost:8080/login/oauth2/code/auth0 +---- + +IMPORTANT: Each callback URL serves a different client: + +* `http://localhost:6274/oauth/callback` -- MCP Inspector +* `http://localhost:3334/oauth/callback` -- `mcp-remote` (used by Claude Desktop, VS Code, Cursor, JetBrains for HTTP mode) +* `http://localhost:8080/login/oauth2/code/auth0` -- Direct server OAuth2 code flow + +==== 4. Run the Server + +[,console] +---- +$ export PROFILES=http +$ export SECURITY_ENABLED=true +$ export OAUTH2_ISSUER_URI=https://your-tenant.auth0.com/ +$ ./gradlew bootRun +---- + +==== 5. Get an Access Token + +[,console] +---- +$ 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: + +[,console] +---- +$ ./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 + +[,console] +---- +$ curl -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \ + http://localhost:8080/mcp +---- + +For the full step-by-step guide, see link:../dev-docs/AUTH0_SETUP.md[Auth0 Setup Guide]. + +=== Keycloak + +==== 1. Start Keycloak + +[,console] +---- +$ 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 + +. Create realm: `solr-mcp` +. 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: `*` + +IMPORTANT: Each redirect URI pattern serves a different client: + +* `http://localhost:6274/*` -- MCP Inspector +* `http://localhost:3334/*` -- `mcp-remote` (used by Claude Desktop, VS Code, Cursor, JetBrains for HTTP mode) +* `http://localhost:8080/*` -- Direct server OAuth2 code flow + +==== 3. Create Test User + +. Navigate to *Users* > *Add user* +. Username: `testuser`, Email verified: ON +. Set password in *Credentials* tab + +==== 4. Run the Server + +[,console] +---- +$ export PROFILES=http +$ export SECURITY_ENABLED=true +$ export OAUTH2_ISSUER_URI=http://localhost:8180/realms/solr-mcp +$ ./gradlew bootRun +---- + +==== 5. Get a Token + +[,console] +---- +$ 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" +---- + +==== 6. Call the MCP Server + +[,console] +---- +$ TOKEN=$(curl -s -X POST "http://localhost:8180/realms/solr-mcp/protocol/openid-connect/token" \ + -d "client_id=solr-mcp-client" \ + -d "username=testuser" \ + -d "password=yourpassword" \ + -d "grant_type=password" | jq -r '.access_token') + +$ curl -X POST http://localhost:8080/mcp \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d '{"jsonrpc":"2.0","method":"tools/list","id":1}' +---- + +For the full guide including GitHub identity provider setup, role-based access control, and production deployment, see link:../dev-docs/KEYCLOAK_SETUP.md[Keycloak Setup Guide]. + +[[security-with-mcp-inspector]] +=== Security with MCP Inspector + +When OAuth2 is enabled, configure MCP Inspector with your provider's OAuth settings: + +. Start MCP Inspector: `npx @modelcontextprotocol/inspector` +. Connect to `http://localhost:8080/mcp` +. Configure OAuth: +** *Authorization URL*: Your provider's authorize endpoint +** *Token URL*: Your provider's token endpoint +** *Client ID*: Your application's Client ID +** *Redirect URI*: `http://localhost:6274/oauth/callback` + +image::mcp-inspector-http-oauth-success.png[MCP Inspector OAuth Success] + +image::mcp-inspector-http-oauth-failure.png[MCP Inspector OAuth Failure] + +== Building + +=== Prerequisites + +* Java 25+ (https://adoptium.net/[Eclipse Temurin] recommended) +* Docker (for integration tests and Docker image builds) + +=== Build from Source + +[,console] +---- +$ git clone https://github.com/apache/solr-mcp.git +$ cd solr-mcp + +$ # Full build with tests +$ ./gradlew build + +$ # Build without tests (faster) +$ ./gradlew assemble +---- + +The build produces: + +* `build/libs/solr-mcp-1.0.0-SNAPSHOT.jar` -- executable (fat) JAR + +=== Build Docker Image + +[,console] +---- +$ # Build to local Docker daemon +$ ./gradlew jibDockerBuild + +$ # Verify +$ docker images | grep solr-mcp +---- + +This creates `solr-mcp:1.0.0-SNAPSHOT` with multi-platform support (amd64 + arm64). + +=== Push to Container Registry + +[,console] +---- +$ # Docker Hub +$ docker login +$ ./gradlew jib -Djib.to.image=YOUR_USERNAME/solr-mcp:1.0.0-SNAPSHOT + +$ # GitHub Container Registry +$ echo $GITHUB_TOKEN | docker login ghcr.io -u YOUR_USERNAME --password-stdin +$ ./gradlew jib -Djib.to.image=ghcr.io/YOUR_USERNAME/solr-mcp:1.0.0-SNAPSHOT +---- + +=== Code Formatting + +Formatting is enforced by https://github.com/diffplug/spotless[Spotless] and runs automatically as part of `./gradlew build`: + +[,console] +---- +$ # Check formatting +$ ./gradlew spotlessCheck + +$ # Auto-fix formatting +$ ./gradlew spotlessApply +---- + +== Debugging with MCP Inspector + +The https://github.com/modelcontextprotocol/inspector[MCP 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 + +[,console] +---- +$ npx @modelcontextprotocol/inspector +---- + +This starts the Inspector UI at `http://localhost:6274`. + +=== Connect via HTTP + +. Start the server in HTTP mode: ++ +[,console] +---- +$ PROFILES=http ./gradlew bootRun +---- +. In MCP Inspector, enter: `http://localhost:8080/mcp` +. Click *Connect* + +image::mcp-inspector-http.png[MCP Inspector HTTP] + +=== Connect via STDIO + +. In MCP Inspector, select *STDIO* transport +. Command: `docker` +. Arguments: `run -i --rm -e SOLR_URL=http://host.docker.internal:8983/solr/ ghcr.io/apache/solr-mcp:latest` +. Click *Connect* + +image::mcp-inspector-stdio.png[MCP Inspector STDIO] + +=== Test Tools + +Once connected, you can: + +. *Browse tools* -- See all available MCP tools and their parameter schemas +. *Invoke tools* -- Fill in parameters and execute tools interactively +. *View responses* -- Inspect JSON responses from each tool call +. *Browse resources* -- Access MCP resources like `solr://collections` + +=== Debug with OAuth2 + +If security is enabled, configure the Inspector's OAuth settings before connecting: + +. Click the *OAuth* settings in the Inspector +. Enter your provider's Authorization URL, Token URL, Client ID, and Redirect URI +. Complete the OAuth flow +. The Inspector will include the Bearer token in all subsequent requests + +See <> for provider-specific settings. + +== Observability with LGTM Stack + +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. + +=== What You Get + +[cols="1,1,3",options="header"] +|=== +|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 +|=== + +=== Start the LGTM Stack + +The project's `compose.yaml` includes a Grafana OTEL LGTM all-in-one container: + +[,console] +---- +$ docker compose up -d +---- + +This starts: + +[cols="1,2,3",options="header"] +|=== +|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 + +[,console] +---- +$ 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 +---- + +=== Explore in Grafana + +. Open http://localhost:3000 +. Click *Explore* in the left sidebar + +==== View Traces (Tempo) + +. Select *Tempo* as the data source +. Use TraceQL to search: ++ +---- +{.service.name="solr-mcp"} +---- +. 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) + +. Select *Loki* as the data source +. Use LogQL to search: ++ +---- +{service_name="solr-mcp"} |= "search" +---- +. Logs are automatically correlated with trace IDs -- click a log line to jump to its trace + +==== View Metrics (Prometheus) + +. Select *Prometheus* as the data source +. Example queries: ++ +[,promql] +---- +# 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])) +---- + +=== What Gets Traced + +Every MCP tool invocation creates a trace span: + +* *Search* operations +* *Indexing* operations (JSON, CSV, XML) +* *Collection* operations (list, stats, health, create) +* *Schema* retrieval + +Additionally, all incoming HTTP requests and outgoing Solr calls are automatically traced. + +=== Production Configuration + +For production, reduce the sampling rate and configure the OTLP endpoint for your collector: + +[,console] +---- +$ 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 +---- + +=== Actuator Endpoints + +The following health and metrics endpoints are exposed in HTTP mode: + +[,console] +---- +$ 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 +---- + +== Implementation Details + +This section covers the technology choices behind the Solr MCP Server. +It is primarily useful for contributors and anyone looking to understand the internals. + +=== Spring AI MCP + +The server is built on the https://docs.spring.io/spring-ai/reference/api/mcp/mcp-server-boot.html[Spring AI MCP] framework (Spring Boot 3.5, Spring AI 1.1.4, Java 25+). +Spring AI MCP provides the MCP protocol implementation, tool registration via `@McpTool` annotations, and transport abstraction (STDIO and HTTP). + +The server's MCP tools are plain Spring `@Service` classes. +Each public method annotated with `@McpTool` becomes a callable tool that AI clients can invoke. +Spring AI handles serialization, transport, and protocol compliance. + +OAuth2 security is provided by the https://github.com/spring-ai-community/mcp-security[Spring AI Community MCP Security] library, which adds `McpServerOAuth2Configurer` for JWT validation and OAuth2 authorization server metadata discovery. + +=== Docker Images with Jib + +Docker images are built using https://github.com/GoogleContainerTools/jib[Jib] instead of Spring Boot Buildpacks. + +*Why Jib?* Spring Boot Buildpacks output build logs to stdout during image creation. +Since the MCP STDIO protocol communicates over stdout, these extra log lines corrupt the protocol stream and break STDIO-mode connections. +Jib produces clean images with no stdout pollution, and also provides: + +* Faster builds (no Docker daemon required for registry pushes) +* Reproducible layers (better caching) +* Multi-platform support (amd64 + arm64) + +[,console] +---- +$ # Build to local Docker daemon +$ ./gradlew jibDockerBuild + +$ # Push directly to a registry (no Docker daemon needed) +$ ./gradlew jib -Djib.to.image=ghcr.io/YOUR_USERNAME/solr-mcp:1.0.0-SNAPSHOT +---- + +=== Testing with Testcontainers + +Integration tests use https://www.testcontainers.org/[Testcontainers] to spin up real Solr instances in Docker. +This ensures tests run against actual Solr behavior rather than mocks. + +The Solr version is configurable via system property: + +[,console] +---- +$ ./gradlew test -Dsolr.test.image=solr:9.9-slim # Default +$ ./gradlew test -Dsolr.test.image=solr:9.4-slim # Solr 9.4 +$ ./gradlew test -Dsolr.test.image=solr:8.11-slim # Solr 8.11 +---- + +Tested compatible versions: 8.11, 9.4, 9.9. + +=== Observability Internals + +All service methods are annotated with `@Observed` (Micrometer), which automatically creates trace spans. +Spring Boot auto-instruments: + +* Incoming HTTP requests +* Outgoing HTTP calls (SolrJ) +* Scheduled tasks + +Actuator endpoints (`/actuator/health`, `/actuator/metrics`, `/actuator/prometheus`) are provided by Spring Boot Actuator and exposed in HTTP mode. + +== Contributing + +We welcome contributions! +Here's the quick version: + +. Fork and create a feature branch: `git checkout -b feature/your-feature` +. Make changes, add tests +. Format: `./gradlew spotlessApply` +. Build and test: `./gradlew build` +. Commit using https://www.conventionalcommits.org/[Conventional Commits]: `feat(search): add fuzzy search support` +. Push and open a Pull Request + +For the full contributing guide, development workflows, and architecture details, see: + +* link:../CONTRIBUTING.md[CONTRIBUTING.md] -- Pull request process, commit conventions +* link:../dev-docs/DEVELOPMENT.md[dev-docs/DEVELOPMENT.md] -- Build system, testing, IDE setup +* link:../dev-docs/ARCHITECTURE.md[dev-docs/ARCHITECTURE.md] -- Project structure, design decisions + +== References + +=== MCP Protocol + +* https://spec.modelcontextprotocol.io/[Model Context Protocol Specification] +* https://github.com/modelcontextprotocol[MCP GitHub Organization] +* https://github.com/modelcontextprotocol/inspector[MCP Inspector] + +=== Spring AI MCP + +* https://docs.spring.io/spring-ai/reference/api/mcp/mcp-server-boot.html[Spring AI MCP Server (Spring Boot)] +* https://spring.io/projects/spring-ai[Spring AI MCP Project] +* https://spring.io/blog/2025/04/02/mcp-server-oauth2/[Spring AI MCP OAuth2 Blog Post] + +=== MCP Security + +* https://github.com/spring-ai-community/mcp-security[Spring AI Community MCP Security] +* https://docs.spring.io/spring-security/reference/servlet/oauth2/resource-server/jwt.html[Spring Security OAuth2 Resource Server] + +=== Apache Solr + +* https://solr.apache.org/guide/[Apache Solr Documentation] +* https://solr.apache.org/guide/solr/latest/deployment-guide/solrj.html[SolrJ Client Library] + +=== Auth Providers + +* https://auth0.com/docs[Auth0 Documentation] +* https://auth0.com/docs/get-started/authentication-and-authorization-flow/client-credentials-flow[Auth0 Client Credentials Flow] +* https://www.keycloak.org/documentation[Keycloak Documentation] + +=== Tools and Libraries + +* https://github.com/GoogleContainerTools/jib[Jib (Docker image builder)] +* https://www.testcontainers.org/[Testcontainers] +* https://opentelemetry.io/[OpenTelemetry] +* https://github.com/grafana/docker-otel-lgtm[Grafana LGTM Stack] + +''' + +_Built with https://spring.io/projects/spring-ai[Spring AI MCP] and https://solr.apache.org/[Apache Solr]. +Licensed under https://www.apache.org/licenses/LICENSE-2.0[Apache License 2.0]._ From 6a7bf85792eff27622b1684aca0cbd502782a004 Mon Sep 17 00:00:00 2001 From: adityamparikh Date: Fri, 24 Apr 2026 13:28:18 -0400 Subject: [PATCH 2/2] Add website and community links to MCP tutorial - Add TIP block near the top linking to solr.apache.org/mcp and the GitHub repo - Add Community section with website, Slack (#solr-mcp), mailing lists, and issue tracker links - Add website to References section Signed-off-by: Aditya Parikh Co-Authored-By: Claude Opus 4.6 (1M context) Signed-off-by: adityamparikh --- .../getting-started/pages/tutorial-solr-mcp.adoc | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/solr/solr-ref-guide/modules/getting-started/pages/tutorial-solr-mcp.adoc b/solr/solr-ref-guide/modules/getting-started/pages/tutorial-solr-mcp.adoc index cae763711550..ac45613a9506 100644 --- a/solr/solr-ref-guide/modules/getting-started/pages/tutorial-solr-mcp.adoc +++ b/solr/solr-ref-guide/modules/getting-started/pages/tutorial-solr-mcp.adoc @@ -39,6 +39,9 @@ Just ask your AI assistant: The Solr MCP Server makes this possible by exposing Solr operations -- searching, indexing, collection management, and schema introspection -- as tools that any MCP-compatible AI client can invoke. +TIP: Visit the https://solr.apache.org/mcp[Solr MCP Server website] for features, community, and downloads. +The source code is at https://github.com/apache/solr-mcp[github.com/apache/solr-mcp]. + == Quick Start Get from zero to a working Claude + Solr integration in under 2 minutes. @@ -1331,6 +1334,13 @@ Spring Boot auto-instruments: Actuator endpoints (`/actuator/health`, `/actuator/metrics`, `/actuator/prometheus`) are provided by Spring Boot Actuator and exposed in HTTP mode. +== Community + +* *Website:* https://solr.apache.org/mcp +* *Slack:* https://the-asf.slack.com/archives/C09TVG3BM1P[`#solr-mcp`] in the `the-asf` Slack workspace +* *Mailing lists:* Shared with Apache Solr -- see https://solr.apache.org/community.html#mailing-lists-chat[mailing lists] +* *Issues:* https://github.com/apache/solr-mcp/issues[GitHub Issues] + == Contributing We welcome contributions! @@ -1370,6 +1380,7 @@ For the full contributing guide, development workflows, and architecture details === Apache Solr +* https://solr.apache.org/mcp[Solr MCP Server Website] * https://solr.apache.org/guide/[Apache Solr Documentation] * https://solr.apache.org/guide/solr/latest/deployment-guide/solrj.html[SolrJ Client Library]