A hands-on walkthrough that goes from an empty Solr to a properly designed, queryable collection — entirely through natural-language conversation with an AI assistant.
The point of this tutorial is not just how to index data. It's why field types matter. You will index a dataset twice: once letting Solr guess, once choosing types deliberately, and see exactly what the difference buys you.
Time: about 15 minutes.
1. Start Solr empty SolrCloud, one container
2. Index blind 61 documents, zero schema work <- it just works
3. Inspect the guess what Solr decided on your behalf <- and here's the catch
4. Design a schema types chosen for the questions you ask
5. Search filters, facets, ranges, sorting
6. Introspect stats, health, schema
You need two things.
A running Solr. This tutorial starts one in a single container — no clone and no build required for Solr itself:
docker run -d --name solr-tutorial -p 8983:8983 solr:9-slim solr start -c -fThe -c matters: it starts SolrCloud with embedded ZooKeeper, which is what the
collection management tools need. Give it a few seconds, then confirm it answers:
curl "http://localhost:8983/solr/admin/collections?action=LIST"An empty "collections":[] is the correct starting point.
An MCP client connected to the Solr MCP server. Any of the supported clients work — see the client setup guides — and the rest of this tutorial is client-agnostic. Everything in a blockquote below is something you say to your assistant; everything in a code block is either a shell command or data you paste.
Confirm the connection before continuing:
"What Solr collections are available?"
An empty list means the server is wired up correctly.
61 streaming television shows, with a mix of field shapes that make schema design matter: single-valued text, repeated categories, integers, and a decimal rating.
curl -O https://raw.githubusercontent.com/apache/solr-mcp/main/src/test/resources/shows.json{
"id": "netflix-001",
"title": "Stranger Things",
"platform": "Netflix",
"genres": ["Sci-Fi", "Horror", "Drama"],
"release_year": 2016,
"seasons": 5,
"imdb_rating": 8.7,
"cast": ["Millie Bobby Brown", "Finn Wolfhard"],
"tags": ["80s", "supernatural"],
"description": "A group of kids in 1980s Indiana uncover supernatural mysteries..."
}If your client cannot read local files, paste the JSON contents directly into the conversation instead of referencing the path.
Solr's _default configset runs in schemaless (data-driven) mode: send it
documents containing fields it has never seen, and it will invent types for them.
"Create a Solr collection called shows-auto."
"Index the contents of ./shows.json into the shows-auto collection."
You should get 61 of 61 documents. No schema, no field definitions, no
configuration — and it worked.
This is genuinely useful. Schemaless mode exists so you can get data in and start exploring before you know what questions you'll ask. The trouble starts when you ask them.
"Show me the breakdown of shows-auto by platform."
This is the most ordinary business question imaginable, and the answer comes back empty:
{ "numFound": 61, "documents": [], "facets": { "platform": {} } }Read that carefully, because it is worse than an error. Sixty-one documents matched. The query succeeded. Solr simply has no breakdown to give you, and it says so without complaining. Nothing here tells you that the data is fine and the field type is the problem — which is exactly the failure mode that makes schemaless deceptive.
To see the cause, look at what Solr decided on your behalf:
"Show me the schema for shows-auto."
| Field | Solr guessed | What that costs you |
|---|---|---|
platform |
text_general |
Tokenized and analyzed, so it is no longer one value. Searching platform:prime matches all 20 Amazon Prime Video shows — nonsense for a category — and faceting it yields no buckets at all. |
title |
text_general |
Searchable, but not sortable or exact-matchable. |
imdb_rating |
pdoubles |
Note the trailing s — that plural means multi-valued. Every rating is a list, so "highest rated" is not a well-defined question. |
release_year |
plongs |
Multi-valued too, which makes range filtering awkward. |
Look at any document that comes back and the giveaway is visible — every field is wrapped in an array:
"title": ["Stranger Things"], "imdb_rating": [8.7]Solr saw one sample of each field and had no reason to assume it would not repeat, so it hedged on all of them.
The lesson: schemaless is an on-ramp, not a destination. Solr guessed from a single document with no knowledge of what you would later want to ask. Faceting, range filtering and sorting all depend on types chosen with those questions in mind.
Field types cannot be changed once created. Worse, at present every collection
created through create-collection shares the same _default configset, so the
guesses from Step 1 are already baked in and a new collection would inherit them
(see Known issues).
So start from a clean slate:
docker rm -f solr-tutorial
docker run -d --name solr-tutorial -p 8983:8983 solr:9-slim solr start -c -fThis takes a few seconds. Wait for the collections endpoint to answer before continuing.
Now create the collection and define its fields before any documents arrive.
"Create a Solr collection called shows."
Then describe the schema you want:
"Add these fields to the shows collection schema: title and description as single-valued text_general; platform, status, country, language and rating as single-valued strings with docValues; genres, tags, cast and creators as multi-valued strings with docValues; release_year, end_year, seasons and episodes as single-valued pint with docValues; imdb_rating as single-valued pdouble with docValues."
The assistant will translate that into add-fields calls. The reasoning behind
each choice:
| Choice | What it buys you |
|---|---|
string rather than text_general |
Exact values. "Amazon Prime Video" stays one facet bucket instead of disappearing into tokens. |
docValues: true |
The column-oriented structure that makes faceting and sorting efficient. |
pint / pdouble |
Real numbers, so range filters like [2020 TO *] and numeric sorting work. |
| Single-valued where the data is single-valued | You can sort on it. Sorting by a multi-valued field is not meaningful. |
text_general kept for prose |
Analysis and tokenizing is exactly right for title and description. |
Note that the difference is not "strings are better than text". Both types appear in this schema. The difference is matching the type to how the field will be queried — categories get exact matching, prose gets analysis.
Now index the same data into the new collection:
"Index the contents of ./shows.json into the shows collection."
And ask the question that failed in Step 2:
"Show me the breakdown of shows by platform."
Netflix 20, Amazon Prime Video 20, HBO Max 7, Apple TV+ 4,
Disney+ 4, Hulu 3, Paramount+ 2, Peacock 1
Same data, same question, same tool. The only thing that changed is that someone decided what the fields meant.
Each of these exercises a different Solr capability. The parameter each one drives is noted so you can connect the natural-language request to what actually runs.
| Ask your assistant | Exercises |
|---|---|
| "Which shows have 'dragon' in the title?" | q — full-text search on an analyzed field |
| "Find shows whose description contains the exact phrase 'a group of'." | q — phrase query |
| "Show me everything on Netflix." | fq — exact filter on a string field |
| "Which shows were released in 2020 or later?" | fq — numeric range, release_year:[2020 TO *] |
| "Find all the comedies." | fq — membership in a multi-valued field |
| "Break the collection down by genre and by status." | facet — multiple fields at once |
| "What are the five highest rated shows?" | sortClauses + rows |
| "Show me shows from 2015 onward rated 8 or above, sorted by rating, with a platform breakdown." | everything combined |
The last one is the interesting one. You did not write:
q=*:*&fq=release_year:[2015 TO *]&fq=imdb_rating:[8 TO *]&sort=imdb_rating desc&facet=true&facet.field=platform&rows=5
The assistant did, because the tool descriptions told it how. That translation is what the server exists to provide.
Search is the headline, but the operational tools are what make this useful in a real workflow.
"Is the shows collection healthy?"
"Give me the stats for the shows collection."
"What's my query result cache hit ratio, and what does that tell me?"
"Explain the shows schema — which fields can I facet on, and which can I sort by?"
That last question is worth asking. The assistant has both the schema and an
understanding of Solr's type semantics, so it can answer a question that would
otherwise mean reading managed-schema and knowing what docValues implies.
Two rough edges worth knowing about. The first is a tracked defect you will meet while following this tutorial; neither is a mistake on your part.
Collections share the _default configset
(#183). create-collection binds
each collection to the shared _default configset rather than copying it, so
schemaless field guesses leak into every collection created afterwards. Symptoms
are add-fields failing with Field 'x' already exists on a brand-new collection,
or a "schemaless" collection silently inheriting another collection's explicit
types. Restarting Solr resets it, which is why Step 3 exists.
Unknown search parameters are dropped silently. Arguments the search tool does
not declare are ignored rather than rejected, so a misnamed one looks like a query
that simply did not do what you asked — results come back, just unsorted or
unfiltered. If a result set ignores part of your request, check the tool's parameter
names via your client's tool inspector before assuming the data is wrong.
- Client setup guides — Claude Desktop, Claude Code, VS Code / Copilot, Cursor, JetBrains, MCP Inspector
- Security — the deployment model, the HTTP transport, and OAuth2 setup with Auth0 or Keycloak
- Observability — traces, metrics and logs via OpenTelemetry
- FAQ — including why an MCP server rather than a prompt-level skill
Things worth trying with what you have running:
- Index your own JSON, CSV or XML and see what the schema guesser makes of it.
- Add a
DenseVectorFieldwithadd-field-typesand try vector search. - Describe a dataset in words and ask the assistant to design a schema for it.
- Point the server at a Solr you already run —
SOLR_URLis the only setting.
docker rm -f solr-tutorial