Skip to main content
Glama
kintopp

rijksmuseum-mcp+

by kintopp

rijksmuseum-mcp+

MCP Protocol MCP SDK MCP Apps

Overview

The rijksmuseum-mcp+ MCP server lets you explore the Rijksmuseum's artwork collections through natural conversation with an AI assistant. It does this by creating a bridge between the AI system's chat environment and an enriched copy of the museum's open-access, curated metadata. This in turn enables many features beyond those offered by the Rijksmuseum's own Search API and collections portal, including full-text semantic search, structured provenance analysis, artwork similarity comparisons, AI-supported visual analysis, and geospatial queries. Rijksmuseum-mcp+ works best when used together with rijksmuseum-iconclass-mcp, a sibling resource for searching and exploring Iconclass concepts.

Please do not treat the data made available by this resource as current or authoritative. It is based on data copied from the Rijksmuseum on May 2nd, 2026. For current data, please always use the Rijksmuseum's own search portal and APIs. Nor have the (in small part, also LLM based) enrichments of the museum's provenance data been reviewed or endorsed by the Rijksmuseum. This is an early pre-release of a technology demo that is still in active development.

This tool was developed as a technology demo by the Research and Infrastructure Support (RISE) group at the University of Basel. We are particularly interested in exploring the research opportunities, methodological risks, and technical challenges posed by retrieving and analysing data with LLMs. If you are interested in collaborating with us in this area, please get in touch.

Related MCP server: Cultural Heritage MCP Server

Features

  • Finding artworks. You can search by keyword, by structured filters (artist, type, material, technique, date, physical dimensions, production place), or by meaning — a semantic search that handles interpretive queries like "melancholy winter scenes at dusk". There's also iconographic search via Iconclass codes, so you can ask for works depicting a specific scene or motif rather than just matching words in titles.

  • Looking closely at works. Any artwork can be opened in an interactive, inline viewer. You can instruct the AI-assistant to inspect image regions by itself — useful for analysing a specific area of the image you've highlighted for it in the viewer. If an artwork has curator defined related artworks (e.g. preparatory sketches, or different impressions of the same design) these can be accessed through the viewer as well — its < / > buttons step through them in place, without leaving the viewer.

  • Collection-level analysis. You can ask for statistical breakdowns across the whole collection: top creators, distributions by decade, type, or theme, geographic spread, as well as demographic questions.

  • Provenance and ownership history. Trace who owned a work and when, which works passed through a particular collector or dealer, sales and confiscations in a given city or period, price histories, and how long families held their collections. This is made possible by an experimental AAM parser that permits structured, CMOA/PLOD-aligned queries.

  • Scholarly apparatus. Lookup bibliographies for individual works, reverse lookups (which artworks cite a given publication), and conservation histories including technical examinations such as X-rays, infrared, and dendrochronology.

  • Relationships between works. A similarity engine ("find images similar to..") compares works across multiple dimensions — visual, thematic, lineage, shared subject — and surfaces pendants, pairs, copies, reproductive prints after paintings, and different impressions of one design.

  • People and places. You can search persons by profession, lifespan, or birthplace and then view their works, or run geospatial queries (e.g. "works depicting places within 20 km of Haarlem").

  • Linked Open Data. Works carry persistent handle.net URIs and other external IDs, and entities (creators, materials, depicted persons and places, themes) carry identifiers linking them to Wikidata, VIAF, ULAN, and RKD.

  • Command-line interface. The bundled rijks-mcp tool runs the same queries from the terminal — each tool exposed as a verb, with JSONL output for piping into tools such as jq so that results are scriptable and reproducible.

Sample Queries

The system is designed to let you search, explore and ask questions about the Rijksmuseum's collections in natural language. For example:

  • What German artworks at the Rijksmuseum evoke vanitas and mortality?

  • Which artworks have a provenance linked to Emperor Bonaparte?

  • List all artworks which include the inscription, 'Amor vincit omnia'

  • Find artworks similar to SK-A-1115

For examples of more complex queries and sample responses, please browse the research scenarios. These demonstrate queries on a variety of topics including subject and iconographic search, curated sets, semantic search, provenance research, inscriptions and marks, and conservation.

Quick Start

The best way to get started is with Claude Desktop or claude.ai by adding rijksmuseum-mcp+ to Claude as a remotely hosted, custom 'Connector' using the URL below. This is currently free for one connector – additional connectors require a paid ('Pro') or higher subscription from Anthropic.

https://rijksmuseum-mcp-plus-production.up.railway.app/mcp

Go to CustomizeConnectorsAdd custom connector → Name it as you like and paste the URL into the Remote MCP Server URL field. You can ignore the Authentication section. Once the connector is configured, optionally set the permissions for its tools (e.g. 'Always allow'). See Anthropic's instructions for more detailed instructions.

Many other desktop and web-based clients such as OpenAI's ChatGPT or Mistral's Chat and open-source applications support remotely hosted, custom MCP servers. Please consult their documentation for more information. Alternatively, you can install rijksmuseum-mcp+ locally on your own computer. Please consult the technical guide for more details.

Afterwards, follow the same procedure to install rijksmuseum-mcp+'s sibling resource for IconClass, rijksmuseum-iconclass-mcp. This allows you to automatically search and explore c. 1.3 million IconClass notations, concepts, and descriptive texts alongside the Rijksmuseum's metadata.

Research skill

The rijksmuseum-mcp+ skill file (.zip archive) gives the AI assistant detailed guidance in natural language on how to use rijksmuseum-mcp+ effectively: which tool to choose for a given question type, how to combine searches, important metadata distinctions and known limitations. The package also includes reference files with full description of the available provenance search patterns and the find_similar functionality. Skills were originally developed by Anthropic for their Claude products but have since become an open standard. Making use of this skill is optional but will significantly improve the quality and efficiency of your AI assistant's responses when exploring the collection. The downloaded skill file can be installed in Claude by following these instructions.

How it works

When you submit a question, the AI assistant reads the descriptions of the tools provided by the MCP server together with their search parameters and then decides which combination of tools and parameters are best used to query museum's metadata for an answer. During this process, it will often chain several tools together in sequence (the so-called 'agentic loop'), each result informing the next query. For example, the assistant might search the collection using structured filters (search_artwork), look up an artwork's full metadata (get_artwork_details), query ownership history (search_provenance), or find artworks by meaning or concept (semantic_search). The results from each tool come back as structured data and text, which the AI assistant interprets, contextualises, and when satisfied, generates for you as an answer in natural language.

At each step, the AI assistant can combine the retrieved data from the Rijksmuseum with its own background knowledge — about artists, periods, iconographic traditions, and historical context — to offer interpretations that go beyond what the museum's metadata alone can provide. But any such interpretation is always 'constrained' by the curated metadata it has retrieved, by the instructions given to the AI assistant in the MCP server, and by the specialised domain knowledge and guidance it draws on from the optional research skill document. Together, these act as a kind of 'harness' for the AI assistant, keeping it factually grounded on the curated metadata and the user's query. In essence, this approach trades the conceptual simplicity of a traditional search interface, where you formulate a keyword-based query, receive results, and interpret these yourself, for a more flexible and powerful but also more complex scenario, where an AI assistant can formulate and combine queries, search metadata, and interpret the results on your behalf. In addition, the AI-assistant can offer a certain degree of 'introspection' on its actions – to explain how and why a search was conducted in a certain way, what the data it retrieved looked like, and recommend follow-up actions.

This blurs the previously clear roles and divisions of responsibility between researcher and data provider. Both sides cede some degree of autonomy to the AI systems over how research can be conducted. And so both should share a degree of responsibility over how these new AI capabilities are defined and employed.

flowchart LR
    User["You"] <-->|conversation| AI["AI Assistant"]

    AI <-->|"MCP tool calls
    (agentic loop)"| Server["rijksmuseum-mcp+
    19 tools"]

    Server --> Search["Search & Discovery
    structured filters,
    semantic search,
    collection statistics"]

    Server --> Details["Details & Metadata
    provenance chains,
    bibliography & conservation,
    similarity comparison"]

    Server --> Images["Image Inspection
    deep-zoom viewer,
    region crops for AI vision,
    overlay annotations"]

    Search --> VocabDB[("Vocab DB
    834K artworks
    418K vocab terms
    14.8M mappings")]
    Search --> EmbeddingsDB[("Embeddings DB
    834K vectors
    semantic search")]
    Details --> VocabDB
    Images --> IIIF["IIIF Image API
    iiif.micr.io"]

    subgraph Harvest ["Periodic harvest (offline)"]
        OAI["OAI-PMH
        data.rijksmuseum.nl/oai"]
        LA["Linked Art
        id.rijksmuseum.nl
        (harvest-time)"]
    end
    OAI -.->|"834K records"| VocabDB
    LA -.->|"vocab + artwork
    enrichment"| VocabDB
    VocabDB -.->|"embedding
    generation"| EmbeddingsDB

Tips and Limitations

  • If something fails unexpectedly, try disconnecting and reconnecting the connector. Because this is a hosted remote MCP server, changes to its configuration from recent updates can leave your connection in an incorrect state — symptoms include queries never being answered, generic error messages, or the AI assistant reporting that a tool is unavailable. If connecting/disconnecting does not resolve the issue, remove the custom connector (MCP server) entirely and re-add it.

  • Ask the assistant to explain which tools and filters it used. Because rijksmuseum-mcp+ exposes many overlapping search patterns (e.g. keyword filters, semantic search, spatial queries), the AI assistant sometimes picks a narrower or broader strategy than you intended. If a result seems incomplete or suspiciously tidy, ask follow-ups like "let me see the remaining artworks for this query as well", or "explain how you reached this result". Being explicit in your prompt about whether you want a structured search (e.g. "all paintings by X made in Y") versus an exploratory search (e.g. "list a few...") will help the AI assistant to interpret your question.

  • Add the optional research skill to help the AI-assistant improve the quality of its responses.

Technical notes

For local setup (stdio or HTTP, also via cli), deployment, architecture, data sources, and configuration, please see the technical guide.

Roadmap

Ongoing:

  • fix bugs and fine-tune queries and tool descriptions

  • update README and other documentation

Later:

  • paper/presentation

  • investigate DINOv3 image retrieval

  • investigate OCR/HTR of artwork images

Maybe:

  • incorporating historical exhibition data

  • integration with other Linked Open Data resources (e.g. Colonial Collections)

  • supporting inferred geolocation data

  • improving the description signal for find_similar (e.g. via a LLM re-ranker)

Authors

Arno BosseRISE, University of Basel with Claude Code, Anthropic.

Citation

If you use rijksmuseum-mcp+ in your research, please cite it as follows:

APA (7th ed.)

Bosse, A. (2026). rijksmuseum-mcp+ (Version 0.93) [Software]. Research and Infrastructure Support (RISE), University of Basel. https://github.com/kintopp/rijksmuseum-mcp-plus

BibTeX

@software{bosse_2026_rijksmuseum_mcp_plus,
  author    = {Bosse, Arno},
  title     = {{rijksmuseum-mcp+}},
  year      = {2026},
  version   = {0.93},
  publisher = {Research and Infrastructure Support (RISE), University of Basel},
  url       = {https://github.com/kintopp/rijksmuseum-mcp-plus},
  orcid     = {0000-0003-3681-1289},
  note      = {Developed with Claude Code (Anthropic, \url{https://www.anthropic.com})}
}

Image and Data Credits

Collection data and images are provided by the Rijksmuseum, Amsterdam via their Linked Open Data APIs.

Licensing: Information and data that are no longer (or never were) protected by copyright carry the Public Domain Mark and/or CC0 1.0. Where the Rijksmuseum holds copyright, it generally waives its rights under CC0 1.0; in cases where it does exercise copyright, materials are made available under CC BY 4.0. Materials under third-party copyright without express permission are not made available as open data. Individual licence designations appear on the collection website.

Attribution: The Rijksmuseum considers it good practice to provide attribution and/or source citation via a credit line and data citation, regardless of the licence applied. Please see the Rijksmuseum's information and data policy for the full terms.

This project was inspired by @r-huijts/rijksmuseum-mcp, the original Rijksmuseum MCP server based on the museum's now superseded REST API.

License

This project is licensed under the MIT License.

Available Tools

13 tools
browse_setBrowse SetA
Read-onlyIdempotent

Enumerate the member artworks of one curated set by setSpec. Get setSpec values from list_curated_sets. DB-backed (warm calls in tens of ms). Returns DB-direct records with objectNumber, title, creator, date (display + earliest/latest), description, dimensions, datestamp, image/IIIF URLs, and a stable lodUri. For multi-row vocab (subjects, materials, type taxonomy, full set memberships), follow up with get_artwork_details on the returned objectNumber. Supports pagination via resumptionToken (stateless base64; not portable across server upgrades). Not for set discovery — use list_curated_sets first.

ParametersJSON Schema
NameRequiredDescriptionDefault
setSpecNoSet identifier from list_curated_sets (e.g. '26121'). Required for initial request, ignored when resumptionToken is provided.
maxResultsNoMaximum records to return (1-50, default 10)
resumptionTokenNoPagination token from a previous browse_set result. When provided, setSpec is ignored.
includeExtentTextNoInclude the verbose extentText (dcterms:extent) per record. Default false — it is large and not rendered in the text channel.

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNo
recordsYes
totalInSetNo
resumptionTokenNo

TDQS

A4.8/5.0
Behavior5/5

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

The annotations already mark the tool as read-only, idempotent, and non-destructive. The description adds meaningful behavioral context beyond those: DB-backed performance characteristics, the exact direct-record response style, stateless pagination that is not portable across server upgrades, and the verbosity/suppression behavior of includeExtentText. No contradiction with annotations.

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?

The description is dense but justifiably so — it covers source data, return fields, pagination, a performance trait, a verbose-flag caveat, and usage boundaries. It is front-loaded with the core purpose. Slightly long, but every sentence earns its place; only a small reorganization into bullets could make it more scannable.

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 and the presence of a rich output schema, the description covers everything an agent needs to invoke it correctly: how to obtain setSpec, what records look like, when to call get_artwork_details, pagination semantics, and the exclusion for set discovery. Nothing critical is missing.

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

Parameters4/5

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

Schema description coverage is 100%, so the baseline is 3. The description adds extra semantic value by explaining where setSpec comes from, that resumptionToken makes setSpec ignored, and that includeExtentText defaults to false because the field is large and not rendered in the text channel. This goes beyond the raw schema.

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 opens with a specific verb and resource: 'Enumerate the member artworks of one curated set by setSpec.' It also explicitly distinguishes itself from list_curated_sets ('Not for set discovery') and positions itself relative to get_artwork_details, so an agent can tell exactly what this tool does versus siblings.

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

Usage Guidelines5/5

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

It gives explicit prerequisites ('Get setSpec values from list_curated_sets'), tells the agent when this tool is not appropriate ('Not for set discovery — use list_curated_sets first'), and names the follow-up alternative for more detail ('follow up with get_artwork_details'). This is strong, decision-ready guidance.

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

find_artworks_citing_publicationFind Artworks Citing a PublicationA
Read-onlyIdempotent

Reverse bibliography: artworks citing a given publication URI or id. Use the publicationUri from get_artwork_bibliography (e.g. 'https://id.rijksmuseum.nl/301154354') or the bare id. Local and resolver-free. Not for topic search of the library catalogue.

ParametersJSON Schema
NameRequiredDescriptionDefault
fullNoIf true, return ALL citing artworks. Default: first 20 + total count.
publicationYesPublication URI (https://id.rijksmuseum.nl/301…) or the bare publication id.

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNo
totalYes
artworksYesArtworks whose bibliography cites this publication. Empty when none (or bibliography not harvested).
warningsNo
publicationIdYes
publicationUriYes

TDQS

A4.7/5.0
Behavior4/5

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

Annotations already declare readOnlyHint, idempotentHint, and non-destructiveness, so the description does not need to repeat those. It adds useful behavioral context beyond the annotations: 'Local and resolver-free' clarifies that no external resolver is needed, and the reverse-bibliography framing explains what kind of lookup this performs.

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?

Three short sentences carry all essential information: purpose, input provenance with example, and an exclusion. It is front-loaded with the core meaning and contains no filler.

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 annotations, schema descriptions, output schema, and the two-parameter simplicity, the description covers everything an agent needs to invoke the tool correctly. It explains the input source, the intended usage, and what the tool is not for, making it complete for this context.

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

Parameters4/5

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

Schema coverage is 100%, so the baseline is 3. The description adds value by providing a concrete example URI and explicitly tying the publication parameter to the output of get_artwork_bibliography, which helps the agent construct a valid input even beyond the schema's description.

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 identifies a specific verb and resource: finding artworks that cite a given publication URI or id. The phrase 'Reverse bibliography' immediately distinguishes it from related tools, and the explicit 'Not for topic search of the library catalogue' prevents confusion with search_artwork.

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

Usage Guidelines5/5

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

The description gives concrete guidance on what input to use and where to obtain it: 'Use the publicationUri from get_artwork_bibliography'. It also states an explicit when-not condition, 'Not for topic search of the library catalogue,' which helps an agent choose between this and sibling tools.

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

get_artwork_bibliographyGet Artwork BibliographyA
Read-onlyIdempotent

Scholarly references (citations) for ONE artwork by objectNumber. Includes linked publication, pages, ISBN where known. Entries with a linked publication carry a [pub NNN] handle — pass it to find_artworks_citing_publication. Follows a search_artwork / get_artwork_details result. By default returns the first 5 plus a total count; set full=true for all entries (major works can have 100+ — mind the context window). Not for general metadata — use get_artwork_details. Not for library-catalogue search.

ParametersJSON Schema
NameRequiredDescriptionDefault
fullNoIf true, return ALL entries (may be 100+). Default: first 5 + total count.
objectNumberYesThe object number of the artwork (e.g. 'SK-C-5').

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNo
totalYesTotal citations for the artwork (full count, even when only the first few entries are returned).
entriesYesScholarly references for the artwork. Empty when none were harvested.
warningsNo
objectNumberYes

TDQS

A4.9/5.0
Behavior5/5

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

Annotations already mark the tool as read-only, idempotent, and non-destructive, so the description's job is to add context. It does: default returns first 5 plus total count, full=true can return 100+ entries, ISBN/publication details appear 'where known', and entries may carry a [pub NNN] handle. No contradiction with annotations.

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?

Four sentences with no filler: purpose, content details, workflow, exclusions, and pagination behavior are all packed efficiently. The most decision-relevant information is front-loaded, and the context-window warning earns its place.

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?

With an output schema present and annotations covering the safety profile, the description is complete for correct invocation. It explains what the entries contain, how pagination works, how to follow up on linked publications, and when not to use the tool. No critical gap remains.

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

Parameters4/5

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

Schema description coverage is 100%, so the baseline is 3. The description adds value by explaining the trade-off of full=true in terms of context window and 100+ entries, and by reinforcing that objectNumber is the key selector. This is modest but useful enrichment beyond the schema.

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 opens with a specific action and resource: scholarly references/citations for ONE artwork by objectNumber. It also distinguishes itself from siblings by stating 'Not for general metadata — use get_artwork_details' and explaining the [pub NNN] handle flow to find_artworks_citing_publication.

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

Usage Guidelines5/5

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

It clearly states when the tool is appropriate: after a search_artwork or get_artwork_details result. It also gives explicit exclusions: not for general metadata and not for library-catalogue search, naming the alternative get_artwork_details. The default-versus-full behavior is also explained.

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

get_artwork_detailsGet Artwork DetailsA
Read-onlyIdempotent

Full metadata for ONE artwork by objectNumber. Covers creator, dates, materials, provenance, inscriptions, related objects. Typically follows a search_artwork / semantic_search / find_similar result, or a user-named objectNumber. Provide exactly one of objectNumber (e.g. 'SK-C-5' for The Night Watch) or uri (a Linked Art URI from relatedObjects).

Returns metadata including titles (primary plus the full set of variants with language and qualifier — Dutch/English brief/full/display/former), creator, date, dateDisplay (free-text form), description, curatorial narrative, dimensions (text + structured: height/width/depth/weight/diameter where present), extentText, materials, object type, production details (with creator life dates, gender, and Wikidata ID where available), provenance, credit line, inscriptions, license, related objects (each carrying objectNumber + iiifId for in-viewer navigation), themes, exhibitions, attributionMarks (signature/inscription counts), externalIds (handle + other), location (museum room when on display, as { roomId, floor, roomName }), recordCreated/recordModified timestamps, plus collection sets and reference metadata. Authority IDs appear at two levels: work-level under externalIds (handle + other), and entity-level under equivalents[] arrays on objectTypes, materials, production entries, subjects.depictedPersons / subjects.depictedPlaces, collectionSetLabels and themes — each entry a { authority, id, uri } triple (VIAF/ULAN/RKD/Getty TGN+AAT/GeoNames/Wikidata), and one entity can carry several, so read every entry (iconclass terms have none). The relatedObjects field carries each peer's objectNumber (canonical handle) plus a Linked Art objectUri; pass either form back here, objectNumber preferred.

Not for filter-based discovery — use search_artwork. Not for similarity discovery — use find_similar. Not for aggregate counts — use collection_stats.

ParametersJSON Schema
NameRequiredDescriptionDefault
uriNoA Linked Art URI (e.g. 'https://id.rijksmuseum.nl/200666460')
objectNumberNoThe object number of the artwork (e.g. 'SK-C-5', 'SK-A-3262')
verboseExtentNoInclude the verbose free-text extentText (dcterms:extent). Default false; the structured dimensions[] and physicalDimensions cover the headline measurements.

Output Schema

ParametersJSON Schema
NameRequiredDescription
idYes
urlYes
dateYes
typeNoPrimary object type — convenience sugar equal to objectTypes[0]?.label when present. objectTypes[] is the authoritative structured form (label + vocabulary id).
errorNo
titleYes
themesYesCuratorial thematic tags (overseas history, political history, costume, …).
titlesYes
creatorYes
licenseYes
parentsYesParent records (e.g. the sketchbook this folio belongs to). Empty for top-level objects.
childrenYesUp to 25 child records, ordered by object_number. Use search_artwork to enumerate the full set.
locationYesCurrent museum room (resolved via current_location → museum_rooms join). Null if not on display.
subjectsYes
materialsYes
childCountYesTotal number of child records (e.g. folios in a sketchbook). 0 for non-parent objects.
creditLineYes
dimensionsYes
extentTextYesFree-text extent / dimensions string (dcterms:extent). Verbose human-readable form.
productionYes
provenanceYes
dateDisplayYesFree-text Rijksmuseum-formatted display date (e.g. '1642', 'c. 1665-1667'). Use this for prose; date for ISO-shaped output.
descriptionYes
exhibitionsYesExhibitions this artwork has appeared in. Most-recent first.
externalIdsYes
objectTypesYes
inscriptionsYes
objectNumberYes
persistentIdYesHarvested handle.net URI for long-term citation; same value as externalIds.handle. Null for the minority of records with no handle.
recordCreatedYesISO 8601 timestamp of catalogue record creation.
collectionSetsYes
recordModifiedYesISO 8601 timestamp of catalogue record's most recent modification.
relatedObjectsYesRelated-variant peer relations — creator-invariant curator-declared edges ('different example' / 'production stadia' / 'pendant'). Other curator-declared relationships (pair, set, recto|verso, original|reproduction, related object) are exposed via find_similar's Related Object channel rather than here. Capped at 25 entries — see relatedObjectsTotalCount.
provenanceChainYesParsed provenance events derived from the raw `provenance` string via the project's PEG parser. Null when no provenance text is available. Clients can re-derive counts, gaps, year spans, transfer-type histograms, and earliest-known-owner from this array; the text channel renders a summary built from the same data.
attributionMarksYesPresence of signature/inscription marks only — a count, not content. The harvested rows carry no transcribed text and their carrier URIs do not resolve; use parsedInscriptions / search_inscriptions for the actual transcriptions.
themesTotalCountYes
bibliographyCountYesCitation count for this artwork — call get_artwork_bibliography for the entries. Null when bibliography data isn't present in this database.
physicalRelationsYesPhysical-companion objects (the artwork's frame(s) / pedestal). Distinct from relatedObjects (creator-invariant variants) and from find_similar groupings. Capped at the same preview limit — see physicalRelationsTotalCount.
inscriptionSummaryYesPer-artwork rollup over parsedInscriptions — lets a client distinguish 'object bears text' from 'verso collector stamp boilerplate' at a glance.
parsedInscriptionsYesStructured parse of the raw `inscriptions` blob (each physical mark is recorded twice — a detailed Dutch form and an English gloss; both are preserved here losslessly, one entry per segment). This is catalogue-entered inscription/mark data — NOT OCR and NOT an exhaustive transcription of visible text. The field is dominated by verso collector's-mark stamps; the artist-/image-applied text is a real but minority component. Use transcribedText to find what is actually written on the work; use isCollectorMark/isPlaceholder to filter ownership-stamp boilerplate.
physicalDimensionsYesShort reconstructed dimensions string (e.g. "h 379.5 cm × w 453.5 cm") from formatDimensions(height, width). Same value and key the viewer tools (get_artwork_image / remount_viewer) emit. For the full structured measurements use dimensions[]; for verbose cataloguer prose use extentText.
techniqueStatementYes
collectionSetLabelsYes
curatorialNarrativeYes
exhibitionsTotalCountYes
relatedObjectsTotalCountYesTotal related-variant peer-relation count before capping. Equals relatedObjects.length when ≤ 25.
physicalRelationsTotalCountYesTotal physical-companion relation count before capping.

TDQS

A5/5.0
Behavior5/5

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

Annotations already declare readOnlyHint, idempotentHint, and destructiveHint; the description adds substantial behavioral detail beyond those: the two-level authority ID structure, the relatedObjects hand-off via objectNumber/iiifId/objectUri, and the caveat that some entries, like iconclass terms, carry no authority IDs. There is no contradiction with annotations.

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 long but information-dense and well organized: scope first, then detailed return content, then routing guidance and exclusions. Each sentence earns its place, and the key usage constraint is front-loaded.

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 output schema, annotations, and parameter descriptions, this tool definition is complete. It covers input requirements, return contents, related-object navigation, authority IDs, and exclusions. There are no significant gaps that would prevent an agent from selecting and invoking it 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?

Although the schema covers each parameter, the description adds a crucial constraint absent from the schema: exactly one of objectNumber or uri must be supplied, with objectNumber preferred. It also explains verboseExtent's default behavior and how structured dimensions relate to it, resolving ambiguity the schema leaves open.

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 opens with a specific operation: 'Full metadata for ONE artwork by objectNumber,' and clarifies the two accepted identifier forms. It is immediately distinguishable from sibling tools like search_artwork and get_artwork_image.

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

Usage Guidelines5/5

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

It explicitly states when to use the tool: after search_artwork, semantic_search, find_similar, or when a user supplies an objectNumber. It also gives clear negatives: not for filter-based discovery, not for similarity discovery, and not for aggregate counts, naming the appropriate alternatives.

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

get_artwork_imageGet Artwork ImageA

Opens an interactive deep-zoom viewer for the user. Use only when they ask to see, show, or view an artwork — not for list, summary, count, or text-only requests. Not for visual analysis by the LLM — use inspect_artwork_image to get image bytes. Not all artworks have images available. Returns metadata and a viewer link, not the image bytes themselves; do not construct or fetch IIIF image URLs manually (downloadable images are on rijksmuseum.nl).

ParametersJSON Schema
NameRequiredDescriptionDefault
objectNumberYesThe object number of the artwork (e.g. 'SK-C-5')

Output Schema

ParametersJSON Schema
NameRequiredDescription
urlNo
dateNo
errorNo
titleNo
widthNo
heightNo
creatorNo
licenseNo
viewUUIDNoViewer session ID for use with navigate_viewer.
iiifInfoUrlNo
objectNumberYes
physicalDimensionsNo

TDQS

A4.7/5.0
Behavior5/5

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

The description discloses important behavior beyond the annotations: it returns metadata and a viewer link rather than image bytes, not all artworks have images, and agents should not manually construct or fetch IIIF URLs. It also implies a stateful viewer interaction, consistent with openWorldHint. No contradiction with the annotations.

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 compact yet information-dense: each sentence serves a purpose, starting with the core action and then layering usage constraints, alternatives, caveats, and return-type expectations. It avoids redundancy with the schema.

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?

For a tool that opens an interactive viewer, the description covers what it returns, when it should be used, who the alternative is for, edge cases (missing images), and an explicit warning about URL construction. The presence of an output schema further reduces the need to explain return values.

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

Parameters3/5

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

There is only one parameter, objectNumber, and the input schema already describes it with an example, giving 100% schema coverage. The description adds context around image availability but does not need to add parameter-specific semantics. Baseline 3 is appropriate.

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 what the tool does ('Opens an interactive deep-zoom viewer for the user') and distinguishes it from inspect_artwork_image, which returns image bytes. It also scopes the resource to artwork viewing, making the purpose unmistakable.

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

Usage Guidelines5/5

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

The description gives explicit use conditions ('Use only when they ask to see, show, or view an artwork'), explicit exclusions ('not for list, summary, count, or text-only requests'), and names a concrete alternative ('use inspect_artwork_image to get image bytes'). This is strong routing guidance.

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

get_conservation_historyGet Conservation HistoryA
Read-onlyIdempotent

Technical examinations and restoration history for ONE artwork. Follows get_artwork_details / a search result, by objectNumber. Returns technical examinations (X-ray, dendrochronology, paint samples, infrared), conservation/restoration treatment events, a count of recorded signature/inscription marks (use search_inscriptions for the actual transcriptions), and a short provenance excerpt. Not for general metadata — use get_artwork_details. Not for transcribed inscriptions — use search_inscriptions. Not for aggregate counts — use collection_stats.

ParametersJSON Schema
NameRequiredDescriptionDefault
objectNumberYesThe object number of the artwork (e.g. 'SK-C-5', 'SK-A-4878').

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNo
titleYes
creatorYes
warningsNo
examinationsYesTechnical examinations / forensic reports (X-ray, dendrochronology, paint samples, infrared, …). Most-recent first.
objectNumberYes
attributionMarksYesPresence of signature/inscription marks only — a count, not content. The harvested rows carry no transcribed text and their carrier URIs do not resolve; use get_artwork_details.parsedInscriptions / search_inscriptions for the actual transcriptions.
conservationHistoryYesRestoration / conservation treatment events. Most-recent first.
provenanceTextSummaryYesShort excerpt of the raw provenance text, for forensic cross-reference. Null when absent.
examinationsTotalCountYes
conservationHistoryTotalCountYes

TDQS

A4.7/5.0
Behavior5/5

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

Annotations already mark this as read-only, idempotent, and non-destructive. The description goes further by disclosing the concrete contents: technical examinations, treatment events, a count of signature/inscription marks (not transcriptions), and a provenance excerpt. This fully sets agent expectations.

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?

Four dense sentences, each earning its place: scope, sequencing, return contents, and explicit exclusions. No filler or repetition of annotation information.

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?

For a single-parameter, read-only tool with an output schema, the description fully covers when to use it, how to use it, what it returns, and what it explicitly avoids. Nothing critical is missing.

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

Parameters3/5

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

Schema coverage is 100% and the only parameter, objectNumber, already has a clear description with examples. The description's 'by objectNumber' adds little beyond the schema, so the baseline 3 is appropriate.

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?

States a specific verb+resource ('Technical examinations and restoration history for ONE artwork') and enumerates exactly what it returns. Explicitly distinguishes itself from get_artwork_details and other tools by declaring what it is not for.

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

Usage Guidelines5/5

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

Provides explicit sequencing guidance: use after get_artwork_details or a search result, keyed by objectNumber. Also gives clear exclusion criteria with named alternatives for general metadata, transcriptions, and aggregate counts.

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

get_recent_changesGet Recent ChangesA
Read-onlyIdempotent

OAI-PMH delta feed of records changed within a date range. Paginated; anchored to a known harvest checkpoint. Use identifiersOnly=true for a lightweight listing (headers only, no full metadata). Full-mode records include an objectNumber for follow-up calls to get_artwork_details or get_artwork_image; identifiersOnly records carry only a LOD URI, so re-run without it to act on a change. Deleted records are flagged with deleted:true (marked [DELETED] in the listing) and carry only a LOD URI + datestamp, no metadata.

ParametersJSON Schema
NameRequiredDescriptionDefault
fromNoStart date in ISO 8601 format (e.g. '2026-02-01T00:00:00Z' or '2026-02-01'). Required for initial request, ignored when resumptionToken is provided.
untilNoEnd date in ISO 8601 format (defaults to now)
setSpecNoRestrict to changes within a specific set
maxResultsNoMaximum records to return (1-50, default 10)
identifiersOnlyNoIf true, returns only record headers (identifier = LOD URI, not objectNumber; datestamp; set memberships) — much faster. Preserved automatically across continuation pages.
resumptionTokenNoPagination token from a previous get_recent_changes result. When provided, all other filters are ignored.

Output Schema

ParametersJSON Schema
NameRequiredDescription
hintNo
errorNo
recordsYes
totalChangesNo
returnedCountYes
identifiersOnlyNo
resumptionTokenNo

TDQS

A4.7/5.0
Behavior5/5

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

Beyond the readOnly/idempotent annotations, the description discloses important behaviors: pagination anchored to a harvest checkpoint, deleted records flagged with deleted:true and [DELETED], identifiersOnly records carrying only a LOD URI, and identifiersOnly being preserved across continuation pages. This materially helps an agent predict results and plan follow-up actions.

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 dense but front-loaded with the tool's core purpose. Every sentence adds distinct value: delta scope, pagination, identifiersOnly mode, follow-up behavior, and deleted-record handling. No filler or redundancy.

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?

For a six-parameter paginated feed tool, the description covers the critical behavioral context: harvesting workflow, continuation tokens, mode differences, follow-up flow, and deleted-record semantics. An output schema exists, so return-value details do not need to be repeated here.

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

Parameters4/5

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

Schema coverage is 100%, so the schema already documents all parameters well. The description adds extra meaning by explaining trade-offs between identifiersOnly and full mode, the follow-up capabilities of objectNumber, and the special shape of deleted records. This goes beyond the parameter descriptions and improves correct parameter choice.

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 identifies the tool as an OAI-PMH delta feed for records changed within a date range, with a specific verb and resource. It also distinguishes its role from sibling tools by framing it around harvest checkpoints and follow-up detail/image calls.

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?

The description gives explicit within-tool guidance: use identifiersOnly=true for lightweight listing, and re-run without it to act on a change. It also explains when full-mode records enable follow-up calls. It does not explicitly state when not to use this tool versus sibling alternatives, but the intended workflow is clear.

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

inspect_artwork_imageInspect Artwork ImageA
Read-onlyIdempotent

Returns image bytes (base64) for the LLM's own visual analysis. Covers a whole artwork or a region. The LLM can see and reason about the image immediately — not for the user to view (use get_artwork_image for the interactive viewer). Not for listing or summarising artworks — use search_artwork.

Use with region 'full' (default) to inspect the complete artwork, or specify a region to zoom into details, read inscriptions, or examine specific areas. The response includes cropPixelWidth/cropPixelHeight: the actual pixel dimensions of the returned image.

Region coordinates: 'pct:x,y,w,h' (percentage of full image, recommended), 'crop_pixels:x,y,w,h' (pixel coordinates of the full image — use with nativeWidth/nativeHeight from a prior response), or 'x,y,w,h' (legacy IIIF pixels, equivalent to crop_pixels). A tight region returns more real detail than a larger size — the server never upscales past the region's own pixels. For multi-panel works, estimate panel percentages from the physical dimensions in get_artwork_details.

When a viewer is open for this artwork, it automatically zooms to the inspected region (navigateViewer defaults to true, no effect when region is 'full'), so no separate navigate_viewer call is needed for basic zoom.

The response includes the active viewUUID (if any) for follow-up navigate_viewer calls.

ParametersJSON Schema
NameRequiredDescriptionDefault
sizeNoWidth of returned image in pixels (200–1988, default 1568). Vision models bill images in 28×28 patches, and that ceiling is the largest width clearing both the per-image patch budget and the stricter per-image limit that applies once a conversation has accumulated many images. Tall and square regions clamp below that automatically — the response reports the width actually delivered.
regionNoIIIF region: 'full', 'square', 'pct:x,y,w,h' (percentage), 'crop_pixels:x,y,w,h' (pixels of the full image — use with nativeWidth/nativeHeight from a prior response), or 'x,y,w,h' (legacy IIIF pixels, equivalent to crop_pixels). E.g. 'pct:0,60,40,40' for bottom-left 40%.full
qualityNoImage quality — 'gray' can help read inscriptions or signaturesdefault
rotationNoClockwise rotation in degrees
viewUUIDNoTarget a specific viewer session (from get_artwork_image). When omitted, auto-discovers a viewer for this artwork.
objectNumberYesThe object number of the artwork (e.g. 'SK-C-5')
navigateViewerNoAuto-navigate the open viewer to the inspected region (default: true). Only effective when a viewer is open for this artwork.

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNo
titleNoArtwork title — mirrors the caption in the text/image channel so structuredContent readers retain it.
regionYes
creatorNoArtwork creator — mirrors the caption in the text/image channel.
qualityYes
rotationYes
viewUUIDNoActive viewer session ID (if a viewer is open for this artwork)
warningsNo
cropRegionNoNormalized IIIF region used for the fetch; crop_pixels: inputs are normalized to plain IIIF pixel regions.
fetchTimeMsNoTime spent fetching from IIIF server (ms)
nativeWidthNo
nativeHeightNo
objectNumberYes
requestedSizeYes
cropPixelWidthNoActual width in pixels of the returned inspect image/crop. Use with cropPixelHeight for crop-local pixel overlays.
regionRecoveryNoOut-of-bounds recovery hint. Present only on an `overlay_region_out_of_bounds` error — mirrors the recovery payload that the text channel renders, so a structuredContent reader can self-correct without parsing prose.
cropPixelHeightNoActual height in pixels of the returned inspect image/crop. Use with cropPixelWidth for crop-local pixel overlays.
viewerNavigatedNoWhether the viewer was auto-navigated to the inspected region

TDQS

A5/5.0
Behavior5/5

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

Annotations already mark the operation read-only, idempotent, and non-destructive, and the description adds concrete behavior: the server never upscales beyond the region's own pixels, tight regions reveal more real detail, viewer auto-navigation occurs, and the response includes crop dimensions and viewUUID. This is substantial behavioral context beyond what annotations provide.

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?

Front-loaded with purpose and exclusions, then organized into region behavior and viewer behavior. Despite its length, each sentence adds operational value and there is no filler.

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?

For a parameter-rich image inspection tool, the description covers target audience, region syntax, resolution behavior, viewer coordination, and relevant response fields. Since an output schema exists, return-value details do not need to be repeated here.

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 input schema already has 100% parameter coverage, but the description adds practical meaning: region syntax variants are explained with usage guidance, crop_pixels should be paired with nativeWidth/nativeHeight from a prior response, tight regions give more real detail, and navigateViewer behavior is clarified. This goes well beyond the schema's 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 opens with a specific verb and resource: 'Returns image bytes (base64) for the LLM's own visual analysis.' It immediately distinguishes the tool from get_artwork_image and search_artwork, so an agent knows exactly what it is for and what it is not for.

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

Usage Guidelines5/5

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

Explicitly names alternatives and conditions: 'not for the user to view (use get_artwork_image)', 'Not for listing or summarising artworks — use search_artwork', and notes that navigateViewer removes the need for a separate navigate_viewer call. This is clear when-to-use versus when-not-to-use guidance.

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

list_curated_setsList Curated SetsA
Read-onlyIdempotent

Browse thematic sets curated by Rijksmuseum staff. Includes sub-collection groupings (drawings, paintings, iconographic sets). Each result carries memberCount, top dominantTypes, top dominantCenturies by membership, and a category heuristic (object_type / iconographic / album / sub_collection / umbrella) so you can pick the right scope. Use minMembers: 100, maxMembers: 200000 to avoid umbrella sets when the user wants a substantive subset. Pair with browse_set(setSpec) to enumerate members. Not for keyword search across artworks — use search_artwork. Not for aggregate counts — use collection_stats.

ParametersJSON Schema
NameRequiredDescriptionDefault
queryNoFilter sets by name (case-insensitive substring match). E.g. 'painting', 'Rembrandt', 'Japanese'
sortByNoSort order: 'name' (alphabetical, default), 'size' (smallest first), 'size_desc' (largest first).
maxMembersNoFilter to sets with at most this many members. Use ~100,000 to exclude umbrella sets like 'Alle gepubliceerde objecten' (834K) and 'Entire Public Domain Set' (732K).
minMembersNoFilter to sets with at least this many members.
includeStatsNoInclude memberCount, dominantTypes, dominantCenturies, category. Default true. Set false for the lightweight legacy shape.

Output Schema

ParametersJSON Schema
NameRequiredDescription
setsYes
errorNo
queryNo
totalSetsYes
filteredFromNo

TDQS

A4.7/5.0
Behavior4/5

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

Annotations already establish readOnly, idempotent, and non-destructive behavior. The description adds useful behavioral context beyond that by explaining what each result carries (memberCount, dominantTypes, dominantCenturies, category) and describing the category heuristic with concrete values. It does not contradict the annotations.

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 and front-loaded: purpose, scope, result contents, usage recommendation, sibling pairing, then exclusions. Every sentence adds distinct value and none is redundant with the schema or annotations.

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?

The tool has 5 optional parameters, an output schema, and read-only annotations, and the description still covers the key contextual gaps: result semantics, category meanings, umbrella avoidance, and alternatives. An agent has enough information to decide when to call this tool and how to shape its parameters.

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

Parameters4/5

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

Schema coverage is 100%, so the base is strong. The description adds cross-parameter guidance not present in any single schema field: the specific minMembers/maxMembers combination of 100/200000 and the intent behind it (avoiding umbrella sets). This elevates parameter semantics from a baseline 3.

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 opens with a specific verb and resource: 'Browse thematic sets curated by Rijksmuseum staff.' It also distinguishes itself from siblings by explicitly stating it is 'Not for keyword search across artworks — use search_artwork' and 'Not for aggregate counts — use collection_stats,' and it references browse_set for enumeration.

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

Usage Guidelines5/5

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

The description gives concrete when-to-use guidance: 'Use minMembers: 100, maxMembers: 200000 to avoid umbrella sets when the user wants a substantive subset.' It also names explicit alternatives for other intents, saying to pair with browse_set to enumerate members and to use search_artwork or collection_stats for other queries.

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

poll_viewer_commandsPoll Viewer CommandsC

Internal: poll for pending viewer navigation commands

ParametersJSON Schema
NameRequiredDescriptionDefault
viewUUIDYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
commandsYesPending viewer navigation commands drained from the queue, in order. Empty when nothing is queued.

TDQS

C2.7/5.0
Behavior2/5

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

Annotations are all false, so description must disclose behavior. It does not clarify if polling is blocking or non-blocking, what happens on no commands, or any side effects. Polling typically implies non-destructive reads, but annotations contradict by setting readOnlyHint to false, creating ambiguity.

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

Conciseness3/5

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

The description is concise (one sentence) and front-loaded with 'Internal:', which is useful. However, it sacrifices necessary detail for brevity, making it insufficient for an agent to use correctly.

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

Completeness2/5

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

Given the tool's simplicity (one param) and existence of an output schema, the description still falls short. It fails to explain the return format, polling behavior, or how it fits with sibling tools like 'navigate_viewer' or 'remount_viewer'. Essential context is missing.

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

Parameters1/5

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

Schema description coverage is 0%, so the description must explain the required parameter 'viewUUID'. It does not, leaving the agent to guess its purpose (likely a viewer identifier). No constraints or format details are provided.

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 identifies the tool's purpose: polling for pending viewer navigation commands. The verb 'poll' and resource 'pending viewer navigation commands' are specific and distinguish it from siblings like 'navigate_viewer' which triggers navigation.

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

Usage Guidelines2/5

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

The description lacks guidance on when to use this tool versus alternatives. The prefix 'Internal:' hints at restricted usage but does not explain polling behavior, repetition, or context (e.g., after navigating). No exclusions or alternatives mentioned.

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

remount_viewerRemount ViewerA

Internal: switch the viewer to a different artwork while preserving the viewUUID. Called by the artwork-viewer iframe during in-viewer related navigation. Any user highlight is cleared on remount because its coordinates belong to the previous artwork.

ParametersJSON Schema
NameRequiredDescriptionDefault
viewUUIDYesExisting viewer UUID returned by a prior get_artwork_image call
objectNumberYesObject number of the artwork to remount into the viewer

Output Schema

ParametersJSON Schema
NameRequiredDescription
urlNo
dateNo
errorNo
titleNo
widthNo
heightNo
creatorNo
licenseNo
viewUUIDNoViewer session ID for use with navigate_viewer.
iiifInfoUrlNo
objectNumberYes
physicalDimensionsNo

TDQS

A4.1/5.0
Behavior5/5

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

The description discloses a concrete side effect beyond the annotations: any user highlight is cleared on remount, and it explains why. It also states that the viewUUID is preserved. Given the annotations only provide false hints, this description carries the behavioral disclosure burden well.

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?

Three short sentences with no filler. The core action is front-loaded, followed by usage context and an important behavioral side effect. Every sentence earns its place.

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

Completeness4/5

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

For a simple two-parameter tool with an output schema and explicit side-effect disclosure, the description is largely complete. The only minor gap is that it does not explicitly contrast itself with navigate_viewer, though the 'Internal' label and iframe call-site reduce ambiguity.

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

Parameters3/5

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

Schema description coverage is 100%, so the baseline is 3. The description does not add additional meaning beyond the schema's own parameter descriptions for viewUUID and objectNumber.

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

Purpose4/5

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

The description uses a specific verb ('switch') and resource ('viewer') and states the key invariant of preserving the viewUUID. The 'Internal' label and iframe call-site help separate it from more general tools, though it does not explicitly name or contrast with the sibling navigate_viewer.

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?

It clearly states when it is used: by the artwork-viewer iframe during in-viewer related navigation. The 'Internal' prefix signals this is not a general-purpose API. However, it does not explicitly say when not to use it or name alternatives like navigate_viewer.

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

search_artworkSearch ArtworkA
Read-onlyIdempotent

Structured filter search — artworks matching ALL given filters. Filters cover subject, material, technique, date, place, person. Returns artwork summaries with titles, creators, and dates; every response includes totalResults (exact match count, not just the returned page). Not for free-text concept queries — use semantic_search for those. Not for artwork-to-artwork similarity — use find_similar with an objectNumber. For demographic person queries (gender, born/died, profession, birth/death place), use search_persons first to get a vocabId, then pass it as creator here. For provenance text and ownership history, use search_provenance. For aggregate counts and distributions, prefer collection_stats — one call vs compact=true loops.

Ranking: relevance (BM25) when text search (description, title, etc.) or geographic proximity is used; otherwise importance (image availability, curatorial attention, metadata richness). For concept-ranked results, use semantic_search.

At least one filter is required. There is no full-text search across all metadata. For concept or thematic searches (e.g. 'winter landscape', 'smell', 'crucifixion'), subject has the highest recall — it searches the large majority of the collection via structured Iconclass vocabulary. Use description for cataloguer observations (compositional details, specific motifs); use curatorialNarrative for curatorial interpretation and art-historical context. These three corpora can return complementary results. For broader concept discovery beyond structured vocabulary, use semantic_search — but combine it with search_artwork(type: 'painting', …) for painting queries since paintings are underrepresented there.

Array values are AND-combined (e.g. subject: ['landscape', 'seascape'] finds artworks with both). If many results share an object-number prefix (e.g. multiple folios of one sketchbook), a warnings note flags it; narrow with type/material filters or treat the shared prefix as the unit. Each result carries an objectNumber for follow-up calls to get_artwork_details (full metadata) or get_artwork_image (deep-zoom viewer for the user).

ParametersJSON Schema
NameRequiredDescriptionDefault
sortNoOrder results by a column (with optional direction). Forms: 'height', 'height:desc' (default), 'dateEarliest:asc'. Overrides BM25 (text-match) and geo-proximity ordering when set. Cannot be used alone — needs at least one substantive filter. Columns: 'height' / 'width' (cm — 95% / 94% coverage; 0.0 sentinels are folded to NULL and ordered last), 'dateEarliest' / 'dateLatest' (year — 99.9% coverage; bracket the dating range, useful for hedged datings like 'c. 1660–1665'), 'recordModified' (ISO date — 62% coverage; ~7 implausibly future-dated rows lead a 'desc' sort, ~2K pre-1990 rows lead an 'asc' sort). Direction defaults to 'desc'. NULLs always sort last regardless of direction. Examples: largest paintings → 'height:desc'; earliest works → 'dateEarliest:asc'; most recently catalogued → 'recordModified:desc'.
typeNoFilter by object type: 'painting', 'print', 'drawing', etc.
queryNoSearch by artwork title — matches against all title variants (brief, full, former × EN/NL). Note: fewer than one artwork in twenty has an English title. For non-title text, use the specific field parameters (description, inscription, curatorialNarrative, creator, subject, etc.).
facetsNoFacet dimensions to compute when results are truncated. Pass an array of dimension names (e.g. ["theme", "rights"]) to compute only those, or true for all dimensions. Available: type, material, technique, century, rights, imageAvailable, creator, depictedPerson, depictedPlace, productionPlace, theme, sourceType. Dimensions already filtered on are excluded automatically and reported in `warnings`.
offsetNoSkip this many results (for pagination). Use with maxResults.
compactNoIf true, returns only total count and IDs without resolving details (faster).
creatorNoSearch by artist name (e.g. 'Rembrandt van Rijn'), or pass a vocabId from search_persons (e.g. '210169673') for an exact match to that one person — preferred over the name when you have it, since shared names can match multiple distinct artists.
groupByNoCollapse component records under their parent (sketchbook folios, album pages, print-series leaves). When 'parent' is set, any child record that appears in the result alongside its parent is dropped, and the parent gains a `groupedChildCount`. Only collapses when both child and parent match the query — children whose parent isn't a hit remain in the result. Applied after the BM25 page is selected, so a parent that ranks below the maxResults cutoff won't pull its children in.
materialNoFilter by material: 'canvas', 'paper', 'wood', etc.
dateMatchNoHow creationDate matches artwork date ranges. "overlaps" (default): artwork range overlaps query range — inclusive, but objects with broad ranges appear in multiple bins. "within": artwork range falls entirely within query range — exclusive bins, but drops broadly-dated objects (~43% of collection spans >1 decade). "midpoint": assigns each artwork to one bin by midpoint of its date range — every object counted exactly once with no data loss. Best for statistical comparisons and charts.
techniqueNoFilter by technique: 'oil painting', 'etching', etc.
aboutActorNoSearch for artworks depicting or about a person (not the creator). E.g. 'Willem van Oranje'. Broader recall than depictedPerson — searches both subject and creator vocabulary, tolerant of cross-language name forms (e.g. 'Louis XIV' finds 'Lodewijk XIV'). Combinable with all other filters. depictedPerson is usually the better first choice (precise, depicted persons only); use aboutActor for broader person matching across depicted persons and creators.
facetLimitNoMaximum entries per facet dimension (1–50, default 5).
maxResultsNoMaximum results to return (1-50, default 25). All results include full metadata.
descriptionNoFull-text search on artwork descriptions (~510K artworks, 61% coverage). Cataloguer observations including compositional details, motifs, physical condition, and attribution remarks. Exact word matching, no stemming.
creationDateNoFilter by creation date. Exact year ('1642') or wildcard ('16*' for 1600s, '164*' for 1640s).
objectNumberNoFilter by object number. Exact match by default (e.g. 'SK-C-5' for The Night Watch). Supports wildcards: '*' matches any run of characters, '?' matches a single character — e.g. 'SK-C-5*' for the Night Watch group, 'RP-P-1906-*' for a print-acquisition series, 'BK-NM-*'. Case-sensitive (object numbers are predominantly uppercase). A wildcard pattern needs at least 2 literal characters.
hasProvenanceNoIf true, only return artworks that have parsed provenance records — roughly 48K, about 6% of the collection. Combine with other filters for cross-domain queries (e.g. type='painting' + hasProvenance=true). Cannot be used alone — combine with at least one other filter.
imageAvailableNoFilter by digitisation: true = only artworks with a digital image, false = only artworks lacking one (e.g. un-photographed works on paper). Cannot be used alone — combine with at least one other filter.

Output Schema

ParametersJSON Schema
NameRequiredDescription
idsNoObject numbers (compact mode).
errorNo
facetsNoCounts per dimension (configurable via facetLimit, default top-5). Computed when results are truncated and facets is set.
sourceNo
resultsNoArtwork summaries. Absent when compact=true.
warningsNo
totalResultsNoTotal matching artworks (always present when vocabulary DB is available). Use with compact=true for efficient counting.
referencePlaceNo

TDQS

A4.8/5.0
Behavior5/5

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

Annotations already mark the tool read-only, idempotent, and non-destructive; the description adds valuable behavioral detail: BM25 vs importance ranking, AND-combined array filters, exact totalResults counting, and warning behavior for shared object-number prefixes. No contradiction with annotations exists.

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?

The description is long but dense, and it is front-loaded with the core scope and exclusions. The main structural waste is the repeated 'use semantic_search' guidance appearing three times; otherwise each paragraph contributes useful routing, ranking, or follow-up information.

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?

For a 19-parameter filter tool, the description covers exclusions, minimum requirements, ranking, array semantics, result summaries, warning behavior, and follow-up calls to get_artwork_details or get_artwork_image. The output schema and rich per-parameter descriptions handle return structure and formatting details, so nothing critical is left to inference.

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

Parameters4/5

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

Schema coverage is 100%, so the baseline is 3, but the description adds cross-parameter semantics: arrays are AND-combined, at least one filter is required, no unrestricted full-text search exists, and specific fields are recommended for different query intents. Minor deduction because it references parameters like 'subject' and 'curatorialNarrative' that are not visible as input properties in the provided schema.

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 opening phrase 'Structured filter search — artworks matching ALL given filters' names a specific verb and resource and clarifies the conjunctive behavior. It also explicitly distinguishes itself from semantic_search, find_similar, and search_persons, so an agent can route correctly without opening schemas.

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

Usage Guidelines5/5

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

The description gives explicit routing rules: free-text concepts → semantic_search, artwork similarity → find_similar, demographic person queries → search_persons first, provenance → search_provenance, aggregates → collection_stats. It also states the 'at least one filter required' constraint and provides field-selection guidance for subject, description, and curatorialNarrative.

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.

  1. 9 tool updatesv0.90.1
    • Changedfind_artworks_citing_publication2 fields changed
      • removedOutput schema / properties / artworks / items / properties / creator / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / artworks / items / properties / creator / type
        Added value: +[
        +  "string",
        +  "null"
        +]
    • Changedget_artwork_bibliography12 fields changed
      • removedOutput schema / properties / entries / items / properties / isbn / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / entries / items / properties / isbn / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / entries / items / properties / libraryUrl / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / entries / items / properties / libraryUrl / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / entries / items / properties / pages / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / entries / items / properties / pages / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • addedOutput schema / properties / entries / items / properties / publicationId
        Added value: +{
        +  "anyOf": [
        +    {
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    {
        +      "type": "null"
        +    }
        +  ],
        +  "description": "Bare publication id from the URI above — pass it to find_artworks_citing_publication. Rendered as [pub NNN] in the text channel."
        +}
      • removedOutput schema / properties / entries / items / properties / publicationUri / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / entries / items / properties / publicationUri / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / entries / items / properties / worldcatUri / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / entries / items / properties / worldcatUri / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • changedOutput schema / properties / entries / items / required
        Previous value: -[
        -  "sequence",
        -  "citation",
        -  "publicationUri",
        -  "pages",
        -  "isbn",
        -  "worldcatUri",
        -  "libraryUrl"
        -]New value: +[
        +  "sequence",
        +  "citation",
        +  "publicationUri",
        +  "publicationId",
        +  "pages",
        +  "isbn",
        +  "worldcatUri",
        +  "libraryUrl"
        +]
    • Changedget_artwork_details79 fields changed
      • removedOutput schema / properties / creditLine / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / creditLine / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / curatorialNarrative / properties / en / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / curatorialNarrative / properties / en / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / curatorialNarrative / properties / nl / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / curatorialNarrative / properties / nl / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / dateDisplay / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / dateDisplay / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / description / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / description / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / dimensions / items / properties / note / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / dimensions / items / properties / note / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / dimensions / items / properties / value / anyOf
        Removed value: -[
        -  {
        -    "type": "number"
        -  },
        -  {
        -    "type": "string"
        -  }
        -]
      • addedOutput schema / properties / dimensions / items / properties / value / type
        Added value: +[
        +  "number",
        +  "string"
        +]
      • removedOutput schema / properties / exhibitions / items / properties / dateEnd / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / exhibitions / items / properties / dateEnd / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / exhibitions / items / properties / dateStart / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / exhibitions / items / properties / dateStart / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / exhibitions / items / properties / titleEn / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / exhibitions / items / properties / titleEn / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / exhibitions / items / properties / titleNl / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / exhibitions / items / properties / titleNl / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / extentText / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / extentText / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / externalIds / properties / handle / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / externalIds / properties / handle / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / license / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / license / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • changedOutput schema / properties / location / anyOf
        Previous value: -[
        -  {
        -    "additionalProperties": false,
        -    "properties": {
        -      "floor": {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      },
        -      "roomId": {
        -        "type": "string"
        -      },
        -      "roomName": {
        -        "anyOf": [
        -          {
        -            "type": "string"
        -          },
        -          {
        -            "type": "null"
        -          }
        -        ]
        -      }
        -    },
        -    "required": [
        -      "roomId",
        -      "floor",
        -      "roomName"
        -    ],
        -    "type": "object"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "additionalProperties": false,
        +    "properties": {
        +      "floor": {
        +        "type": [
        +          "string",
        +          "null"
        +        ]
        +      },
        +      "roomId": {
        +        "type": "string"
        +      },
        +      "roomName": {
        +        "type": [
        +          "string",
        +          "null"
        +        ]
        +      }
        +    },
        +    "required": [
        +      "roomId",
        +      "floor",
        +      "roomName"
        +    ],
        +    "type": "object"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • removedOutput schema / properties / parsedInscriptions / items / properties / normalizedPlacement / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / parsedInscriptions / items / properties / normalizedPlacement / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / parsedInscriptions / items / properties / normalizedTechnique / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / parsedInscriptions / items / properties / normalizedTechnique / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / parsedInscriptions / items / properties / normalizedType / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / parsedInscriptions / items / properties / normalizedType / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / parsedInscriptions / items / properties / placement / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / parsedInscriptions / items / properties / placement / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / parsedInscriptions / items / properties / technique / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / parsedInscriptions / items / properties / technique / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / parsedInscriptions / items / properties / type / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / parsedInscriptions / items / properties / type / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / parsedInscriptions / items / properties / value / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / parsedInscriptions / items / properties / value / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / persistentId / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / persistentId / description
        Added value: +"Harvested handle.net URI for long-term citation; same value as externalIds.handle. Null for the minority of records with no handle."
      • addedOutput schema / properties / persistentId / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / physicalDimensions / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / physicalDimensions / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / physicalRelations / items / properties / iiifId / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / physicalRelations / items / properties / iiifId / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / physicalRelations / items / properties / objectNumber / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / physicalRelations / items / properties / objectNumber / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / physicalRelations / items / properties / title / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / physicalRelations / items / properties / title / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / production / items / properties / attributionQualifier / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / production / items / properties / attributionQualifier / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / production / items / properties / personInfo / properties / gender / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / production / items / properties / personInfo / properties / gender / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / production / items / properties / personInfo / properties / wikidataId / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / production / items / properties / personInfo / properties / wikidataId / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / production / items / properties / place / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / production / items / properties / place / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / production / items / properties / role / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / production / items / properties / role / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / provenance / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / provenance / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • changedOutput schema / properties / provenanceChain / anyOf
        Previous value: -[
        -  {
        -    "items": {
        -      "additionalProperties": false,
        -      "properties": {
        -        "date": {
        -          "anyOf": [
        -            {
        -              "additionalProperties": false,
        -              "properties": {
        -                "text": {
        -                  "description": "Original date expression as it appeared in the source.",
        -                  "type": "string"
        -                },
        -                "year": {
        -                  "anyOf": [
        -                    {
        -                      "maximum": 9007199254740991,
        -                      "minimum": -9007199254740991,
        -                      "type": "integer"
        -                    },
        -                    {
        -                      "type": "null"
        -                    }
        -                  ],
        -                  "description": "Best-effort single year; null if the date couldn't be reduced to a year."
        -                }
        -              },
        -              "required": [
        -                "year",
        -                "text"
        -              ],
        -              "type": "object"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ]
        -        },
        -        "gap": {
        -          "type": "boolean"
        -        },
        -        "location": {
        -          "anyOf": [
        -            {
        -              "type": "string"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ]
        -        },
        -        "party": {
        -          "anyOf": [
        -            {
        -              "additionalProperties": false,
        -              "properties": {
        -                "name": {
        -                  "type": "string"
        -                }
        -              },
        -              "required": [
        -                "name"
        -              ],
        -              "type": "object"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ]
        -        },
        -        "price": {
        -          "anyOf": [
        -            {
        -              "additionalProperties": false,
        -              "properties": {
        -                "amount": {
        -                  "anyOf": [
        -                    {
        -                      "type": "number"
        -                    },
        -                    {
        -                      "type": "null"
        -                    }
        -                  ]
        -                },
        -                "currency": {
        -                  "type": "string"
        -                },
        -                "text": {
        -                  "type": "string"
        -                }
        -              },
        -              "required": [
        -                "currency",
        -                "amount",
        -                "text"
        -              ],
        -              "type": "object"
        -            },
        -            {
        -              "type": "null"
        -            }
        -          ]
        -        },
        -        "sequence": {
        -          "maximum": 9007199254740991,
        -          "minimum": -9007199254740991,
        -          "type": "integer"
        -        },
        -        "transferType": {
        -          "description": "Normalized transfer type: sale, inheritance, by_descent, widowhood, bequest, commission, confiscation, theft, looting, recuperation, loan, transfer, collection, gift, exchange, deposit, restitution, inventory, or unknown.",
        -          "type": "string"
        -        },
        -        "uncertain": {
        -          "type": "boolean"
        -        }
        -      },
        -      "required": [
        -        "sequence",
        -        "gap",
        -        "uncertain",
        -        "transferType",
        -        "party",
        -        "location",
        -        "date",
        -        "price"
        -      ],
        -      "type": "object"
        -    },
        -    "type": "array"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "items": {
        +      "additionalProperties": false,
        +      "properties": {
        +        "date": {
        +          "anyOf": [
        +            {
        +              "additionalProperties": false,
        +              "properties": {
        +                "text": {
        +                  "description": "Original date expression as it appeared in the source.",
        +                  "type": "string"
        +                },
        +                "year": {
        +                  "anyOf": [
        +                    {
        +                      "maximum": 9007199254740991,
        +                      "minimum": -9007199254740991,
        +                      "type": "integer"
        +                    },
        +                    {
        +                      "type": "null"
        +                    }
        +                  ],
        +                  "description": "Best-effort single year; null if the date couldn't be reduced to a year."
        +                }
        +              },
        +              "required": [
        +                "year",
        +                "text"
        +              ],
        +              "type": "object"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ]
        +        },
        +        "gap": {
        +          "type": "boolean"
        +        },
        +        "location": {
        +          "type": [
        +            "string",
        +            "null"
        +          ]
        +        },
        +        "party": {
        +          "anyOf": [
        +            {
        +              "additionalProperties": false,
        +              "properties": {
        +                "name": {
        +                  "type": "string"
        +                }
        +              },
        +              "required": [
        +                "name"
        +              ],
        +              "type": "object"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ]
        +        },
        +        "price": {
        +          "anyOf": [
        +            {
        +              "additionalProperties": false,
        +              "properties": {
        +                "amount": {
        +                  "type": [
        +                    "number",
        +                    "null"
        +                  ]
        +                },
        +                "currency": {
        +                  "type": "string"
        +                },
        +                "text": {
        +                  "type": "string"
        +                }
        +              },
        +              "required": [
        +                "currency",
        +                "amount",
        +                "text"
        +              ],
        +              "type": "object"
        +            },
        +            {
        +              "type": "null"
        +            }
        +          ]
        +        },
        +        "sequence": {
        +          "maximum": 9007199254740991,
        +          "minimum": -9007199254740991,
        +          "type": "integer"
        +        },
        +        "transferType": {
        +          "description": "Normalized transfer type: sale, inheritance, by_descent, widowhood, bequest, commission, confiscation, theft, looting, recuperation, loan, transfer, collection, gift, exchange, deposit, restitution, inventory, or unknown.",
        +          "type": "string"
        +        },
        +        "uncertain": {
        +          "type": "boolean"
        +        }
        +      },
        +      "required": [
        +        "sequence",
        +        "gap",
        +        "uncertain",
        +        "transferType",
        +        "party",
        +        "location",
        +        "date",
        +        "price"
        +      ],
        +      "type": "object"
        +    },
        +    "type": "array"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • removedOutput schema / properties / recordCreated / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / recordCreated / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / recordModified / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / recordModified / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / relatedObjects / items / properties / iiifId / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / relatedObjects / items / properties / iiifId / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / relatedObjects / items / properties / objectNumber / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / relatedObjects / items / properties / objectNumber / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / relatedObjects / items / properties / title / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / relatedObjects / items / properties / title / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / techniqueStatement / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / techniqueStatement / type
        Added value: +[
        +  "string",
        +  "null"
        +]
    • Changedget_artwork_image8 fields changed
      • removedOutput schema / properties / creator / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / creator / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / date / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / date / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / license / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / license / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / physicalDimensions / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / physicalDimensions / type
        Added value: +[
        +  "string",
        +  "null"
        +]
    • Changedget_conservation_history26 fields changed
      • removedOutput schema / properties / conservationHistory / items / properties / date / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / conservationHistory / items / properties / date / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / conservationHistory / items / properties / dateBegin / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / conservationHistory / items / properties / dateBegin / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / conservationHistory / items / properties / dateEnd / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / conservationHistory / items / properties / dateEnd / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / conservationHistory / items / properties / description / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / conservationHistory / items / properties / description / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / conservationHistory / items / properties / modifierUri / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / conservationHistory / items / properties / modifierUri / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / creator / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / creator / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / examinations / items / properties / date / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / examinations / items / properties / date / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / examinations / items / properties / dateBegin / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / examinations / items / properties / dateBegin / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / examinations / items / properties / dateEnd / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / examinations / items / properties / dateEnd / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / examinations / items / properties / examiner / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / examinations / items / properties / examiner / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / examinations / items / properties / reportTypeLabel / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / examinations / items / properties / reportTypeLabel / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / provenanceTextSummary / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / provenanceTextSummary / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / title / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / title / type
        Added value: +[
        +  "string",
        +  "null"
        +]
    • Changedget_recent_changes1 field changed
      • changedInput schema / properties / identifiersOnly / description
        Previous value: -"If true, returns only record headers (identifier, datestamp, set memberships) — much faster. Preserved automatically across continuation pages."New value: +"If true, returns only record headers (identifier = LOD URI, not objectNumber; datestamp; set memberships) — much faster. Preserved automatically across continuation pages."
    • Changedinspect_artwork_image5 fields changed
      • changedInput schema / properties / size / description
        Previous value: -"Width of returned image in pixels (200–2016, default 1568). Defaults align to multiples of 28 for clean LLM coordinate handling: 1568 is Sonnet 4.6's native resolution cap, 2016 is the highest ×28 multiple that stays within Opus 4.7's per-image token budget across common aspect ratios."New value: +"Width of returned image in pixels (200–1988, default 1568). Vision models bill images in 28×28 patches, and that ceiling is the largest width clearing both the per-image patch budget and the stricter per-image limit that applies once a conversation has accumulated many images. Tall and square regions clamp below that automatically — the response reports the width actually delivered."
      • changedInput schema / properties / size / maximum
        Previous value: -2016New value: +1988
      • removedOutput schema / properties / creator / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / creator / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • addedOutput schema / properties / warnings
        Added value: +{
        +  "items": {
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
    • Changedremount_viewer8 fields changed
      • removedOutput schema / properties / creator / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / creator / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / date / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / date / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / license / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / license / type
        Added value: +[
        +  "string",
        +  "null"
        +]
      • removedOutput schema / properties / physicalDimensions / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedOutput schema / properties / physicalDimensions / type
        Added value: +[
        +  "string",
        +  "null"
        +]
    • Changedsearch_artwork3 fields changed
      • changedInput schema / properties / groupBy / description
        Previous value: -"Collapse component records under their parent (sketchbook folios, album pages, print-series leaves). When 'parent' is set, any child record that appears in the result alongside its parent is dropped, and the parent gains a `groupedChildCount`. Only collapses when both child and parent match the query — children whose parent isn't a hit remain in the result. Applied after the BM25 page is selected, so a parent that ranks below the maxResults cutoff won't pull its children in. Closes #28."New value: +"Collapse component records under their parent (sketchbook folios, album pages, print-series leaves). When 'parent' is set, any child record that appears in the result alongside its parent is dropped, and the parent gains a `groupedChildCount`. Only collapses when both child and parent match the query — children whose parent isn't a hit remain in the result. Applied after the BM25 page is selected, so a parent that ranks below the maxResults cutoff won't pull its children in."
      • changedInput schema / properties / hasProvenance / description
        Previous value: -"If true, only return artworks that have parsed provenance records (~48K of 832K). Combine with other filters for cross-domain queries (e.g. type='painting' + hasProvenance=true). Cannot be used alone — combine with at least one other filter."New value: +"If true, only return artworks that have parsed provenance records — roughly 48K, about 6% of the collection. Combine with other filters for cross-domain queries (e.g. type='painting' + hasProvenance=true). Cannot be used alone — combine with at least one other filter."
      • changedInput schema / properties / query / description
        Previous value: -"Search by artwork title — matches against all title variants (brief, full, former × EN/NL). Note: only ~4% of artworks have an English title (~35K of 833K). For non-title text, use the specific field parameters (description, inscription, curatorialNarrative, creator, subject, etc.)."New value: +"Search by artwork title — matches against all title variants (brief, full, former × EN/NL). Note: fewer than one artwork in twenty has an English title. For non-title text, use the specific field parameters (description, inscription, curatorialNarrative, creator, subject, etc.)."
  2. 13 tool updatesv0.90.0
    • First observedbrowse_set
    • First observedfind_artworks_citing_publication
    • First observedget_artwork_bibliography
    • First observedget_artwork_details
    • First observedget_artwork_image
    • First observedget_conservation_history
    • First observedget_recent_changes
    • First observedinspect_artwork_image
    • First observedlist_curated_sets
    • First observednavigate_viewer
    • First observedpoll_viewer_commands
    • First observedremount_viewer
    • First observedsearch_artwork

TDQS

A3.9/5.0

Scored across 13 tools

Disambiguation5/5

Each listed tool has a clearly distinct target: search/discovery, single-artwork metadata, viewer control, set browsing, or change harvesting. The descriptions actively disambiguate close pairs like get_artwork_image vs inspect_artwork_image and navigate_viewer vs inspect_artwork_image, so misselection risk is low.

Naming Consistency4/5

Tool names are consistently snake_case verb_noun and mostly follow predictable groups: search_artwork/get_artwork_*, *_viewer, list/browse sets. Minor deviations like get_conservation_history instead of get_artwork_conservation_history and the long find_artworks_citing_publication keep it from being perfectly uniform.

Tool Count5/5

13 tools is within the ideal range, and each covers a distinct part of the museum workflow: searching, details, images, bibliography, conservation, curated sets, and change feeds. The viewer-related tools are numerous but justified by the interactive viewer feature.

Completeness2/5

The core collection access surface is solid, but descriptions frequently point to tools that are not in this server, including semantic_search, find_similar, collection_stats, search_persons, search_provenance, and search_inscriptions. Any agent following those directions will hit dead ends, and there is no full-text concept search among the available tools. This is a significant gap despite the otherwise rich metadata surface.

Maintenance

ActivityActive
ResponsivenessWithin a week

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Allows you to search for artworks, retrieve detailed information about specific artworks, access image tiles for artworks, and explore user-created collections from the Rijksmuseum.
    16 npm
    72
    MIT
  • F
    license
    Not graded
    quality
    D
    maintenance
    Provides access to European cultural heritage collections and artworks, allowing users to search for items, get detailed information about specific artworks, browse collections by institution, and receive AI-powered recommendations based on interests.
    1
    -
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables natural language search and exploration of the Dutch WWII Oorlogsbronnen archives, allowing users to query historical documents, photographs, and personal accounts through AI assistants.
    9 npm
    15
    MIT
  • A
    license
    B
    quality
    D
    maintenance
    Enables AI agents to search and explore over 570,000 artworks from the Metropolitan Museum of Art and Art Institute of Chicago without needing an API key.
    9
    2
    MIT