{
  "markdown": "> 🇨🇭 **Part of the [Swiss Public Data MCP Portfolio](https://github.com/malkreide)**\n\n# 🏛️ swiss-cultural-heritage-mcp\n\n![Version](https://img.shields.io/badge/version-0.5.0-blue)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)\n[![MCP](https://img.shields.io/badge/MCP-Model%20Context%20Protocol-purple)](https://modelcontextprotocol.io/)\n[![No Auth Required](https://img.shields.io/badge/auth-none%20required-brightgreen)](https://github.com/malkreide/swiss-cultural-heritage-mcp)\n![CI](https://github.com/malkreide/swiss-cultural-heritage-mcp/actions/workflows/ci.yml/badge.svg)\n\n> MCP Server for Swiss cultural heritage — SIK-ISEA artists, Nationalmuseum collections, and the Nationalbibliothek bibliography\n\n[🇩🇪 Deutsche Version](README.de.md)\n\n---\n\n## Overview\n\n`swiss-cultural-heritage-mcp` provides AI-native access to Swiss cultural heritage data sources, all without authentication:\n\n| Source | Data | API |\n|--------|------|-----|\n| **SIK-ISEA (SIKART)** | ~17,000 Swiss artists — SIKART biographical data | opendata.swiss CKAN |\n| **Nationalmuseum (SNM)** | Museum collections (numismatics, seals, special collections) | opendata.swiss CKAN |\n| **Nationalbibliothek (NB)** | Swiss national bibliography (Helveticat) | OAI-PMH |\n| **Memoriav / Memobase** | Audiovisual heritage (photo, audio, video) | Linked Open Data (JSON-LD / Hydra) |\n| **Dodis** | Diplomatic Documents of Switzerland (documents, persons, organisations) | JSON-REST (Solr) + permalinks |\n\nThis server completes the humanistic dimension of the Swiss public data portfolio — history, literature, and art — alongside existing servers for law ([fedlex-mcp](https://github.com/malkreide/fedlex-mcp)), transport, statistics, and more.\n\nThe **memory-institution facade** (Memobase + Dodis) is exposed through three\nfederated tools — `search_heritage`, `get_heritage_item`, `list_heritage_collections` —\nrather than one tool-family per source. Every result carries **source, permalink and\nlicence**, and the licence is reported **separately for metadata and for the\ndigitised object** (they diverge: metadata is open Linked Open Data, but a\ndigitised object may be *In Copyright*). Only metadata and links are returned —\ncopyright-protected full texts (e.g. Dodis transcriptions) are never reproduced.\n\n**Anchor demo query (art):** *\"Find works by Zurich-based painters from the 19th century in the Nationalmuseum, and cross-reference with their biography in the SIK-ISEA artist database.\"*\n\n**Anchor demo query (memory institutions):** *\"Which sources on the development of the Zurich Volksschule in the 19th century can be found in the Swiss memory institutions?\"* → `search_heritage(query=\"Volksschule Zürich\", collection=\"all\", date_from=\"1800\", date_to=\"1899\")`.\n\n### Demo\n\n![Demo: Claude using heritage_cross_search](docs/assets/demo.svg)\n\n---\n\n## Features\n\n- 🏛️ **11 tools, 2 resources, 2 prompts** across five data sources\n- 🔍 **`heritage_cross_search`** — parallel search across SIK-ISEA + SNM + NB in a single call\n- 🏛️ **`search_heritage`** — federated facade over Memobase + Dodis with per-result source, permalink and split metadata/digitised-object licence\n- 🌐 **Bilingual output** (Markdown / JSON)\n- 🔓 **No API key required** — all data under open licenses\n- ☁️ **Dual transport** — stdio (Claude Desktop) + Streamable HTTP (cloud)\n- 📚 **Prompt templates** for art research and finding educational materials\n\n**Project phase:** **Phase 1 — read-only.** Every tool is annotated `readOnlyHint: true`; there are no write or destructive operations. Moving to Phase 2 (write-capable) requires the prerequisites in [`docs/roadmap.md`](docs/roadmap.md).\n\n---\n\n## Prerequisites\n\n- Python 3.11+\n- [uv](https://github.com/astral-sh/uv) (recommended) or pip\n\n---\n\n## Installation\n\n```bash\n# Clone the repository\ngit clone https://github.com/malkreide/swiss-cultural-heritage-mcp.git\ncd swiss-cultural-heritage-mcp\n\n# Install\npip install -e .\n# or with uv:\nuv pip install -e .\n```\n\nOr with `uvx` (no permanent installation):\n\n```bash\nuvx swiss-cultural-heritage-mcp\n```\n\n---\n\n## Quickstart\n\n```bash\n# stdio (for Claude Desktop)\npython -m swiss_cultural_heritage_mcp.server\n\n# Streamable HTTP (port 8000)\npython -m swiss_cultural_heritage_mcp.server --http --port 8000\n```\n\nTry it immediately in Claude Desktop:\n\n> *\"Who is Ferdinand Hodler?\"*\n> *\"What coins does the Nationalmuseum have from Zurich?\"*\n> *\"Find publications about Volksschule in the Swiss national bibliography\"*\n\n[→ More use cases by audience →](EXAMPLES.md)\n\n---\n\n## Configuration\n\n### Claude Desktop\n\nEdit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\\Claude\\claude_desktop_config.json` (Windows):\n\n```json\n{\n  \"mcpServers\": {\n    \"swiss-cultural-heritage\": {\n      \"command\": \"python\",\n      \"args\": [\"-m\", \"swiss_cultural_heritage_mcp.server\"]\n    }\n  }\n}\n```\n\nOr with `uvx`:\n\n```json\n{\n  \"mcpServers\": {\n    \"swiss-cultural-heritage\": {\n      \"command\": \"uvx\",\n      \"args\": [\"swiss-cultural-heritage-mcp\"]\n    }\n  }\n}\n```\n\n**Config file locations:**\n- macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`\n- Windows: `%APPDATA%\\Claude\\claude_desktop_config.json`\n\n### Cloud Deployment (SSE for browser access)\n\nFor use via **claude.ai in the browser** (e.g. on managed workstations without local software):\n\n**Render.com (recommended):**\n1. Push/fork the repository to GitHub\n2. On [render.com](https://render.com): New Web Service → connect GitHub repo\n3. **Select region `Frankfurt` (EU)** — required for Swiss public-sector use under revDSG / EDÖB. See [`docs/data-residency.md`](docs/data-residency.md).\n4. Set start command: `python -m swiss_cultural_heritage_mcp.server --http --port 8000`\n5. In claude.ai under Settings → MCP Servers, add: `https://your-app.onrender.com/sse`\n\n> 💡 *\"stdio for the developer laptop, SSE for the browser.\"*\n\nFor container deployments (Docker / Kubernetes / Cloud Run): the repository ships a hardened `Dockerfile` (non-root UID 10001). See [`docs/security.md`](docs/security.md) for recommended `SecurityContext` and [`docs/network-egress.md`](docs/network-egress.md) for egress policy. The service runs **single-instance** by default; before scaling horizontally, see [`docs/scaling.md`](docs/scaling.md) for the session-affinity prerequisites.\n\n---\n\n## Available Tools\n\n### SIK-ISEA (Swiss Art Research)\n\n| Tool | Description |\n|------|-------------|\n| `heritage_search_artists` | Search ~17,000 Swiss artists (SIKART) by name or place |\n| `heritage_get_artist` | Full artist profile by SIKART ID (HAUPTNR) |\n\n### Nationalmuseum (SNM)\n\n| Tool | Description |\n|------|-------------|\n| `heritage_search_museum_datasets` | Search SNM datasets on opendata.swiss |\n| `heritage_browse_collection` | Browse objects within a collection via CKAN DataStore |\n\n### Nationalbibliothek (NB)\n\n| Tool | Description |\n|------|-------------|\n| `heritage_search_helveticat` | Search Swiss national bibliography via OAI-PMH |\n| `heritage_list_nb_collections` | List available OAI-PMH sets |\n| `heritage_get_publication` | Full Dublin Core metadata for a publication |\n\n### Cross-Source\n\n| Tool | Description |\n|------|-------------|\n| `heritage_cross_search` | Parallel search across SIK-ISEA + SNM + NB |\n\n### Memory institutions (Memobase + Dodis) — federated facade\n\n| Tool | Description |\n|------|-------------|\n| `search_heritage` | Federated search over Memobase + Dodis (`collection = memobase \\| dodis \\| all`), with `date_from` / `date_to` / `media_type` filters. Every result carries source, permalink and a split metadata/digitised-object licence |\n| `get_heritage_item` | Full metadata for one object (`collection`, `item_id`). Metadata + links only — protected full texts are never reproduced |\n| `list_heritage_collections` | Discovery: which collections exist, their protocol, auth and licences — including the probed-but-not-connected sources (Bundesarchiv, Landesmuseum) and *why* |\n\n### Example Use Cases\n\n| Query | Tool |\n|-------|------|\n| *\"Who is Ferdinand Hodler?\"* | `heritage_get_artist` |\n| *\"Find Swiss artists born in Basel\"* | `heritage_search_artists` |\n| *\"What coins from Zurich does the Nationalmuseum have?\"* | `heritage_browse_collection` |\n| *\"Find publications about Volksschule\"* | `heritage_search_helveticat` |\n| *\"Search for everything about Sophie Taeuber-Arp\"* | `heritage_cross_search` |\n| *\"Sources on the 19th-c. Zurich Volksschule in Swiss memory institutions\"* | `search_heritage` |\n\n---\n\n## Architecture\n\n```\n┌─────────────────┐     ┌──────────────────────────────┐     ┌──────────────────────────┐\n│   Claude / AI   │────▶│  Swiss Cultural Heritage MCP  │────▶│  SIK-ISEA                │\n│   (MCP Host)    │◀────│  (MCP Server)                │◀────│  opendata.swiss / CKAN   │\n└─────────────────┘     │                              │     ├──────────────────────────┤\n                        │  11 Tools · 2 Resources      │────▶│  Nationalmuseum (SNM)    │\n                        │  2 Prompts                   │◀────│  opendata.swiss / CKAN   │\n                        │  Stdio | SSE                 │     ├──────────────────────────┤\n                        │                              │────▶│  Nationalbibliothek (NB) │\n                        │  No authentication required  │◀────│  OAI-PMH (Helveticat)    │\n                        │                              │     ├──────────────────────────┤\n                        │  search_heritage facade      │────▶│  Memobase (JSON-LD/Hydra)│\n                        │                              │◀────│  Dodis (JSON-REST/Solr)  │\n                        └──────────────────────────────┘     └──────────────────────────┘\n```\n\n### Data Source Characteristics\n\n| Source | Protocol | Coverage | Auth |\n|--------|----------|----------|------|\n| SIK-ISEA (SIKART) | CKAN DataStore | ~17,000 Swiss artists | None |\n| Nationalmuseum | CKAN DataStore | Museum collections | None |\n| Nationalbibliothek | OAI-PMH | Swiss national bibliography | None |\n| Memoriav / Memobase | Linked Open Data (JSON-LD / Hydra, RiC-O) | Audiovisual heritage (~460k records) | None |\n| Dodis | JSON-REST (Solr) + stable permalinks | Diplomatic documents, persons, organisations | None |\n\n### Architecture decision — memory-institution facade\n\nVerified by a live probe on **2026-07-19** (methodology: *mcp-data-source-probe*).\nFour memory institutions were evaluated; only two expose a clean, no-auth,\nstandardised interface and are connected:\n\n| Source | Result | Why |\n|--------|--------|-----|\n| **Memobase** | ✅ connected | Linked-Open-Data API (`api.memobase.ch`, JSON-LD/Hydra); full-text search via `?q=`, single record via `/record/<id>`; pagination via `offset`/`size`. Metadata open; digitised objects carry per-object `rightsstatements.org` rights (\"In Copyright\", access \"onsite\"). |\n| **Dodis** | ✅ connected | JSON-REST/Solr (`beta.dodis.ch/api`): search via `POST /api/solr/query`, item via `GET /api/solr/full/<id>`; stable permalinks `dodis.ch/<id>`. Metadata open (citation required); documents carry per-document rights (TEI/PDF behind the permalink). |\n| **Bundesarchiv** | ⛔ not connected | The `recherche.bar.admin.ch` backend (CMI AIS) sits behind **eIAM** login and **Google reCAPTCHA** — not machine-accessible without emulating a session, which is fragile and against the operator's intent. |\n| **Landesmuseum** | ⛔ not connected | `sammlung.nationalmuseum.ch` has **no public API** (only an internal, undocumented Ajax/HTML surface) — connecting it would require scraping, which violates the resilience guardrails. |\n\nConsequences: three federated tools instead of four tool-families; every result\ncarries source + permalink + a **split** metadata/digitised-object licence; no\ncopyright-protected full text is reproduced (metadata + links only); `bar` and\n`landesmuseum` are documented as gated via `list_heritage_collections`, not scraped.\n\n---\n\n## Project Structure\n\n```\nswiss-cultural-heritage-mcp/\n├── src/swiss_cultural_heritage_mcp/\n│   ├── __init__.py              # Package\n│   └── server.py                # 11 tools, 2 resources, 2 prompts\n├── tests/\n│   └── test_server.py           # Unit + integration tests (mocked HTTP)\n├── .github/workflows/ci.yml     # GitHub Actions (Python 3.11/3.12/3.13)\n├── .github/dependabot.yml       # Monthly dependency + SDK update PRs\n├── Dockerfile                   # Multi-stage, non-root, HEALTHCHECK\n├── docs/                        # security, network-egress, scaling, data-residency, roadmap\n├── pyproject.toml\n├── CHANGELOG.md\n├── CONTRIBUTING.md\n├── LICENSE\n├── README.md                    # This file (English)\n└── README.de.md                 # German version\n```\n\n> **Single-file server:** the 11 tools live in one `server.py` rather than a `tools/` package. At this size a single, linear module is easier to read and review than a split; if the tool count grows materially, the SIK-ISEA / SNM / NB / cross-search blocks are the natural split points.\n\n---\n\n## Safety & Limits\n\n- **Read-only:** All tools perform HTTP GET requests only — no data is written, modified, or deleted.\n- **No personal data:** The APIs return institutional records (artworks, publications, artists). No personally identifiable information (PII) is processed or stored by this server.\n- **Rate limits:** The opendata.swiss and OAI-PMH endpoints are not rate-limit-documented; use `limit` parameters conservatively. The server enforces a 30s timeout per request.\n- **Data freshness:** Records reflect the upstream source at query time. No caching is performed by this server.\n- **Terms of service:** Data is subject to the ToS of each source — [SIK-ISEA](https://www.sik-isea.ch), [opendata.swiss](https://opendata.swiss/terms-of-use), [Nationalbibliothek OAI-PMH](https://www.nb.admin.ch/). All data is published under open licenses (CC0 / CC BY).\n- **No guarantees:** This server is a community project, not affiliated with SIK-ISEA, SNM, or NB. Availability depends on upstream APIs.\n\n---\n\n## Known Limitations\n\n- **SIK-ISEA:** Artist data is updated periodically; very recent acquisitions may not yet be reflected\n- **Nationalmuseum:** Only datasets published on opendata.swiss are accessible; not all SNM collections are available\n- **Nationalbibliothek:** OAI-PMH harvesting is rate-limited; large result sets require pagination\n- **Cross-search:** Response time depends on the slowest of the three sources\n\n---\n\n## Testing\n\n```bash\n# Unit tests (no API key required)\nPYTHONPATH=src pytest tests/ -m \"not live\"\n\n# Integration tests (live API calls)\npytest tests/ -m \"live\"\n\n# Lint and format, as CI runs them\nruff check src/ tests/ scripts/\nruff format --check src/ tests/ scripts/\n```\n\nRuff is pinned to an exact version in `pyproject.toml` (`[project.optional-dependencies] dev`), so `pip install -e \".[dev]\"` gives you the version CI uses and the lint gates agree with it. Installing a newer ruff on top changes the rule set and the formatter, and reports differences on code nobody touched. See [CONTRIBUTING.md](CONTRIBUTING.md#code-style).\n\n---\n\n## MCP Protocol Version\n\n| Item | Value |\n|---|---|\n| SDK | `mcp[cli]>=2.0.0,<3` (pinned in `pyproject.toml`) |\n| Served via the `initialize` handshake | `2024-11-05` … `2025-11-25` — the handshake ceiling |\n| Served via the per-request envelope | `2026-07-28` |\n| Who picks | The client's first request, once per connection: a request carrying the `2026-07-28` `_meta` envelope opens a modern connection, anything else opens a handshake connection. A later claim from the other era is refused. |\n| Update policy | The SDK pin is the source of truth for the protocol version. [Dependabot](.github/dependabot.yml) opens monthly `mcp` update PRs; protocol-version bumps are reviewed there and recorded in [CHANGELOG.md](CHANGELOG.md). |\n\nThis server does not override the negotiation — the official `mcp` SDK decides, and both eras are reachable over either transport (stdio and HTTP alike). Pin the SDK, not a hand-rolled version string, to control which protocol versions are spoken. The numbers above are the pinned SDK's own registry (`mcp_types.version`: `HANDSHAKE_PROTOCOL_VERSIONS`, `MODERN_PROTOCOL_VERSIONS`) — read them there rather than from this table if the pin has moved.\n\nBoth revisions are pinned in\n[`tests/test_protocol_version.py`](tests/test_protocol_version.py) and asserted\nagainst the installed SDK — including the handshake ceiling, measured against a\nlive `initialize` through the assembled ASGI stack. A Dependabot bump of `mcp`\ncan no longer move either number without this table going stale unnoticed.\n\n---\n\n## Changelog\n\nSee [CHANGELOG.md](CHANGELOG.md)\n\n---\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md)\n\n---\n\n## Security\n\nSee [SECURITY.md](SECURITY.md) ([Deutsch](SECURITY.de.md)) for the security\nposture and how to report a vulnerability.\n\n---\n\n## License\n\nMIT License — see [LICENSE](LICENSE)\n\n---\n\n## Author\n\nHayal Oezkan · [malkreide](https://github.com/malkreide)\n\n---\n\n## Credits & Related Projects\n\n- **SIK-ISEA:** [www.sik-isea.ch](https://www.sik-isea.ch/) — Swiss Institute for Art Research\n- **Nationalmuseum:** [www.nationalmuseum.ch](https://www.nationalmuseum.ch/) / [opendata.swiss](https://opendata.swiss/)\n- **Nationalbibliothek:** [www.nb.admin.ch](https://www.nb.admin.ch/) — Swiss National Library\n- **Protocol:** [Model Context Protocol](https://modelcontextprotocol.io/) — Anthropic / Linux Foundation\n- **Related:** [eth-library-mcp](https://github.com/malkreide/eth-library-mcp) — ETH Library: full Swiss library coverage (ETH = science, NB = humanities)\n- **Related:** [fedlex-mcp](https://github.com/malkreide/fedlex-mcp) — Cultural heritage law + primary legislation\n- **Related:** [zurich-opendata-mcp](https://github.com/malkreide/zurich-opendata-mcp) — Spatial-historical: museum objects + Zurich geodata\n- **Portfolio:** [Swiss Public Data MCP Portfolio](https://github.com/malkreide)\n\n<!-- mcp-name: io.github.malkreide/swiss-cultural-heritage-mcp -->\n\n<!-- BEGIN GENERATED: install -->\n## Installation\n\nRun via [`uv`](https://docs.astral.sh/uv/)'s `uvx` — no clone or manual install needed. Add to your MCP client config (`mcpServers` for Claude Desktop, Cursor and Windsurf; use a top-level `servers` key for VS Code in `.vscode/mcp.json`):\n\n```json\n{\n  \"mcpServers\": {\n    \"swiss-cultural-heritage-mcp\": {\n      \"command\": \"uvx\",\n      \"args\": [\n        \"swiss-cultural-heritage-mcp\"\n      ]\n    }\n  }\n}\n```\n<!-- END GENERATED: install -->\n",
  "bytes": 18623,
  "sha": "39f1a3ebf5d21371cfba4c190ce65322367e739ab0378b23bf49460a5d3bdd98",
  "repo_slug": "malkreide/swiss-cultural-heritage-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_malkreide_swiss_cultural_herit_20f4842c/readme"
}