MCP Server

A public, stateless, read-only Streamable HTTP MCP server at https://zanreal.com/mcp that serves the ZanReal documentation to AI agents and other MCP clients. No account, API key or authentication required.

https://zanreal.com/mcp is a Model Context Protocol server that exposes the documentation on this site (/docs) to AI agents and other MCP clients over Streamable HTTP. It is public, stateless and read-only: there is nothing to sign up for, no API key to generate and no tool on it writes anything.

Point any MCP-compatible client at the URL above and it can list, search and read every page in these docs, in either language.

Connect a client

Add the server to a client that supports Streamable HTTP with just the URL:

mcp.json
{
  "mcpServers": {
    "zanreal-docs": {
      "url": "https://zanreal.com/mcp"
    }
  }
}

Or talk to it directly. Every request is a single JSON-RPC 2.0 object sent as a POST, with both content-type: application/json and accept: application/json, text/event-stream set - the server replies with a Streamable HTTP response, which arrives as one event: message / data: ... frame rather than a plain JSON body:

curl https://zanreal.com/mcp \
  -H "content-type: application/json" \
  -H "accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
response
event: message
data: {"result":{"tools":[{"name":"list_docs_pages", ...}, ...]},"jsonrpc":"2.0","id":1}

Calling a tool looks the same, with tools/call and a params object naming the tool and its arguments:

curl https://zanreal.com/mcp \
  -H "content-type: application/json" \
  -H "accept: application/json, text/event-stream" \
  -d '{
    "jsonrpc": "2.0",
    "id": 2,
    "method": "tools/call",
    "params": {
      "name": "get_docs_page",
      "arguments": { "path": "/docs/oss/search" }
    }
  }'

The server does not use HTTP sessions to hold state - initialize is optional, and a client that skips straight to tools/list or tools/call gets served normally. An Mcp-Session-Id does come back on every response for clients that want to carry one, but nothing about the tools below depends on it.

Tools

All three tools are read-only (readOnlyHint: true) and take no argument that performs a write.

list_docs_pages

Lists every page in the docs, in sidebar reading order.

ParameterTypeDefaultNotes
locale"en" | "pl""en"Which language to list.

Returns a JSON array of { title, url, description }, where url is an absolute https://zanreal.com/... link already carrying the requested locale's prefix.

search_docs

Full-text search across the docs, returning ranked page and heading matches.

ParameterTypeDefaultNotes
querystring-Required. 2 to 200 characters.
locale"en" | "pl""en"Which language's index to search.
limitinteger101 to 20 results.

Each result carries a type ("page" or "heading"), the matched content, breadcrumbs, and a url you can pass straight to get_docs_page.

Polish search is weaker than English

The search index is built with English stemming for the whole site, not a separate Polish analyzer. search_docs still returns Polish results for locale: "pl", but matching is closer to a literal substring search than the language-aware ranking English queries get. Prefer list_docs_pages or a more literal query when searching Polish content.

get_docs_page

Reads one page as resolved Markdown - relative links and install-command blocks already expanded.

ParameterTypeDefaultNotes
pathstring-Required. 1 to 300 characters.
locale"en" | "pl""en"Used only when path carries no locale prefix.

path accepts any of the forms the other two tools hand back:

  • an absolute URL on this site (https://zanreal.com/pl/docs/oss/search/api)
  • an absolute site path (/docs/oss/search/api, optionally locale-prefixed)
  • a bare slug (oss/search/api), optionally prefixed with docs/ and a locale

A locale prefix in path always wins over the locale argument. Both list_docs_pages and search_docs hand out URLs that already carry a locale prefix, and the whole point of feeding one straight back into get_docs_page is that it reads back in the language it was found in - so an explicit /pl/... prefix is honoured even if the caller also passed locale: "en". locale only applies to a path with no prefix at all, such as a bare slug.

An off-origin absolute URL is rejected outright rather than reinterpreted against this site's own tree.

Requests and limits

MethodBehavior
POSTThe JSON-RPC endpoint. This is the only method that does real work.
GETAnswered with a JSON-RPC 405 body - this server has no standalone SSE stream.
DELETENot implemented at all; answered with a bare HTTP 405.
OPTIONSAnswered 204, for CORS preflight.

CORS is open (Access-Control-Allow-Origin: *), so a browser-based MCP client can call this server directly without a proxy.

A few limits are worth knowing before you build against it:

  • Request bodies are capped at 64 KiB. A real call to any of these tools is tiny - the largest single argument is get_docs_page's 300-character path - so this is generous headroom, not a tight budget.
  • JSON-RPC batching is refused. A top-level JSON array is rejected with {"error":{"code":-32600,"message":"JSON-RPC batching is not supported. ..."}} and HTTP 400, rather than executed. Batching was removed from MCP in protocol revision 2025-06-18, and this server never accepted it - send one request object per HTTP request.
  • 60 requests per minute per IP address. Exceeding it returns HTTP 429. The limiter fails open: if its backing store is unavailable, requests are served rather than blocked, since this endpoint only ever reads already public documentation.

Machine-readable descriptor

https://zanreal.com/.well-known/mcp/server-card.json publishes this server's tool list and endpoint as a single JSON document, for clients and directories that discover MCP servers by fetching a well-known URL rather than connecting first.

On this page