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:
{
"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"}'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.
| Parameter | Type | Default | Notes |
|---|---|---|---|
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.
| Parameter | Type | Default | Notes |
|---|---|---|---|
query | string | - | Required. 2 to 200 characters. |
locale | "en" | "pl" | "en" | Which language's index to search. |
limit | integer | 10 | 1 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.
| Parameter | Type | Default | Notes |
|---|---|---|---|
path | string | - | 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 withdocs/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
| Method | Behavior |
|---|---|
POST | The JSON-RPC endpoint. This is the only method that does real work. |
GET | Answered with a JSON-RPC 405 body - this server has no standalone SSE stream. |
DELETE | Not implemented at all; answered with a bare HTTP 405. |
OPTIONS | Answered 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-characterpath- 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 HTTP400, 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.