Skip to main content
Glama
AxRS37
by AxRS37

uk-company-check — UK Companies House as MCP agent tools

An MCP server that turns the free, official Companies House API (the UK company registry — profiles, officers, filing history for every UK company) into four tools your AI agent can call.

Every UK B2B seller doing prospect research needs this data: is the prospect still trading, who are its directors, what industry codes is it under. Non-UK (US included) lead-gen and KYB sellers need it too — UK registry data is public, in English, and every company number is a join key.

  • Audience: B2B prospect researchers, lead-gen sellers, KYB/due-diligence workflows, any agent that needs UK company facts.

  • Cost: £0. The API key is free (2-minute signup, no credit card). The server has no other dependencies beyond the official MCP SDK.

  • No API key? It still runs. The server starts, lists its tools, and returns a plain-English "here's how to get the free key" message instead of crashing (agents can read that to the user).

What it does — the four tools

Tool

What it answers

search_companies(query)

"Find me UK companies named X" → name, company number, status, incorporation date, address

get_company(company_number)

Full registry profile: status (active/dissolved/…), incorporation date, registered office, SIC codes with plain-English descriptions, current officers (directors & secretary) with appointment dates and occupations

get_filing_history(company_number)

What the company filed and when — confirmation statements, accounts, officer changes

explain_sic_code(code)

Decode any UK SIC code to its official plain-English description. Works offline (embedded official list) — no key, no network

get_company calls two registry endpoints (profile + officers) and returns one merged answer, so an agent doesn't have to orchestrate. Company numbers are accepted with or without leading zeros (123456 → 00123456), case-insensitively for SC/NI prefixes.

Related MCP server: companieswise

5-minute setup

Requirements: Python 3.10+ and either uv or pip. Nothing else — no Node, no database, no paid services.

1. Get your free Companies House API key (2 minutes, no card).

Go to https://developer.company-information.service.gov.uk/signin and register an account. Sign in, open Applications, create a new application, and copy the API key it shows you. That's the whole signup. (Do not commit the key anywhere — see the .env.example.)

Companies House documents the limit as 600 requests per 5-minute window per key — orders of magnitude more than prospect research needs. This server also caches answers for an hour, so repeat questions cost no quota.

2. Install.

# with uv (fastest):
uv venv && uv pip install -e .
# or with plain pip:
python3 -m venv .venv && .venv/bin/pip install -e .

3. Test the install (30 seconds).

.venv/bin/python -m pytest tests/ -q

You'll see 43 passed — all tests run offline against a pretend registry on localhost, so they never spend your API quota or need the network.

4. Wire it into your MCP client.

Example for Claude Desktop / Cursor / any MCP client that uses JSON config:

{
  "mcpServers": {
    "uk-company-check": {
      "command": "/ABSOLUTE/PATH/TO/uk-company-check/.venv/bin/python",
      "args": ["-m", "uk_company_check"],
      "env": { "CH_API_KEY": "your_real_api_key" }
    }
  }
}

(Any MCP client works the same way: launch python -m uk_company_check on stdio with CH_API_KEY in the environment. Alternative env name: COMPANIES_HOUSE_API_KEY.)

5. Try it. In your client, ask:

Find UK companies called "Driver Plumbing" and tell me whether the top one is active, who its directors are, and what its SIC codes mean.

The agent will call search_companies → get_company → explain_sic_code and answer with sourced registry facts.

Example tool calls and responses

These are real outputs from this server's test suite (run against a pretend registry whose fixture company mirrors the live API's exact field shapes — see tests/fake_ch.py). With your API key, the live Companies House returns the same shapes with real data.

search_companies("driver plumbing") →

{
  "query": "driver plumbing",
  "total_results": 2,
  "companies": [
    {
      "company_number": "00123456",
      "company_name": "DRIVER PLUMBING & HEATING LTD",
      "company_status": "active",
      "incorporated": "2015-03-10",
      "address": "28 London Road, Great Glen, Leicestershire, LE8 9FL",
      "nature_of_business": "43220"
    },
    {
      "company_number": "08765432",
      "company_name": "OLD ROOFS LTD",
      "company_status": "dissolved",
      "incorporated": "2001-01-01",
      "address": "1 Old Street, Leicester, LE1 1AA",
      "nature_of_business": null
    }
  ]
}

get_company("123456") → (officers listed newest appointment first; resigned officers filtered out)

{
  "company_name": "DRIVER PLUMBING & HEATING LTD",
  "company_number": "00123456",
  "status": "active",
  "type": "ltd",
  "incorporated": "2015-03-10",
  "ceased": null,
  "registered_office": "28 London Road, Great Glen, Leicestershire, LE8 9FL, United Kingdom",
  "sic_codes": [
    { "code": "43220", "description": "Plumbing, heat and air-conditioning installation" },
    { "code": "99999", "description": "Dormant Company" }
  ],
  "has_charges": false,
  "has_insolvency_history": false,
  "officers": [
    {
      "name": "Acme Corporate Services Limited",
      "role": "corporate-secretary",
      "appointed_on": "2020-01-01",
      "occupation": null,
      "nationality": null,
      "year_of_birth": null
    },
    {
      "name": "John Driver",
      "role": "director",
      "appointed_on": "2015-03-10",
      "occupation": "Plumber",
      "nationality": "British",
      "year_of_birth": 1980
    }
  ],
  "note": null
}

get_filing_history("00123456") →

{
  "company_number": "00123456",
  "total_count": 2,
  "filings": [
    {
      "date": "2025-06-01",
      "type": "CS01",
      "category": "confirmation-statement",
      "description": "confirmation statement (2025-05-10)",
      "description_values": { "made_up_to": "2025-05-10" }
    },
    {
      "date": "2024-12-15",
      "type": "AA",
      "category": "accounts",
      "description": "legacy (group of companies' accounts made up to 31 March 2024)",
      "description_values": { "description": "group of companies' accounts made up to 31 March 2024" }
    }
  ]
}

explain_sic_code("43220") →

{ "code": "43220", "description": "Plumbing, heat and air-conditioning installation" }

How it's tested (and why you can trust the README)

43 tests in three layers — all offline, no network, no API quota:

  1. Client unit tests (tests/test_ch_api.py) — company-number normalisation, caching (a cached call provably makes zero HTTP requests), friendly errors for 401/404/429, SIC descriptions.

  2. Tool layer tests (tests/test_server_tools.py) — each tool's output shape, resigned-officer filtering, SIC enrichment, all four tools registered, every tool has a docstring (agent-visible descriptions).

  3. Protocol tests (tests/test_protocol.py) — launch the real server as a subprocess, speak MCP JSON-RPC over stdio (initialize → tools/list → tools/call), and verify responses. Also proves zero-key mode starts and self-explains instead of crashing.

The fake registry (tests/fake_ch.py) mirrors the exact Companies House response field names (company_name, company_status, sic_codes, officer_role, appointed_on, …) as documented on the official reference pages.

Run them yourself:

.venv/bin/python -m pytest tests/ -v

Works with both MCP SDK generations

The official Python SDK renamed its main class between versions: 1.x exposes mcp.server.fastmcp.FastMCP, 2.x renamed it to mcp.server.mcpserver.MCPServer. This server imports whichever is installed, so pip install mcp can give you either and it still runs. The protocol tests pass against both. (Tested against 1.14.0 and 2.2.0, on Python 3.12 and 3.14.)

Who it's for

  • B2B sellers and agencies doing UK prospect research (segment by SIC code, verify a company is active before outreach).

  • US and non-UK lead-gen sellers — UK registry data is public, in English, structured; the company number is a stable join key for enrichment.

  • KYB / due-diligence agents — status, officers, and filing history are the three core checks.

  • Any MCP client user who just wants UK company facts on tap.

Licence

MIT for the code (see LICENSE). The embedded SIC code descriptions in src/uk_company_check/sic_data.py are official UK SIC 2007 condensed-list data from Companies House, under the Open Government Licence v3.0 — Crown copyright preserved. Companies House data returned at runtime belongs to the UK Crown / Companies House and is used under OGL v3.0.

Available Tools

4 tools
explain_sic_codeA

Decode a UK SIC code (the 5-digit 'nature of business' code on every company record) into its official plain-English description. Works offline from the official UK SIC 2007 condensed list — no API key needed. Example: explain_sic_code('43220') -> 'Plumbing, heat and air-conditioning installation'.

Args: code: The SIC code, e.g. "43220". Leading zeros are kept.

ParametersJSON Schema
NameRequiredDescriptionDefault
codeYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden, and it does disclose meaningful traits: it is a pure offline lookup, requires no API key/auth, and preserves leading zeros. It stops short of stating what happens for an invalid or unknown code, which is the one behavioral gap.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core purpose in the first sentence and the example immediately after; almost every sentence earns its place. The trailing "Args:" block partially restates the format already given above, which is mild redundancy rather than bloat.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-argument lookup with an output schema present, the description is largely complete — the output schema handles return values and the description still adds a sample mapping. The only thin spot is invalid-code behavior, which neither the description nor the schema covers.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0% with one parameter, so the description must compensate, and it does: it gives the expected format (5-digit, example "43220") and explicitly notes that leading zeros are kept — a real semantic detail given the string type. Missing only validation/error semantics for malformed input.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Specific verb ("Decode") plus specific resource ("UK SIC code"), with the domain role spelled out ("the 5-digit 'nature of business' code on every company record"). It is unmistakable against siblings search_companies, get_company, and get_filing_history, and the worked example removes any ambiguity about output.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description situates the tool in the company-record workflow (SIC codes appear on company records) and states the operational context: works offline, no API key needed. It does not explicitly name siblings or say when NOT to use it, but the alternatives are not plausibly confusable, so the implicit guidance is sufficient.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_companyB

Full profile of one UK company from its official registry record: status (active/dissolved/...), incorporation date, registered office, SIC codes with plain-English descriptions, and current officers (directors and secretary) with appointment dates and occupations.

Args: company_number: The 8-character Companies House number, e.g. "00123456", "123456", "SC123456" or "NI123456" — leading zeros optional.

ParametersJSON Schema
NameRequiredDescriptionDefault
company_numberYes

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

B3.1/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full behavioral burden, and it discloses very little beyond content: no auth/permission requirements, no rate limits, no note on whether a dissolved company's record behaves differently, and no indication of what happens on an unknown number. 'From its official registry record' hints at the data source, which is the only real behavioral signal.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the resource and scope, followed by a compact args block; both sentences of the summary earn their place. The field enumeration slightly duplicates the existing output schema, but the overall size is appropriate for a one-parameter tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple one-parameter lookup with an output schema, the calling essentials (parameter format) are covered, and return structure need not be explained. However, the absence of any when-to-use or sibling-routing guidance leaves a real gap given three related siblings, and the return-field list partly re-describes what the output schema already holds.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

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, and it does well: it specifies the 8-character Companies House number format, gives four representative examples including SC/NI prefixes, and notes that leading zeros are optional. That is exactly the format detail the bare string schema lacks.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific resource and scope — the full profile of one UK company from its official registry record — and enumerates the fields returned (status, incorporation date, registered office, SIC codes, officers). This implicitly separates it from the list-oriented search_companies sibling, but it never names or contrasts any sibling explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no when-to-use guidance, no prerequisites, and no routing advice such as 'use search_companies to resolve a company number first'. The agent must infer from the name that this is a single-record lookup and that explain_sic_code / get_filing_history exist for adjacent tasks.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_filing_historyA

The most recent filings a company has made at Companies House (confirmation statements, accounts, officer changes...). Useful for spotting dormancy (nothing filed for years), late accounts, or a change of directors last week.

Args: company_number: The Companies House number (leading zeros optional). items_per_page: How many filings to return (1-100, default 10).

ParametersJSON Schema
NameRequiredDescriptionDefault
company_numberYes
items_per_pageNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.1/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden. It usefully discloses the return content ('most recent' ordering and the filing types returned), which is genuine behavioral context. However, it says nothing about permissions, rate limits, or result volume/pagination behavior beyond the page-size parameter.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads purpose, then usage context, then Args — a clean and skimmable structure. The parenthetical example lists add some length but earn their place by clarifying scope.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values needn't be spelled out. For a simple two-parameter read tool the description covers purpose, triggers, and parameter formats adequately; only pagination/ordering details are thin.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

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, and it does: it explains company_number accepts leading zeros optionally and gives the items_per_page range (1-100) — details absent from the schema. Both parameters receive meaningful documentation, though deeper format/validation guidance is limited.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: retrieves 'the most recent filings a company has made at Companies House', with concrete examples (confirmation statements, accounts, officer changes). This clearly distinguishes it from get_company (company details) and search_companies without needing to open any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear when-to-use context ('spotting dormancy, late accounts, or a change of directors last week'), which tells the agent the practical triggers for calling it. It does not explicitly name alternatives or exclusions, so it falls short of the top tier but is well above mere implication.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_companiesA

Search the UK company register by name. Returns matches with company number, status, address snippet and incorporation date — use the company_number from the best match with get_company.

Args: query: Company name or part of it, e.g. "Driver Plumbing" or "TESCO". items_per_page: How many matches to return (1-100, default 10).

ParametersJSON Schema
NameRequiredDescriptionDefault
queryYes
items_per_pageNo

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.1/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden. It does useful work by naming the returned fields (number, status, address snippet, incorporation date), which tells the agent this is a non-destructive read and what to expect. However, it says nothing about result ordering/'best match' semantics, rate limits, or pagination beyond the page size.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action and return shape, then a compact Args block. Every sentence is useful; the Args block is minimally redundant with the schema but serves as a fallback given zero schema descriptions.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple two-parameter search with a sibling for follow-up lookup, the description covers purpose, return fields, and the hand-off to get_company. Since an output schema exists, return values need not be detailed, and the remaining gaps (ordering, no-match behavior) are minor.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

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, and it does: 'query' is explained with concrete examples ('Driver Plumbing', 'TESCO') and 'items_per_page' gets a range and default (1-100, default 10) that the schema itself omits. Only the integer type/format nuance is left implicit.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Search the UK company register by name') and lists the returned fields, so the agent knows exactly what comes back. It also distinguishes itself from the sibling get_company by explaining that this is the name-lookup entry point.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly routes the agent forward: 'use the company_number from the best match with get_company.' That is a clear when-to-use chain, but there is no exclusion guidance (e.g., what to do if no match is found, or when to skip straight to a number lookup).

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.

  1. 4 tool updatesv1.0.0
    • First observedexplain_sic_code
    • First observedget_company
    • First observedget_filing_history
    • First observedsearch_companies

TDQS

A4/5.0

Scored across 4 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: name search, full company profile, filing history, and SIC code decoding. There is no overlap in function or ambiguity about when to use each.

Naming Consistency5/5

All names use snake_case and follow a verb_noun pattern: search_companies, get_company, get_filing_history, explain_sic_code. The convention is consistent and readable.

Tool Count5/5

Four tools are well-scoped for a read-only UK company lookup service. Each tool earns its place without redundancy or excessive granularity.

Completeness4/5

The set covers the core due-diligence workflow: find a company, get its profile including officers, check filings, and decode SIC codes. Minor gaps exist, such as no dedicated PSC/charges lookup or advanced search filters, but agents can work around them for basic checks.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables looking up UK companies, officers, ownership, filings, and running due diligence checks via the Companies House API, usable from AI tools like Claude or Cursor.
    3 npm
    13
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    Provides verified UK company lookup and number validation for AI agents using official Companies House data. Enables lookup of registered details by number, validation of company number format, and search by company name.
    3
    20 npm
    Apache 2.0
  • A
    license
    A
    quality
    C
    maintenance
    Enables AI assistants to search and retrieve UK Companies House data including company profiles, officers, and filing history via the official API.
    4
    179 npm
    1
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables querying UK company data including search, profiles, officers, filings, and persons with significant control via Companies House API.
    179 npm
    MIT