Endpoints
Sizes measured at build time, so they cannot drift from what is served.Every entry, one request. No key, no pagination, no rate limit.
Inverted index: proprietary product to open source alternatives. Two requests answer a licence inventory.
The catalogues harvested, their access routes and entry counts, plus the ones surveyed and rejected with reasons.
Counts, the controlled vocabulary for functions and countries, and generated_at. Poll this, not the pages.
Last run, per-step results, open items. Whether the machine is still running.
One entry, and the fields that carry rules
A real record — LibreOffice — trimmed to the fields worth explaining.
{
"id": "opensource-muenchen-de-libreoffice-metadata",
"name": "LibreOffice",
"description": "LibreOffice is a powerful free and open source office suite",
"country": "DE",
"countries": [
"DE",
"FR",
"GLOBAL",
"IT"
],
"source": "DE/opensource.muenchen.de",
"sources": [
"DE/opensource.muenchen.de",
"FR/sill",
"GLOBAL/dpg",
"IT/developers-italia"
],
"repo_url": "https://github.com/tdf/libreoffice-metadata",
"licence": "LGPL-3.0-or-later AND MPL-2.0+",
"licence_spdx": null,
"wikidata": "Q10135",
"catalogue_count": 4,
"catalogues": [
{
"source": "IT/developers-italia",
"label": "Developers Italia",
"country": "IT",
"catalogue_url": "https://developers.italia.it/en/software",
"entry_url": null,
"name_there": "LibreOffice"
},
{
"source": "FR/sill",
"label": "SILL",
"country": "FR",
"catalogue_url": "https://code.gouv.fr/sill",
"entry_url": "https://code.gouv.fr/sill/detail?name=LibreOffice",
"name_there": "LibreOffice"
},
"... 2 more"
],
"replaces": [
{
"product": "Microsoft Office",
"vendor": "Microsoft",
"confidence": "strong",
"kind": "software"
},
{
"product": "Microsoft 365",
"vendor": "Microsoft",
"confidence": "partial",
"kind": "service"
}
],
"link_dead": false,
"repo_archived": false,
"last_checked": "2026-08-17T11:14:26Z",
"translated_from": null,
"excluded": false
}licencenull when the upstream catalogue did not state a real SPDX identifier. It is never guessed from the repository - an spdx-named field holding 'GPLv3+' is worse than a null, because a consumer will trust the name.
entry_urlnull when a catalogue has no per-entry page. A constructed link would 404 for about 40% of one source, so it is left empty instead.
link_deadtrue only after TWO consecutive failed checks. Single 404s oscillate - an unstable signal is worse than a steady wrong one, because it trains you to ignore the report.
replaceshand-curated, not inferred. Each carries `confidence` (strong/partial/adjacent) and `kind`: software replaces the software, service means the paid item is hosting or content, paid-tier means it is a commercial edition of something already open source.
excludedthe entry was harvested but held out of the default view - forks, CI plumbing, deployment recipes, locale bundles. It keeps `exclude_reason` and stays in the data; it is flagged, never deleted.
translated_fromset when the description is machine-translated, with the original in `description_original`. Absent means the publisher wrote it in English - the two are never conflated.
cataloguesone object per government catalogue that lists this software, each with a deep link, so a cross-listing claim can be verified upstream rather than taken on trust.
MCP server
5 tools over the same public data.{
"mcpServers": {
"govoss": {
"url": "https://govoss-mcp.devin-31f.workers.dev"
}
}
}Add that to your MCP client config. No key, no account. The server reads the same public JSON as everyone else, so it can never return something the published data does not contain.
search_entries(query?: string, country?: string, function?: string, source?: string, licence?: string, limit?: number = 20)Full-text search over name, description, owner and also-known-as, with optional facet filters. Every filter is AND-ed.
returns matching entries, most-catalogued first
find_replacements(product: string)The procurement question, answered from an invoice line: give it 'Qualtrics' and it returns the open source alternatives, each marked strong / partial / adjacent and software / service / paid-tier.
returns entries that can replace that product, with confidence and kind
get_entry(id: string)Fetch a single entry by its stable id, including the deep links back to each government catalogue that lists it.
returns one entry, every field
list_sources(include_survey?: boolean = false)Where the data comes from, with each catalogue's access route and entry count. With include_survey, also the ones checked and rejected and why - which saves repeating a dead end.
returns the catalogues harvested, optionally those surveyed and rejected
get_stats((none))How big the catalogue is, when it was last harvested, and the controlled vocabulary for functions and countries.
returns counts, category enum, freshness
Etiquette
Cache it for a week
The catalogue is rebuilt on Mondays. Polling more often than that cannot return anything new; `generated_at` in /meta.json tells you when it last changed.
Use the MCP server for interactive work
If an agent needs a handful of entries rather than all 3,070, the server does the filtering server-side and returns kilobytes instead of megabytes.
Don't drive a browser at the HTML
The first consumer of this catalogue probed eight dead API paths and then ran a headless browser. Everything the page shows comes from entries.json, which is one request and always current.
Don't probe for endpoints
There are five, they are all on this page, and there is no /v2, no GraphQL and no undocumented search to discover. /api/entries, /api/catalog, /catalog.json and /data.json redirect here because they are what the first consumer tried.
Licence and citation
The compilation is CC BY 4.0 and the pipeline code is MIT. The individual entries are not ours to relicense — each describes software published by a government catalogue under that country's own terms, and every entry links back to its source. Cite the government for a fact about one project; cite this catalogue for the aggregate.