geldersarchief-mcp
# Gelders Archief scan core
Lokale **MCP-server**, Python-core en CLI voor het zoeken van Gelders Archief-aktes,
het ontdekken van alle registerscans en downloaden met provenance.
De MCP-server draait via stdio met de officiële SDK. OCR is optioneel en standaard
uitgeschakeld in MCP; zoeken, inspecteren en expliciet downloaden werken zonder OCR.
```bash
uv sync --frozen
uv run --frozen geldersarchief-mcp
```
Verbind een MCP-client met [de clientconfiguratie](examples/mcp-client.json).
Zie [MCP-tools en gebruik](docs/mcp.md) voor de volledige interface en downloadflow.
De voorbeeldpermalink is live getest op 5 oktober 2026: **192 unieke scans**, met
volgorde 1–192. De viewer laadt aanvankelijk 25 referenties. De core ontdekt alle
scans rechtstreeks via HTTP, zonder Chromium te starten. Scan 176 is via de
expliciete viewer-downloadlink opgeslagen als JPEG, 3019 × 4170 pixels,
1.372.341 bytes. SHA256:
```text
c9488c8abf3aa2c97921c7f04e080cc2299a52af79156f606640f36b04091611
```
Dit is de door de viewer aangeboden downloadrepresentatie. Het archiefmaster-
bestand is niet onafhankelijk beschikbaar gesteld of op byte-identiteit getest.
Scan 176 is een technisch testobject; er is niet vastgesteld dat deze scan de
akte uit de voorbeeldpermalink bevat.
## Installatie
Vereist: Python 3.12+ en [uv](https://docs.astral.sh/uv/).
```bash
uv sync --frozen
# Alleen nodig voor vieweronderzoek en browserfallbacks:
uv run playwright install chromium
```
## CLI
```bash
uv run geldersarchief inspect \
'https://permalink.geldersarchief.nl/E42035012A364A3E9190403665F46E77'
uv run geldersarchief download-scan \
'https://permalink.geldersarchief.nl/E42035012A364A3E9190403665F46E77' \
--sequence 176
```
JSON-resultaten staan op stdout; geredigeerde JSON-logs op stderr. Gebruik
`geldersarchief --debug inspect URL` voor batchdiagnostiek. Downloads komen
standaard in `data/downloads/`; `--output DIRECTORY` overschrijft dat per opdracht.
Bestanden heten `<register>_scan-<volgnummer>.<ext>`. De sidecar bevat bronpermalink,
register, inventaris, scan-ID, oorspronkelijke download-URL, UTC-downloadtijd,
SHA256, dimensies, discoverymethode en representatietype. Aktenummer en confidence
blijven bij een expliciet gekozen CLI-scan `null`. MCP-downloads bewaren daarnaast
de resolutiestatus en het eventuele bewijs van een aktekoppeling. Afbeeldingen worden zonder
hercompressie opgeslagen.
## Vieweronderzoek
```bash
uv run python scripts/inspect_viewer.py --load-all --output debug/research
```
Dit legt consolemeldingen, requests, redirects, relevante JSON/JavaScript,
DOM, scriptbronnen, window-keys en stores vast. `--load-all` laadt de batches van
het geselecteerde register opeenvolgend met 350 ms vertraging. `--headed` opent
een zichtbaar venster. Een expliciete viewer-URL kan als positioneel argument
worden meegegeven om ook de iframe-/tileviewer te onderzoeken.
Op de ontwikkelmachine sluit het lokale netwerkverkeer van Chromium verbindingen
met deze site af, terwijl HTTP met OS-certificaatvertrouwen werkt. Hiervoor is er
een expliciete transportoptie:
```bash
uv run python scripts/inspect_viewer.py --http-transport --load-all
GA_BROWSER_HTTP_TRANSPORT=true uv run pytest -m live
```
Hierbij voert Chromium nog steeds de viewer-JavaScript uit en traceert Playwright
requests; HTTPX verzorgt het transport met gecontroleerde TLS via de OS-truststore.
TLS-verificatie wordt niet uitgeschakeld. Deze optie is geen site-authenticatie- of
CAPTCHA-omzeiling. Normale CLI-discovery heeft deze optie niet nodig.
## Python-interface
```python
import asyncio
from geldersarchief_mcp.archives.geldersarchief import GeldersArchiefAdapter
async def main():
async with GeldersArchiefAdapter() as archive:
register = await archive.inspect_register(
'https://permalink.geldersarchief.nl/E42035012A364A3E9190403665F46E77'
)
image = await archive.get_scan(register.scans[175])
# image bevat de originele bytes van de viewer-downloadrepresentatie.
asyncio.run(main())
```
`inspect_register` geeft alleen een volledig register terug. Ontbrekende batches,
conflicterende posities of een onbekend totaal geven een expliciete exception.
`download_scan` geeft naast bytes ook de gevalideerde URL, MIME en dimensies terug.
Een verlopen URL vereist verse registerdiscovery; langdurige tokencaching is nog
niet geïmplementeerd.
## Configuratie
| Variabele | Default |
|---|---|
| `GA_DATA_DIR` | `data` |
| `GA_DOWNLOAD_DIR` | `<GA_DATA_DIR>/downloads` |
| `GA_BROWSER_HEADLESS` | `true` |
| `GA_BROWSER_HTTP_TRANSPORT` | `false` |
| `GA_MAX_CONCURRENT_REQUESTS` | `2` |
| `GA_MAX_IMAGE_DOWNLOADS` | `2` |
Eén adapter beheert één herbruikbare browser, maximaal twee contexts, maximaal twee
registeroperaties en twee downloads met de defaults. Bulk-batches zijn sequentieel
met 350 ms vertraging. HTTP 429/502/503/504 krijgt beperkte retries met back-off en
`Retry-After`. Alleen openbare bronnen worden gebruikt; geen externe AI-services.
De resolver gebruikt uitsluitend lokale OCR en een lokale observatiecache.
Debugoutput en lokale downloads zijn uitgesloten via `.gitignore`. Debugoutput
redigeert sessies en toegangstokens, ook in base64-HTML en ge-escapete JSON.
**Lokale provenance bevat de volledige publieke download-URL** voor reproduceerbaarheid;
publiceer die sidecars niet zonder de URL-tokens te redigeren.
## Tests
```bash
uv run pytest # offline; live tests uitgesloten
uv run pytest -m live # bewuste publieke netwerkcontrole
```
Offline tests dekken parsing, volgorde, ontdubbeling, storeselectie, ontbrekende
batches, downloadvalidatie, provenance, concurrency, redactie en back-off.
Live tests herhalen discovery/download met verse HTTP-clients en browserinstances.
CI draait alleen offline tests, op Python 3.12 en 3.14.
De bewezen HTTP-route is primair. Browserstore-, DOM- en navigatiefallbacks zijn
voor toekomstige wijzigingen; hun algemene werking buiten het geteste register
is niet aangetoond. Zie [het onderzoeksrapport](docs/reverse-engineering.md) voor
waarnemingen, beperkingen en de tien onderzoeksvragen.
Docker is nog niet geïmplementeerd. De observatiecache is geen volledige
registerindex.
MIT-licentie. Het project is niet verbonden aan het Gelders Archief of DE REE.
## Open Archieven-integratie
Zoeken en het normaliseren van records zijn geïmplementeerd via de officiële
Open Archieven 1.1 API. Zoekresultaten worden verrijkt met de volledige A2A-records,
zodat aktenummer, inventarisnummer en archiefbron beschikbaar zijn.
```bash
uv run geldersarchief search-acts --name 'Derk Jan van Brink' \
--place Terwolde --year 1921 --record-type geboorte
uv run geldersarchief get-record \
'gld:E4203501-2A36-4A3E-9190-403665F46E77'
uv run geldersarchief inspect \
--record 'gld:E4203501-2A36-4A3E-9190-403665F46E77'
```
`download-scan` accepteert eveneens `--record` in plaats van een URL, maar vereist
nog steeds een expliciet `--sequence`. Dat is **geen automatische akte→scan-match**.
De sidecar bewaart het aangevraagde record apart van de ongeverifieerde aktevelden.
Typen: `birth`/`geboorte`, `death`/`overlijden`, `marriage`/`huwelijk`. Een `--date`
filtert op de gebeurtenisdatum. `--limit` (1–100) en `--start` bedienen paginering;
`number_found` is het aantal persoonstreffers van de API, vóór lokale filtering en
ontdubbeling op record-ID. `next_start` verwijst naar de volgende API-pagina.
De bekende geboorteakte heeft `event_date=1921-12-30`, `act_date=1922-01-02` en
`act_number="1"`. De resolver gebruikt de aktedatum voor nummerpositionering.
Onvolledige datums worden niet aangevuld met verzonnen maanden of dagen.
De client begrenst opeenvolgende calls tot maximaal één per 350 ms. Ontbrekende
records, HTTP-fouten en API-foutcodes worden expliciet afgehandeld. Er is geen
API-key of AI-provider nodig. Configureer `GA_USER_AGENT` met je project-URL of
contactadres bij publiek gebruik, zoals Open Archieven vraagt.
Details en bronnen: [Open Archieven-integratie](docs/openarchieven.md).
## Conservatieve akte→scan-resolver
Installeer voor `resolve` lokaal Tesseract en Nederlandse taaldata, bijvoorbeeld
op macOS met `brew install tesseract tesseract-lang`.
```bash
uv run geldersarchief resolve \
--record 'gld:E4203501-2A36-4A3E-9190-403665F46E77' --max-scans 12
uv run geldersarchief resolve 'https://permalink.geldersarchief.nl/E42035012A364A3E9190403665F46E77' \
--act 1 --date 1922-01-02 --name 'Derk Jan van Brink'
```
Bij `resolve` betekent `--date` de **aktedatum**. De zoekstrategie controleert
expliciete scanmetadata, bemonstert het register en gebruikt interpolatie alleen
bij voldoende monotone nummerankers. Het scanbudget voorkomt een onbeperkte
OCR-doorloop. Kandidaten en buurscans zijn verwijzingen, geen automatische download
van een als juist bevestigde akte.
Live proef op het voorbeeldregister: na 12 bekeken scans blijft het resultaat
`AMBIGUOUS`. Tesseract las losse nummers, maar bevestigde geen bijbehorende datum
of naam. Vervolgonderzoek heeft scan **3** visueel bevestigd als akte 1. De optionele
lokale Kraken-reader herkent de aktedatum en stelt scan 3 voor als kandidaat
(`AMBIGUOUS`), maar bevestigt de akte nog niet automatisch. Zie [lokale HTR](docs/local-htr.md) voor installatie en downloadbewijs. Algorithmische tests met
gecontroleerde observaties bewijzen de zoeklogica, niet de leeskwaliteit van deze
handgeschreven bron. Zie [resolver en live beperkingen](docs/resolver.md).
| Variabele | Default |
|---|---|
| `GA_CACHE_DB` | `<GA_DATA_DIR>/cache.sqlite` |
| `GA_RESOLVER_MAX_SCANS` | `24` |
| `GA_OCR_EXECUTABLE` | `tesseract` |
| `GA_OCR_LANGUAGE` | `nld` |
De lokale SQLite-cache bewaart OCR-tekst met afbeeldings-SHA256 en readeridentiteit.
Verwijder de cache na het vervangen van taalmodelbestanden; hun inhoud is geen
onderdeel van de readeridentiteit. Cache en scans blijven buiten Git.
TDQS
Scored across 6 tools
Most tools have distinct purposes (search, get, inspect, resolve, download), but resolve_act_scan and download_act overlap since download_act also resolves, and download_scan vs download_act both download scans. Descriptions provide enough guidance to differentiate them, keeping this a minor issue.
All six tools follow a consistent snake_case verb_noun pattern: get_record, search_acts, inspect_register, resolve_act_scan, download_scan, download_act. The convention is predictable and readable throughout.
Six tools is well-scoped for a focused archival/genealogy resolution workflow. Each tool targets a distinct stage (search, retrieve, inspect, resolve, download) without redundancy bloat.
The surface covers the full discovery-to-download lifecycle: searching acts, fetching records, inspecting registers, resolving acts to scans, and downloading scans/acts. Minor gap in that there's no explicit listing of collections/registers beyond inspect_register, but core workflows are covered.