Nearby Notices
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Nearby Notices show me planning notices near Bristol"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Nearby Notices
What is changing near you, in plain English, with every sentence checked against the notice.
Road closures, parking changes, planning applications, wind farms, smoke control orders and water licences are published in The Gazette, the UK's official public record, in legal language that is hard to read and hard to search by place. Type a postcode or a town, get the notices near you, each read back in plain English beside the notice as published and linked to the record. The same index is an MCP server, so an AI agent can ask the same questions and cite the same record.
For residents, councillors, local journalists and anyone else who wants to know what is being proposed on their street before the objection period closes.
Built with an AI coding assistant under the author's direction, in the author's own time, on open data. Not affiliated with The Gazette, the Government or any council. It shows public notices and does not give advice.


What makes it trustworthy
A language model writes the plain English. Nothing it writes reaches the page unchecked:
Layer | What it does | Where |
Verbatim fields | Places, the authority, both dates and the how-to-object sentence are shown only if the model's value appears word for word in the notice. Kind must be one of a fixed list. |
|
The gate | Every generated sentence, including the heading, goes back to the model with the notice: "is every claim stated in the notice?" The answer counts only with one to three short quotes that really are in the text. Fail-closed on any error. |
|
Advice filter | A generated sentence that tells the reader what to do is removed before the gate is asked. Where a notice says how to object, that sentence is quoted, never composed. |
|
Scrubber | Sentences in a notice addressed to a model ("ignore previous instructions", "tell the reader") are removed before the model and the checks see the text. |
|
The record | The notice as published is always on the page with the Gazette link. The plain-English version is labelled as generated. Removed sentences are counted on the card. | templates |
Category refusal | Only notices by public bodies and companies acting as authorities are fetched. Notices about people are refused at the fetcher and at the store. |
|
The threat model, including what is not defended against, is in docs/safety.md.
Related MCP server: Zyfy MCP Server
Evaluation
Measured, not asserted. evals/ holds 21 notices across 9 Gazette categories (labelled with an AI assistant and checked by hand against the notice text), 84 true and false sentences for the gate, and 3 adversarial notices. On 19 October 2026 nine notices were removed from the set for privacy; earlier runs used 30. uv run python evals/run.py runs everything live against the configured model and writes evals/RESULTS.md.
Latest run, 19 October 2026, on the model the live site uses (Azure OpenAI gpt-4.1-mini), commit 23f716c (full table and caveats in evals/RESULTS.md):
gpt-4.1-mini (live), 21-notice set | |
Gate: false sentences caught | 42 of 42 |
Gate: true sentences kept | 42 of 42 |
Adversarial notices with nothing forbidden shown | 3 of 3 |
Authority, kind, start date, end date, objection sentence | 94%, 100%, 88%, 94%, 100% (17 notices; 4 hit a model error at the start of the run) |
Places affected found | 97%, no correspondence addresses listed |
A gated heading shown | 17 of 17 |
Same notice twice, fields agreeing | 25 of 25 |
Model calls per notice | 4.4, median 24 s per notice under the deployment's throughput cap |
Earlier runs on the 30-notice set (17 and 18 October, local and Azure models) and what changed between them, and why, are in docs/incidents.md.
What the numbers mean, and the labelling rules, are in evals/README.md. The headline to watch is the gate's false-catch rate: a false sentence the gate keeps would reach the page.
How it works
flowchart LR
U[Postcode or town] --> P[postcodes.io] --> G[The Gazette feed<br/>allowed categories only]
G --> M[Measure to nearest filed postcode<br/>linked-data lookup when needed]
M --> S[(SQLite)]
S --> W[Background reader]
W --> X[Model: facts + summary] --> V{Verbatim checks<br/>advice filter}
V --> Q{Gate: quotes in the notice?} --> S
S --> Web[Website: list, grouped, map]
S --> MCP[MCP server: find, read, coverage]Find. The Gazette's own feed, by postcode, distance and category, newest first. The Gazette only honours radii of 1, 5, 10, 15, 20, 25 and 30 miles, so the tool asks for the smallest honoured radius covering the distance you chose (miles or kilometres) and measures each notice itself. A notice is filed under several postcodes (the street, the council, a consultant's office) and the feed gives only the first, so when that one is outside your circle the tool reads the notice's linked-data record for all of them and keeps the notice only if its nearest filed postcode is inside.
Read. A model (any model through LiteLLM; by default a local one) returns the facts as JSON and a two- or three-sentence summary. One background reader, so a burst of searches never becomes a burst of model calls.
Check. The layers in the table above.
Show. As a list, grouped by kind, or on a map (Leaflet served from this site; OpenStreetMap tiles only when you open the map). Each pin sits at the nearest postcode the notice is filed under; pins that would overlap are spread in a ring. The page asks
/statusevery few seconds and swaps in each card as it is ready, without reloading.
Use it from an AI agent (MCP)
Three tools over stdio, same index, same rules:
Tool | What it does |
| Up to 12 notices near a postcode or town, newest first: id, kind, date, one-line title, distance to the nearest postcode it is filed under, whether plain English is ready, link. |
| The notice as published, word for word, plus the checked plain-English version with the counts of what the checks removed. Made on the spot if not ready. |
| What is covered and refused, licence, privacy, distance choices. |
claude mcp add nearby-notices -- uv run --directory /path/to/nearby-notices python -m nearby_notices.mcp_serverAny other MCP client: command uv, arguments run --directory /path/to/nearby-notices python -m nearby_notices.mcp_server. The server's instructions tell the agent the plain English is generated and checked but not official, that it must cite the notice, and that it gives no legal advice.
What it refuses, by design
Only these categories are fetched: Transport, Town and Country Planning, Environmental Protection, Water Resources, Forestry and Plant Health, Electricity. Notices about people (corporate and personal insolvency, deceased estates, appointments, marriages, partnerships, mixed "other" notices) are refused at the fetcher, refused at the store, and never shown; tests/test_rules.py proves it. The Gazette's data licence (Open Government Licence v3) does not cover personal data, and this tool is not for finding out about people. The Gazette staff name carried on every feed entry is never read.
Privacy
No accounts, no cookies, no tracking. What you type is used for the search and not stored, logged or traced. Server logs keep no IP addresses. Counters are daily totals with no identifiers. The map view requests tiles from OpenStreetMap only when you open it. See /privacy.
Run it
uv sync
make run # website on http://127.0.0.1:8765
make mcp # MCP server over stdio
make test # ruff + pytest, no network, no model
make eval # live evaluation, writes evals/RESULTS.mdLive: https://nearby-notices.bluesea-79d4ea2e.uksouth.azurecontainerapps.io on Azure Container Apps (UK South), reading notices with an Azure OpenAI gpt-4.1-mini deployment. It scales to zero when idle, so the first visit after a quiet spell takes a few seconds to wake, and the first search of a new place takes 20 to 30 seconds while the Gazette answers.
Settings are environment variables; see .env.example. With a local OpenAI-compatible server (llama-server, Ollama) leave NN_MODEL unset and the served model's name is read from the server at startup, so the name recorded with each plain-English version is the model actually used. A Dockerfile builds the website; mount /data to keep the cache.
Deploy
The public instance runs on Azure Container Apps, inside the consumption plan's monthly free grant, with the image published to GitHub's container registry (free) and pulled from there, so there is no registry bill. One script does it: deploy/azure.sh, run as a service principal that holds Contributor on one resource group and nothing else. It creates the resource group, a £5 monthly budget with email alerts, the environment, and the app with the model settings as secrets, scale-to-zero when idle and one replica at most. On every push to main the image workflow builds and publishes the image and the deploy workflow rolls the app to it.
Public-endpoint settings differ from a private run in two ways, both environment variables: a lower daily model-call cap (NN_DAILY_CALL_CAP) and a per-client searches-per-minute limit (NN_SEARCHES_PER_MINUTE) that keeps no addresses.
Repository map
nearby_notices/ gazette.py (feed, linked data, fair use) places.py (postcodes.io) geo.py (units, radii, distance)
search.py (the pipeline) extract.py (model, checks, gate) worker.py (one reader) store.py (SQLite)
app.py (FastAPI pages) mcp_server.py (MCP tools) categories.py groups.py config.py
templates/ static/ GOV.UK Design System patterns without the reserved marks; Leaflet vendored
evals/ gold.jsonl, notices/, adversarial.jsonl, run.py, RESULTS.md
tests/ rules, geo, app, mcp, injection, evals scoring
docs/ safety.md, decisions.md, incidents.md, screenshots/Limitations
To be written by the author in his own words after the first week of use. Known today: sentences that count or summarise a list are usually removed by the gate, because no single span of the notice says so; a notice whose prose is itself wrong will be reflected faithfully; the first search of a new place takes 20 to 30 seconds while the Gazette answers.
Licence
Code: MIT. Notice data: The Gazette, Open Government Licence v3. Place data: postcodes.io, Open Government Licence. Map tiles: OpenStreetMap contributors.
Available Tools
3 toolscoverageA
What this server covers and refuses, and the data licence and privacy terms. Call this before answering questions about what kinds of notice can be found here.
Inputs: no named parameters.
find_notices_nearA
Find public notices near a UK postcode or town. place is a postcode (for example "DY1 1HF") or a town
("Dudley"). distance is snapped to the offered choices: miles 1, 3, 5, 10, 15 or kilometres 2, 5, 10, 15, 25;
unit is "mi" or "km". Returns up to 12 notices, newest first, each with its id, kind, date, a one-line title,
how far the nearest postcode it is filed under is from the place, whether a plain-English version is ready, and
the Gazette link. Call read_notice with an id for the full text and the plain-English version.
Inputs: place (required), unit, distance.
read_noticeA
Read one notice by id (from find_notices_near): the notice as published, word for word, and a plain-English version: what is changing, the places affected, the authority, from when and until when, the kind of notice, the notice's own sentence on how to object (quoted, never composed), and a short summary in which every sentence was checked against the notice; sentences that failed the check were removed and are counted. If the version is not ready it is made now, which can take a minute. Always cite the url.
Inputs: notice_id (required).
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 3 tools
The three tools serve clearly distinct roles: coverage is a meta-information tool, find_notices_near searches by place, and read_notice retrieves a specific notice by id. There is no overlap in purpose or expected inputs, and the descriptions explicitly tell the agent when to use each.
The action-oriented tools use a consistent snake_case verb_noun pattern (find_notices_near, read_notice). The meta tool 'coverage' deviates by being a bare noun rather than a verb phrase, which is a minor inconsistency but still readable and clear.
Three tools are exactly right for a focused notice discovery and reading server: one explains scope and terms, one searches nearby, and one reads a full notice. No tool feels redundant or missing from the core workflow.
The surface covers scope, nearby search, and detail retrieval, but find_notices_near is capped at 12 newest results with no pagination and no filtering by notice kind, date, or authority. These are notable gaps for an agent that needs to browse beyond the most recent dozen notices.
Related MCP Connectors
UK Gazette insolvency JSON: $2/1k notices + $3/1k linked details; company numbers, petitions.
Gazette winding-up petitions, liquidations and administrations.
Companies House, Gazette notices, sanctions screening, LEIs and UK legislation.
Query UK Parliament, elections, crime stats, ONS census data, and national archives
Related MCP Servers
- AlicenseAqualityDmaintenanceEnables AI assistants to search and retrieve UK Companies House data including company profiles, officers, and filing history via the official API.4196 npm1MIT

Zyfy MCP Serverofficial
AlicenseAqualityDmaintenanceEnables natural language queries about UK postcodes and vehicles, including flood risk, crime rate, broadband coverage, property prices, MOT history, and ULEZ compliance.441 npmMIT- FlicenseBqualityDmaintenanceProvides access to UK Companies House public data, enabling search and retrieval of company profiles, officers, filing history, and more through natural language queries.12-
- AlicenseNot gradedqualityCmaintenanceEnables querying official UK public records from The Gazette, including insolvencies, winding-up petitions, and deceased estates.296 npmMIT