{
  "markdown": "# IWAC MCP Server\n\n[![CI](https://github.com/fmadore/iwac-mcp-server/actions/workflows/ci.yml/badge.svg)](https://github.com/fmadore/iwac-mcp-server/actions/workflows/ci.yml)\n[![Latest release](https://img.shields.io/github/v/release/fmadore/iwac-mcp-server?label=release)](https://github.com/fmadore/iwac-mcp-server/releases/latest)\n[![MCP Registry](https://img.shields.io/badge/MCP_Registry-io.github.fmadore%2Fiwac--mcp--server-0a7ea4)](https://registry.modelcontextprotocol.io/?search=iwac)\n[![License: MIT](https://img.shields.io/badge/license-MIT-blue)](LICENSE)\n[![DOI](https://img.shields.io/badge/DOI-10.5281%2Fzenodo.21805837-blue)](https://doi.org/10.5281/zenodo.21805837)\n\nA read-only [Model Context Protocol](https://modelcontextprotocol.io/) server for the\n[Islam West Africa Collection (IWAC)](https://islam.zmo.de/s/westafrica/).\nShips as a one-click [Desktop Extension](https://github.com/modelcontextprotocol/mcpb)\n(`.mcpb`) for Claude Desktop, backed by the\n[IWAC Hugging Face dataset](https://huggingface.co/datasets/fmadore/islam-west-africa-collection).\nAlso available as a **hosted endpoint** at `https://islam.zmo.de/mcp/` for ChatGPT\nand other MCP clients — see [docs/connecting.md](docs/connecting.md) for the\nfull connection walkthrough (Claude Desktop and ChatGPT).\n\n## Install\n\nEach [release](https://github.com/fmadore/iwac-mcp-server/releases) ships a\nserver bundle **for your operating system** plus a research-skill `.zip`. The\n`.mcpb` gives Claude the data and tools; the `.zip` adds a research skill that\nteaches Claude *how* to use them. Install the server first, then **install the\nskill too — strongly recommended** for getting the most out of the tools: it\nmakes Claude search and synthesize far more efficiently, with fewer wasted\nqueries.\n\n### 1. The MCP server — pick the bundle for your OS\n\n| Your OS                            | Download                       |\n| ---------------------------------- | ------------------------------ |\n| Windows (Intel/AMD or Snapdragon)  | `iwac-mcp-server-windows.mcpb` |\n| macOS (Apple Silicon or Intel)     | `iwac-mcp-server-macos.mcpb`   |\n\n1. Download the bundle for your OS from\n   [Releases](https://github.com/fmadore/iwac-mcp-server/releases).\n2. Double-click the file. Claude Desktop shows an install dialog — click **Install**.\n3. On first use the server downloads ~250 MB of parquet data from Hugging Face\n   into `~/.iwac-mcp/cache/` (override in the extension settings).\n\nNo Python, no `uv`, no venv — the bundle ships a self-contained Node runtime and\nthe DuckDB binaries for your OS (x64 and arm64; Claude Desktop picks the right\none). Claude Desktop has no Linux build, so no Linux bundle is published.\n\n### 2. The research skill — `iwac-mcp-skill.zip` (strongly recommended)\n\nThe [`iwac-mcp` skill](.agents/skills/iwac-mcp/SKILL.md) wraps the raw tools in a\nstructured research workflow: a five-phase methodology, francophone search\nstrategy, source attribution with confidence grading, and bias/coverage caveats.\n**It makes the server far more efficient to use** — Claude picks the right tool\nand search terms on the first pass (fewer wasted queries), searches French\nsources properly, and returns a cited synthesis instead of a raw tool dump. You\ncan run the tools without it, but you'll get more out of every query with it\ninstalled.\n\nDownload `iwac-mcp-skill.zip` from the same release, then:\n\n- **Claude Desktop** — open **Customize → Skills → + → Create skill → Upload a\n  skill** and select the zip. (Or unzip it into `~/.claude/skills/` and restart\n  Claude Desktop.)\n- **Claude Code** — unzip it into your skills directory; Claude Code discovers it\n  live, no restart needed:\n\n  ```bash\n  # macOS / Linux\n  unzip iwac-mcp-skill.zip -d ~/.claude/skills/\n  ```\n\n  ```powershell\n  # Windows (PowerShell)\n  Expand-Archive iwac-mcp-skill.zip -DestinationPath $HOME\\.claude\\skills\\\n  ```\n\n  Both land the skill at `~/.claude/skills/iwac-mcp/`. The repository source of\n  truth is `.agents/skills/iwac-mcp/`; keep project-local copies there rather\n  than duplicating the same skill under `.claude/`.\n\n  Installing it this way is still worth doing: an installed skill is matched\n  against your question automatically, before any tool is called.\n\n#### The server also serves the skill (`skill://`, prototype)\n\n> **Prototype.** This is an experiment tracking a draft spec, not a supported\n> interface. The URIs and the catalogue shape may change or be withdrawn\n> without a major version bump. Installing the skill from the `.zip` above is\n> still the supported path on Claude Desktop and Claude Code. Do not rely on\n> `skill://` in anything you build.\n\nEvery build also embeds the skill and exposes it as MCP resources, so a client\nthat has not installed it can still read it:\n\n| Resource | What it is |\n| --- | --- |\n| `skill://iwac-mcp` | Catalogue: every file with its size and SHA-256 digest |\n| `skill://iwac-mcp/SKILL.md` | The workflow itself |\n| `skill://iwac-mcp/references/…` | The four reference files, read on demand |\n\nA host that implements the draft extension can instead discover the same\ncatalogue through `skills/list` and `skills/get`, which the server declares via\nthe `io.modelcontextprotocol/skills` capability. Both routes read one catalogue,\nso they cannot disagree.\n\nThis matters most for the remote HTTP endpoint, where there is no release\nartifact to download: add the connector and the manual comes with it. The\nserver's handshake instructions point at `skill://iwac-mcp/SKILL.md`, and\nnothing is pushed into the context until something asks for it.\n\nThe shape follows [SEP-2640](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/2640)\n(\"Skills over MCP\"), **an open draft PR against the MCP spec: not accepted, and\nsubject to change**. Two routes reach the same catalogue: the `resources/*` one\nabove, which every current client already speaks, and the extension's own\n`skills/list` / `skills/get`, for hosts that implement the draft. The SEP's one\noptional method, `resources/directory/read`, is **not** served — the bare\n`skill://iwac-mcp` is this server's catalogue document and cannot also be a\ndirectory resource — so the capability is declared without `directoryRead`.\nIf the SEP changes shape or is rejected, all of this moves with it.\n\n## What it gives Claude\n\n37 possible read-only tools across seven IWAC subsets. **34 work out of the\nbox**; the 3 `semantic_search_*` tools are optional and require a free\nGoogle/Gemini API key (disabled by default). All keyword and filter matching is\naccent- and case-insensitive. The unified `search`/`fetch` pair, the stats\ntools, the aggregates, `list_periodicals`, and `get_sentiment_distribution` also\nreturn MCP structured content (`outputSchema` + `structuredContent`), which the\nChatGPT connector contract requires.\n\n| Group        | Tools                                                                                       |\n| ------------ | ------------------------------------------------------------------------------------------- |\n| Cross-subset | `search`, `fetch`                                                                           |\n| Articles     | `search_articles`, `get_article`, `semantic_search_articles`                                |\n| Sentiment    | `search_by_sentiment`, `get_sentiment_distribution`                                         |\n| Index        | `search_index`, `get_index_entry`, `list_subjects`, `list_locations`, `list_persons`        |\n| Stats        | `get_collection_stats`, `get_newspaper_stats`, `get_country_comparison`, `get_temporal_distribution` |\n| Aggregates   | `get_topic_distribution`, `get_field_distribution`, `get_cooccurrence`, `get_lexical_metrics`, `get_place_distribution`, `get_semantic_map`, `get_similar_items` |\n| Publications | `search_publications`, `list_periodicals`, `get_publication_fulltext`, `semantic_search_publications` |\n| References   | `search_references`, `get_reference`                                                        |\n| Images       | `search_images`, `get_image`, `semantic_search_images`                                      |\n| Other        | `search_documents`, `get_document`, `search_audiovisual`, `list_audiovisual`, `get_audiovisual` |\n\nThe **aggregates** answer questions about a whole set rather than returning its\nitems: how it spreads across the 30 precomputed LDA topics, which subjects,\nplaces or bylines dominate it, what gets discussed alongside what, how its prose\nreads, where on a map it points, how it lays out in embedding space, and what a\ngiven item's nearest neighbours are. Eleven tools in all — the stats family plus\nthese — declare an MCP App view, so in Claude they render as interactive charts\nrather than JSON.\n\n`get_temporal_distribution` also reads the **Islamic calendar**. With\n`granularity=\"lunar_month\"` it pools every year into the twelve lunar months —\nthe one bucket a Gregorian axis structurally cannot produce, because the Hijri\nyear drifts ~11 days annually and so smears each observance across all twelve\nGregorian months. Over the 13,261 fully-dated articles the archive's rhythm is\nplain: Ramadan +74%, Dhu al-Hijja +68% (hajj and Tabaski) and Shawwal +42%\n(Korité) against an even split, while Rabi' I — Maouloud — sits flat. `search_articles`\nand `search_publications` take `hijri_month` (1–12 or a name in either\ntransliteration) and `hijri_year` to read the items behind a peak. The lunar\ndates are precomputed in the dataset pipeline with the Umm al-Qura tables, the\nsame converter the on-this-day block on islam.zmo.de uses, so the two never\ndisagree; items dated only to a year or month have no lunar date and are reported\nin `imprecise_date_count` rather than plotted.\n\nThe three full-text tools — `get_article`, `get_document`, and\n`get_publication_fulltext` — optionally take a `keyword` to return ~2000-char\nexcerpts around each match, so Claude reads just the relevant passages of a long\narticle, archival document, or periodical issue instead of the whole OCR.\n\nEvery result object includes a `url` field pointing at the canonical IWAC record,\ne.g. `https://islam.zmo.de/s/afrique_ouest/item/28576`.\n\n## About the collection\n\nIWAC is a digital archive focused on Islam and Muslims in West Africa:\n\n- **12,000+ newspaper articles** from Benin, Burkina Faso, Côte d'Ivoire, Niger,\n  and Togo, 1960s–present (mostly French), each with an AI abstract and AI\n  sentiment analysis (polarity / centrality / subjectivity), scored\n  independently by five models — `gpt-5-6-luna` (the one the inline columns\n  report), `mistral-small-2603`, `deepseek-v4-flash-0731`, `gemma-4-31b-it` and\n  `qwen3-8-27b`. All five agree on polarity for only ~32% of articles, so\n  `get_sentiment_distribution(model=\"all\")` is the honest way to quote a figure.\n  They do not all cover the same articles either — `qwen3-8-27b` scores 12,098\n  where the rest score 12,298 — so each model reports its own `coverage`.\n  `model=\"consensus\"` returns the panel's precomputed majority (not a sixth\n  model), and `search_by_sentiment(disputed=…)` reads the articles it split on\n- **4,700+ authority records** (persons, organisations, places, events, subjects)\n- **1,500+ Islamic publications** (periodical issues, books) with full OCR\n- **860+ academic references**, half with abstracts\n- **1,700+ audiovisual items** — francophone web video from Burkina Faso, Togo\n  and Benin (harvested from public channels, still growing, searchable by\n  channel and reachable through a watch URL), plus 47 deposited Nigerian\n  Hausa/Arabic recordings with files — and archival documents\n\n## Architecture\n\n- **Data**: parquet files from the\n  [IWAC Hugging Face dataset](https://huggingface.co/datasets/fmadore/islam-west-africa-collection)\n  are lazily downloaded per subset (articles, publications, documents,\n  audiovisual, index, references) into a local cache and queried through DuckDB\n  views. All SQL is parameterised; matching is accent/case-insensitive.\n- **Transports**: stdio (the default — what the Claude Desktop `.mcpb` uses),\n  and a stateless Streamable-HTTP mode (`node server/index.js --http`) behind a\n  bearer token, which the Docker image runs for the hosted\n  `https://islam.zmo.de/mcp/` endpoint.\n- **Docker**: every release publishes `ghcr.io/fmadore/iwac-mcp-server` for\n  self-hosting the HTTP endpoint — see\n  [`mcpb/README.md`](mcpb/README.md#remote-http--docker-deployment) for the\n  required env vars and token setup.\n\n## Develop\n\nThe bundle lives under [`mcpb/`](mcpb/). See [`mcpb/README.md`](mcpb/README.md)\nfor the build / pack workflow.\n\n```bash\ncd mcpb\nnpm install\nnpm run install-bindings   # fetch the 4 macOS/Windows DuckDB binaries\nnpm run typecheck   # tsc --noEmit\nnpm run lint        # biome (linter only)\nnpm run build       # esbuild -> single server/index.js\nnpm test            # unit tests + offline fixture & HTTP MCP round-trips (no network)\nnpm run test:live   # full smoke test against the real HF dataset (~250 MB)\n```\n\nCI runs the version check, typecheck, lint, build, unit tests, and the offline\nfixture + HTTP round-trip tests on every push to `main` and every pull request;\nthe live smoke test runs weekly (its pinned counts are the dataset-drift alarm).\nReleases: push a `v*` tag — the release workflow re-runs the full test suite,\npacks the per-OS `.mcpb` bundles and skill zip, smoke-tests and pushes the\nDocker image, uploads the release assets, and publishes to the MCP Registry.\n\n## Roadmap\n\nSee [TODO.md](TODO.md) — near-term: submit to the Anthropic extension directory,\nsign the bundle with a production code-signing cert, and replace Gemini\nsemantic-search with a free local model.\n\n## How to cite\n\nMachine-readable metadata lives in [CITATION.cff](CITATION.cff) — GitHub's\n**Cite this repository** button (sidebar) renders it as APA or BibTeX with the\ncurrent version filled in. In text:\n\n> Madore, F. (2026). *IWAC MCP Server* (Version 3.6.0) [Computer software].\n> Zenodo. https://doi.org/10.5281/zenodo.21805837\n\n```bibtex\n@software{madore_iwac_mcp_server,\n  author    = {Madore, Frédérick},\n  title     = {{IWAC MCP Server}},\n  year      = {2026},\n  version   = {3.6.0},\n  publisher = {Zenodo},\n  doi       = {10.5281/zenodo.21805837},\n  url       = {https://github.com/fmadore/iwac-mcp-server},\n  license   = {MIT}\n}\n```\n\nThat DOI is the **concept DOI** — it always resolves to the newest release, so it\nstays correct as versions come and go. If you need to cite the exact version you\nran, take the per-version DOI from the\n[Zenodo record](https://doi.org/10.5281/zenodo.21805837).\n\nIf the software helped you reach a finding, please cite the\n[collection itself](https://islam.zmo.de/s/westafrica/) as well — that is where\nthe archival work lives.\n\n## License\n\n[MIT](LICENSE)\n\n## Related\n\n- [IWAC Hugging Face Dataset](https://huggingface.co/datasets/fmadore/islam-west-africa-collection)\n- [IWAC Digital Archive](https://islam.zmo.de/s/westafrica/)\n- [Desktop Extensions spec (MCPB)](https://github.com/modelcontextprotocol/mcpb)\n\n## Optional private full-text access\n\nPublic data remains the default and needs no token. In the desktop extension,\nenable **Use private full dataset**, enter the **Hugging Face token (private dataset only)**,\nand restart. Use a fine-grained token with read access to\n`fmadore/islam-west-africa-collection-full`. The token field is marked sensitive.\nNever paste your token into a chat or commit it.\n\nOther local launchers can set `IWAC_PRIVATE_DATASET=true` and provide\n`IWAC_HF_TOKEN` (or `HF_TOKEN`). A token alone does not enable private mode;\npublic downloads do not send it. No new dependency or account system is needed.\n\nPrivate files use a separate `private-full/` subdirectory of `IWAC_CACHE_DIR`\n(default: `~/.iwac-mcp/cache`). Restart after changing modes. Missing tokens\nand private HTTP 401/403/404 errors fail without cache fallback. Network outages\nmay use that mode's cache. Explicit `IWAC_OFFLINE=true` uses downloaded files\nwithout authentication; removing a token does not erase private files.\n\nKeep the shared hosted endpoint public. This setting applies to the whole instance:\neveryone who can query a private instance can access its full text.\n",
  "bytes": 16172,
  "sha": "bc352a3e93fcf2408016028f9c12c5118161584e33ea938eda850f927169400e",
  "repo_slug": "fmadore/iwac-mcp-server",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_fmadore_iwac_mcp_server_89d6a062/readme"
}