Model Context Protocol (MCP)
Searchcraft includes a native Model Context Protocol server, so AI agents and LLM applications (Claude, IDE assistants, custom agent frameworks) can call your search cluster directly as a tool provider — no separate bridge service required.
The MCP endpoint is served at /mcp on the same port as the rest of the API, behind the same authentication:
POST https://your-instance.example.com/mcpAuthorization: <your access key>It implements the MCP Streamable HTTP transport. Clients on protocol revisions prior to 2026-07-28 are issued a session via the Mcp-Session-Id header; clients on 2026-07-28 or later are served statelessly, per the specification.
Every tool call is authorized against the calling access key’s permissions, the same permission model used by the REST API — a key cannot do anything through MCP that it could not do through the corresponding REST endpoint. Tools the key is not permitted to call are also omitted from tools/list, so agents don’t waste tokens attempting them. See Access Keys for the permission model.
Host Validation
Section titled “Host Validation”To defend against DNS-rebinding attacks, the /mcp endpoint validates the Host header of every request. This protection matters most for self-hosted instances running on localhost or private networks — a malicious web page can otherwise use a visitor’s browser to reach servers the page itself never could.
By default, only loopback hosts are accepted (localhost, 127.0.0.1, ::1). Local development and single-machine self-hosted installs need no configuration at all.
Deploying behind a load balancer, reverse proxy, or real hostname
Section titled “Deploying behind a load balancer, reverse proxy, or real hostname”If your instance is reached through any real hostname, you must allowlist that hostname or the endpoint is unusable:
SEARCHCRAFT_MCP_ALLOWED_HOSTS=search.example.comThe failure looks like this: the server starts normally, every REST endpoint works, but every request to
/mcpreturns403 Forbiddenwith the bodyForbidden: Host header is not allowed. If you see that response, the request’sHostheader is not in the allowlist.
Rules for the value:
- Comma-separated hostnames or
host:portauthorities, e.g.search.example.com,search.example.com:8000. - An entry without a port matches any port.
- The value replaces the loopback default entirely. Add
localhostback to the list if you also want to reach/mcpfrom the machine itself (for example when debugging inside a container). *disables Host validation entirely. Not recommended for anything reachable from a browser’s network.
Searchcraft Cloud instances are configured automatically; this only concerns self-hosted deployments.
Browser origins (optional)
Section titled “Browser origins (optional)”If a browser-based MCP client will call your instance, you can additionally restrict which web origins may do so:
SEARCHCRAFT_MCP_ALLOWED_ORIGINS=https://app.example.comOrigins match on scheme, host, and port, and must include the scheme. Requests without an Origin header — which includes every non-browser MCP client — always pass, so leaving this unset (the default, which disables Origin validation) is correct for almost all deployments.
Authentication and Discovery
Section titled “Authentication and Discovery”/mcp uses the same bearer authentication as the rest of the API: pass an access key in the Authorization header. On instances running without authentication (no SEARCHCRAFT_AUTHORIZATION_CODE), the endpoint is open like every other route — see the security notes before exposing such an instance to a network.
Responses follow the MCP authorization specification’s status codes:
401 Unauthorized— no key, or an invalid key. The response carries aWWW-Authenticate: Bearerchallenge.403 ForbiddenwithWWW-Authenticate: Bearer error="insufficient_scope"— the key is valid but lacks the permissions the request requires. The correct client reaction is to obtain a key with more permissions, not to re-authenticate.
OAuth authorization server discovery (optional)
Section titled “OAuth authorization server discovery (optional)”If an OAuth authorization server issues tokens for your instance, two settings advertise it to spec-conformant MCP clients:
SEARCHCRAFT_MCP_AUTH_ISSUER=https://auth.example.comSEARCHCRAFT_MCP_RESOURCE_URL=https://search.example.com/mcpSEARCHCRAFT_MCP_AUTH_ISSUER— the authorization server’s URL.SEARCHCRAFT_MCP_RESOURCE_URL— the externally-reachable URL of your MCP endpoint, used as the resource identifier.
With both set:
401challenges include the issuer and aresource_metadatapointer.- The instance serves an RFC 9728 Protected Resource Metadata document at
/.well-known/oauth-protected-resource(and at the path-suffixed variant clients derive from the resource URL, e.g./.well-known/oauth-protected-resource/mcp). This document is intentionally served without authentication — its purpose is to tell a client that does not yet have a token where to get one — and contains no secrets.
The two settings must be set together, and both must be absolute http(s) URLs; the server refuses to start on a half-configured or malformed pair rather than serving broken discovery information.
With neither set (the default, and the normal state for instances using Searchcraft access keys directly), challenges carry a bare Bearer scheme and the well-known route returns 404. Keys are provisioned through the auth API or Vektron instead.
Configuration Reference
Section titled “Configuration Reference”| Environment variable | Default | Purpose |
|---|---|---|
SEARCHCRAFT_MCP_ALLOWED_HOSTS | loopback only | Host header allowlist for /mcp. Required behind any real hostname. * disables. |
SEARCHCRAFT_MCP_ALLOWED_ORIGINS | (unset — disabled) | Browser Origin allowlist for /mcp. |
SEARCHCRAFT_MCP_AUTH_ISSUER | (unset) | OAuth authorization server URL; enables discovery. Set together with the resource URL. |
SEARCHCRAFT_MCP_RESOURCE_URL | (unset) | Externally-reachable URL of the MCP endpoint; the RFC 9728 resource identifier. |
SEARCHCRAFT_MCP_RATE_LIMIT_PER_MINUTE | 120 | Tool calls allowed per minute, per access key. 0 disables. |
SEARCHCRAFT_MCP_DESTRUCTIVE_TOOLS_ENABLED | false | Lets agents write over MCP. While it is off, MCP is read-only for every key. See Turning on writes. |
SEARCHCRAFT_MCP_UNDO_TTL_MINUTES | 60 | How long an agent’s undo records last without undo activity. 0 disables undo, and with it every write tool. |
All of these also exist as CLI flags — see the Searchcraft Core CLI reference.
The tool surface is versioned with Searchcraft Core. tools/list against a running instance always reflects exactly what your key may call, and every instance serves a guide at GET /auth.md listing the exact permission each tool requires.
Every tool carries MCP annotations: a title, and whether it only reads, can remove or overwrite data, and is safe to repeat. Clients that support them can run the read-only tools without asking and ask before destructive ones.
Search tools
Section titled “Search tools”These work with any key that can search, including read keys.
| Tool | What it does |
|---|---|
describe_index | Lists an index’s fields, facet fields, and search modes, which text fields hold exact values (such as ids) rather than full text, and the index’s upsert key if it has one. Agents call it before searching or writing to an unfamiliar index. |
search | Searches one index in dynamic, fuzzy, exact, or term mode, with pagination, sorting, and field selection. |
get_facets | Returns facet counts for an index, optionally scoped to a query. |
more_like_this | Finds documents similar to one returned by a search. |
list_federations, search_federation | Lists the federations your key can use, and searches across a federation’s member indexes in one call. |
semantic_search, semantic_search_federation | Natural-language semantic search. Requires AI to be configured on the index or federation and a key with AI permissions. |
list_changes, undo_change | Lists and reverses your own changes — see Undoing changes. undo_change is only available when writes are turned on. |
Write tools
Section titled “Write tools”These need a key with the same write permission the equivalent REST endpoint requires. Searchcraft Cloud ingest keys have all of them, and an agent authorized through Searchcraft Cloud gets them when the user grants the ingest scope. The tools that change data also need writes turned on for the instance.
| Tool | What it does |
|---|---|
get_synonyms, add_synonyms, remove_synonyms | Read and change an index’s synonyms. |
get_stop_words, add_stop_words, remove_stop_words | Read and change an index’s stopwords. |
add_documents, upsert_documents, delete_documents | Add documents, replace documents by their id, or delete them by the document_id on search results. See Document write tools. |
Synonyms added this way are one-way: a fuzzy-mode search for the word also matches its synonyms. As with the REST API, a custom stopword list replaces the language’s default list rather than extending it; the tools say so when a change drops the defaults.
Turning on writes
Section titled “Turning on writes”MCP is read-only by default. Until the operator turns writes on, no key can change data over MCP, whatever its permissions, and the tools that would (including undo_change) do not appear in tools/list. This stops an agent from writing just because it was handed a key with write permissions by mistake. To turn writes on:
SEARCHCRAFT_MCP_DESTRUCTIVE_TOOLS_ENABLED=trueWrites are turned on in Searchcraft Cloud. They also need undo: with SEARCHCRAFT_MCP_UNDO_TTL_MINUTES=0, MCP stays read-only.
Document write tools
Section titled “Document write tools”Document writes are searchable as soon as the call returns, whatever the index’s auto-commit setting: each call commits before it returns. If the index rejects any document in a batch, nothing from that call is written.
// add_documents{ "index": "products", "documents": [{ "title": "Trail running shoe" }] }// → { "count": 1, "document_ids": ["8422791443"], "change_id": "chg-12", "reversible": true, "visibility": "searchable now", … }add_documentsaccepts up to 100 documents per call and always adds. It returns each new document’sdocument_id. Fields the index schema does not define, and missing required fields, are rejected before anything is written. Documents go through the index’s ingestion enrichment exactly as they do through the documents API.upsert_documentstakes the same documents, each with a stringid, and replaces any document with the sameid, so an agent can safely retry a call. The index needs anidfield declared as"type": "text", "indexed": false, which matches the whole value exactly.describe_indexreports it as the index’supsert_key.delete_documentsaccepts up to 100document_idvalues from search results, and refuses ids that match no document.
Undoing changes
Section titled “Undoing changes”Every write returns a change_id. Passing it to undo_change restores the index to its state before that write, and list_changes shows the changes you can still undo.
- Undoing a document write deletes the documents it added and restores the documents it deleted or replaced, under their original
document_ids. - Undo records belong to the key that made the change; no other key can see or undo them.
- Records expire after
SEARCHCRAFT_MCP_UNDO_TTL_MINUTES(default 60) without undo activity, and are always cleared when the instance restarts. Undo is for an agent correcting its own recent work, not a backup. - An undo is refused if what it would restore has changed since, so it never overwrites newer work. An undo can itself be undone, which re-applies the original change.
Writes that cannot be undone
Section titled “Writes that cannot be undone”MCP refuses a write it could not undo, with one exception.
- A document delete or upsert that would remove more than 4 MiB of documents is refused, and nothing is written. Split it into smaller calls.
- On an index with fields that are not stored, a delete or upsert that removes documents still runs, but cannot be undone, because the removed documents cannot be rebuilt. Its result has
"reversible": falseand nochange_id.