Spec Driven Development
MCP Server that facilitates spec-driven development workflows, not just Vibe Coding.
Description from the maker (original English)
ETH Library Discovery API
These three are never merged into one score: opinions, measurements and popularity are different things.
We have not written a plain-language summary for this one yet. Below are the facts we read from the registry.
Pick the AI app you use, then copy the settings.
You need
Which app do you use?
Pick your app above. We remember it, so next time the button says “Install in …”.
Open Claude Desktop → Settings → Developer → Edit Config, and paste this into claude_desktop_config.json
{
"mcpServers": {
"eth-library": {
"command": "uvx",
"args": [
"eth-library-mcp"
]
}
}
}Run this in your terminal
claude mcp add eth-library -- uvx eth-library-mcpPaste into .cursor/mcp.json in your project, or ~/.cursor/mcp.json
{
"mcpServers": {
"eth-library": {
"command": "uvx",
"args": [
"eth-library-mcp"
]
}
}
}Your browser asks to open the app, then the app shows the settings and asks you to confirm. Key values are left empty for you to fill in.
Paste into .vscode/mcp.json in your project
{
"servers": {
"eth-library": {
"type": "stdio",
"command": "uvx",
"args": [
"eth-library-mcp"
]
}
}
}Your browser asks to open the app, then the app shows the settings and asks you to confirm. Key values are left empty for you to fill in.
This one runs on your computer, and ChatGPT can only connect to servers on the internet. Pick another app.
Your choice stays on this device in a cookie; no account needed.
These settings are generated from the maker’s registry entry. If the README says otherwise, follow the README.
Runs on your computer; the tool list appears in your AI app after you install it.
We check information anyone can see; we have not read the code. Checks that do not apply are left out of the count. · Checked Nov 7, 2026
The registry name was verified with the GitHub account malkreide, which owns the repo
We have not read this repo from GitHub yet
We have not read this repo from GitHub yet
This one runs on your computer; there is no internet endpoint
Runs on your computer and uses local settings instead
Runs on your computer; we can only read tool lists from internet endpoints
Compared with every active server in this category in the registry. Stars count only when the publisher owns the repo.
It passed 1 of 1 applicable basic checks. We have not read the code. Before adding a key or token, see what access the server asks for and use a key with only the permissions you need.
The registry does not list a required key, though some servers ask you to sign in on first use.
It runs on your computer. Your AI app starts it when needed, and data does not pass through the maker’s servers (unless it calls an online service itself).
The GitHub repo last changed –, and the latest version (0.4.0) reached the registry 2 months ago.
Apps that support MCP, such as Claude Desktop, Claude Code, Cursor and VS Code. You also need Python (uv) on your computer.
In the same category: Spec Driven Development, Remote Desktop Commander, Qemu MCP
Servers in the same category from other makers, sorted by stars.
Reading a card:★ GitHub starsiThree pillars: reviews · checks · usageiUpdated = latest version published to the registryi
MCP Server that facilitates spec-driven development workflows, not just Vibe Coding.
Remote Desktop Commander: use files, terminal and processes on your own computers from any AI app.
Boot and drive QEMU VMs from an AI agent: keys, screenshots, serial. No guest agent.
Copied from the maker’s repo as written. PopNx MCP has not reviewed or endorsed it. HTML, images and scripts are removed. Links lead off this site.
🇨🇭 Part of the [Swiss Public Data MCP Portfolio](https://github.com/malkreide)
🌐 English | [Deutsch](README.de.md)
MCP server giving AI models direct access to 30M+ resources at ETH Library Zurich – books, maps, images and archival material.
eth-library-mcp connects AI assistants like Claude to the largest natural-science library in Switzerland. It exposes full-text search, archive-level queries and resource-type filtering via the ETH Library's Discovery API – all through a single, standardised MCP interface.
6 Tools · 1 API · 2 Resources · 2 Prompts
MCP Protocol Version: 2026-07-28 (via mcp[cli]>=2.0.0,<3).
BUG-02 is resolved — by removing the tool.
eth_search_personswas documented
as "currently non-functional, correct URL to be verified". It has now been verified,
and there is no correct URL: the Persons API is gone from the gateway, not merely
locked. The gateway routes *before* it checks the API key, so an existing route
answers
401and a missing one answers404—/discovery/v1/resourcesgives 401,
every
/persons/v1/*path gives 404, and so does a deliberately invented Discovery
path used as a control. Offering a capability that cannot exist is the same mistake as
returning an empty result, only louder. The measurement is recorded and dated in
tests/fixtures/api_routes.json.
Anchor demo query: *"Find historical documents about Zurich school history in the ETH Library archives."*
# Clone the repository
git clone https://github.com/malkreide/eth-library-mcp.git cd eth-library-mcp
pip install -e .
uv pip install -e .
# Set the API key
export ETH_LIBRARY_API_KEY=your_key_here # macOS / Linux
python -m eth_library_mcp.server
Without an API key the server returns a helpful error message with the registration link – no crashes.
Try it immediately in Claude Desktop:
*"Find books about Swiss education history in the ETH Library."*
*"Search the Max Frisch archive for manuscripts about Zurich."*
→ More use cases by audience →
| Variable | Description | Required |
|---|---|---|
ETH_LIBRARY_API_KEY | API key for the Discovery API | ✅ |
ETH_LIBRARY_LOG_LEVEL | Log level (DEBUG/INFO/WARNING/ERROR), default INFO | — |
ETH_LIBRARY_CORS_ORIGINS | Comma-separated CORS allow-origins for --http. Empty by default: no browser client is permitted. * allows any origin and is logged as a warning. Does not affect stdio clients. | — |
ETH_LIBRARY_ALLOWED_HOSTS | Comma-separated hostnames this server is reachable under. Required for a non-loopback bind (--host 0.0.0.0): the process cannot derive its own public name, and without this the SDK answers 421 Invalid Host header to every request. Empty by default; loopback stays reachable either way. | — |
{
"mcpServers": { "eth-library": { "command": "python", "args": ["-m", "eth_library_mcp.server"], "env": { "ETH_LIBRARY_API_KEY": "your_key_here" } } } }
Config file locations:
~/Library/Application Support/Claude/claude_desktop_config.json%APPDATA%\Claude\claude_desktop_config.jsonFor use via claude.ai in the browser (e.g. on managed workstations without local software):
python -m eth_library_mcp.server --http --port 8000
The HTTP transport binds to 127.0.0.1 by default. To expose it on another interface, pass --host explicitly:
# Only behind a reverse-proxy / firewall that terminates TLS and enforces auth.
python -m eth_library_mcp.server --http --host 0.0.0.0 --port 8000
⚠️ Do not bind to `0.0.0.0` without a reverse proxy. The server has no
built-in auth, rate-limiting or TLS — any LAN neighbour could call your tools.
💡 *"stdio for the developer laptop, HTTP for the browser — behind a proxy."*
| Tool | Description |
|---|---|
eth_search_resources | Full-text search over 30M+ resources with fields, operators, facets |
eth_get_resource | Full metadata for a specific resource via MMS-ID |
eth_search_archive | Search within a specific archive (University Archives, Max Frisch, Thomas Mann, etc.) |
eth_search_by_type | Filter by resource type (books, maps, images, archival material, etc.) |
eth_search_education | Curated search for education topics (pedagogy, school history, etc.) |
| Tool | Description |
|---|---|
eth_library_info | Server overview: all types and archives at a glance |
| Item | Type | Description |
|---|---|---|
eth://resource-types | Resource | All available resource types |
eth://archives | Resource | All available archives and collections |
research-workflow | Prompt | Structured research workflow |
education-research | Prompt | Education topics workflow (Schulamt-optimised) |
The Discovery API uses structured queries:
field,operator,value
| Field | Meaning |
|---|---|
any | All fields (recommended for starters) |
title | Title only |
creator | Author / creator |
sub | Subject headings / topics |
| Operator | Meaning |
|---|---|
contains | Term is present |
exact | Exact match |
begins_with | Starts with |
Examples:
any,contains,Volksschule Zürich
title,contains,Pädagogik creator,exact,Einstein Albert sub,contains,Bildungsforschung title,contains,Schule;sub,contains,Geschichte
| Identifier | Description |
|---|---|
ETH_Hochschularchiv | Institutional memory of ETH Zurich |
ETH_MaxFrischArchiv | Estate of Swiss author Max Frisch |
ETH_ThomasMannArchiv | Letters and documents of Thomas Mann |
ETH_GraphischeSammlung | Prints, drawings, graphic works |
ETH_Bildarchiv | Science/technology history, Swissair (E-Pics) |
| Query | Tool |
|---|---|
| *"Find books about Zurich school history"* | eth_search_education |
| *"What's in the Max Frisch archive?"* | eth_search_archive |
| *"Find historical maps of Switzerland"* | eth_search_by_type |
| *"Get full metadata for resource ID 991170525863705501"* | eth_get_resource |
| *"Which archives does the ETH Library hold?"* | eth_library_info |
eth-library-mcp/
├── src/ │ └── eth_library_mcp/ │ ├── init.py # Package init, version │ └── server.py # FastMCP server, all tools ├── tests/ │ └── test_server.py # Unit tests ├── CHANGELOG.md ├── CONTRIBUTING.md # Contribution guide (English) ├── CONTRIBUTING.de.md # Contribution guide (German) ├── SECURITY.md # Security posture (English) ├── SECURITY.de.md # Security posture (German) ├── LICENSE ├── README.md # This file (English) ├── README.de.md # German version ├── claude_desktop_config.json # Example Claude Desktop configuration └── pyproject.toml # Build configuration
This server speaks two protocol eras over the same endpoint. The client's first request on a connection decides which one applies; a later claim from the other era is refused.
| Era | Revision | Who reaches it |
|---|---|---|
initialize handshake | 2024-11-05 … `2025-11-25` | What today's clients speak. The server answers with the revision asked for, or with the 2025-11-25 ceiling when the request asks for something newer. |
| Per-request envelope | `2026-07-28` | A request carrying the 2026-07-28 _meta envelope opens a modern connection. |
Both revisions are pinned in tests/test_protocol_version.py and asserted against the installed SDK, so a Dependabot bump of mcp cannot move either one silently. The handshake ceiling is measured against a live initialize through the assembled ASGI stack, not read off a constant name.
Note that the SDK's LATEST_PROTOCOL_VERSION is an alias for the modern era, not for the handshake era — pinning against it alone would leave the era that current clients actually negotiate free to drift.
Update policy. When the gate fails, do not edit the constant blindly: read the spec changelog between the two revisions, verify the server still behaves, then move the constant, this section, README.de.md and CHANGELOG.md together.
serverInfo)2026-07-28 stamps the server's Implementation block into every modern result under _meta.io.modelcontextprotocol/serverInfo (spec #3002) — earlier revisions carried it only in the initialize result. What used to be a one-time field is now repeated on every call, and version is required.
The SDK fills none of it: *"An unversioned server reports an empty version; the SDK never substitutes its own."* Measured against the assembled ASGI stack, this server used to answer "version": "" in both eras while server.json told the registry 0.3.4. It now declares:
| Field | Value | Source |
|---|---|---|
name | eth-library-mcp | the programmatic identifier — the same string as the distribution name in pyproject.toml, packages[0].identifier in server.json and the suffix of the registry name io.github.malkreide/eth-library-mcp. It used to read eth_library_mcp, the module path: a name under which this server is available nowhere. |
title | ETH-Bibliothek Zürich | SERVER_TITLE in server.py — the only value with no source outside |
version | the installed distribution's version | importlib.metadata, so it cannot drift from pyproject.toml |
description | the distribution summary | importlib.metadata |
websiteUrl | the Homepage project URL | importlib.metadata |
icons stays unset: this repository ships none, and an invented path would assert a file that does not exist.
M
Only the beginning is shown; read the rest in the repo