Arviro
Provides search and reading of Kiwix ZIM files, enabling offline access to content such as Wikipedia and Wikivoyage through a local kiwix-serve instance.
Integrates with Ollama embedding models to enable semantic search, allowing questions to find relevant passages by meaning across languages.
Enables search and reading of OpenStreetMap extracts to answer questions about places and what is near them.
Allows searching and reading offline Wikipedia articles from Kiwix ZIM files, with evidence checks for name confirmation and suggestions for misspellings.
Allows searching and reading offline Wikivoyage travel guides from Kiwix ZIM files.
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., "@Arvirosearch my library for how to make water safe to drink"
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.
Arviro
Arviro is a small MCP server that lets a local language model search and read your own offline library:
documents in folders on disk (PDF, Markdown, text, HTML, CSV, JSON);
Kiwix ZIM files such as an offline Wikipedia or Wikivoyage;
OpenStreetMap extracts, for questions about places and what is near them.
Everything runs on your own computer. Arviro only reads; it cannot change your files, and it does not use the internet.
It is made for chat apps that speak MCP, such as Open WebUI with a model served by Ollama.
What the model gets
Two tools:
Tool | What it does |
| Searches one source and returns the best passages, each with ready-made arguments for reading on. |
| Returns part of a document (by page for a PDF, by line otherwise) or of an encyclopedia article. |
Some things are built in because small local models need them:
One source per search. The model chooses a source; the tool description lists your sources with your own descriptions.
Search by meaning and by words. Passages are found with SQLite full-text search and, when Ollama is available, with embeddings. A Dutch question finds an English manual.
An evidence check for "who is X?" questions. A name only counts as confirmed when a source has exactly that title. An unknown name gives "not found", and a misspelled name in an encyclopedia gives "did you mean…", so the model has no reason to make something up.
Bounded answers. Results are short, long documents are read in parts, and each part says how to continue.
Protection against loops. A repeated identical call gets the earlier result back with a note to stop, and there is a call budget per minute.
Private and public sources. Sources marked
privateare only served on/mcp;/public/mcpleaves them out. This lets you give housemates the library without your personal notes; see Security for what that takes.
Related MCP server: DocAgent-MCP
Requirements
Node.js 22.13 or newer.
Optional, depending on what you want to search:
Ollama with an embedding model, for search by meaning (
ollama pull qwen3-embedding:0.6b);pdftotextfrom poppler, for PDF files;kiwix-servefrom kiwix-tools, for ZIM files;osmiumfrom osmium-tool, for map data.
On macOS with Homebrew: brew install node poppler osmium-tool. Download kiwix-tools from kiwix.org and put kiwix-serve in your PATH or in ~/.local/bin.
Install
git clone https://github.com/ymebosma/arviro.git
cd arviro
npm install
mkdir -p ~/.config/arviro
cp arviro.config.example.json ~/.config/arviro/config.jsonEdit ~/.config/arviro/config.json so that it points at your own folders (see Configuration). Then:
node bin/arviro.js doctor # checks the configuration and the helper programs
node bin/arviro.js index # builds the search index; run it again after adding documents
node bin/arviro.js serve # starts the server on http://127.0.0.1:8765npm link makes the arviro command available everywhere, so you can type arviro serve.
Try a search without any chat app:
node bin/arviro.js search library "how do I make water safe to drink?"
node bin/arviro.js read library manuals/water.mdUse with Open WebUI
Open WebUI (0.6.31 or newer) connects to MCP servers over Streamable HTTP, which is what arviro serve offers.
Start Arviro:
arviro serve.In Open WebUI, as admin, open Settings and choose Integrations in the admin part. At External Tool Servers press + and fill in:
Type: MCP (Streamable HTTP)
URL:
http://127.0.0.1:8765/mcp, orhttp://127.0.0.1:8765/public/mcpfor the sources without your private onesAuth: None, or Bearer with the token when you have set one
ID:
arviro
With Access Control you decide which users may use the connection. To give yourself all sources and others only the public ones, add two connections with different IDs.
In a chat, switch the tool on with the integrations button under the message box. To have it on by default, create a model under Workspace → Models: choose your Ollama model as base, paste a system prompt (see
examples/), and tick the Arviro tool server. Leave function calling on Native.
Open WebUI puts the connection ID in front of the tool names, so with the ID arviro the model sees arviro_search_library and arviro_read_document. It calls its MCP support experimental; this setup was tested with Open WebUI 0.11.4.
Two things that matter for local models:
Give the model enough context. Tool results are a few thousand tokens each; a context of 16k tokens or more works well.
Open WebUI adds its own built-in tools in native mode. For a strictly offline assistant, switch those off for the model (Capabilities → Builtin Tools).
If Open WebUI runs in Docker, 127.0.0.1 is the container itself. Set server.host to 0.0.0.0, add host.docker.internal:8765 to server.allowedHosts, set server.authToken and server.publicToken, and use http://host.docker.internal:8765/mcp with Auth Bearer.
Use with other MCP clients
Clients that start MCP servers themselves can use the stdio transport:
{
"mcpServers": {
"arviro": {
"command": "node",
"args": ["/path/to/arviro/bin/arviro.js", "stdio"]
}
}
}Add "--public" to the arguments to leave out private sources.
Configuration
The configuration is one JSON file: ~/.config/arviro/config.json, or the file named by --config or $ARVIRO_CONFIG. Paths may start with ~; relative paths are relative to the configuration file.
{
"dataDir": "~/.local/share/arviro",
"sources": {
"library": {
"path": "~/Library/Offline",
"description": "Offline reference library: emergency plans, first aid, survival guides and technical manuals.",
"expandQueries": true,
"routes": [{ "prefix": "medical", "terms": ["first aid", "medical"] }]
},
"notes": { "path": "~/Notes", "description": "Personal notes.", "private": true }
},
"kiwix": { "zimDir": "~/Library/Offline/zim" },
"maps": { "regions": { "nl": "~/Library/Offline/maps/netherlands-latest.osm.pbf" } }
}Setting | Meaning |
| Where the search index is kept. Default |
| A folder with documents. The id is what the model uses to choose the source. |
| One sentence telling the model what is in the source. Worth writing well. |
|
|
|
|
| Narrows a search to a folder when the question contains one of the terms. If that finds nothing, the whole source is searched. |
| Extra folder or file names to leave out. |
| A folder with |
| Descriptions per ZIM source, for example |
| Port for the kiwix-serve process that Arviro starts on 127.0.0.1. Default 8767. |
| List of ZIM source ids to treat as private, for example |
| OpenStreetMap extracts ( |
| Description of the map source for the model, and |
|
|
| Default |
| Default |
| Bearer token for |
| Bearer token for |
| Extra |
| How similar a passage must be when none of the question's words occur in it. Default 0.76, tuned for |
| List of |
| Size of one part returned by |
| Loop protection: at most 20 calls per 60 seconds for one connection, and 120 for all connections together. |
| Paths of the helper programs, when they are not found automatically. |
Documents
Arviro indexes .md, .txt, .html, .csv, .tsv and .json files up to 8 MB, and .pdf files up to 64 MB.
A PDF can have a text copy that is used in its place, for indexing and for reading. That is useful for a scanned PDF, or when you have a better text version than pdftotext gives. The copy is report.txt next to report.pdf, or in a sibling folder named text (or tekst) when the PDF is in documents (or documenten). Results still point at the PDF and its page numbers, provided the copy has a form feed between pages, as pdftotext writes it.
When the folder of one source lies inside the folder of another, its documents belong to the inner source only. A private folder inside a public one therefore stays private.
Updating
Run arviro index after adding or changing documents. It only processes what changed, and a running server picks up the new index by itself. arviro index --full rebuilds everything.
If a source folder cannot be read during a run, for example because a disk is not connected, its documents stay in the index.
Run it as a service on macOS
examples/launchd.plist is a LaunchAgent that starts Arviro at login and restarts it when it stops. Replace the paths in it, copy it to ~/Library/LaunchAgents/local.arviro.plist and load it:
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/local.arviro.plistSecurity
Read-only.
read_documentonly returns documents that a source offers. Paths are resolved first, so a symbolic link cannot lead outside the source or into a hidden or excluded folder.Local by default. The server listens on 127.0.0.1. Requests that carry a web page's
Originheader or an unknownHostheader are refused, so a website in your browser cannot query it.No login by default. Without tokens, every program and every user on the computer can call both endpoints. Private sources are then kept from the public endpoint, but not from someone who calls
/mcpdirectly. Setserver.authTokenwhen that matters, and always when the host is not 127.0.0.1.Private and public. To share only the public sources with other people, give their chat app the
/public/mcpURL and keep the token of/mcpto yourself. In Open WebUI that means two connections, each with its own access control.Documents are untrusted input. The tool descriptions tell the model so, but a model can still be misled by text in a document. Do not connect Arviro to a model that can also take actions you would not want a document to trigger.
Error messages to the model never contain file paths; details go to the server's log.
Development
npm testThe tests build a small library in a temporary folder and use stand-ins for Ollama, kiwix-serve, osmium and pdftotext, so none of those need to be installed.
Layout: bin/arviro.js is the command line; src/arviro.js ties the sources together; src/documents.js, src/kiwix.js and src/osm.js search; src/reader.js reads files; src/indexer.js builds the index; src/mcp.js and src/http.js expose it over MCP.
Not there yet
Map search only knows places and amenities that OpenStreetMap stores as a point. A hospital or shop drawn as a building outline is not found yet.
Downloading and updating library content (ZIM files, map extracts).
Pages to view articles and maps in a browser, so answers can link to them.
A tool for the assistant's own notes and tasks.
License
MIT; see LICENSE.
This server cannot be deployed
Maintenance
Related MCP Connectors
Read-only MCP server exposing a user ORANO library to their own AI agent.
Agentic search over your Dewey document collections from any MCP-compatible client.
Search your AI chat history (ChatGPT, Claude, Codex) from any MCP client. Remote, private, read-only
Related MCP Servers
- AlicenseAqualityBmaintenanceAn MCP server that provides offline access to ZIM file archives, including Wikipedia, medical knowledge, and maps. It dynamically exposes tools like search, article retrieval, and driving route planning based on available ZIM files.4MIT
- FlicenseNot gradedqualityDmaintenanceEnables local document question-answering and retrieval via MCP, supporting multi-turn conversation, intent recognition, and tools for document search, Q&A, and summarization.5-
- AlicenseNot gradedqualityBmaintenanceOpenZIM MCP Server provides AI models structured, offline access to ZIM format knowledge archives (Wikipedia, Wiktionary, Stack Exchange, Kiwix Library) via a Model Context Protocol server with smart namespace navigation, full-text search with suggestions, structure-aware retrieval (sections, tables of contents, related articles), link-graph extraction, archive-type presets, and both Simple (single natural-language tool) and Advanced (8 specialized tools) modes with streamable HTTP transport, bearer auth, and per-entry resources with subscriptions.MIT
- FlicenseNot gradedqualityBmaintenanceEnables agents to search and retrieve clean, structured content from local offline ZIM archives such as Wikipedia, medical docs, DevDocs, and Stack Exchange through a unified MCP interface.-