Skip to main content
Glama

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-mcp

The 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 --help

Get 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 claude

For 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-files

Wire 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 surfacezim_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 + subscriptionszim://{name}/entry/{path} with native MIME types; clients open a subscriptions/listen stream and get resources/list_changed when a ZIM appears or disappears, resources/updated when 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 introspectionzim_health(zim_file_path=...) validates an archive's integrity (Archive.check() + checksum), and zim_metadata reports archive identity, full-text / title index capabilities, and an M/Counter mimetype 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.sqlite next 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

Get started

Introduction · Installation · Quick start · ZIM concepts · LLM integration patterns · Worked examples

Concepts

Smart retrieval · Search reranking · Architecture overview

Reference

API reference · Configuration · Resources, prompts & subscriptions · CLI reference

Operate

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


Made with ❤️ by Cameron Rye

Available Tools

8 tools
zim_browseA
Read-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".

ParametersJSON Schema
NameRequiredDescriptionDefault
modeNopage
limitNo
cursorNo
offsetNo
namespaceYes
zim_file_pathYes
include_assetsNo

TDQS

A5/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters5/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_getA
Read-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 + optional view. 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.). view is locked to "full" in this branch.

  • Batch: pass entry_paths (list of strings). Returns each entry's clean body, first page only; non-full view / content_offset return invalid_path_combination.

  • Main page: pass main_page=True (no entry_path). Returns the archive's main page. view, entry_path, entry_paths, binary are 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.

ParametersJSON Schema
NameRequiredDescriptionDefault
viewNofull
binaryNo
compactNo
main_pageNo
entry_pathNo
entry_pathsNo
zim_file_pathYes
compact_budgetNo
content_offsetNo
max_content_lengthNo

TDQS

A5/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters5/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_sectionA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
compactNo
max_charsNo
entry_pathYes
section_idYes
zim_file_pathYes
compact_budgetNo
include_subsectionsNo

TDQS

A5/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters5/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_healthA
Read-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}.

ParametersJSON Schema
NameRequiredDescriptionDefault
zim_file_pathNo

TDQS

A4.7/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters5/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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_metadataA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
zim_file_pathYes

TDQS

A4.7/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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_queryA
Read-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.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo
queryYes
cursorNo
offsetNo
compactNo
synthesizeNo
zim_file_pathNo
compact_budgetNo
content_offsetNo
max_content_lengthNo

TDQS

A4.7/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters5/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 7 tool updatesv3.2.5
    • Addedzim_browse
    • Addedzim_get
    • Addedzim_get_section
    • Addedzim_health
    • Addedzim_links
    • Addedzim_metadata
    • Addedzim_search
  2. 1 tool updatev3.2.1
    • Changedzim_query16 fields changed
      • removedInput schema / properties / compact / title
        Removed value: -"Compact"
      • removedInput schema / properties / compact_budget / default
        Removed value: -null
      • removedInput schema / properties / compact_budget / title
        Removed value: -"Compact Budget"
      • removedInput schema / properties / content_offset / title
        Removed value: -"Content Offset"
      • removedInput schema / properties / cursor / default
        Removed value: -null
      • removedInput schema / properties / cursor / title
        Removed value: -"Cursor"
      • removedInput schema / properties / limit / default
        Removed value: -null
      • removedInput schema / properties / limit / title
        Removed value: -"Limit"
      • removedInput schema / properties / max_content_length / default
        Removed value: -null
      • removedInput schema / properties / max_content_length / title
        Removed value: -"Max Content Length"
      • removedInput schema / properties / offset / title
        Removed value: -"Offset"
      • removedInput schema / properties / query / title
        Removed value: -"Query"
      • removedInput schema / properties / synthesize / title
        Removed value: -"Synthesize"
      • removedInput schema / properties / zim_file_path / default
        Removed value: -null
      • removedInput schema / properties / zim_file_path / title
        Removed value: -"Zim File Path"
      • removedInput schema / title
        Removed value: -"zim_queryArguments"
  3. 1 tool updatev2.6.0
    • Changedzim_query1 field changed
      • changedOutput 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
  4. 1 tool updatev2.5.4
    • Changedzim_query3 fields changed
      • addedOutput schema / $defs / MetaEnvelope / properties / detected_type
        Added value: +{
        +  "title": "Detected Type",
        +  "type": "string"
        +}
      • addedOutput schema / $defs / MetaEnvelope / properties / detection_confidence
        Added value: +{
        +  "title": "Detection Confidence",
        +  "type": "string"
        +}
      • addedOutput schema / $defs / MetaEnvelope / properties / preset_applied
        Added value: +{
        +  "title": "Preset Applied",
        +  "type": "string"
        +}

TDQS

A4.7/5.0

Scored across 8 tools

Disambiguation3/5

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.

Naming Consistency5/5

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.

Tool Count5/5

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.

Completeness5/5

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

ActivityActive
ResponsivenessWithin a week

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables 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
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables large language models to directly access and search content in ZIM files, allowing offline question answering and information retrieval from resources like Wikipedia.
    20
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Provides offline search and retrieval of Wikipedia articles using Kiwix .zim files, enabling LLMs to access full Wikipedia content without internet.
    2
    MIT