OpenZIM MCP Server
The OpenZIM MCP Server gives AI models structured, offline access to ZIM knowledge archives (Wikipedia, Stack Exchange, etc.) through MCP tools that search, retrieve, browse, inspect, and analyze archive content.
Natural-language querying:
zim_querytranslates plain-language requests into the right operation (fetch article, search, summarize, list namespaces, etc.), with compact output modes for small LLMs and a cross-archive synthesize mode with citations.Searching:
zim_searchsupports full-text BM25 search with namespace/content-type filters, typo-tolerant title lookup, and prefix autocomplete, including cross-archive fan-out.Fetching content:
zim_getretrieves article bodies, summaries, tables of contents, section structures, batch entries, binary assets (images/videos/PDFs), and the archive main page.Section extraction:
zim_get_sectionfetches a specific article section by TOC id, optionally including subsections.Browsing:
zim_browsepaginates or fully walks archive namespaces (e.g. articles, images, metadata), with optional asset inclusion.Metadata and inventory:
zim_metadatareturns archive identity, M-namespace fields, per-namespace counts, index capabilities, and MIME-type breakdowns.Link analysis:
zim_linkslists outbound links (internal/external/media), inbound links ("what links here" via sidecar), and related articles by link overlap.Health and validation:
zim_healthreports server state, loaded archives, configuration, and validates a ZIM archive's integrity/checksum/index status.Deployment modes: Simple mode (one tool) for smaller models and Advanced mode (all eight tools plus prompts/resources) for larger models; supports stdio and streamable HTTP transports with Docker, auth, and CORS.
Provides access to ZIM format knowledge bases created by Kiwix, enabling AI agents to search and retrieve content from offline Wikipedia and other reference materials stored in compressed ZIM archives.
Allows access to Wikibooks content stored in ZIM format archives, enabling AI agents to search and retrieve educational content from offline Wikibooks collections.
Enables AI agents to access Wikipedia content stored in offline ZIM archives, providing tools for searching articles, browsing by namespace, extracting article structure, and retrieving detailed content without requiring internet connectivity.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@OpenZIM MCP Serversearch for information about quantum computing"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
✨ Highlights. A lean 8-tool advanced surface (
zim_query,zim_search,zim_get,zim_get_section,zim_browse,zim_metadata,zim_links,zim_health) with a schema small enough for small-model dispatch — or one-tool Simple mode for natural-language queries. Archive-type presets auto-tune retrieval per source (Wikipedia, Stack Exchange, …), inbound link discovery answers "what links here," and native libzim introspection validates and inspects any archive. Available on Smithery and the official MCP Registry. Release notes → Docs →
OpenZIM MCP is a modern, secure, high-performance Model Context Protocol server that gives AI models structured, offline access to ZIM format knowledge archives — Wikipedia, Wiktionary, Stack Exchange, and the rest of the Kiwix Library.
Built for research assistants, knowledge chatbots, and content-analysis systems that need intelligent access to vast knowledge repositories — not just a raw text dump. Smart navigation by namespace (articles, metadata, media), structure-aware retrieval (sections, tables of contents, related articles), full-text search with suggestions and multi-archive search, and link-graph extraction to map content relationships. Cached, paginated operations keep things responsive across massive archives; comprehensive input validation and path-traversal protection keep things safe.
Streamable HTTP transport, per-entry MCP resources with live change notifications, and dual Simple / Advanced modes are all built in.
Install
# uv (recommended — isolated CLI tool)
uv tool install openzim-mcp
# pip
pip install openzim-mcp
# Docker (multi-arch image, ghcr.io) — runs as a local stdio MCP server
docker pull ghcr.io/cameronrye/openzim-mcp
docker run -i --rm -v ~/zim-files:/data ghcr.io/cameronrye/openzim-mcpThe container defaults to stdio transport, so docker run -i speaks MCP over stdin/stdout — wire it into an MCP client the same way as the binary (see Quick start). For the long-running HTTP service (bearer auth, CORS, health endpoints), opt in at runtime with -e OPENZIM_MCP_TRANSPORT=http -e OPENZIM_MCP_HOST=0.0.0.0 -e OPENZIM_MCP_AUTH_TOKEN=… -p 8000:8000; see HTTP & Docker deployment.
Verify the install:
openzim-mcp --helpGet your first ZIM archive
The server does nothing without an archive to read. Grab a real one — a 13.6 MB extract of English Wikipedia on climate change, from the openZIM project's own testing suite. No account, nothing to install:
mkdir -p ~/zim-files
curl -fsSL -o ~/zim-files/wikipedia_en_climate_change_mini_2024-06.zim \
https://raw.githubusercontent.com/openzim/zim-testing-suite/main/data/withns/wikipedia_en_climate_change_mini_2024-06.zim~/zim-files is the directory every example below points the server at — the server expands ~ itself, so it works from a shell and from a client config file alike. For full archives — Wikipedia, Wiktionary, Stack Exchange and the rest, ranging from a few hundred MB to tens of GB — browse browse.library.kiwix.org and save the .zim into the same directory. More detail, including checksums and a Windows PowerShell equivalent: Quick start.
Smithery & one-click install
OpenZIM MCP is listed on the Smithery registry and the official MCP Registry (as io.github.cameronrye/openzim-mcp). Add it to your MCP client with the Smithery CLI:
npx @smithery/cli mcp add rye/openzim-mcp --client claudeFor a one-click Claude Desktop extension, download the openzim-mcp-<version>.mcpb asset (and its .sha256) from the latest release and double-click it. The bundle launches the version-pinned uvx openzim-mcp@<version> (so the host needs uv) and prompts for your ZIM directory. Maintainer runbook: docs/distribution.md.
Related MCP server: ZIM MCP Server
Quick start
Run the server in Simple mode (default — exposes one natural-language tool, zim_query):
openzim-mcp ~/zim-filesWire it into your MCP client. Example for Claude Desktop's claude_desktop_config.json (any MCP client that speaks stdio works the same way):
{
"mcpServers": {
"openzim-mcp": {
"command": "uvx",
"args": ["openzim-mcp", "~/zim-files"]
}
}
}Once the client connects, ask your LLM: "summarize the article on Photosynthesis" — zim_query dispatches to the right underlying tool automatically.
For full control, run in Advanced mode to expose all 8 specialized tools:
{
"mcpServers": {
"openzim-mcp-advanced": {
"command": "uvx",
"args": ["openzim-mcp", "--mode", "advanced", "~/zim-files"]
}
}
}For HTTP transport (long-running service with bearer auth, CORS, and health endpoints) see HTTP & Docker deployment.
Highlights
8-tool advanced surface —
zim_query,zim_search,zim_get,zim_get_section,zim_browse,zim_metadata,zim_links,zim_health. Down from 22; advanced-mode schema drops from ~36KB to ~24.1KB, clearing the MCP Tax pain band. API reference →Streamable HTTP transport — bearer-token auth, CORS, health endpoints, multi-arch Docker image. HTTP & Docker deployment →
Per-entry MCP resources + subscriptions —
zim://{name}/entry/{path}with native MIME types; clients open asubscriptions/listenstream and getresources/list_changedwhen a ZIM appears or disappears,resources/updatedwhen one is replaced. Resources, prompts & subscriptions →Simple-mode
zim_query— one natural-language tool that dispatches to the right operation, tuned for small-model deployment targets. Quick start →Archive-type presets — OpenZIM MCP detects the archive type (Wikipedia, Stack Exchange, and more) and auto-tunes retrieval and summarization for it — e.g. Stack Exchange dumps render as clean Q&A instead of vote-score noise. Operators can override the bundled defaults with a TOML file (
OPENZIM_MCP_PRESETS_OVERRIDE_PATH).Native libzim introspection —
zim_health(zim_file_path=...)validates an archive's integrity (Archive.check()+ checksum), andzim_metadatareports archive identity, full-text / title index capabilities, and anM/Countermimetype breakdown. API reference →Inbound link discovery ("what links here") —
zim_links(direction="inbound")returns pages that link to an entry, ranked by linker importance. Requires a pre-built sidecar:openzim-mcp build link-graph <archive>.zim(writes<archive>.zim.linkgraph.sqlitenext to the archive). API reference →
Modes
OpenZIM MCP ships two modes; pick one per client.
Simple mode (default) exposes a single intelligent tool, zim_query, that parses natural-language requests and dispatches to the right underlying operation. Built for small-model deployment targets — the wire footprint is minimal and the dispatch happens server-side, not in the LLM context. Start here unless you have a specific reason not to.
Advanced mode exposes all 8 specialized tools (zim_query, zim_search, zim_get, zim_get_section, zim_browse, zim_metadata, zim_links, zim_health) plus 3 MCP prompts (/research, /summarize, /explore) and per-entry resources. Built for larger models that can reliably dispatch over the full schema, and for clients that want fine-grained control over pagination, namespace browsing, and link-graph extraction.
Rule of thumb: models ≤ 13B parameters benefit from Simple mode; larger models (Claude Sonnet/Opus, GPT-4o-class, Llama 70B+) can dispatch Advanced mode directly. See LLM integration patterns for guidance on choosing.
Documentation
Full documentation lives at https://cameronrye.github.io/openzim-mcp/docs/.
Group | Pages |
Introduction · Installation · Quick start · ZIM concepts · LLM integration patterns · Worked examples | |
Smart retrieval · Search reranking · Architecture overview | |
API reference · Configuration · Resources, prompts & subscriptions · CLI reference | |
HTTP and Docker deployment · Performance optimization · Security best practices · Troubleshooting · FAQ · Upgrading |
Project status
v3.3.4 is the current release (2026-09-18).
v2.0.0 GA shipped 2026-05-27. Per SECURITY.md, the v1.x maintenance window closed when v2.5.0 shipped (2026-06-18); all active development is on the current major line. v3.0.0 is a breaking release for HTTP subscription clients: resources/subscribe/unsubscribe are no longer served — live updates ride subscriptions/listen on the 2026-07-28 protocol revision — and link-graph sidecars built by 2.x must be rebuilt. Tools, resources, and prompts are unchanged, and legacy-handshake clients keep working. Details in CHANGELOG.md, and step-by-step instructions in the upgrade guide.
Contributing
See CONTRIBUTING.md for development setup, test commands, code style, and the release process.
Security
See SECURITY.md for the vulnerability disclosure policy. No known CVEs.
License
MIT. See LICENSE.
Acknowledgments
Model Context Protocol for the open client-server protocol
The open-source community and contributors
Made with ❤️ by Cameron Rye
Available Tools
8 toolszim_browseARead-only
Browse a ZIM archive's namespace — paginated lookup or full walk.
EXTRACT whether the caller wants a paginated page or a full walk
before calling. Most read-the-table-of-contents-style requests are
mode="page"; only full-enumeration tasks (e.g. "list every article
in namespace A") need mode="walk".
ALIASES: "browse ", "list ", "walk namespace ". Route through THIS tool with the matching mode.
PARAMETERS:
zim_file_path REQUIRED. The archive to browse.
namespace REQUIRED. ZIM namespace letter (e.g. "C" for
content, "A" for articles in legacy archives,
"I" for images).
mode "page" (default) — paginated browse.
"walk" — full namespace enumeration.
cursor Opaque pagination handle from next_cursor.
limit Page size: page 1-200 (default 50), walk 1-500
(default 200).
offset Page-mode pagination offset (walk rejects it).
include_assets Default False hides assets (css/js/fonts/images/
media) in C-browse; True surfaces them, e.g. media
paths for zim_get(binary=True).
RESPONSE:
BrowseNamespaceResponse (mode="page") or WalkNamespaceResponse
(mode="walk"). Both carry results, next_cursor, and page_info.
ERRORS:
Invalid mode returns invalid_mode; an empty namespace returns
a validation envelope. An unknown namespace letter is a soft reject
(isError=false): _meta.reason: "bad_namespace", plus page-only
total: 0/discovery_method: "rejected_unknown_namespace".
| Name | Required | Description | Default |
|---|---|---|---|
| mode | No | page | |
| limit | No | ||
| cursor | No | ||
| offset | No | ||
| namespace | Yes | ||
| zim_file_path | Yes | ||
| include_assets | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark this as read-only and non-open-world, so the safety profile is known. The description adds valuable behavioral detail: walk rejects offset, include_assets hides or surfaces asset entries, pagination uses an opaque cursor, and unknown namespace letters produce a soft reject with specific _meta.reason values. This goes well beyond what annotations provide.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the core purpose, then uses clear section headers for usage, aliases, parameters, response, and errors. Although long, every sentence earns its place: parameter semantics are essential given the bare schema, and the error/response notes prevent misinvocation. No fluff or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With seven parameters, two modes, no output schema, and complex error behavior, this description is complete enough for an agent to call the tool correctly. It covers parameter choice, pagination state, response type names, and soft-error semantics, leaving no obvious operational gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has 0% description coverage, so the description carries the full burden — and it succeeds. Every parameter is explained: zim_file_path and namespace are marked required, namespace letters are exemplified, mode values and defaults are given, cursor is identified as an opaque handle, limit ranges differ by mode, and offset's incompatibility with walk is stated.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource — 'Browse a ZIM archive's namespace' — and immediately clarifies the two operational modes, 'paginated lookup' and 'full walk'. It names common aliases ('browse <namespace>', 'list <namespace>') and routes them to this tool, making it easy to distinguish from siblings like zim_query or zim_search.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly instructs the agent to decide between 'page' and 'walk' before calling, and gives concrete selection criteria: read-the-table-of-contents-style requests use 'page', full-enumeration tasks use 'walk'. It also maps aliases to the correct mode, providing clear when-to-use guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
zim_getARead-only
Fetch entries from a ZIM archive — single, batch, binary, or main page.
EXTRACT the right path-shape before calling — the parameters form four mutually-exclusive branches:
Single entry, body view (default): pass
entry_path+ optionalview. Returns the article body for view="full", a short summary for view="summary", a TOC tree for view="toc", a flat section list for view="structure".Single entry, binary: pass
entry_path+binary=True. Returns raw bytes (image, video, PDF, etc.).viewis locked to "full" in this branch.Batch: pass
entry_paths(list of strings). Returns each entry's clean body, first page only; non-fullview/content_offsetreturninvalid_path_combination.Main page: pass
main_page=True(no entry_path). Returns the archive's main page.view,entry_path,entry_paths,binaryare all forbidden in this branch.
ALIASES: callers may say "get article", "fetch", "show me ", "summary of ", "structure of ", "main page". Route through THIS tool with the matching branch.
PARAMETERS:
zim_file_path REQUIRED. The archive containing the entry.
entry_path Single-entry path (string). Mutually exclusive
with entry_paths and main_page.
entry_paths Batch-mode path list. Mutually exclusive with
entry_path, binary, main_page.
view Body slice when not binary/main_page:
"full" (default, full markdown body),
"summary" (short snippet),
"toc" (heading tree),
"structure" (flat section list).
binary Default False. Set True to fetch raw bytes
(single entry only).
main_page Default False. Set True for the archive's
main page (zero-path fetch).
max_content_length Char cap for view="full" (default 100,000); with
binary=True caps fetched bytes (default 10MB,
oversize returns metadata + truncated: true).
content_offset Char offset into the body for view="full"
(default 0). Used with the truncation footer's
pass content_offset=N hint. Single-entry only.
compact Default False. Set True for small-LLM
compaction. (zim_query defaults it True.)
compact_budget Inert here — never forwarded. Only zim_query
honors it.
RESPONSE:
Branch-dependent dict — EntryResponse / BatchEntryResponse /
EntrySummaryResponse / TableOfContentsResponse /
ArticleStructureResponse / BinaryEntryResponse — or
ToolErrorPayload on invalid combinations
(invalid_path_combination).
ERRORS:
Invalid branch combinations return structured
invalid_path_combination; message names the conflict.
Defense-in-depth: even if a small model flattens the wire-schema
oneOf and sends an impossible payload, the handler rejects it
cleanly.
| Name | Required | Description | Default |
|---|---|---|---|
| view | No | full | |
| binary | No | ||
| compact | No | ||
| main_page | No | ||
| entry_path | No | ||
| entry_paths | No | ||
| zim_file_path | Yes | ||
| compact_budget | No | ||
| content_offset | No | ||
| max_content_length | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description goes well beyond the readOnlyHint annotation by disclosing truncation behavior, content_offset continuation hints, binary mode's view lock, and the fact that compact_budget is never forwarded. It also explains the structured invalid_path_combination error and defense-in-depth rejection behavior, all of which are valuable for an agent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long, but it is densely informative and well-structured with labeled sections: branch summary, aliases, parameters, response, and errors. Every sentence adds necessary call guidance, and the front-loaded overview helps an agent quickly understand the tool's shape.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the absence of an output schema, the RESPONSE section properly enumerates the branch-dependent response types and the error payload. The ERROR section clarifies how invalid combinations are reported, so an agent has sufficient context to invoke the tool and interpret results correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has 0% description coverage, so the PARAMETERS section carries the full burden. It explains every parameter's role, default, mutual exclusions, and special interactions, such as max_content_length capping bytes when binary=True and view being locked to 'full' in binary mode. This fully compensates for the schema's lack of descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific action and object: 'Fetch entries from a ZIM archive — single, batch, binary, or main page.' It then enumerates the four distinct retrieval modes, making it clear what this tool does and how it differs from searching or querying. The alias list further reinforces the intended purpose.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly instructs the caller to select one of four mutually exclusive branches and details which parameters to pass for each. It also names forbidden combinations, such as non-full views in batch mode and extra parameters in main-page mode. The note that compact_budget is only honored by zim_query provides a clear cross-tool alternative.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
zim_get_sectionARead-only
Fetch one named section of an article — by section_id (from the
TOC), with optional subsection inclusion.
EXTRACT the section id before calling — zim_get(view="toc") lists
them if the caller didn't supply one.
ALIASES: callers may say "section of ", "show me the section", " section ". Route through THIS tool.
PARAMETERS:
zim_file_path REQUIRED. The archive containing the article.
entry_path REQUIRED. The article whose section to fetch.
section_id REQUIRED. The TOC id (e.g. "History").
max_chars Optional char cap on the section body.
include_subsections Default True: include nested subsections.
False: stop at the next heading of any level.
compact Default True: oversized tables become
placeholders and link markup is stripped (the
zim_get compact=True shape). False: raw body
with full tables and links.
compact_budget Inert — never forwarded. Use max_chars to cap
this tool; only zim_query honors this one.
RESPONSE: GetSectionResponse — section body markdown, metadata, and any nested subsections.
ERRORS:
Unknown section_id → ToolErrorPayload with available_section_ids
(not a hint) and closest_match. Missing entry → entry_not_found.
| Name | Required | Description | Default |
|---|---|---|---|
| compact | No | ||
| max_chars | No | ||
| entry_path | Yes | ||
| section_id | Yes | ||
| zim_file_path | Yes | ||
| compact_budget | No | ||
| include_subsections | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint and openWorldHint; the description goes well beyond by documenting that compact strips link markup and replaces oversized tables, compact_budget is inert and never forwarded, include_subsections=False stops at the next heading, and error payloads expose available_section_ids and closest_match rather than a hint.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded purpose, then compact label-style sections for aliases, parameters, response, and errors. Every sentence adds semantic value; the parameter annotations are organized and directly scannable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with no output schema and no schema-level parameter descriptions, the response shape and error cases are spelled out. The combination of prerequisites (get section_id from TOC), parameter behavior, response contents, and error payloads leaves no critical gap for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description carries the full burden, and it succeeds: all seven parameters are explained, with defaults for include_subsections and compact, and the inert nature of compact_budget is explicitly called out. Error semantics for section_id are also covered.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence identifies a specific verb and resource: 'Fetch one named section of an article' by section_id from the TOC, with optional subsection inclusion. This makes it clearly distinct from siblings like zim_get (whole article/TOC) and zim_query.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly tells the agent to extract section_id before calling and points to zim_get(view='toc') as the source when the caller didn't supply one. The ALIASES block gives concrete caller phrasings and directs routing through this tool, and it warns that compact_budget is only honored by zim_query, so the agent knows not to use it here.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
zim_healthARead-only
Inspect the openzim-mcp server's state — or validate one archive — in one call.
With NO argument: returns health checks (cache stats, directory probes,
recommendations), configuration (allowed directories, cache config,
server PID), and loaded_archives (every *.zim found; readable: false
marks files that fail the ZIM signature check).
Collapses the legacy get_server_health + get_server_configuration +
list_zim_files triple into one answer to "what is this server, what
does it have, and is it OK".
With a zim_file_path: validates/diagnoses that one archive — runs
Archive.check() (integrity), reports checksum, index, and identity.
ALIASES: "is the server ok", "list archives", "what's loaded", "server health" (no arg); "validate this zim", "is this archive corrupt" (with path).
PARAMETERS: zim_file_path OPTIONAL. Omit for server state; pass to validate one archive.
RESPONSE:
No arg → ServerHealthResponse {health, configuration, loaded_archives, _meta}.
With path → ArchiveValidationResponse {is_valid (check() result), has_checksum, checksum, has_fulltext_index, has_title_index, uuid, is_multipart, path, name, _meta}.
| Name | Required | Description | Default |
|---|---|---|---|
| zim_file_path | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, but the description adds substantial behavioral detail beyond that: it describes health checks, configuration fields, loaded_archives, the meaning of readable:false, and the validation behavior including Archive.check() and the returned fields. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is longer than average but well-structured with clear sections and front-loaded information. Most sentences add value, especially the response field enumeration, which is necessary because no output schema exists. Minor redundancy exists around the omit/pass guidance, but it is not wasteful.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given there is no output schema, the description thoughtfully includes the full response shapes for both invocation modes. The single optional parameter is fully explained, and the tool's behavior is covered for both branches. Nothing an agent needs to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema provides no property descriptions, so schema coverage is 0%. The description fully compensates by explaining that zim_file_path is optional, what omitting it does, and what passing it does. This is exactly the semantic guidance the schema lacks.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Inspect the openzim-mcp server's state — or validate one archive — in one call.' It clearly distinguishes the tool from the content-access siblings by positioning it as a health/state/validation tool rather than a content-retrieval tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit usage conditions: no argument for server state, a zim_file_path for validating one archive. It also supplies helpful aliases. It does not explicitly contrast with sibling tools like zim_search or zim_get, but the behavioral split is clear enough.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
zim_linksARead-only
Look up links from one article — outbound/inbound link buckets or related-article suggestions.
EXTRACT the direction before calling: "outbound" = the article's
own links (internal / external / media buckets); "inbound" = pages
that link TO it; "related" = "see also" by outbound-link overlap.
ALIASES: "links in " / "what does link to" (outbound); "what links here" / "pages linking to " (inbound); "related to " / "articles like " (related). Route through THIS tool with the matching direction.
DIRECTIONS:
"outbound" (default) — paginated.
"inbound" — ranked by linker importance; paginated. Requires a
built link-graph sidecar (openzim-mcp build link-graph).
"related" — one ranked set (no pagination).
PARAMETERS:
zim_file_path REQUIRED. The archive containing the article.
entry_path REQUIRED. The article whose links to inspect.
direction See DIRECTIONS above.
kind Outbound only — others reject it. Which bucket:
"internal" (default) / "external" / "media". One
per call; category_totals reports four counts.
cursor Cursor handle (outbound/inbound).
limit Page size. Outbound 1-500 (default 100);
inbound and related 1-100 (default 10).
offset Offset (outbound/inbound; related rejects it).
RESPONSE:
LinksResponse (outbound) or RelatedArticlesResponse (inbound /
related). Outbound is occurrence-level (document order, duplicates
kept; total counts them). url is the raw href; internal rows
add path, the entry path for zim_get. Related dedupes targets
and reports mention_count.
category_totals.internal excludes #anchor links (counted as
category_totals.anchor) and anchor-wrapped assets, which move to
the media bucket as type: "asset" (or fold into the <img> row
for the same entry, which then carries path).
ERRORS:
Bad direction/kind → invalid_argument (enum-typed, so it is
rejected before the body runs). Missing/stale inbound sidecar →
inbound_sidecar_unavailable. Unknown entry_path →
not-found envelope (related: outbound_error, total: 0).
Cursor from another archive/entry/tool →
cursor_context_mismatch / cursor_mismatch.
| Name | Required | Description | Default |
|---|---|---|---|
| kind | No | internal | |
| limit | No | ||
| cursor | No | ||
| offset | No | ||
| direction | No | outbound | |
| entry_path | Yes | ||
| zim_file_path | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description discloses pagination behavior, occurrence-level vs deduplicated responses, duplicate handling, anchor-link counting, and error conditions. It also explains sidecar requirements and cursor validation, far exceeding what the readOnlyHint annotation provides. No contradiction exists between description and annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but every sentence carries operational weight, with clear headers for directions, parameters, response, and errors. It is front-loaded with the purpose and direction extraction guidance, making the most critical routing information immediately available. The length is justified by the tool's complexity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite having no output schema, the description documents the response shapes and semantic differences between LinksResponse and RelatedArticlesResponse. It also covers all error paths and parameter constraints, so an agent has everything needed to invoke correctly. Sibling context is not required because the description is self-contained.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, but the PARAMETERS section fully compensates. It explains each parameter's role, defaults, valid ranges, and interdependencies, such as kind being outbound-only and offset being rejected for related. This adds significant meaning beyond the raw input schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Look up links from one article' and immediately distinguishes the three buckets (outbound/inbound/related). It also provides alias phrasing so an agent can map user intent to the exact call. This clearly sets it apart from sibling tools like zim_get or zim_search.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit direction-level guidance with aliases and tells the agent to route through this tool when the user asks about links, linkers, or related articles. It also states per-direction constraints such as inbound requiring the link-graph sidecar, and related having no pagination. This is comprehensive routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
zim_metadataARead-only
Inspect a ZIM archive's metadata + namespace inventory.
Returns the M-namespace fields (Name, Title, Creator, Date, …) plus
the per-namespace entry counts in one combined response. Replaces
the legacy get_zim_metadata + list_namespaces pair.
ALIASES: callers may say "metadata for ", "what's in this zim", "describe the archive". Route through THIS tool.
PARAMETERS: zim_file_path REQUIRED. The archive to inspect.
RESPONSE:
ArchiveMetadataResponse with:
- metadata: flat dict[str, str] of M-namespace fields.
- namespaces: list of NamespaceInfo (letter + total + diagnostics).
- archive_identity {uuid, is_multipart} + index_capabilities
{has_fulltext_index, has_title_index} — identity and whether
search / suggestions will work.
- counter_breakdown {mimetype: count} parsed from M/Counter;
omitted when absent.
- _meta: standard envelope.
NO main_page_path field. The canonical main-page fetch is
zim_get(main_page=True) — surfacing the path here would create
two routes a small model would null-check unnecessarily.
ERRORS:
Missing/invalid zim_file_path returns a structured error envelope.
| Name | Required | Description | Default |
|---|---|---|---|
| zim_file_path | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnlyHint=true annotation, the description discloses the full response shape (metadata dict, namespaces list, archive_identity, index_capabilities), the conditional omission of counter_breakdown, the deliberate exclusion of main_page_path with rationale, and a structured error envelope for invalid input. No contradiction with the read-only / non-open-world annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose is front-loaded and the body is cleanly sectioned (PARAMETERS, RESPONSE, ERRORS, ALIASES) with bolded callouts for the main_page_path exclusion. The length is justified because the RESPONSE section carries documentation that would otherwise be missing given there is no output schema; every sentence adds value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter, read-only tool with no output schema, the description is remarkably complete: it documents response fields, conditional fields, exclusions and their rationale, error behavior, aliases, and the legacy tools it replaces. Nothing an agent needs to invoke it correctly appears to be missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate; it states the parameter is REQUIRED and identifies 'the archive to inspect', which adds only modest meaning over the self-descriptive name zim_file_path. It doesn't specify the expected form (local path vs identifier) or resolution behavior, though the error note softens this gap.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb-resource pair ('Inspect a ZIM archive's metadata + namespace inventory') and details the exact payload (M-namespace fields plus per-namespace counts). It distinguishes itself from siblings by explicitly excluding main_page_path and routing that need to zim_get, and it lists natural-language aliases to aid intent matching.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit routing guidance: the ALIASES section tells callers to 'Route through THIS tool' for phrases like 'what's in this zim', and the main_page_path note gives a concrete when-not with an alternative (zim_get(main_page=True)). It also documents that it replaces the legacy get_zim_metadata + list_namespaces pair.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
zim_queryARead-only
Query ZIM archives using natural language.
Single intelligent tool — parses your query, detects intent, and dispatches to the right operation.
EXTRACT INTENT BEFORE CALLING. Do not pass the user's raw
message as query. Translate it into one of the operations
below:
"test this tool" -> query="list available ZIM files"
"what's in here" -> query="show main page"
"explore" -> query="list namespaces"
"tell me about cats" -> query="tell me about cats"
-> query=""
ALIASES: users may call this tool "openzim", "openzim mcp", "openzim mcp tool", "ZIM tool", "ZIM file tool", "ZIM archive query", or "zim_query". All mean THIS tool — always call it; never claim it does not exist.
OPERATIONS (pass one as query):
list available ZIM files - list loaded archives
show main page - active archive main page
list namespaces - list entry types
metadata for - archive metadata
tell me about - fetch article (auto on
strong title match)
search for - full-text search
get article - fetch specific article
show structure of - section outline
links in - article-out links
suggestions for - title autocomplete
browse namespace - list namespace entries
search in namespace - filtered search
search all files for - cross-archive search
walk namespace - enumerate namespace
find article titled - title lookup
articles related to - related articles
what links to - article-in links
summary of - lead summary
table of contents - heading list
section of - one section's body
get image - binary bytes (base64)
get articles , - batch fetch
Args:
query: REQUIRED. Translated from user intent — never the
user's raw message.
zim_file_path: Optional. Omit entirely (recommended) —
the tool auto-selects the loaded archive (or opens
all of them when synthesize=True). Pass a real
path ONLY when multiple archives are loaded and you
need to target a specific one; call list available ZIM files first to see the real paths. NEVER pass
an article title, topic, or made-up filename here,
and do NOT invent a path from this docstring —
paths that don't match a loaded archive are silently
auto-corrected when only one archive is loaded, and
surface a path-listing error otherwise.
limit: Max results to return. When omitted, each list
intent applies its own per-intent default (search 10,
browse 50, walk 200, links 25, search-all 5/archive);
pass a value to override. Ignored for atomic intents
that return a single item or a fixed-shape payload —
get article <name>, show structure of <name>,
show main page, list namespaces, metadata for <file>, list available ZIM files, summary of <name>, table of contents <name>, section <X> of <name>. Setting it there has no effect; omit
it on those calls.
offset: Pagination offset (default: 0). Not honoured by
suggestions for <prefix>, find article titled <name> or articles related to <name>; raise
limit there instead.
cursor: Opaque handle from a prior next_cursor.
max_content_length: Article body cap (default: 4000).
content_offset: Character offset to start reading the
article body from (default: 0). The truncation footer
on long articles surfaces a pass content_offset=N
hint — wire that value back here to read the next
page. Negative values are rejected with an
invalid_content_offset error.
compact: When True (the default in both modes), apply
small-LLM optimizations — strip markdown link-soup,
drop section previews from structure responses,
flatten link/title/related listings into compact
markdown, fetch only the article lead section, and
cap total response size. Set False for the verbose
advanced-mode-style response.
compact_budget: Hard char-cap on the final response when
compact=True. Accepts either a named profile —
"tiny" (2 000), "small" (4 000), "medium" (6 000,
default), "large" (12 000) — or a raw integer. Size
it to the calling model's context window. Has no
effect when compact=False.
synthesize: When True, bypass intent classification and
run the synthesize pipeline — multi-archive Xapian
search, RRF fusion, passage extraction, section
attribution, and citation rendering. Returns a
SynthesizeResponse dict instead of markdown text.
Defaults to False (legacy markdown path unchanged).
NOTE: this is a mode toggle, not a "search harder"
flag. Don't flip it on a follow-up just because the
previous response was unhelpful — refine the query
or offset instead. The synthesize pipeline runs
one structured query and returns one answer; calling
it twice with the same query yields the same answer.
Returns: Markdown string (synthesize=False) or SynthesizeResponse dict (synthesize=True) with answer_markdown, passages, citations, and archives_searched.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| query | Yes | ||
| cursor | No | ||
| offset | No | ||
| compact | No | ||
| synthesize | No | ||
| zim_file_path | No | ||
| compact_budget | No | ||
| content_offset | No | ||
| max_content_length | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description goes far beyond the readOnlyHint annotation by disclosing silent path auto-correction, per-intent limit defaults, parameters that are ignored on certain operations, the truncation/content_offset loop, compact mode behavior, and synthesize mode semantics. There is no contradiction with the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The definition is long, but the tool is genuinely complex and the structure—headers, operation list, per-parameter notes—makes it navigable. Minor redundancy between the EXTRACT INTENT examples and the operations list keeps it from a perfect conciseness score.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 10-parameter tool with no output schema and no inline parameter descriptions, the description covers the full calling contract: input transformation, return format, pagination semantics, per-intent defaults, and mode toggles. Nothing essential for correct invocation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must carry the full semantic burden, and it does: every parameter gets operational guidance, examples, defaults, ignored-case caveats, or failure modes. This is exemplary compensation for a bare schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb and resource ('Query ZIM archives using natural language') and immediately defines itself as the single natural-language dispatcher, which sets it apart from the focused sibling tools even though their names are not repeated in the text. The operation list makes the scope concrete and unmistakable.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives strong usage guidance: translate intent before calling, never pass raw user messages, treat aliases as triggers for this tool, and omit zim_file_path unless targeting a specific loaded archive. It does not, however, explicitly explain when to prefer this dispatcher over specialized siblings like zim_search or zim_get.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
zim_searchARead-only
Search a ZIM archive — three modes, one tool.
EXTRACT the search intent before calling. Pick the mode that matches
what the user actually needs; the wrong mode silently returns the
wrong shape of results.
MODES (pass one as mode):
"fulltext" (default) — Xapian BM25 search with optional
namespace/content_typefilters. Use for queries with multiple keywords ("history of Rome", "Tesla electricity") or when the caller wants snippets, not just titles. Cross-archive viacross_file=True."title" — Exact / typo-tolerant title lookup. Returns titles matching the query (case ladder + suggestion expansion + Levenshtein-1). Use when the caller knows the article name and wants to confirm it exists or find near matches ("find article titled Detroit"). Single-archive applies Z3/Z4/OPP-1 promotion; cross-archive (
cross_file=True) returns raw matches (promotion is per-archive)."suggest" — Prefix autocomplete via libzim SuggestionSearcher. Returns title candidates only — no snippets, no body. Use for typeahead-style completion ("prefix
Det"). Does NOT supportcross_file=True(per-archive).
ALIASES: callers may say "search", "find", "lookup", or "autocomplete".
All route through THIS tool — pick the matching mode.
PARAMETERS:
query REQUIRED. Plain terms, all AND-ed (drop one to widen);
AND/OR/NOT, quotes and wildcards are not parsed
(matched as literal words).
mode One of {"fulltext", "title", "suggest"}. Default
"fulltext".
zim_file_path Optional. Omit to auto-select the single loaded
archive, or use cross_file=True to fan out.
cross_file Default False. Set True to fan out across every
loaded archive (modes "fulltext" and "title" only;
"suggest" rejects this with invalid_combination).
namespace Only valid in mode="fulltext". Restricts search to
one ZIM namespace letter (e.g. "C" for content).
Rejected in title/suggest modes.
content_type Only valid in mode="fulltext". Restricts search to
one MIME bucket (e.g. "text/html").
limit Max results; cap 50 title/suggest/cross_file, 100 filtered, else 1000.
offset Pagination offset (default 0); single-archive
fulltext only. Next page: offset +
page_info.source_consumed (else returned_count).
cursor Unsupported; page fulltext via offset.
RESPONSE:
fulltext rows carry path, title, snippet; title rows carry
path, title, score — pass path as entry_path to
zim_get. cross_file=True nests hits under
results[].result.results. suggest items are {text, path, type}.
Title-mode _meta.promotion_applied is True when a candidate was
hoisted; False with a hint when cross-archive blocked it.
ERRORS:
Returns a ToolErrorPayload on:
- mode="suggest" with cross_file=True (invalid_combination)
- limit out of range, negative offset (invalid_limit,
invalid_offset)
- missing archive when zim_file_path is required but cross_file
is False and auto-selection fails
| Name | Required | Description | Default |
|---|---|---|---|
| mode | No | fulltext | |
| limit | No | ||
| query | Yes | ||
| cursor | No | ||
| offset | No | ||
| namespace | No | ||
| cross_file | No | ||
| content_type | No | ||
| zim_file_path | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description goes well beyond the readOnlyHint annotation by explaining mode-specific response shapes, cross-file nesting, error payloads, limit caps, pagination semantics, unsupported cursor, and title-mode promotion behavior. It gives a clear model of what the tool will do and what can go wrong.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but every section earns its place: mode selection, parameter details, response shapes, and error cases are all needed for a tool of this complexity. It is well-structured with clear headers, front-loads the most important guidance, and avoids repetition of the schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With nine parameters, three modes, no output schema, and no parameter descriptions in the schema, the description must be highly self-sufficient. It covers result shapes, pagination, cross-file nesting, limit caps, and error conditions, leaving no critical gap for an agent deciding how to invoke the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description carries full responsibility for parameter semantics. It explains every parameter: query term handling, mode enum, namespace/content_type constraints, cross_file behavior, zim_file_path auto-selection, limit/offset rules, and cursor unsupported. This is comprehensive and highly actionable.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states that the tool searches a ZIM archive and immediately distinguishes three search modes (fulltext, title, suggest). The verb-resource pairing is explicit, and the mode breakdown makes it easy to understand what the tool does versus the related sibling tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly instructs the agent to extract search intent before calling and provides detailed when-to-use guidance for each mode, including examples and exclusions (e.g., suggest does not support cross_file=True). Aliases are mapped, and the wrong-mode consequence is disclosed, which is strong usage guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
7 tool updates
v3.2.5- Added
zim_browse - Added
zim_get - Added
zim_get_section - Added
zim_health - Added
zim_links - Added
zim_metadata - Added
zim_search
1 tool update
v3.2.1- Changed
zim_query16 fields changed- removed
Input schema / properties / compact / titleRemoved value: -"Compact" - removed
Input schema / properties / compact_budget / defaultRemoved value: -null - removed
Input schema / properties / compact_budget / titleRemoved value: -"Compact Budget" - removed
Input schema / properties / content_offset / titleRemoved value: -"Content Offset" - removed
Input schema / properties / cursor / defaultRemoved value: -null - removed
Input schema / properties / cursor / titleRemoved value: -"Cursor" - removed
Input schema / properties / limit / defaultRemoved value: -null - removed
Input schema / properties / limit / titleRemoved value: -"Limit" - removed
Input schema / properties / max_content_length / defaultRemoved value: -null - removed
Input schema / properties / max_content_length / titleRemoved value: -"Max Content Length" - removed
Input schema / properties / offset / titleRemoved value: -"Offset" - removed
Input schema / properties / query / titleRemoved value: -"Query" - removed
Input schema / properties / synthesize / titleRemoved value: -"Synthesize" - removed
Input schema / properties / zim_file_path / defaultRemoved value: -null - removed
Input schema / properties / zim_file_path / titleRemoved value: -"Zim File Path" - removed
Input schema / titleRemoved value: -"zim_queryArguments"
1 tool update
v2.6.0- Changed
zim_query1 field changed- changed
Output schema / (root)Previous value: -{ - "$defs": { - "Citation": { - "description": "A citation in a SynthesizeResponse.\n\n``total=False`` lets D8 (v2.0.0a9) attach ``rank`` and ``score``\nin compact-mode synthesize responses — fields the verbose path\nkeeps on ``SynthesizePassage`` but compact mode drops the\npassages array entirely to save tokens. Compact callers correlate\nrank/score with the citation directly.", - "properties": { - "archive": { - "title": "Archive", - "type": "string" - }, - "cite_id": { - "title": "Cite Id", - "type": "string" - }, - "entry_path": { - "title": "Entry Path", - "type": "string" - }, - "rank": { - "title": "Rank", - "type": "integer" - }, - "score": { - "title": "Score", - "type": "number" - }, - "section_id": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Section Id" - }, - "section_title": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "null" - } - ], - "title": "Section Title" - }, - "title": { - "title": "Title", - "type": "string" - } - }, - "title": "Citation", - "type": "object" - }, - "ConsideredArticle": { - "description": "A14: an article hit not selected as the featured citation, surfaced\nso the caller can pivot in a follow-up turn without re-running search.\n\n``archive`` + ``entry_path`` form the handle the caller passes to\n``get_zim_entries`` (or composes into a ``cite_id``). ``score`` is the\nunderlying ranking score at the point of selection — informational,\nnot part of the handle.", - "properties": { - "archive": { - "title": "Archive", - "type": "string" - }, - "entry_path": { - "title": "Entry Path", - "type": "string" - }, - "score": { - "title": "Score", - "type": "number" - }, - "title": { - "title": "Title", - "type": "string" - } - }, - "title": "ConsideredArticle", - "type": "object" - }, - "ConsideredSection": { - "description": "A14: a section of the featured article not selected as the featured\npassage. ``section_id`` is the handle the caller passes to\n``get_section`` (or composes into a ``cite_id`` suffix).", - "properties": { - "section_id": { - "title": "Section Id", - "type": "string" - }, - "title": { - "title": "Title", - "type": "string" - } - }, - "title": "ConsideredSection", - "type": "object" - }, - "MetaEnvelope": { - "properties": { - "chars": { - "title": "Chars", - "type": "integer" - }, - "detected_type": { - "title": "Detected Type", - "type": "string" - }, - "detection_confidence": { - "title": "Detection Confidence", - "type": "string" - }, - "more_at_offset": { - "title": "More At Offset", - "type": "integer" - }, - "preset_applied": { - "title": "Preset Applied", - "type": "string" - }, - "reason": { - "title": "Reason", - "type": "string" - }, - "suggestions": { - "items": { - "additionalProperties": { - "type": "string" - }, - "type": "object" - }, - "title": "Suggestions", - "type": "array" - }, - "tokens_est": { - "title": "Tokens Est", - "type": "integer" - }, - "total_chars": { - "title": "Total Chars", - "type": "integer" - }, - "truncated": { - "title": "Truncated", - "type": "boolean" - } - }, - "title": "MetaEnvelope", - "type": "object" - }, - "SynthesizePassage": { - "properties": { - "cite_id": { - "title": "Cite Id", - "type": "string" - }, - "rank": { - "title": "Rank", - "type": "integer" - }, - "score": { - "title": "Score", - "type": "number" - }, - "text_markdown": { - "title": "Text Markdown", - "type": "string" - } - }, - "required": [ - "cite_id", - "text_markdown", - "rank", - "score" - ], - "title": "SynthesizePassage", - "type": "object" - }, - "SynthesizeResponse": { - "properties": { - "_meta": { - "$ref": "#/$defs/MetaEnvelope" - }, - "answer_markdown": { - "title": "Answer Markdown", - "type": "string" - }, - "archives_searched": { - "items": { - "type": "string" - }, - "title": "Archives Searched", - "type": "array" - }, - "citations": { - "items": { - "$ref": "#/$defs/Citation" - }, - "title": "Citations", - "type": "array" - }, - "considered_articles": { - "items": { - "$ref": "#/$defs/ConsideredArticle" - }, - "title": "Considered Articles", - "type": "array" - }, - "considered_sections": { - "items": { - "$ref": "#/$defs/ConsideredSection" - }, - "title": "Considered Sections", - "type": "array" - }, - "fallback_used": { - "enum": [ - "xapian_score", - "rrf_fusion", - "reranker" - ], - "title": "Fallback Used", - "type": "string" - }, - "passages": { - "items": { - "$ref": "#/$defs/SynthesizePassage" - }, - "title": "Passages", - "type": "array" - }, - "query": { - "title": "Query", - "type": "string" - }, - "total_chars": { - "title": "Total Chars", - "type": "integer" - }, - "total_words": { - "title": "Total Words", - "type": "integer" - } - }, - "title": "SynthesizeResponse", - "type": "object" - }, - "ToolErrorPayload": { - "description": "Envelope for tool errors returned via structuredContent.\n\n``error`` is always ``True`` so a client can branch on a single key\nwithout inspecting the operation name. ``message`` carries the\nsame human-readable text the tool would have returned as a string\n(markdown is fine — it's a string field, not nested JSON).", - "properties": { - "context": { - "title": "Context", - "type": "string" - }, - "error": { - "title": "Error", - "type": "boolean" - }, - "message": { - "title": "Message", - "type": "string" - }, - "operation": { - "title": "Operation", - "type": "string" - } - }, - "required": [ - "error", - "operation", - "message" - ], - "title": "ToolErrorPayload", - "type": "object" - } - }, - "properties": { - "result": { - "anyOf": [ - { - "type": "string" - }, - { - "$ref": "#/$defs/SynthesizeResponse" - }, - { - "$ref": "#/$defs/ToolErrorPayload" - } - ], - "title": "Result" - } - }, - "required": [ - "result" - ], - "title": "zim_queryOutput", - "type": "object" -}New value: +null
1 tool update
v2.5.4- Changed
zim_query3 fields changed- added
Output schema / $defs / MetaEnvelope / properties / detected_typeAdded value: +{ + "title": "Detected Type", + "type": "string" +} - added
Output schema / $defs / MetaEnvelope / properties / detection_confidenceAdded value: +{ + "title": "Detection Confidence", + "type": "string" +} - added
Output schema / $defs / MetaEnvelope / properties / preset_appliedAdded value: +{ + "title": "Preset Applied", + "type": "string" +}
TDQS
Scored across 8 tools
zim_query is a catch-all tool that overlaps with zim_search, zim_get, zim_browse, and zim_links, creating ambiguity about when to use the general tool versus the specific ones. While each specific tool has a clear purpose, the existence of a meta-tool that handles the same intents increases the risk of misselection.
All tools follow a consistent 'zim_<verb_noun>' pattern (e.g., zim_search, zim_get, zim_browse, zim_metadata, zim_links, zim_health, zim_get_section). The naming is uniform and predictable, with no mixing of conventions.
With 8 tools, the server is well-scoped for its purpose of ZIM archive access. Each tool has a distinct role, and the count is within the ideal 3-15 range, providing enough granularity without overwhelming the agent.
The tool set comprehensively covers read operations for ZIM archives: article retrieval (zim_get), section fetching (zim_get_section), search (zim_search), browsing/namespace enumeration (zim_browse), metadata inspection (zim_metadata), link analysis (zim_links), and server health (zim_health). No obvious gaps exist for the stated read-only domain.
Maintenance
Related MCP Connectors
Personal wiki and memory layer for AI assistants. Persistent, structured memory across sessions.
Search and reason over your Obsidian-style Markdown vault, right from ChatGPT.
Search your knowledge bases from any AI assistant using hybrid RAG.
Personal context for every AI: search, read, and write back to your private Markdown library.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables interaction with .zim archives by providing tools for article search, content retrieval, and metadata discovery. It features a TF-IDF based RAG engine for semantic retrieval over extracted article chunks from compressed ZIM files.GPL 3.0
- AlicenseNot gradedqualityDmaintenanceEnables large language models to directly access and search content in ZIM files, allowing offline question answering and information retrieval from resources like Wikipedia.20MIT
- FlicenseNot gradedqualityDmaintenanceProvides access to offline Wikipedia and other content through Kiwix, enabling search and retrieval of articles from local ZIM files.17-
- AlicenseNot gradedqualityDmaintenanceProvides offline search and retrieval of Wikipedia articles using Kiwix .zim files, enabling LLMs to access full Wikipedia content without internet.2MIT