Skip to main content
Glama

corpus-mcp

Un servidor local MCP que ofrece a un agente un acceso limpio y eficiente a un corpus de conocimiento local de archivos ZIM sin conexión — Wikipedia, artículos médicos, documentación para desarrolladores (DevDocs) y Stack Exchange — a través de una interfaz uniforme. Sin internet, sin embeddings, sin base de datos vectorial: búsqueda de texto completo con libzim y una limpieza determinista del contenido dentro del propio servidor.

La superficie pública de MCP son exactamente dos herramientas:

search(query, limit?)
fetch(ref, sections?)

El corpus configurado es un asunto del operador, no del agente. El agente solo:

discover  →  search()
select    →  fetch()

Familias de corpus

Corpus

kind

Documento

Modelo de secciones

Wikipedia, MDWiki

article

artículo

árbol de encabezados (h2+), sección inicial con id ""

DevDocs (C, CMake, Python)

documentation

página de documentación

árbol de encabezados; TOC de la página y elementos de navegación eliminados

Stack Exchange

thread

pregunta + respuestas

secciones sintéticas: question, accepted-answer, answer-<id>

Toda la identificación del corpus, el enrutamiento, el acceso a ZIM, la interpretación del HTML, la limpieza, la clasificación, el manejo de redirecciones y la normalización siguen siendo responsabilidades del servidor. El agente nunca tiene que parsear HTML, resolver redirecciones, construir o parser alguna referencia, ni conocer nada sobre libzim, los espacios de nombres de ZIM o los detalles del almacenamiento del corpus.

Related MCP server: mcpzim

References

search() devuelve resultados con un ref opaco (p. ej., corpus://Wikipedia/Bell_test); fetch() lo consume. El agente no debe nunca construir, parsear o modificar de null, ni inde que la from derivar el corpus a partir de un ref:

search() produces ref      fetch() consumes ref

Arquitectura

Local agent
    │  MCP / Streamable HTTP  →  http://127.0.0.1:8000/mcp
    ▼
┌──────────────────────────────────────────────┐
│ Corpus MCP Server                            │
│  search()  fetch()                           │
│  ├─ CorpusManager (routing, cache,          │
│  │   bounded-concurrency fan-out)           │
│  ├─ federated ranking (RRF + lexical title  │
│  │   reranking + diversity)                 │
│  ├─ adapters: mediawiki / devdocs /         │
│  │   stackexchange                           │
│  ├─ HTML cleaner → Markdown, section trees  │
│  └─ GlobalRef codec (opaque refs)           │
└─────────────┬────────────────────────────────┘
              ▼
      per-library ZIM service (only libzim touchpoint,
      one search lock per archive)
              ▼
      corpus/  (read-only volume, N .zim archives)
      corpus.toml  (manifest: name, adapter, path)

La capa MCP no expone información de libzim: no espacios de nombres, IDs de clúster, entradas en bruto, tipos MIME ni HTML en bruto.

Prerequisitos

  • Docker y Docker Compose

  • Archivos ZIM (ver más abajo)

  • Para ejecutar la suite de pruebas localmente: Python 3.12 y uv (o pip)

Estructura del corpus

El servidor nunca descarga los lugares por sí mismo — la adquisición del corpus está deliberadamente desacoplada del arranque de la aplicación. Copia las estructura por defecto:

corpus/
  wikipedia/wikipedia_en_all_nopic_*.zim
  medical/mdwiki_en_all_maxi_*.zim
  devdocs/devdocs_en_cpp_*.zim
  devdocs/devdocs_en_cmake_*.zim
  devdocs/devdocs_en_python_*.zim
  stackexchange/stackoverflow.com_en_all_*.zim
  stackexchange/security.stackexchange.com_en_all_*.zim
  stackexchange/softwareengineering.stackexchange.com_en_all_*.zim
corpus.toml

corpus.toml names cada biblioteca, su adaptador y su ruta (relativa a la raíz del corpus):

version = 1

[[library]]
name = "Wikipedia"
path = "wikipedia/wikipedia_en_all_nopic_2026-06.zim"
adapter = "mediawiki"

[[library]]
name = "CMake-Docs"
path = "devdocs/devdocs_en_cmake_2026-08.zim"
adapter = "devdocs"

Reglas de validación: nombres únicos, adaptadores conocidos, rutas que deben permanecer dentro de la raíz del corpus. Verifica un corpus antes de iniciar el servidor:

make validate-corpus   # opens every archive, reports metadata
make corpus-list       # list configured libraries

Inicio / apagado

make start           # build + start (docker compose, detached)
make logs            # tail logs
make ps              # container status
make stop            # stop (keep containers)
make down            # stop + remove
make restart
make build

El endpoint MCP queda disponible en http://127.0.0.1:8000/mcp (Streamable HTTP). El puerto del host está vinculado a loopback por defecto; el contenedor escucha en 0.0.0.0:8000 internamente.

Si no se puede abrir algún ZIM configurado, el servidor falla al iniciar e indica la bibliotecaproblemática; no hay un modo parcialmente funcional.

Esquemas de las herramientas

search(query: str, limit?: int) (Busca en el índice de texto completo de todas las bibliotecas configuradas (con concurrencia acotada, un worker por archivo), fusiona las listas clasificadas con Reciprocal Rank Fusion, reordena los candidatos empatados entre corpus por la cobertura léxica de título, aplica una pasada determinista dediversidad y devuelve resultados limpios. limit se limita por defecto a 5; el servidor impone un máximo absoluto (SEARCH_MAX_LIMIT, por defecto 10).

{
  "results": [
    {
      "ref": "corpus://Wikipedia/Bell_test",
      "library": "Wikipedia",
      "kind": "article",
      "title": "Bell test",
      "snapshot": "2026-06",
      "snippet": "To close the detection loophole, an apparatus with a high detection efficiency is needed.",
      "relevant_sections": [
        { "id": "Notable_experiments", "title": "Notable experiments" },
        { "id": "Loopholes", "title": "Loopholes" }
      ]
    }
  ]
}
  • ref: identificador global opaco; pásalo de vuelta a fetch().

  • library / kind / snapshot: procedencia — qué archivo, qué tipo de documento y la instantánea del corpus (derivada de los metadatos del archivo).

  • relevant_sections: 0–3 and hints léxicos deterministas (vacío cuando ninguna sección coincide claramente). Los IDs de sección son determinados por el servidor; el agente no debe reconstruirlos.

Una única biblioteca con fallos degrada la búsqueda (las demás siguen respondiendo) pero nunca la matra.

fetch(ref: str, sections?: list[str])

Devuelve el documento limpio en formato Markdown estructurado.

  • Sin sections: el documento completo (limitado por MAX_FETCH_CHARS; truncated: true si se corta en el límite de una sección).

  • Con sections: solo esas secciones (incluidos los subárboles). Los IDs de sección provienen de los avisos de search() o de available_sections. La sección inicial tiene el id "". En los hilos las secciones son question, accepted-answer y answer-<id>; su metadata contiene lo puntaje, aceptación y etiquetas.

{
  "ref": "corpus://Wikipedia/Bell_test",
  "library": "Wikipedia",
  "kind": "article",
  "title": "Bell test",
  "snapshot": "2026-06",
  "sections": [
    { "id": "Loopholes", "title": "Loopholes", "content": "## Loopholes\n\n..." }
  ],
  "available_sections": [
    { "id": "", "title": "Bell test" },
    { "id": "Background", "title": "Background" },
    { "id": "Loopholes", "title": "Loopholes" }
  ],
  "truncated": false
}

Los errores son concursos y ofrecen una orientación:

{ "error": "invalid_ref", "message": "invalid reference: ..." }
{ "error": "not_found", "message": "Document not found in Wikipedia: Foo_bar" }
{
  "error": "section_not_found",
  "missing_sections": ["Experiments"],
  "available_sections": [ { "id": "Loopholes", "title": "Loopholes" }, "..." ]
}

Ejemplo de flujo de un payload

search("Bell experiment loopholes")
    ↓
fetch("corpus://Wikipedia/Bell_test", ["Notable_experiments", "Loopholes"])

Configuración

Variables de entorno (valores predeterminados del contenedor):

Variable

Default

Meaning

CORPUS_ROOT

/corpus

Directorio raíz del corpus dentro del contenedor (obligatorio)

CORPUS_CONFIG

/config/corpus.toml

Ruta del archivo de configuración dentro del contenedor (obligatorio) (obligatorio)

MCP_HOST

0.0.0.0

Dirección de escucha dentro del contenedor

MCP_PORT

8000

Puerto de escucha dentro del contenedor

SEARCH_LIMIT

5

limit por defecto para search()

SEARCH_MAX_LIMIT

10

Máximo absoluto para search(limit=…)

MAX_FETCH_CHARS

100000

Límite de salida para el contenido recuperado por fetch()

SEARCH_WORKERS

8

Búsquedas concurrentes en archivos durante el fan-out

SEARCH_MAX_CONSECUTIVE

2

Pasada de diversidad: máximo de resultados consecutivos de una misma biblioteca

LOG_QUERIES

true

Registrar el texto de las consultas (privacidad)

ZIM_CHECK

false

Ejecutar la verificación completa de suma de comprobación de libzim (bytes exies) al arrancar (lee todo el corpus: optativo, lento en copias grandes)

Variables de Docker, lado central: CORPUS_ROOT (default ./corpus) y CORPUS_CONFIG (default ./corpus.toml).

El servidor falla rápido antes una configuración no válida.

Tests

make test     # unit + integration + MCP surface tests (needs .venv)
make lint
make format

Configuración para una ejecución local de pruebas:

uv venv .venv --python 3.12
uv pip install -e . --python .venv/bin/python
uv pip install --python .venv/bin/python pytest pytest-asyncio ruff
make test

Las pruebas generan sus propios fixtures ZIM con sunergy-writer de libzim (corpus por biblioteca); no es necesario corpus real. La prueba de regresión de la superficie MCP comprueba que el servidor expone exactamente dos herramientas search y fetch, y no expone prompts ni recursos.

Postura de seguridad

Servicio local por diseño: bind del host únicamente a loopback por defecto, volúmenes introspection de corpi read-onmembers-only, el contenedor se ejecuta con un usuario no root, no tiene modo privilegiarlo, no hay socket de Docker, no hay acceso arbitrario al sistema de archivos, no se realiza fetching de URLs y no se ejecutan comandos shell. Ninguna herramienta acepta rutas de archivos, URLs, comandos ni contenido ejecutable —/tmp/reuse is no. ref es simplemente un identificador opaco y exclusivo.

F
license - not found
Not graded
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    A
    quality
    A
    maintenance
    Enables AI models to access and search offline Wikipedia and other knowledge bases stored in ZIM format files. Provides intelligent content retrieval, structured browsing, advanced search capabilities, and metadata extraction for comprehensive offline knowledge access.
    1
    118
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    An 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.
    4
    MIT
  • 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.
    19
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables offline CRUD and semantic search on Wikipedia ZIM archives via MCP tools for reading, writing, editing, deleting, and searching articles.
    1
    MIT

View all related MCP servers

Related MCP Connectors

  • Shared, peer-validated knowledge archive for AI agents — search, contribute, and validate via MCP

  • Agentic search over your Dewey document collections from any MCP-compatible client.

  • Agent-native MCP server over the public saagarpatel.dev corpus. Read-only, stateless.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/MagoDelBlocco/mcp-wiki'

If you have feedback or need assistance with the MCP directory API, please join our Discord server