ndl-mcp

ndl-mcp

MCP server for searching the National Diet Library of Japan (NDL Search), enabling Japanese-script bibliographic and article searches with rate limiting and attribution.

Category
Visit Server

README

ndl-mcp

An MCP server for searching 国立国会図書館サーチ (NDL Search), operated by the National Diet Library of Japan, over the SRU searchRetrieve interface.

Third in a series with cinii-mcp and jstage-mcp, and sharing their response envelope: typed query and script, matching mode, graduated breadth, per-item matched_in, typed diagnostics, a loggable receipt, attribution.

Before you run this

There is no credential. The NDL search APIs are open. No API key, no application ID, no token, nothing to paste into a config file. If you are waiting for something to arrive before you can use this, you are waiting for something that is not coming.

There is still an obligation. Section 17 of APIのご利用について asks continuous API users to report their contact details and the nature of their use through the application form — 「事前の利用申請の要否にかかわらず」, whether or not a prior usage application is required of them. A formal 利用申請 is required only for revenue-generating use; the notification is asked of everyone who accesses continuously.

Because access is not gated on the filing, nothing in the world will stop you skipping it. So install.ps1 stops you: it refuses to register the server until the notification is recorded, and writes the date to NDL-API-NOTIFICATION.txt.

.\install.ps1 -NotificationFiled 2026-08-19

Run it without the flag and it prints the form URL, offers to open it, and exits.

What the server will not do

The undertakings below were filed with the NDL. They are implemented, not aspired to, and the installer's smoke test asserts the first three:

Undertaking Implementation
Requests issued serially; no concurrent access _rate_lock is held across the wait and the request
Minimum one-second interval MIN_REQUEST_INTERVAL = 1.0
A cap on records per search; no bulk retrieval MAX_RECORDS = 100, a fifth of the NDL's own 500; no auto-pagination
The harvesting interface is not used OAI-PMH is not implemented
Credit on every response ATTRIBUTION plus provider_credit() on every envelope
Metadata displayed, not accumulated no cache, no local store

Change any of them and you are changing what was declared to a national library. File a supplementary notification first.

Providers

Only the five sets declared in the application are reachable. All are NDL-created and CC BY, and none requires a usage application:

dpid 名称
iss-ndl-opac 国立国会図書館蔵書
iss-ndl-opacnational 国立国会図書館全国書誌情報
zassaku 国立国会図書館雑誌記事索引
zassaku-online 国立国会図書館雑誌記事索引オンライン資料編
ndl-dl-open 国立国会図書館デジタルコレクション(オープンデータ)

ndl-dl and ndl-dl-online — the wider Digital Collections — are marked △ on the provider list and require an application that has not been made. A request naming them is refused in process, with a DPID_NOT_PERMITTED diagnostic, rather than sent.

Tools

Tool Set searched
ndl_search_books 蔵書
ndl_search_national_bibliography 全国書誌情報
ndl_search_articles 雑誌記事索引 (both sets)
ndl_search_digital_open デジタルコレクション(オープンデータ)
ndl_search_all all five
ndl_get_record one record by jpno or ndl_bib_id

Search fields: title, creator, publisher, subject, anywhere, ndc, isbn, issn, from_year, to_year. They are combined with AND; title, creator, publisher and subject match partially, ndc by prefix, identifiers exactly.

ndl_get_record is a fetch, so its envelope omits searched_for — no term was chosen.

Two things that will bite

An uppercase AND, OR or NOT inside a search term makes NDL reject the whole query. Not "returns nothing" — rejects. The rule is case-sensitive as the specification states it: War AND Peace is caught, War and Peace passes. The server checks before sending and returns a RESERVED_WORD_IN_QUERY diagnostic naming the offending field, rather than letting the library answer with a parse failure.

NDL enforces a rate limit it will not quantify, and answers HTTP 429. The help page says only 「同時リクエスト数には制限を設けています」 and declines to publish a figure. In testing on 19 August 2026 a 429 arrived at well under one sustained request per second — so the one-second floor filed with the library is a minimum, not a guarantee. A 429 buys one backoff, honouring Retry-After, and then the server stops rather than pressing. It reports RATE_LIMITED, deliberately distinct from API_ERROR, because the two mean different things to a reader: a rate-limited search has an unknown result, not an empty one, and must never be written up as an absence.

A romanised term will under-return. NDL Search indexes Japanese-language records in Japanese script. A Latin-script query against a Japanese corpus is the romaji trap, and the envelope raises SCRIPT_LATIN_QUERY for it. The searched_for headline exists so that the term the assistant actually chose is visible at the top of the response rather than buried — that is the whole point of the field, and the reason a disclosure can report the terms a search used.

Receipts

mediation.emit() writes each response envelope to the append-only, hash-chained ledger at MCP_RECEIPT_LOG, which install.ps1 sets to the same file the other servers use. Unset the variable and nothing is written and nothing fails.

Note what the ledger holds and what it does not: the query, the normalised term, the parameters sent, the timestamp, a SHA-256 over query and parameters, and the identifiers of the records returned. It does not hold the bibliographic records themselves. Logging a query is not accumulating a database, and the undertaking against accumulation is not breached by keeping the receipt — but the distinction is worth stating rather than assuming, because the two look similar from outside.

Why SRU only

The application declares SRU and OpenSearch. This server implements SRU alone, which is less than was declared and therefore safe — you may always use less than you told the library you would.

The reason is evidential. The OpenSearch response format is not documented in the 第1.4版 specification: no element table, no sample, and the appendices cover SRU and OAI-PMH only. Worse, the spec states that a malformed parameter returns a zero-result response rather than an error — 「引数(パラメータ)誤りの場合には検索結果ゼロ件となる」 — so a typo in a field name is indistinguishable from a genuine absence. For a tool whose purpose is to let a historian trust that nothing was found, that is disqualifying. SRU returns typed diagnostics and a documented DC-NDL record schema. Adding OpenSearch later needs no new notification; it needs a documented response format.

Sources

Licence

MIT. Metadata retrieved through this server is CC BY 4.0 from the National Diet Library; the credit line the server emits is the attribution that licence requires, and it should survive into anything you publish from the results.

What has been tested, and what has not

Verified against the live API on 19 August 2026:

  • Japanese-script search across 蔵書 and 雑誌記事索引 — correct totals, correct records, correct years and identifiers.
  • DC-NDL parsing, including the manifestation-stub filter. NDL returns two BibResource elements per record; taking both doubled the result set with blanks until the filter went in.
  • searched_for reports the term chosen, not the assembled CQL, so its script detection is meaningful; the exact CQL is carried in query.params and is fixed by the receipt hash.
  • The DPID_NOT_PERMITTED guard: a request naming ndl-dl is refused in process.
  • RESERVED_WORD_IN_QUERY: War AND Peace caught, War and Peace passed.
  • The rate limiter, involuntarily — see HTTP 429 above.

Not verified against the live API, and read rather than run: the "Record does not exist" passthrough, ndl_get_record, and the backoff path. Testing stopped at the 429 rather than continuing, because characterising an undisclosed rate limit by probing it is precisely the 継続して大量のアクセス the terms warn about, and the point of this server is not to be the thing the National Diet Library has to block. Exercise those paths in ordinary use, a query at a time.

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured