nhs-intelligence-mcp
This server provides deterministic NHS waiting-time and trust-quality data tools for MCP clients, with no network calls at query time.
Look up the latest waiting time (in weeks) for a trust and specialty from weekly My Planned Care data.
Rank NHS trusts by waiting time for a specialty, optionally filtered by region or limited in number.
Get waiting-time trends for a trust and specialty from monthly RTT data, including change, direction, and monthly series.
Fetch a trust's CQC quality rating overall and by domain using its CQC provider ID.- Build a combined trust profile joining current wait, trend, and CQC rating for a trust identified by provider code or name.
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., "@nhs-intelligence-mcpWhat's the current waiting time for hip replacements at Guy's and St Thomas'?"
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.
nhs-intelligence-mcp
MCP server for NHS waiting times and trust quality. Connects to Claude Code, Claude Desktop, or any MCP-compatible client.
No LLM inside — deterministic data tools only. Reasoning happens in the client.
Install
bash <(curl -fsSL https://raw.githubusercontent.com/Hydaspex/nhs-intelligence-mcp/main/scripts/setup.sh)Downloads the latest nhs_intel.db, verifies checksum, registers a weekly refresh job, prints the .mcp.json snippet.
Related MCP server: NHS MCP Server
Tools
Tool | Input | Returns |
| provider name, specialty | latest wait in weeks |
| specialty, region?, limit? | trusts ranked longest-first |
| provider_code, specialty | delta, direction, monthly series |
| cqc_provider_id | overall + per-domain CQC ratings |
| identifier, specialty, by_name? | current wait + trend + CQC rating |
Example: "Cardiology waiting times at Chelsea and Westminster?" → 10 weeks, Outstanding (Aug 2026).
Data sources
Source | Frequency | Covers |
NHS My Planned Care | Weekly | Current waits — 130 trusts, 74 specialties |
NHS England RTT | Monthly | Trend data |
CQC HSCA Active Locations | Monthly | Trust quality ratings |
All ingested into a single SQLite DB, published as a GitHub release. No network calls at query time.
DB location
OS | Path |
Mac |
|
Linux |
|
Windows |
|
Override: NHS_INTEL_DB=/path/to/nhs_intel.db
Architecture
src/nhs_intel/
domain/ # value objects
sources/ # SQLite-backed adapters
analysis/ # pure trend, ranking, profile logic
ingest/ # rtt_ingest, cqc_ingest, load_db CLIs
server.py # FastMCP layer
data/schema.sql
scripts/setup.sh, refresh_data.sh
.github/workflows/publish_db.ymlDevelopment
uv sync --extra dev
uv run pytest
# Populate DB
uv run nhs-intel-load-db --rtt rtt.csv --planned-care planned_care.csv
uv run nhs-intel-cqc-ingest --out /tmp/cqc.csv && uv run nhs-intel-load-db --cqc /tmp/cqc.csv
uv run nhs-intel-mcpCI
Runs every Sunday 02:00 UTC. Seeds from the previous release, scrapes 130 trusts, refreshes CQC data, and incrementally backfills any recent RTT months the DB is missing, so waiting-time history accrues across runs. Publishes nhs_intel.db + SHA-256.
Requires WEBSCRAPER_READ_TOKEN secret — see .github/SECRETS.md.
Available Tools
5 toolsget_trust_ratingA
Look up a trust's current CQC quality rating by its CQC provider id (e.g. '1-101681210'). Returns the overall rating (e.g. 'Good', 'Requires improvement') and any per-domain ratings (safe, effective, caring, responsive, well-led). Returns found=false if the provider is unknown or not yet rated; do not infer a rating in that case.
| Name | Required | Description | Default |
|---|---|---|---|
| cqc_provider_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the behavioral disclosure burden. It discloses the return shape (overall plus per-domain ratings), the not-found behavior (found=false), and an important instruction not to infer a rating. This is strong for a read-only lookup tool, though it does not explicitly mention safety or data freshness.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, each earning its place: purpose and input, return content, and the critical not-found behavior. Information is front-loaded and no filler is present.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter lookup tool with an output schema, the description is complete. It covers input, expected outputs, the not-found case, and the correct behavior when no rating exists. Nothing essential for an agent to select and call the tool correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must compensate. It explains that cqc_provider_id is the CQC provider id and supplies a realistic example ('1-101681210'), adding meaning beyond the bare schema field. It does not elaborate on id source or formatting rules, but the example and context are sufficient for correct invocation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly identifies the action (look up), the resource (a trust's current CQC quality rating), and the lookup key (CQC provider id), with a concrete example. It also distinguishes itself from sibling tools focused on wait times and trust profiles by explicitly focusing on CQC quality ratings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description states the task and input clearly enough that an agent knows when to invoke it: whenever a trust's CQC rating is needed. It does not explicitly name sibling alternatives or exclusion conditions, but the focused wording and the contrast with wait-time-related siblings imply the appropriate use case.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
lookup_wait_timeA
Look up the latest reported waiting time for one NHS trust and specialty from My Planned Care (updated weekly). Waits are in whole weeks. Provide the trust name as published (e.g. 'Guy's and St Thomas'') and the specialty (e.g. 'Cardiology'). Returns found=false if the trust/specialty is not held; do not invent a figure. Note the trust is identified by name here, unlike wait_time_trend which uses an RTT provider code.
| Name | Required | Description | Default |
|---|---|---|---|
| provider | Yes | ||
| specialty | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden of behavioral disclosure. It states that waits are in whole weeks, data is updated weekly, found=false is returned when the trust/specialty is not held, and that the agent must not invent a figure. These are material behaviors beyond the schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Every sentence adds necessary information: purpose and source, units, parameter formatting, not-found behavior, and the sibling-tool distinction. The description is front-loaded with the core purpose and contains no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter lookup tool with an output schema, this description is remarkably complete. It covers source, freshness, units, input formatting, missing-data behavior, and the key alternative tool, leaving no significant gap for an agent to resolve.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. It does so thoroughly by explaining that provider should be 'the trust name as published' with an example, and specialty should be like 'Cardiology' — also clarifying the name-based identifier, which is essential for correct use.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb and resource: 'Look up the latest reported waiting time for one NHS trust and specialty from My Planned Care.' It clearly distinguishes this tool from wait_time_trend by noting the trust is identified by name here rather than by RTT provider code.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly contrasts this tool with wait_time_trend, stating that lookup_wait_time uses the trust name while wait_time_trend uses an RTT provider code. This gives the agent a concrete basis for choosing between the two alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
rank_trusts_by_waitA
Rank NHS trusts by their latest waiting time for a specialty (longest first), using My Planned Care weekly data. Provide the specialty; optionally restrict to a region and cap the number of trusts returned. Trusts that publish the specialty but no wait figure are listed after the ranked ones, so coverage gaps are visible rather than hidden.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | ||
| region | No | ||
| specialty | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description must carry behavioral disclosure, and it does: it reveals the ordering, the optional filters, and the important edge-case behavior that trusts without figures are listed after ranked ones. It does not mention read-only status or availability constraints, but for a data-query tool the stated behavior is substantively transparent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences contain the core purpose, data source, ordering, optional parameters, and an edge-case behavior with zero filler. The statement is front-loaded with the action and resource.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a ranking tool with an output schema, the description is largely complete: it explains the data source, ordering, filters, and gap behavior. Minor details like the unit of waiting time or whether limit applies to gap-listed trusts are not stated, but an agent can invoke the tool correctly from this description.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema has 0% parameter coverage, so the description must compensate, and it maps all three parameters: specialty is the required filter, region restricts geography, and limit caps the number of returned trusts. It does not enumerate valid specialty/region values, but it conveys the role of each parameter beyond the bare schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific action ('Rank NHS trusts by their latest waiting time for a specialty'), specifies ordering ('longest first'), and identifies the data source. This clearly differentiates it from siblings like wait_time_trend or lookup_wait_time, which are point/trend lookups rather than cross-trust rankings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description states the use case clearly—comparing trusts across a specialty and optionally filtering by region or count. It does not explicitly name sibling alternatives or say when not to use it, but the ranking purpose and data source give enough context for an agent to select it over lookup/trend tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
trust_profileA
Build a combined profile for one NHS trust and specialty, joining its current wait (My Planned Care), waiting-time trend (RTT), and CQC quality rating. Identify the trust by RTT provider code (e.g. 'RGT') or trust name (e.g. 'Guy's and St Thomas''); set by_name=true when passing a name. Each section is null when that source holds no data. If the trust is not in the identity mapping, returns found=false.
| Name | Required | Description | Default |
|---|---|---|---|
| by_name | No | ||
| specialty | Yes | ||
| identifier | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the behavioral disclosure burden and does disclose key edge cases: sections are null when a source has no data and found=false when the trust isn't in the identity mapping. It does not mention any side effects, auth, or rate limits, but for a read/composite tool these may be less critical; output schema can cover return details.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, no filler: purpose first, then identity parameters, then fallback/null behavior. Every sentence adds a distinct piece of knowledge an agent needs.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The core behavior, identity resolution, nullable sections, and not-found case are all covered, and an output schema exists for return shapes. The main remaining gap is valid specialty values, but the description is otherwise sufficient for correct tool selection and invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must compensate. It explains identifier as an RTT provider code or trust name and defines by_name=true for names, but specialty is only implied by context with no accepted values, format, or examples, leaving one required parameter underspecified.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific composite verb+resource: builds a combined profile for one NHS trust and specialty, joining three named sources. This clearly differentiates it from siblings like wait_time_trend and get_trust_rating, which presumably cover a single source.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description establishes clear context for when to use it — when current wait, RTT trend, and CQC rating are needed together. It also gives conditional guidance for identifier mode via by_name, but doesn't explicitly name sibling alternatives for single-source queries, so no exclusions are stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
wait_time_trendA
Summarise how the waiting time for a given NHS trust and specialty has moved over time, using NHS England RTT monthly data. Waits are in weeks. Provide the provider code (e.g. 'RGT') and specialty (e.g. 'Cardiology'). Returns the start and end values, the change in weeks, the percentage change, a direction (improving | worsening | flat), and the full monthly series. If no data is held for that trust/specialty, returns found=false; do not invent a trend in that case.
| Name | Required | Description | Default |
|---|---|---|---|
| specialty | Yes | ||
| provider_code | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full behavioral disclosure burden and does an excellent job. It discloses the output return fields (start/end values, change, percentage, direction, full monthly series), the units (weeks), and the found=false edge case, explicitly instructing not to invent a trend when data is absent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact yet information-dense: purpose, units, input guidance, output summary, and edge-case handling are all included in three sentences. Every sentence earns its place and no filler exists.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's modest complexity, an output schema, and no annotations, the description is complete. It covers the data source, input semantics, units, expected return values, and the missing-data behavior, so an agent has everything needed to invoke it correctly and interpret results appropriately.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate for both parameters. It does by explaining that provider_code is an NHS trust code with an example ('RGT') and specialty is a clinical specialty with an example ('Cardiology'), giving an agent enough semantic grounding to call the tool correctly.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states a specific verb ('Summarise') and a specific resource ('waiting time for a given NHS trust and specialty... moved over time'), which distinguishes it from sibling tools like lookup_wait_time or rank_trusts_by_wait. It also previews concrete outputs, leaving no ambiguity about what the tool does.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description clearly implies when to call this tool: when a trend summary over time is needed, rather than a point lookup or ranking. It gives concrete input requirements (provider code, specialty) and an explicit no-data behavior, but it does not explicitly name alternative tools or state when not to use it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
5 tool updates
v0.1.0- First observed
get_trust_rating - First observed
lookup_wait_time - First observed
rank_trusts_by_wait - First observed
trust_profile - First observed
wait_time_trend
TDQS
Scored across 5 tools
Each tool targets a clearly distinct query: single-trust trend, single-trust latest wait, cross-trust ranking, quality rating, and combined profile. The descriptions explicitly call out different data sources and identity keys, so an agent should not misselect.
Three tools use a verb-first pattern (lookup_, rank_, get_), but wait_time_trend and trust_profile are noun phrases, so the set lacks a single consistent convention. The names are still readable and specific, but the pattern is mixed.
Five tools is a well-scoped size for an NHS intelligence read-only server. Each tool covers a distinct query need without redundancy or bloat.
The surface covers current waiting times, historical trends, cross-trust ranking, quality ratings, and an integrated profile joining those sources. Because trust_profile accepts either an RTT code or a trust name, it also bridges the identifier gap, so there are no dead-end lookup paths.
Maintenance
Related MCP Connectors
Access CQC care ratings, NHS health services, and food hygiene data across the UK
Hosted MCP server exposing US hospital procedure cost data to AI assistants
UK NIHR (National Institute for Health and Care Research) open-data MCP.
Hosted MCP server for Cliniko — patients, appointments, availability, and invoices for AI agents.
Related MCP Servers
- AlicenseAqualityCmaintenanceEnables querying of current A\&E waiting times, specialist outpatient waiting times, and general outpatient clinic quotas in Hong Kong using natural language through MCP.34MIT
- FlicenseAqualityDmaintenanceEnables AI assistants to query NHS public health datasets, including prescribing data, dataset exploration, and organisation lookup via the NHSBSA Open Data Portal.9-
- AlicenseNot gradedqualityBmaintenanceMCP server for the Semble practice-management API, enabling AI agents to search for patients, contacts, and users, as well as retrieve patient relationships via read-only tools.MIT
- AlicenseAqualityBmaintenanceEnables querying the Polish National Health Fund (NFZ) public API for medical waiting lists and service dictionary, allowing AI to compare wait times and find providers.3MIT