A second Model Context Protocol server, built after junelife-ops
and deliberately not a copy of it. That one governs a 388,000-page publishing estate, where the
expensive failure is an agent acting on a stale number. This one governs a corpus — 740,552 business records — where the expensive failure is different: an unbounded query, or an agent mailing a stranger about a website that is not theirs.
Same doctrine, different organ. The architecture follows the difference.
The architecture
Read down, write once. Seats call tools; tools run named queries against BigQuery; exactly one tool writes, and only to a receipts sink. No tool files a ruling, edits the ledger, or fires a build — not by policy an agent is asked to respect, but as a capability it does not have.
What makes this one different from junelife-ops
The data source is a bill, not a repository
junelife-ops reads an estate it owns. This one reads a 48.9 GB public table and a derived
corpus of 740,552 places across 11 tables. An unfenced query here is not a mistake, it is an invoice.
So the read path is constrained three ways, and each one is structural rather than advisory:
- Named queries only. There is no free-form SQL path. Seventeen queries exist, each with its own description and its own reason to exist. This is what makes the byte cap a promise — a cap you can route around with arbitrary SQL is not a cap.
- Every query dry-runs before it runs, and the estimated bytes are recorded and returned in the response. The caller sees the cost of the answer alongside the answer.
- A hard byte ceiling of 2 GB per call, enforced before execution.
The inputs are strangers’ data, so the parameters are never SQL
place_site_check takes a business name. That name travels as a BigQuery named parameter and
never becomes SQL text. A non-match returns a clean empty result carrying a finding — not an
error, and not a silence.
The tool answers with its own doubt
The corpus records a website for each business, taken from Overture. It is wrong roughly two times in five — directories, aggregators and other companies’ sites sit in that field. So the tool that returns it says so, in the response, every time:
The URL comes from Overture and is wrong roughly two times in five — directories, aggregators and other businesses’ sites appear in it. Do not mail it to anyone as evidence about their own site.
That caution is not documentation. It is a field in the payload, because documentation is not present at the moment somebody acts.
Measured example. A barber shop on Staten Island, booking_dependent, carries exactly one
website on record: a shipping company’s domain. A name-matching script passes it — both
strings share a word. The tool returns the row and the caution together, and a human reading it
sees in one line what a regex could not.
Absence has two names, and they are not the same
A verdict of NOT_TIERED means the business sits outside the crawled fleet, so nothing was ever
fetched. NOT_CRAWLED means it is in the fleet and was never fetched. Neither means “no
defects.” They are reported as distinct states rather than collapsed into an empty field,
because a reader who cannot tell them apart will read both as clean.
The same discipline governs the flags: where no page was fetched, the has_* flags are
suppressed rather than returned as zero — four zeros would read as four defects where there
is one absence.
The catalog reads itself
bq_catalog returns every backing table’s schema read live from INFORMATION_SCHEMA on each
call, never a copy baked into the deployed image.
The reason is a failure that had already happened: a seat needed a column name, the catalog it held was stale, and the work stopped. A catalog shipped inside an image ages silently, and the first symptom is a blocked seat. Reading it live costs a round trip and removes the failure mode.
Authorization, and what a public endpoint means
The endpoint is public; the application does the enforcing. OAuth 2.1 with PKCE and dynamic client registration — the client registers itself, so there is no secret to paste anywhere. An unauthenticated call receives a 401 carrying the discovery pointer, not a 200 and not a bare 403.
Authentication to Google is keyless, on workload identity federation. Zero stored service-account keys, marker-verified rather than assumed — a cure that came out of an incident, not a preference.
Where it is honest about itself
The server reports, in every response, that the registers it serves are an image snapshot taken
at build time, not main — so a ruling filed after the image was built reads as absent, and the
response says to re-check against git before concluding anything is unfiled.
A server that quietly served stale governance would be the most dangerous component in the estate. This one announces its own staleness in the payload, and that line is not removable without changing the code.