Agent-First Entity Database: Schema, MCP Contract, and Benchmarks
EntityScope is a working, self-hosted entity knowledge base whose primary client is an agent. It uses DuckDB for storage, exposes four bounded MCP tools, tracks provenance at field level, and has no application UI.
The interesting decision was not “remove the dashboard.” It was to replace a forgiving human interface with a stricter machine contract. An agent needs explicit identifiers, bounded queries, freshness signals, provenance, and failure states. A blank cell and a stale fact cannot look the same.
What exists today
I inspected the repository and measured the current local database on 28 July 2026. These are implementation facts, not roadmap claims:
| Artifact | Observed state | Why it matters |
|---|---|---|
| Entity spine | 1,010 rows | One stable record per resolved legal entity |
| Field provenance | 8,018 rows | Source, confidence, URL, and verification time can vary by field |
| Prospect profiles | 479 rows | Curated and imported commercial context remains separate from the legal spine |
| Berlin source rows | 1,000 rows | Raw source data is retained instead of being collapsed too early |
| MCP surface | 4 read tools | Query, entity lookup, source inventory, and health |
| Automated suite | 130 pass; 1 stale fixture fails | The failure expects 100 prospect files although the corpus now has 479 |
That failed fixture is worth reporting. A test count is not evidence if the assertion has drifted away from production data. The correct repair is to test an invariant—such as “all valid files were ingested”—instead of hard-coding a historical corpus size.
The schema separates identity, claims, and evidence
entities
hrb_id stable legal identifier
canonical_name resolved legal name
address_city normalized location
industry_label normalized classification
employee_count latest known total
employees_on_site latest known local count
revenue_estimate latest estimate
entity_sources
hrb_id + field_name + source_name
confidence
source_url
last_verified
prospects
slug working identifier
hrb_id nullable link to legal entity
funding_stage
total_funding
team_size
tags
enrichment_status
The key design choice is the composite provenance record. “Company X has 50 employees” is not stored as timeless truth. It is a claim about one field, from one source, observed at one time, with a confidence level. Conflicting claims can coexist until a resolution policy chooses what to present.
Why agents should not generate SQL
The query path translates intent into an allow-listed filter object. The database layer then builds parameterized predicates. The agent never receives database credentials and never emits executable SQL.
{
"filters": {
"city": "München",
"employees_on_site_max": 10
},
"confidence": 0.8,
"explanation": "location=München; max 10 on-site employees"
}
Common patterns use deterministic parsing first. A model is an optional fallback for unsupported language. This ordering reduces latency and cost, but more importantly it makes common queries testable. If translation confidence is zero, the system should return “unsupported,” not silently broaden the search.
The four-tool MCP contract
| Tool | Responsibility | Required guardrail |
|---|---|---|
entityscope_query | Intent to bounded entity list | Allow-listed filters and maximum result limit |
entityscope_get_entity | One profile by HRB ID, registration number, name, or slug | Return ambiguity rather than guessing between matches |
entityscope_list_sources | Source inventory and freshness | Expose missing verification timestamps |
entityscope_health | Counts, enrichment progress, and staleness | Health must describe data quality, not only process uptime |
The current service is deliberately read-only at the agent boundary. Ingestion and enrichment happen through separate controlled jobs. That separation limits blast radius and makes the read contract easier to trust.
Measured query performance
I opened the 7 MB DuckDB file read-only, warmed the structured filter path 20 times, then ran the same Munich and small-team query 500 times through the production query function.
| Runs | Rows returned | Median | p95 | Maximum |
|---|---|---|---|---|
| 500 | 1 | 1.972 ms | 2.329 ms | 2.709 ms |
This is a local warm-cache measurement, not an end-to-end SLO. It excludes natural-language translation, MCP serialization, process startup, network transport, and model calls. The downloadable protocol records the corpus, filter, warm-up, sample count, and percentile calculation so the result can be rerun instead of repeated as folklore.
Freshness is part of the answer
EntityScope computes staleness from field-level verification timestamps. The current health policy warns when more than 30% of provenance rows are missing a recent verification. That is a useful start, but a production policy should vary by field:
- legal identity may tolerate a longer refresh interval;
- headcount and funding signals decay faster;
- contact details should expire quickly;
- a high-impact decision may require live reconciliation regardless of age.
An agent response should distinguish verified, stale, conflicting, and unknown. Returning a value without its evidence state invites confident misuse.
Entity resolution is the real hard problem
Storage is straightforward. Joining “Acme,” “Acme GmbH,” a website domain, and a registry number without merging two different companies is not. The resolution pipeline should be conservative:
- Match stable registry identifiers exactly when available.
- Normalize legal suffixes, Unicode, punctuation, and domains.
- Generate candidates using name and location.
- Score candidates using independent attributes.
- Auto-merge only above a calibrated threshold.
- Persist rejected and ambiguous candidates for review.
False merges are usually more expensive than duplicates because they contaminate every downstream fact. “No match” is a valid result.
When zero UI works—and when it does not
Zero UI works when the users are automated systems, the tool surface is small, the schema is stable, and operational state is observable elsewhere. It is a poor choice when humans must resolve conflicts, correct records, explore unfamiliar data, or approve consequential changes.
The next interface EntityScope needs is therefore not a general dashboard. It is a focused review surface for ambiguous matches, conflicting claims, and stale critical fields. Agent-first does not mean human-absent; it means human attention is reserved for decisions that automation cannot justify.