Skip to main content
Glama

DDB MCP Server

MCP server and CLI for the Deutsches Zeitungsportal, the newspaper collection of the Deutsche Digitale Bibliothek (DDB). Search the full text of ~33.8 million digitised German newspaper pages, of which roughly 27.9 million fall between 1850 and 1949.

  • search: full Solr syntax over page OCR — exact phrases, boolean operators, wildcards, fuzzy matching and proximity — with filters for date, title, place, language and holding institution. Every hit is an individual page, and comes with highlighted snippets showing where the query matched.

  • facets: list the values a filter can take, with page counts — the places, holding institutions, languages and newspaper titles the index actually holds, either across the whole corpus or within one query's results.

  • snippets: locate a query inside one page or across every page of an issue you already have in hand.

  • get: download the OCR text of a page or a whole issue, cached locally.

There are two ways to use it: an MCP server for clients that speak MCP, and a ddb CLI for agents driven through a shell. Both share one client, one cache and one set of behaviours. The CLI is what the bundled ddb-search skill uses.

Installation

Install the code

uv sync

Install the CLI

uv tool install .        # puts `ddb` on your PATH

Install to MCP CLIs

Installs to Claude Code, Codex CLI, and Gemini CLI:

uv run ddb-mcp-install

Verify the installation:

claude mcp list   # For Claude Code
codex mcp list    # For Codex CLI
gemini mcp list   # For Gemini CLI

Related MCP server: bbaw-dse-mcp

Usage

ddb search '"Luftschiffhafen Friedrichshafen"'                # 29 pages, 1909-1935
ddb search '"Luftschiffhafen Friedrichshafen"' --pages all    # sweep a bounded query
ddb search 'Zeppelin' --from-year 1900 --to-year 1910 --rows 50
ddb search 'Straßenbahn AND Unfall' --place Berlin
ddb facets place                                              # places the index holds, by page count
ddb facets place 'Zeppelin' --limit 5                         # where a term appears
ddb facets title 'Zeppelin' --from-year 1900 --to-year 1910   # which papers carried it
ddb snippets BGQICR4U4JYQ35MJ35MNBWQSJ6LA7KDR 'Zeppelin'      # where it appears in an issue
ddb get BGQICR4U4JYQ35MJ35MNBWQSJ6LA7KDR-ALTO10268886_DDB_FULLTEXT   # cached OCR text path

Add --json for machine-readable output.

--place and --provider match a whole string, which is what facets is for. They are Solr string fields, so a near-miss is not a near-miss: --place Halle reports 0 pages matched with no error at all, while --place 'Halle (Saale)' matches 1.1 million pages. Institution names are worse, being long and official — Bayerische Staatsbibliothek matches 8.3 million pages and Bayerische matches none. ddb facets place and ddb facets provider print the values verbatim, so they can be copied across. --title is the forgiving one: it is analysed text with German stemming, so a fragment of a title is enough.

Given a query, facets describes that result set rather than the corpus, which makes it a characterisation tool as much as a lookup: the geography of a term, or the newspapers that carried it. Counts are computed by the index over the whole result set, not over the results already fetched. facets title lists ZDB identifiers with one recorded title form each — the title field is stemmed text and facets into word stems (zeitung, nachricht) rather than titles, so titles are counted through zdb_id and labelled afterwards. The label is a signpost, not a date-accurate title: the recorded string describes a paper's whole run, so a date-bounded listing can show a subtitle the paper only acquired later. The identifier beside it is the exact thing, and goes straight into --zdb-id.

The filters the portal itself offers are year, title, place, provider and language, and all five are here. There is no facet for publication frequency, region or state, subject, format, contributor or material type: those fields are absent from this index, not merely unexposed.

Search already includes snippets, which is the important workflow difference from the sibling clients. DDB returns highlighted excerpts in the search response itself, so judging a hit costs nothing beyond the search that found it. Reach for get only when a page or issue is worth reading at length. Use --no-snippets when you want a compact listing.

There is no date ordering, deliberately. publication_date is a Solr DateRangeField and the server refuses to sort on it, so results always come back by relevance. Rather than offer a flag that quietly reordered only the handful of results already fetched — a chronology in name while the selection stayed relevance-ranked — the client omits it. Chronological work means bounding the query with --from-year/--to-year and sweeping the range with --pages all; the ordering then falls out of the sweep.

The result total is a true count. Solr reports numFoundExact, and it survives checking: "Luftschiffhafen Friedrichshafen" reports 29 results and returns exactly 29 documents, spanning 1909 to 1935. This is unlike Gallica, whose totals are a ranking depth — here a total can be quoted, and a swept query really has been swept.

Downloads are cached in $XDG_CACHE_HOME/ddb-mcp (override with --cache-dir or DDB_CACHE_DIR). The cache location does not depend on the working directory, so the CLI can be run from anywhere.

Requests are paced one per second by default, overridable with DDB_MIN_REQUEST_INTERVAL. DDB publishes no rate limit for this endpoint, sends no rate-limit headers, and serves no robots.txt on the API host; none was observed across roughly eighty requests including a deliberate burst. One second is therefore a conservative choice, not a measured ceiling — there is no evidence about where the real limit sits, only that ordinary use does not come near it.

API key

None is needed: the newspaper search index answers unauthenticated. That may be an unenforced gate rather than deliberate policy, so if you hold a DDB API key, set DDB_API_KEY and the client will send it — the CLI keeps working if enforcement is ever switched on.

Where to get one: https://www.deutsche-digitale-bibliothek.de/user/apikey — the key page inside your DDB account. It needs a free DDB account first, registered at https://www.deutsche-digitale-bibliothek.de/user/register; once logged in, the key is generated on that page and shown immediately.

It is free and needs no institutional affiliation. Per DDB's own documentation, "Alle registrierten Nutzer*innen der Deutschen Digitalen Bibliothek können sich einen Authentifikationsschlüssel für die Verwendung der APIs erzeugen lassen" — any registered DDB user can have a key generated, from the Meine DDB area of their own account. There is no paid tier and no approval step.

Then:

export DDB_API_KEY=your_key_here

Both links live on the www host, which serves an anti-bot challenge to scripted clients but passes a real browser transparently — so open them in a browser, and expect curl to get a challenge page instead. The apikey URL is DDB's own, taken from the documentation page linked above; the registration path has not been walked through here.

MCP server

Run the server directly:

uv run ddb-mcp

Test with MCP Inspector:

uv run fastmcp dev src/ddb_mcp/server.py

Available Tools

3 tools
download_ddb_textA

Download the OCR text of a page, or of every page of an issue.

Args: identifier: A page id ('ITEMID-pagename') or an issue item id ('ITEMID') refresh: Ignore any cached copy and fetch again

Returns: Path to the cached text file. Files run to tens of kilobytes per page, so read slices of them rather than the whole thing.

ParametersJSON Schema
NameRequiredDescriptionDefault
refreshNo
identifierYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden. It discloses caching behavior (refresh parameter), file size advice, and that the tool returns a path to a text file. This adds useful behavioral context beyond a simple 'download' statement.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with a purpose statement, parameter explanations, and return value note. Every sentence contributes meaningful information without redundancy. It is appropriately sized for the tool's complexity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given that an output schema exists, the description adds useful context about return values (path, file size, read slice advice). The tool has two simple parameters, and the description covers all necessary aspects for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, but the description fully compensates by explaining both parameters: identifier format ('ITEMID-pagename' or 'ITEMID') and refresh function. Each parameter's semantics are clearly defined.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool downloads OCR text for a page or all pages of an issue. It uses a specific verb ('Download') and resource ('OCR text'), and distinguishes from siblings (get_ddb_snippets and search_ddb) by focusing on full-text download.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides implied usage context (use when you need OCR text) but does not explicitly state when to use this tool versus alternatives like get_ddb_snippets or search_ddb. No exclusions or when-not-to-use guidance is given.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_ddb_snippetsA

Find where a query appears inside one page or one whole issue.

Args: identifier: A page id ('ITEMID-pagename') or an issue item id ('ITEMID') query: Solr query over page OCR text

Returns: The matching pages, with snippets showing the terms in {braces}.

ParametersJSON Schema
NameRequiredDescriptionDefault
queryYes
identifierYes

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden and clearly indicates a non-destructive read operation by stating 'Find' and 'Returns'. It explains the output format (pages with snippets in {braces}) but does not explicitly mention read-only behavior, which is a minor gap for complete transparency.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is extremely concise: one sentence for the purpose, followed by a clear arg/return list. Every sentence adds value without redundancy. It is front-loaded with the core action, making it easy for an agent to quickly grasp the tool's purpose.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's simplicity (two string params, no output schema), the description is complete: it explains what the tool does, how to use the parameters, and what the output looks like. It provides sufficient context for an agent to select and invoke the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema has 0% description coverage, but the description adds significant meaning: 'identifier' is explained as a page id ('ITEMID-pagename') or issue item id ('ITEMID'), and 'query' is described as a Solr query over page OCR text. This goes well beyond the bare schema types, compensating fully for the lack of schema descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool finds where a query appears inside one page or one whole issue. It uses a specific verb ('find') and resource ('page' or 'issue'), and distinguishes itself from sibling tools like search_ddb (likely broader search) and download_ddb_text (download full text) by focusing on snippet extraction within a specific identifier.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage when you have a page or issue identifier and want OCR snippets, but it does not explicitly state when to use this tool versus its siblings. No exclusions or alternatives are mentioned, leaving the agent to infer the context from the tool's specific functionality.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_ddbA

Search German newspaper pages in the Deutsches Zeitungsportal.

Covers ~33.8M digitised pages, densest between 1850 and 1949. Results are individual newspaper pages, and each carries highlighted snippets showing where the query matched, with matched terms in {braces} - so a single search is usually enough to judge a hit without downloading anything.

Args: query: Solr query over page OCR text. Supports: - Exact phrases: '"Bert Reese"' - Boolean operators: 'Hellseher AND Telepathie', 'A OR B', 'A NOT B' - Wildcards: 'Hellseh*' - Fuzziness for OCR damage: 'Hanussen~1' - Proximity: '"Hellseher Hanussen"~10' page: Result page number, 1-indexed rows: Results per page (max 100) from_year: Earliest publication year, inclusive to_year: Latest publication year, inclusive paper_title: Restrict to one newspaper title place: Restrict to a place of distribution language: Language code, ISO 639-2 (e.g. 'ger')

Returns: total_results (a true count, not a ranking depth), total_pages, and the matching pages with their metadata, viewer URL and snippets. Results are ordered by relevance; DDB cannot order by date, so chronological work means bounding the query with from_year/to_year and sweeping it whole.

ParametersJSON Schema
NameRequiredDescriptionDefault
pageNo
rowsNo
placeNo
queryYes
to_yearNo
languageNo
from_yearNo
paper_titleNo

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations provided, so description carries full burden. Discloses ordering limitation (cannot sort by date), snippet format (matched terms in braces), and result semantics (total_results as true count). Clearly describes behavioral traits beyond schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Well-structured with a clear introductory sentence followed by coverage, result format, and parameter details. Slightly verbose but front-loaded with key information. Every section adds value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (8 parameters, no output schema), the description is remarkably complete. Covers purpose, coverage, result format, behavioral quirks, and detailed parameter usage. No significant gaps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, but the description provides extensive parameter details in the Args list, including query syntax (phrases, booleans, wildcards, fuzziness, proximity), and explanations for each field. Fully compensates for missing schema descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Clearly states the tool searches German newspaper pages in the Deutsches Zeitungsportal. Specifies the resource and action, and implies differentiation from siblings by noting that results include snippets.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides context on coverage (33.8M pages, densest 1850-1949), result format (pages with snippets), and ordering (relevance only). Offers guidance for chronological work but no explicit when-not-to-use or alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.

  1. 3 tool updatesv0.1.0
    • First observeddownload_ddb_text
    • First observedget_ddb_snippets
    • First observedsearch_ddb

TDQS

A4.5/5.0
Disambiguation5/5

Each tool has a distinct purpose: search_ddb for searching across the database, get_ddb_snippets for finding query matches within a specific page or issue, and download_ddb_text for downloading OCR text. No overlap in functionality.

Naming Consistency4/5

All tool names follow a consistent verb_noun pattern in snake_case. However, 'get' and 'download' are slightly different verbs for similar retrieval actions, causing minor inconsistency.

Tool Count5/5

With 3 tools covering search, snippet retrieval, and text download, the count is well-scoped for the domain of accessing digitized newspaper pages. No excess or shortage.

Completeness4/5

The tool set supports a complete workflow: search across pages, examine snippets in context, and download full text. Minor gap: no dedicated metadata retrieval tool, but metadata is included in search results.

Maintenance

ActivitySlowing
ResponsivenessNo issues

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

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

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    B
    maintenance
    Enables searching and accessing OCR text from millions of digitized documents in Gallica, the digital library of the Bibliothèque nationale de France, through MCP tools for text search, snippet retrieval, and full-text download.
    3
    1
    Apache 2.0
  • A
    license
    A
    quality
    B
    maintenance
    Enables natural-language querying of multiple digital scholarly editions, aggregating Schleiermacher digital, Praktiken der Monarchie, and correspSearch into a single MCP endpoint.
    44
    MIT
  • A
    license
    A
    quality
    A
    maintenance
    A local MCP server for searching scientific papers, retrieving metadata and abstracts, and legally downloading Open Access PDFs via OpenAlex, CrossRef, and Unpaywall APIs.
    5
    3
    MIT
  • A
    license
    A
    quality
    C
    maintenance
    MCP server for searching and accessing historical Austrian newspapers from ANNO, providing full-text search, snippet extraction, and OCR text download.
    3
    Apache 2.0

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/nestordemeure/ddb-mcp'

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