Skip to content

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/mcp
Authorization: <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.

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:

Terminal window
SEARCHCRAFT_MCP_ALLOWED_HOSTS=search.example.com

The failure looks like this: the server starts normally, every REST endpoint works, but every request to /mcp returns 403 Forbidden with the body Forbidden: Host header is not allowed. If you see that response, the request’s Host header is not in the allowlist.

Rules for the value:

  • Comma-separated hostnames or host:port authorities, 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 localhost back to the list if you also want to reach /mcp from 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.

If a browser-based MCP client will call your instance, you can additionally restrict which web origins may do so:

Terminal window
SEARCHCRAFT_MCP_ALLOWED_ORIGINS=https://app.example.com

Origins 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.

/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 a WWW-Authenticate: Bearer challenge.
  • 403 Forbidden with WWW-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:

Terminal window
SEARCHCRAFT_MCP_AUTH_ISSUER=https://auth.example.com
SEARCHCRAFT_MCP_RESOURCE_URL=https://search.example.com/mcp
  • SEARCHCRAFT_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:

  • 401 challenges include the issuer and a resource_metadata pointer.
  • 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.

Environment variableDefaultPurpose
SEARCHCRAFT_MCP_ALLOWED_HOSTSloopback onlyHost 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_MINUTE120Tool calls allowed per minute, per access key. 0 disables.
SEARCHCRAFT_MCP_DESTRUCTIVE_TOOLS_ENABLEDfalseLets agents write over MCP. While it is off, MCP is read-only for every key. See Turning on writes.
SEARCHCRAFT_MCP_UNDO_TTL_MINUTES60How 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.

These work with any key that can search, including read keys.

ToolWhat it does
describe_indexLists 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.
searchSearches one index in dynamic, fuzzy, exact, or term mode, with pagination, sorting, and field selection.
get_facetsReturns facet counts for an index, optionally scoped to a query.
more_like_thisFinds documents similar to one returned by a search.
list_federations, search_federationLists the federations your key can use, and searches across a federation’s member indexes in one call.
semantic_search, semantic_search_federationNatural-language semantic search. Requires AI to be configured on the index or federation and a key with AI permissions.
list_changes, undo_changeLists and reverses your own changes — see Undoing changes. undo_change is only available when writes are turned on.

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.

ToolWhat it does
get_synonyms, add_synonyms, remove_synonymsRead and change an index’s synonyms.
get_stop_words, add_stop_words, remove_stop_wordsRead and change an index’s stopwords.
add_documents, upsert_documents, delete_documentsAdd 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.

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:

Terminal window
SEARCHCRAFT_MCP_DESTRUCTIVE_TOOLS_ENABLED=true

Writes are turned on in Searchcraft Cloud. They also need undo: with SEARCHCRAFT_MCP_UNDO_TTL_MINUTES=0, MCP stays read-only.

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_documents accepts up to 100 documents per call and always adds. It returns each new document’s document_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_documents takes the same documents, each with a string id, and replaces any document with the same id, so an agent can safely retry a call. The index needs an id field declared as "type": "text", "indexed": false, which matches the whole value exactly. describe_index reports it as the index’s upsert_key.
  • delete_documents accepts up to 100 document_id values from search results, and refuses ids that match no document.

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.

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": false and no change_id.