Give your AI agents managed hybrid search
One config entry, and Claude, Cursor, or any MCP-compatible agent can search, index, and answer from your Opensolr indexes — hybrid BM25 + kNN, embeddings computed server-side, RAG answers grounded in your own content.
The whole setup
Claude Desktop, Claude Code, Cursor, Windsurf — same shape everywhere: stdio transport, two environment variables.
{
"mcpServers": {
"opensolr": {
"command": "uvx",
"args": ["opensolr-mcp"],
"env": {
"OPENSOLR_EMAIL": "you@example.com",
"OPENSOLR_API_KEY": "YOUR_OPENSOLR_API_KEY"
}
}
}
}Claude Code one-liner: claude mcp add opensolr -e OPENSOLR_EMAIL=... -e OPENSOLR_API_KEY=... -- uvx opensolr-mcp
Try it without an account
A public demo account, so the quickstart above runs before you decide anything.
export OPENSOLR_EMAIL=mcp@opensolr.com export OPENSOLR_API_KEY=420b8b23e7b12dc8ab838932145a5065
The index mcp_demo_d1__dense is already loaded with 300 news articles, so search, filtering and grounded answers work the moment you connect. You also get the write path: create your own index on the account, ingest into it and query it. Deletion is not available on this shared key — no index here can be deleted or reconfigured by hand. Whatever you create is removed automatically after 3 days.
- Anything you create there is deleted after 3 days. Automatically, without warning or export — indexes you created included.
- The account is shared with everyone reading this page. Your index is visible to them and they can add documents to it, as you can to theirs. Nobody can delete or reconfigure an index here — that is switched off for this key — but never put anything real, private or client-owned in it.
- The limits are per index, and deliberately small. 200 MB of bandwidth and 50 MB of disk per index. Bandwidth is the one you will hit first: it covers a demo, a tutorial and a proof of concept, and it will not carry an application.
When you want an index that is private, yours and still there next week, get your own key — the free plan is free forever, no card — and change the two variables above. Nothing else in your code changes.
16 tools your agent gets
Plain text in, ranked results out — the agent never touches a vector.
| Tool | What it does |
|---|---|
opensolr_search | Hybrid (keyword + semantic) or pure semantic search, with Solr filters and a date range — a PDF comes back as its best page, with a link that opens it at that page |
opensolr_search_by_image | Search with a photo — Opensolr reads its visual labels, OCR text and any barcode/QR, then searches with those words (no image vector stored) |
opensolr_read_document | Read a result in full — a PDF page by page, any other document as one text |
opensolr_ai_answer | Grounded RAG answer — the top hybrid hits become the LLM context, same pipeline as our hosted search UI |
opensolr_index_files | Index a local file or a whole folder: PDFs one document per page, Word, RTF, OpenDocument, text, HTML, scans and pictures through OCR |
opensolr_extract_text | Read local files without indexing them: their text, the OCR of their pictures, a PDF page by page |
opensolr_describe_image | What a picture shows (a sentence), the text printed on it, its labels and barcodes |
opensolr_add_documents | Index plain text + metadata — embedded server-side automatically |
opensolr_delete_documents | Remove documents by id or by a raw Solr query |
opensolr_ingest_status | Track an async ingestion job (documents become searchable in ~1 min) |
opensolr_list_indexes / opensolr_index_info | Inspect the account's indexes (credentials never returned) |
opensolr_create_index | Provision a vector index in a vector region: an environment from opensolr_vector_regions, or a short form like us matched against that live list |
opensolr_vector_regions | Live list of vector-enabled regions |
opensolr_check_schema | Whether an index is ready for every tool, what it can do, and exactly why not |
opensolr_apply_schema | Install the Opensolr vector schema on an index of a vector region |
Why agents love it
The chat is the UI — there is nothing to build.
Zero integration work
No SDK, no glue code, no frontend. Add the config entry, and "index our FAQ, then find everything about refunds" just works — in conversation.
Hybrid by default
BM25 catches the exact word "refund"; kNN catches "giving customers their money back". Scores fuse per document via Opensolr's native {!hybrid} Solr parser.
Verified publisher
Listed in the official MCP Registry under the domain-verified com.opensolr namespace — the source Claude Desktop, Cursor, and MCP directories pull from — and in the Glama MCP directory, where the server is claimed and its tools are enumerated.
Building in code instead? LangChain · LlamaIndex · Haystack · Laravel
Your agent can search with a photo
Point the agent at an image and it searches your index with it. Opensolr reads the picture three ways — what it depicts, the text printed on it, and any barcode or QR code — then searches with those words. No image vector is stored; the picture simply becomes a query.
# The agent calls one tool with a local image path: opensolr_search_by_image( index="catalog__dense", image_path="/tmp/shelf-photo.jpg", using="auto", # or "meaning" | "text" | "code" | "all" k=5, ) # -> { "read": {text, mode, labels, codes}, "results": [...] } # The agent sees BOTH what the picture was read as and the matching documents.
using picks the reading: meaning (visual labels), text (OCR only), code (exact barcode / QR), or all (everything combined). Search mode, alpha, fresh bias and filters work exactly as in opensolr_search.
Local files and folders, PDFs page by page
Point the agent at a folder and it is searchable. Each file is read on Opensolr’s servers — its text, the text in its pictures (OCR, more than 100 languages), a short description of the pictures without text — and a PDF becomes one document per page, so a search lands on the page that answers it instead of a 200-page file that mentions it somewhere. Word, RTF, OpenDocument, text, HTML and scanned pictures are one document each.
# A file or a whole folder from the machine the agent runs on: opensolr_index_files( index="contracts__dense", path="~/Documents/contracts", pattern="*.pdf", # every file when left out metadata={"team": "legal"}, ) # -> {"documents": [...], "pending": [], "failed": [], "jobs": [...]} # Or just read them, nothing indexed: opensolr_extract_text(index="contracts__dense", path="~/Downloads/scan-0412.pdf") # -> {"files": [{path, state, mime, "pages": [{page, text, is_ocr, lang}]}]}
The bytes travel once: a file the account already sent is not uploaded again, and sending the same files again replaces their documents. Pictures read by OCR count 0.5 of an AI request each; a file read before is free. Big files are read in the background: whatever is still being read comes back as pending — run again to finish them.
A PDF comes back as the page that answers
On an index where PDFs are stored page by page — your files, PDFs sent to Data Ingestion, PDFs found by the Web Crawler — a search returns each PDF once, as its best page, with a link that opens it right there, and its other matching pages under it. And a question that names a period searches only that period.
opensolr_search(index="contracts__dense", query="termination notice period", date_from="2025-01-01") # -> [{"title": "Master services agreement", "page": 14, # "page_url": "https://.../msa.pdf#page=14", opens the PDF at that page # "more_pages": [{"page": 3, ...}, ...], "document_id": "9f2c...", ...}] opensolr_read_document(index="contracts__dense", document="9f2c...", page_from=14)
group_pages=false returns the pages as separate results. date_from / date_to take YYYY-MM-DD, both included, either one can be left out. opensolr_read_document reads any result in full.
Index requirements, checked for you
Data Ingestion, vector and hybrid search and PDF pages need an index in a vector region that runs the Opensolr vector schema. Every index the package creates has it. On any other index the package checks once, with one request — never on every search — and tells you exactly what the index cannot do and how to fix it.
# What the index can do, and why not: opensolr_check_schema(index="my_index") # -> {"ready": false, # "capabilities": {"ingestion": true, "vector_search": false, "pdf_pages": true, "keyword_search": true}, # "problems": ["... 1 differ: knn_vector (vectorDimension 768, expected 1024)."], # "fix": {"action": "apply_schema", "text": "apply_schema installs the Opensolr vector schema ..."}} # Install the Opensolr vector schema (force=true when the index already holds documents): opensolr_apply_schema(index="my_index")
- Only what cannot work is stopped. Data Ingestion on an index outside the vector regions, and vector or hybrid search on an index without the vector field, are refused with the exact reason before anything is uploaded or embedded. Keyword search runs on any index that has
title,descriptionandtextfields. opensolr_check_schemaanswers whether the index is ready, what it can do (ingestion, vector search, PDF pages, keyword search), what differs from the Opensolr vector schema, and the fix.opensolr_apply_schemainstalls the Opensolr vector schema, the configuration every Opensolr vector index runs, so everything above works on the index. It replaces the index configuration: on an index that already holds documents it needsforce=true, and those documents must be sent again.- An index outside the vector regions cannot take it. Create a new index (
opensolr_create_index) in one of the regions ofopensolr_vector_regionsand send your documents there.
Your Search Tuning follows you
Relevance is configured once, in your Control Panel — not re-implemented in every codebase.
- Saved per index: everything you set in Index Settings → Search Tuning (semantic↔lexical balance, field weights, minimum match, search mode, vector candidate pool, content quality boost) is stored with your index.
- Applies automatically here: every search and every RAG answer from this integration runs through the same tuned pipeline as your hosted search page — change a slider in the Control Panel and the very next query uses it. No redeploy, no code change.
- Overridable per call:
tuning={"search_mode": "keywords_required", "fw_title": 0.2, "mm": "strict"}beats the saved settings for that one request. Defaults match the platform exactly when you send nothing. - Fresh Results Bias: pass
fresh_biasto rank newer documents higher — scores are multiplied by a recency curve oncreation_date. It re-orders and never filters: the hit count is unchanged and undated documents keep their place. This is the same control visitors get as the Fresh toggle on the hosted search page. Not to be confused withfreshness_boost, which is a hard date window in days and does remove results.
Tested on our own production index
Every release runs a live end-to-end suite against real Opensolr infrastructure — no mocks.
- Full write path through the async Data Ingestion queue: queued → server-side embeddings & enrichment → searchable, with metadata and id round-trips verified. Metadata lands in typed Solr fields; the suffixes and what they enable are in the Site Search Schema Reference.
- Real-corpus retrieval against a replica of opensolr.com's own search index: pure-semantic hits with zero keyword overlap („how do I get my data back after a disaster” → backup docs), cross-lingual queries (non-English → English content), all hybrid modes and the full alpha range.
- PDF ingestion via
rtf:true: server-side text extraction and content-type detection, then semantic retrieval from the extracted content. - Grounded RAG answers: one call runs hybrid retrieval and feeds the top hits to the LLM (configurable docs/words, custom instruction) — verified with a question answerable only from the ingested PDF.
- Every tool exercised live: search modes (hybrid / semantic / lexical), ingestion with wait, job status, deletes by id and query, grounded RAG answers.
Open source
This integration is free, MIT licensed and maintained in the open. Browse the code, open an issue, or sponsor the work that keeps it current.
Your agent could be searching in two minutes
Free forever plan, no credit card — the included AI quota covers plenty of agent conversations.