Search UK street crime, outcomes, stop and search, and neighbourhood teams (Scotland: BTP only).
Search UK street-level crime, police outcomes, stop and search, and neighbourhood teams from data.police.uk: England, Wales and Northern Ireland forces, plus British Transport Police (Scotland's only coverage), via MCP. STDIO or Streamable HTTP.
Monthly street-level crime, police outcomes, and stop and search records from data.police.uk, plus the neighbourhood policing teams behind them. Coverage is the 43 territorial forces of England and Wales and the Police Service of Northern Ireland, plus British Transport Police, whose station records are the only coverage of Scotland. Search by point, polygon, map point, neighbourhood, or whole force; follow a crime's outcome history; find who polices a place. Runs as a stdio process or a local Streamable HTTP server. No API key required.
| Tool | Description |
|---|---|
ukcrime_list_reference | Decode force ids, crime categories, a force's neighbourhood ids, and which months and forces are published |
ukcrime_search_crimes | Search the street-level crimes recorded in one month inside an area, with counts by category and latest outcome |
ukcrime_search_outcomes | List the police outcomes recorded in one month inside an area, for crimes from that month or earlier |
ukcrime_get_crime_outcomes | Fetch the full outcome history of up to 25 crimes by persistent_id |
ukcrime_search_stops | Search stop and search records for one month inside an area or across a whole force, with breakdowns and filters |
ukcrime_find_neighbourhood | Find the force and neighbourhood policing team for a point, or look one up by id |
ukcrime_list_reference tooltopic: forces, categories, availability, or neighbourhoods (needs force); name_contains filters forces and neighbourhoods by name, and month narrows availability to one rowavailability returns latest_month, earliest_month, and which forces published stop and search each month; with force, the months that force did and did not publishforces adds British Transport Police (btp) and each force's known coverage gaps; errors are typed (force_required, unknown_force, invalid_filter)ukcrime_search_crimes toolarea: point (lat, lng; a 1-mile radius), polygon (3–2,500 vertices), location (location_id), neighbourhood (force + neighbourhood_id), or force_unplaced (force: the crimes it could not place); optional month (default: latest published) and category (default: every category)total, by_category, by_outcome, up to 10 top_locations, and a page of crimes, each with the persistent_id that ukcrime_get_crime_outcomes takes; limit defaults to 25 (max 200), and next_offset continuesreason, such as month_not_published, unknown_category, or area_too_largeukcrime_search_outcomes toolukcrime_search_crimes except force_unplaced; month is when the outcome was recorded, and category counts only outcomes for crimes in that categorytotal, unfiltered_total, by_outcome (code, name, count), by_crime_month, and a page of outcomes, each with its crime; limit defaults to 20 (max 200)ukcrime_get_crime_outcomes toolpersistent_ids: 1–25 64-character ids from ukcrime_search_crimes or ukcrime_search_outcomes; anti-social behaviour records carry nonehistory_available: false marks a crime with no published historynot_found, failed lookups in failed, so one bad id never fails the batchukcrime_search_stops toolarea: point, polygon, location, neighbourhood, or force (every stop the force published, placed or not); up to 8 filters on type, self_defined_ethnicity, officer_defined_ethnicity, outcome, object_of_search, legislation, age_range, or gendertotal, unfiltered_total, unplaced, force_published, a breakdown per filterable field, and a page of stops; limit defaults to 15 (max 200)ukcrime_find_neighbourhood toollat + lng or by force + neighbourhood_id; include picks priorities, team, events (the default three) and boundaryevents_total counts all), and the boundary as a polygon string the search tools acceptfound: false with guidanceBuilt on @cyanheads/mcp-ts-core: stdio and Streamable HTTP transports, pluggable auth (none / jwt / oauth), swappable storage (in-memory, filesystem, Supabase, Cloudflare KV/R2/D1), structured logging with optional OpenTelemetry tracing.
data.police.uk-specific:
month searches the latest published month and echoes it; coverage gaps per force are dated and named in each result's noticeAgent-friendly output:
data_note on what the records can and cannot saylimit / offset / next_offset page the rowsnotice that separates "no data published" from "nothing happened"Under investigation(not recorded); stop datetime is UTC while months follow UK local timeAdd the following to your MCP client configuration file.
{
"mcpServers": {
"uk-police-crime-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/uk-police-crime-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with npx (no Bun required):
{
"mcpServers": {
"uk-police-crime-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/uk-police-crime-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}
Or with Docker:
{
"mcpServers": {
"uk-police-crime-mcp-server": {
"type": "stdio",
"command": "docker",
"args": ["run", "-i", "--rm", "-e", "MCP_TRANSPORT_TYPE=stdio", "ghcr.io/cyanheads/uk-police-crime-mcp-server:latest"]
}
}
}
For Streamable HTTP, set the transport and start the server:
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http
# Server listens at http://localhost:3010/mcp
git clone https://github.com/cyanheads/uk-police-crime-mcp-server.git
cd uk-police-crime-mcp-server
bun install
The server reads no environment variables of its own. data.police.uk allows 15 requests a second with a burst of 30 per client IP; the server paces every request process-wide under that limit, so a hosted deployment shares one budget behind its egress IP, and requests queue for their turn.
| Variable | Description | Default |
|---|---|---|
MCP_TRANSPORT_TYPE | Transport: stdio or http. | stdio |
MCP_HTTP_PORT | HTTP server port. | 3010 |
MCP_SESSION_MODE | HTTP session mode: stateless, stateful, or auto. | stateless |
MCP_AUTH_MODE | Authentication: none, jwt, or oauth. | none |
MCP_LOG_LEVEL | Log level (debug, info, warning, error, etc.). | info |
LOGS_DIR | Directory for log files (Node.js only). | <app-root>/logs |
STORAGE_PROVIDER_TYPE | Storage backend: in-memory, filesystem, supabase, cloudflare-kv/r2/d1. | in-memory |
OTEL_ENABLED | Enable OpenTelemetry. | false |
See .env.example for the common framework overrides.
Build and run the production version:
# One-time build
bun run rebuild
# Run the built server
bun run start:http
# or
bun run start:stdio
Run checks and tests:
bun run devcheck # Lints, formats, type-checks, and more
bun run test # Runs the test suite
| Directory | Purpose |
|---|---|
src/mcp-server/tools | Tool definitions (*.tool.ts), plus the area handling, input vocabulary and output shapes the three search tools share. |
src/services/police-api | data.police.uk client — request pacer, retries, caches, upstream schemas, record normalization, and the dated coverage-gaps table. |
tests/ | Unit and integration tests, mirroring the src/ structure. |
See CLAUDE.md for development guidelines and architectural rules. The short version:
try/catch in tool logicctx.log for logging, ctx.state for storagecreateApp() arrays in src/index.tsIssues are welcome. Run checks and tests before submitting:
bun run devcheck
bun run test
This project is licensed under the Apache 2.0 License. See the LICENSE file for details.
Data: Contains public sector information licensed under the Open Government Licence v3.0. Source: data.police.uk. Every tool response carries this attribution; storing, caching and redistributing the data are permitted with it. This project is independent of the Home Office, data.police.uk and the police forces.
Source-derived launch command. Check the maintainer’s required arguments and credentials before running:
npx -y @cyanheads/uk-police-crime-mcp-serverMerge this template into ~/Library/Application Support/Claude/claude_desktop_config.json. Keep existing servers. Add any arguments, credentials, and permissions required by the maintainer; this template has not been install-tested.
{
"mcpServers": {
"io-github-cyanheads-uk-police-crime-mcp-server": {
"command": "npx",
"args": [
"-y",
"@cyanheads/uk-police-crime-mcp-server"
]
}
}
}Restart Claude Desktop completely for changes to take effect. Confirm the server appears connected in the client’s tool list, then try a read-only example from its documentation.
Claude Desktop setup referenceio.github.cyanheads/uk-police-crime-mcp-server works with any MCP-compatible client. Copy the config snippet from the Configuration section above and add it to the file shown for your client, then restart the application.
~/Library/Application Support/Claude/claude_desktop_config.jsonRestart Claude Desktop completely for changes to take effect.~/.cursor/mcp.jsonRestart Cursor for changes to take effect..vscode/mcp.jsonReload VS Code window for changes to take effect.~/.codeium/windsurf/mcp_config.jsonRestart Windsurf for changes to take effect..mcp.jsonSave at the project root, then start Claude Code in that project and review the MCP server approval prompt. Keep real credentials out of shared files.