About ZimContext

An offline, SEO-and-LLM-friendly ZIM archive server. Pure Go implementation designed for serving compressed offline content with real article search and a JSON API for LLM tool use.

What is ZimContext?

ZimContext is a Go server that reads ZIM archives and serves their content over HTTP with server-side rendering. It gives search engines, LLMs, and humans direct access to the articles inside ZIM files without any client-side JavaScript framework.

Fast

Natively compiled Go with efficient memory management and concurrent request handling.

SEO Friendly

Server-side rendering delivers complete HTML to search engines and bots.

LLM Ready

JSON search API lets LLMs search and retrieve articles from offline documentation.

Offline First

No internet required at runtime. All content comes from local ZIM archives.

What is ZIM?

ZIM (Zeno IMproved) is an open file format from OpenZIM designed for storing web content offline. A single ZIM file can hold an entire website, including HTML, images, CSS, and JavaScript, compressed into a portable archive.

Common ZIM archives include Wikipedia, Stack Overflow, Project Gutenberg, DevDocs (React, Node.js, Python, etc.), and many other knowledge bases. You can download ZIM files from the Kiwix Library.

Using with LLMs

ZimContext turns your ZIM archives into a search tool that any LLM can use. Point the LLM at the /zimcontext/api/search endpoint and it can:

This is especially useful for giving LLMs access to up-to-date documentation that may be beyond their training cutoff, or for grounding responses in authoritative offline sources.

API Reference

GET /zimcontext/api/archives

List all loaded ZIM archives with metadata. Useful for discovering archive keys to pass to /zimcontext/api/search?archive=.

ParameterTypeDefaultDescription
pageint1Page number (1-indexed)
limitint20Results per page

Example request:

GET /zimcontext/api/archives?page=1&limit=5

Example response:

{
  "page": 1,
  "limit": 5,
  "total": 13,
  "archives": [
    {
      "key": "devdocs_en_react_2025-07",
      "title": "React",
      "description": "React documentation",
      "language": "en",
      "article_count": 136,
      "size": 37748736,
      "date": "2025-07"
    }
  ]
}

GET /zimcontext/api/search

Search articles across all loaded ZIM archives. Returns JSON.

ParameterTypeDefaultDescription
qstring(required)Search query
archivestring(all)Filter by archive key (filename stem)
limitint20Maximum number of results
offsetint0Skip first N results (for pagination)

Example request:

GET /zimcontext/api/search?q=useEffect&archive=devdocs_en_react_2025-07&limit=5&offset=0

Example response:

{
  "query": "useEffect",
  "archive": "devdocs_en_react_2025-07",
  "total": 12,
  "offset": 0,
  "results": [
    {
      "title": "useEffect",
      "archive": "devdocs_en_react_2025-07",
      "path": "reference/react/useEffect.html",
      "url": "/zimcontext/archive/devdocs_en_react_2025-07/reference/react/useEffect.html",
      "snippet": "...useEffect is a React Hook that lets you synchronize a component with an external system..."
    }
  ]
}

LLM Tool Definition

Copy-paste this tool definition into your LLM configuration to enable ZimContext search:

{
  "type": "function",
  "function": {
    "name": "search_zimcontext",
    "description": "Search articles in offline ZIM archives (documentation, Wikipedia, etc.) hosted by ZimContext. Returns titles, snippets, and URLs.",
    "parameters": {
      "type": "object",
      "properties": {
        "query": {
          "type": "string",
          "description": "Search query to find articles by title"
        },
        "archive": {
          "type": "string",
          "description": "Optional: filter by archive key (e.g. 'devdocs_en_react_2025-07'). Omit to search all archives."
        },
        "limit": {
          "type": "integer",
          "description": "Maximum results to return (default 20)"
        }
      },
      "required": ["query"]
    }
  }
}

List archives tool definition:

{
  "type": "function",
  "function": {
    "name": "list_zimcontext_archives",
    "description": "List all ZIM archives loaded in ZimContext. Returns archive keys, titles, and metadata. Use this to discover available archives before searching.",
    "parameters": {
      "type": "object",
      "properties": {
        "page": {
          "type": "integer",
          "description": "Page number, 1-indexed (default 1)"
        },
        "limit": {
          "type": "integer",
          "description": "Results per page (default 20)"
        }
      },
      "required": []
    }
  }
}

MCP Integration

ZimContext exposes an MCP (Model Context Protocol) endpoint at /zimcontext/mcp. This lets LLM tools like Cursor, Claude Code, and other MCP clients discover and call ZimContext tools natively — no manual tool definitions needed.

Cursor

Add a remote MCP server in Cursor Settings > MCP Servers. Paste:

{
  "mcpServers": {
    "zimcontext": {
      "url": "http://demo.carefuldream.com/zimcontext/mcp"
    }
  }
}

Claude Code

Run this command to register ZimContext as an MCP server:

claude mcp add zimcontext --transport http http://demo.carefuldream.com/zimcontext/mcp

Generic MCP Clients

Point any MCP Streamable HTTP client at:

POST http://demo.carefuldream.com/zimcontext/mcp
Content-Type: application/json

The server exposes three tools: list_archives, search_docs, and get_doc. Clients discover them automatically via the tools/list method.

SearXNG Integration

ZimContext can be used as a search engine in SearXNG, a self-hosted metasearch engine. This lets you search your ZIM archives alongside public search engines, with your local documents prioritized in the results.

How It Works

SearXNG's built-in json_engine can query ZimContext's search API directly. No custom Python code is needed — just add a configuration block to your SearXNG settings.yml. Set the weight higher than other engines so your local documents rank first.

SearXNG Configuration

Add this to the engines: section of your SearXNG settings.yml. Replace the search_url with the address where SearXNG can reach ZimContext.

Option A: Public URL (HTTPS)

If SearXNG reaches ZimContext through its public URL:

engines:
  - name: ZimContext
    engine: json_engine
    shortcut: zim
    search_url: http://demo.carefuldream.com/zimcontext/api/search?q={query}&limit=10&offset={pageno}
    results_query: results
    url_query: url
    title_query: title
    content_query: snippet
    categories: [general]
    paging: true
    page_size: 10
    first_page_num: 0
    disabled: false
    weight: 3
    timeout: 5.0

Option B: Docker Internal Network (HTTP)

If SearXNG and ZimContext run on the same Docker network, use the container name directly. Add enable_http: true since the connection is plain HTTP:

engines:
  - name: ZimContext
    engine: json_engine
    shortcut: zim
    search_url: http://zimcontext:8080/api/search?q={query}&limit=10&offset={pageno}
    results_query: results
    url_query: url
    title_query: title
    content_query: snippet
    categories: [general]
    paging: true
    page_size: 10
    first_page_num: 0
    disabled: false
    weight: 3
    timeout: 5.0
    enable_http: true

Configuration Reference

SettingValuePurpose
enginejson_engineSearXNG's built-in generic JSON engine
search_urlZimContext API URLUse your public HTTPS URL or Docker internal address
results_queryresultsJSON path to the results array
url_queryurlJSON field containing the article URL
title_querytitleJSON field containing the article title
content_querysnippetJSON field containing the text snippet
weight3Multiplier for result ranking. Higher values = results rank above other engines. Default for most engines is 1.
page_size10Controls how {pageno} is calculated. Must match the limit value in the URL.
first_page_num0Offset starts at 0 (not 1)
timeout5.0Seconds to wait for ZimContext response
enable_httptrueRequired when search_url uses plain HTTP. Omit for HTTPS.

Per-Archive Engines

You can also add separate SearXNG engines for specific archives. This lets users filter by source in the SearXNG interface:

  - name: Wikipedia (ZimContext)
    engine: json_engine
    shortcut: zimwiki
    search_url: http://demo.carefuldream.com/zimcontext/api/search?q={query}&archive=wikipedia_en_all&limit=10&offset={pageno}
    results_query: results
    url_query: url
    title_query: title
    content_query: snippet
    categories: [general]
    paging: true
    page_size: 10
    first_page_num: 0
    disabled: false
    weight: 3
    timeout: 5.0

Use the archive keys from the archives API as the archive parameter value.

Docker Compose Example

Run SearXNG and ZimContext together on the same Docker network:

services:
  searxng:
    image: searxng/searxng:latest
    ports:
      - "8888:8080"
    volumes:
      - ./searxng/settings.yml:/etc/searxng/settings.yml
    depends_on:
      - zimcontext

  zimcontext:
    image: zimcontext:latest
    volumes:
      - ./library:/app/library
      - ./data:/app/data
    environment:
      - BASE_PATH=
      - PORT=8080

In this setup, use http://zimcontext:8080/api/search?q={query}&limit=10&offset={pageno} as the search_url with enable_http: true, since both containers communicate over the internal Docker network.

Available Archives

See the Archives page for the list of currently loaded ZIM files.

Rescan ZIM Directory

Added new ZIM files? Scan the directory to pick them up without restarting the server.

Browse Archives Search Content