registry-mcp

El registro de empresas MCP: datos empresariales para agentes de IA de registros comerciales nacionales. Noruega (brreg / Enhetsregisteret: consulta de orgnr, búsqueda por nombre, registro de IVA, plazos de presentación) y Reino Unido (Companies House: consulta por número de empresa, búsqueda, cuentas y plazos de declaración de confirmación).

Documentación

registry-mcp — el MCP del registro de empresas

PyPI PyPI alias npm CI License: MIT Listed on mcpservers.org

Datos de empresas para agentes de IA, en cualquier país. Un solo servidor MCP y API REST, tres registros nacionales hoy: el Companies House del Reino Unido, consultado por número de empresa; el Enhetsregisteret / Brønnøysundregistrene (brreg) de Noruega, consultado por organisasjonsnummer (orgnr); y el Bolagsverket de Suecia, consultado por organisationsnummer — una misma forma JSON sin importar cuál consultes.

claude mcp add registry-mcp --transport http https://api.foretak.dev/mcp

Sin paso de instalación, por stdio:

claude mcp add registry-mcp -- uvx registry-mcp

Lo que hace que valga la pena un espacio de herramienta:

  • Plazos que citan la norma, no solo una fecha. company_deadlines da la próxima fecha de presentación y nombra el motivo en applies_because — una obligación legal de una forma jurídica noruega, o "Companies House publica esta fecha para la propia empresa" cuando el registro la indica en lugar de calcularla nosotros. Cita el motivo, no solo el número.
  • Nunca más de 24 horas de desactualización, y lo dice. Cada respuesta lleva cached y fetched_at. La propia base de conocimiento de OpenCorporates dice a los usuarios que "permitan 30 días" para que una corrección llegue a su sitio — una brecha de frescura de 30×, declarada por el propio titular sobre sí mismo.
  • Siete herramientas, no cincuenta — cinco herramientas de registro más dos alias de conector para ChatGPT. La precisión de selección de herramientas degradada más allá de 30-50 herramientas cargadas en el contexto de un agente, y algunos clientes limitan alrededor de 40. Siete herramientas es aproximadamente el 17% de ese presupuesto, frente a competidores en este espacio que envían de 23 a 78 herramientas para el mismo trabajo.

Seguridad. Solo lectura, siempre — nada aquí escribe en un registro ni en ningún otro lugar. No se requieren credenciales de quien llama; la credencial ascendente propia de este despliegue (COMPANIES_HOUSE_API_KEY) se lee del entorno y nunca se registra ni se devuelve. Tres fuentes ascendentes nombradas, y nada más se llama jamás: data.brreg.no, api.company-information.service.gov.uk y gw.api.bolagsverket.se. Sin datos personales más allá de lo que cada registro nacional ya publica sobre la propia entidad — y como el número de empresa de un autónomo sueco es su personnummer, el registro de uso no almacena ningún identificador en absoluto para un país cuyos identificadores pueden ser de una persona natural (legal/privacy.md). Este servicio no realiza cribado de sanciones, PEP ni medios adversos, y no verifica datos de cuentas bancarias. Detalles: SECURITY.md.

Instalación en un clic, para un servidor remoto streamable-HTTP:

Install in VS Code Install in VS Code Insiders Install in Cursor

Otros clientes (Claude Desktop, Cursor, VS Code, Cline, configuraciones JSON simples): consulta docs/clients.md.

Añadir a ChatGPT

ChatGPT llega a un servidor MCP mediante un conector personalizado, y su modo de investigación profunda llama exactamente a dos herramientas — search y fetch — que este servidor incluye junto a las cinco herramientas de registro. En ChatGPT, abre Configuración → Conectores, añade un conector personalizado y dale:

https://api.foretak.dev/mcp

Sin autenticación, sin clave, sin cuenta. Si tu plan de ChatGPT no muestra conectores personalizados en Configuración → Conectores, activa primero Configuración → Seguridad e inicio de sesión → Modo desarrollador, y luego añade la URL de https://chatgpt.com/plugins.

search toma una consulta de texto libre — un nombre de empresa, un identificador nacional, o un nombre más un país ("Tesco Reino Unido") — y devuelve filas citables; fetch toma el id de una fila ("NO:923609016") y devuelve el registro de esa empresa y sus plazos legales de presentación, con el JSON completo de ambos en metadata.

Añadir a Claude Desktop

Claude Desktop toma la misma URL como conector personalizado: Configuración → Conectores → Añadir conector personalizado, luego https://api.foretak.dev/mcp. Sin clave. Para una instalación local por stdio en su lugar, consulta Configuración.

Estado: 0.3.0, en vivo — GET /health devuelve {"version":"0.3.0","countries":["GB","NO","SE"]}. Las cinco herramientas de registro y sus formas de respuesta están congeladas; dos alias de conector (search, fetch) las envuelven para ChatGPT y no añaden ninguna forma nueva. La API alojada en api.foretak.dev está en vivo y listada en el registro oficial de MCP como io.github.foretak/registry-mcp. Países: Reino Unido (Companies House), Noruega (brreg), Suecia (Bolagsverket) — consulta abajo para el formato de identificador de cada país y ejemplos de llamadas.

Añadir a Claude Code

Los mismos dos comandos de arriba — Streamable HTTP o stdio local. Para añadirlo como archivo .mcp.json a nivel de proyecto en lugar de la CLI, consulta Configuración.

Qué devuelve

$ curl https://api.foretak.dev/v1/NO/company/923609016
{
  "country": "NO", "registry": "brreg",
  "id": "923609016", "id_formatted": "923 609 016", "id_scheme": "organisasjonsnummer", "euid": null,
  "name": "EQUINOR ASA",
  "legal_form_code": "ASA", "legal_form": "Public limited company", "legal_form_local": "Allmennaksjeselskap",
  "status": "active", "is_active": true, "registered_at": "1995-03-12",
  "vat_registered": true, "vat_number": "NO923609016MVA", "vat_registered_at": "1989-07-01",
  "employees": 21239, "share_capital": 5976872600.0, "share_capital_currency": "NOK",
  "business_address": {"lines": ["Forusbeen 50"], "postal_code": "4035", "city": "STAVANGER"},
  "advertising_protected": null,
  "source": "Enhetsregisteret (Brønnøysundregistrene)", "license": "NLOD 2.0"
}

Abreviado — el CompanyReport completo también lleva previous_names, industry_codes, registers, purpose, parent_id, confidence, cached, fetched_at y notes. Cada campo está documentado en llms-full.txt §5.

euid es el identificador a nivel de la UE que algunos registros de estados miembros publican (Finlandia lo hace; ninguno de los nuestros aún) — nunca el LEI, nunca construido a partir de partes. advertising_protected es true/false/null: si el registro marca esta entidad como protegida contra el uso de marketing directo, null significa que el registro no publica tal indicador en absoluto (Noruega y el Reino Unido, hoy); donde es true (el reklamspärr de Suecia, por ejemplo), una frase de notes lo indica y esa marca debe viajar con cualquier dato de contacto que transmitas.

El Reino Unido, misma forma, misma abreviatura:

$ curl https://api.foretak.dev/v1/GB/company/00445790
{
  "country": "GB", "registry": "companies-house",
  "id": "00445790", "id_formatted": null, "id_scheme": "company number", "euid": null,
  "name": "TESCO PLC",
  "legal_form_code": "plc", "legal_form": "Public limited company",
  "status": "active", "is_active": true, "registered_at": "1947-11-27",
  "vat_registered": null, "vat_number": null,
  "employees": null, "employees_reported": false,
  "registers": {"charges": false, "insolvency": false},
  "industry_codes": [{"code": "47110", "description": null, "scheme": "SIC 2007", "rank": 1}],
  "business_address": {"lines": ["Tesco House, Shire Park", "Kestrel Way"], "postal_code": "AL7 1GA", "city": "Welwyn Garden City"},
  "advertising_protected": null,
  "published_deadlines": [
    {"kind": "annual_accounts", "due_date": "2027-08-26", "period_end": "2027-02-26", "overdue": false, "source": "accounts.next_accounts.due_on"},
    {"kind": "confirmation_statement", "due_date": "2027-07-02", "period_end": "2027-06-18", "overdue": false, "source": "confirmation_statement.next_due"}
  ],
  "source": "Companies House (UK)", "license": "Crown copyright — Companies House public register, free to re-use"
}

published_deadlines lleva las fechas que el propio registro publica, con el campo ascendente del que provienen. Es [] para Noruega y Suecia, que calculan todas las suyas.

Suecia, añadido en 0.3.0, es donde "una forma" empieza a cumplir la promesa:

$ curl https://api.foretak.dev/v1/SE/company/5560160680
{
  "country": "SE", "registry": "bolagsverket",
  "id": "5560160680", "id_formatted": "556016-0680", "id_scheme": "organisationsnummer", "euid": null,
  "name": "Telefonaktiebolaget LM Ericsson",
  "legal_form_code": "AB", "legal_form": "Private or public limited company", "legal_form_local": "Aktiebolag",
  "status": "active", "is_active": true, "registered_at": "1918-08-19",
  "vat_registered": null, "vat_number": null,
  "employees": null, "employees_reported": false,
  "industry_codes": [{"code": "70100", "description": "Verksamheter som utövas av huvudkontor", "scheme": "SNI 2007", "rank": 1}],
  "postal_address": {"postal_code": "16483", "city": "STOCKHOLM", "country_code": "SE"},
  "advertising_protected": null,
  "published_deadlines": [],
  "source": "Bolagsverket (bolagsverket.se)",
  "license": "Free re-use (Bolagsverket/SCB high-value datasets, EU Open Data Directive) — the publisher names no licence"
}

Bolagsverket no nombra ninguna licencia para estos datos, así que nosotros tampoco: la cadena dice cuál es el permiso y dice claramente que no hay nombre de licencia que citar, porque un nombre familiar en ese campo sería una fabricación.

Suecia no publica ningún campo de estado. status se deriva de tres señales independientes — una fecha de baja, un procedimiento en curso de liquidación o reestructuración, y el indicador de "económicamente activa" de Statistics Sweden — y is_active por tanto significa en el registro y no en proceso de cierre, que no es lo mismo que estar operando. Cuando cualquiera de eso no está disponible, la respuesta es unknown, nunca active.

Dos fechas se calculan, y cada una lleva la disposición de la que proviene:

$ curl "https://api.foretak.dev/v1/SE/company/5560160680/deadlines?today=2026-09-07"
{"kind": "general_meeting",  "due_date": "2027-06-30", "days_until": 296, "rolled_forward": false, "period_label": "2026"}
{"kind": "annual_accounts",  "due_date": "2027-07-31", "days_until": 327, "rolled_forward": false, "period_label": "2026"}

Seis meses hasta la junta general anual (aktiebolagslagen 7 kap. 10 §) y siete hasta la presentación antes de que una multa por retraso se aplique (årsredovisningslagen 8 kap. 6 §). Ninguna fecha se desplaza por un fin de semana, porque ninguna fuente sueca dice que se mueva. Ambas asumen un ejercicio fiscal que termina el 31 de diciembre, que el conjunto de datos gratuito no publica — y una frase de notes dice exactamente eso, incluyendo cómo desplazar ambas fechas si el cierre del ejercicio es diferente. search_company responde not_implemented para Suecia: la API gratuita tiene cuatro operaciones y ninguna acepta un nombre.

Observa los null. Companies House no publica estado de IVA, número de empleados ni capital social de ninguna empresa, así que esos campos son null en lugar de adivinados — null significa "este registro no lo dice", nunca "no". Esa honestidad es el punto de una forma entre países.

Y los plazos, que es donde el módulo del Reino Unido demuestra su valor:

$ curl "https://api.foretak.dev/v1/GB/company/00445790/deadlines?today=2026-09-04"
{
  "company_name": "TESCO PLC", "today": "2026-09-04",
  "deadlines": [
    {"kind": "confirmation_statement", "local_name": "Confirmation statement (CS01)",
     "due_date": "2027-07-02", "period_end": "2027-06-18", "days_until": 301,
     "applies_because": "Companies House publishes this date for the company itself; it is the register's own figure, not a calculation."},
    {"kind": "annual_accounts", "local_name": "Annual accounts",
     "due_date": "2027-08-26", "period_end": "2027-02-26", "days_until": 356,
     "applies_because": "Companies House publishes this date for the company itself; it is the register's own figure, not a calculation."}
  ]
}

Donde Companies House publica una fecha, se cita; donde no, la fecha se calcula a partir de una ley citada y applies_because lo dice. Los plazos del Reino Unido nunca se desplazan por un fin de semana o un día festivo, y days_until se vuelve negativo para una presentación que el registro aún muestra como vencida.

¿Lo ejecutas tú mismo? El servicio alojado en api.foretak.dev tiene todas las credenciales configuradas. Una copia autoalojada necesita una clave gratuita de Companies House para GB y un par de cliente OAuth 2 de Bolagsverket (BOLAGSVERKET_CLIENT_ID, BOLAGSVERKET_CLIENT_SECRET) para SE; sin ellas, esos dos países devuelven upstream_error nombrando la variable, y todos los demás países siguen respondiendo. Noruega no necesita nada.

Herramientas

HerramientaQué hace
lookup_company(id, country="NO")CompanyReport completo para una empresa por identificador nacional
search_company(name, country="NO", limit=10)SearchResult — candidatos con identificadores, en el orden de relevancia del registro, cada uno puntuado
company_deadlines(id, country="NO", today=None)DeadlineReport — la próxima ocurrencia de cada obligación legal de presentación
validate_company_id(id, country="NO")ValidationResult — valida y normaliza un identificador sin llamada de red
list_countries()Qué registros nacionales están soportados ahora mismo

Alias de conector — para ChatGPT, que llega a un servidor MCP mediante exactamente search y fetch (Añadir a ChatGPT); no añaden ninguna forma de respuesta nueva y no tienen gemelo REST.

HerramientaQué hace
search(query)Alias de conector para ChatGPT de search_company — una consulta de texto libre, {"results": [{"id", "title", "url"}]}
fetch(id)Alias de conector para ChatGPT de lookup_company + company_deadlines — un "{COUNTRY}:{identifier}", un documento Markdown con ambos informes en metadata

Además, el recurso registry://rules/{country} (reglas de identificadores, formas jurídicas, reglas de plazos — léelo una vez en lugar de validar en bucle) y el prompt explain_company.

parent_id y in_group en un CompanyReport noruego describen la relación propia de padre/subunidad de Enhetsregisteret para esa entidad — nada más. No hay herramienta de recorrido de grupo: seguir un grupo corporativo hacia arriba significa llamar a lookup_company de nuevo sobre parent_id, repetidamente, y ese recorrido responde "¿qué lista el registro como padre de esta entidad?", no "¿quién es el beneficiario efectivo o controla esta empresa?" — una pregunta diferente que este servicio no responde. Consulta llms-full.txt §5.

Por qué un agente verifica una empresa

Tres reglas hacen de esto un deber más que un lujo. El Rundskriv 15/2019 de Finanstilsynet § 4.4.1 acepta un oppslag contra Enhetsregisteret de no más de tres meses, un mes cuando la verificación se basa en datos de empresa proporcionados por el cliente, y pide notoritet sobre la consulta: qué se consultó y cuándo. Desde el 1 de enero de 2027, las empresas noruegas con obligación contable deben facturarse entre sí mediante factura electrónica, y el receptor se resuelve en ELMA como 0192: más organisasjonsnummer, el identificador que estas herramientas ya aceptan. Desde el 10 de julio de 2027, el AMLR Artículo 23(4) exige "prueba válida de registro o un extracto reciente del registro" para cada nueva relación comercial con una entidad jurídica.

Para eso están source_url, fetched_at, cached, license y applies_because: qué registro se consultó, cuándo se leyó, si vino de la caché de 24 h, los términos bajo los que viaja, y si un plazo se citó del registro o se calculó a partir de una regla nombrada.

Los límites, declarados en lugar de implícitos: sin cribado de sanciones ni PEP; sin verificación de cuentas bancarias, y el fraude de factura más común es la redirección de pago, donde el proveedor es real y solo el número de cuenta es incorrecto; y sin beneficiarios efectivos, que brreg libera solo bajo solicitud, a categorías de solicitantes que no incluyen a un proveedor de productos. Versión completa en llms-full.txt §9.

Configuración

Claude Code.mcp.json en la raíz del proyecto
{
  "mcpServers": {
    "registry-mcp": {
      "command": "uvx",
      "args": ["registry-mcp"],
      "env": {
        "REGISTRY_MCP_CONTACT_EMAIL": "you@example.com",
        "COMPANIES_HOUSE_API_KEY": "your-companies-house-key"
      }
    }
  }
}

Drop COMPANIES_HOUSE_API_KEY si solo necesitas Noruega; todos los demás países funcionan sin él.

Cursor~/.cursor/mcp.json (o .cursor/mcp.json en el proyecto)
{
  "mcpServers": {
    "registry-mcp": {
      "command": "uvx",
      "args": ["registry-mcp"],
      "env": { "REGISTRY_MCP_CONTACT_EMAIL": "you@example.com" }
    }
  }
}
Claude Desktopclaude_desktop_config.json

macOS: ~/Library/Application Support/Claude/claude_desktop_config.json Windows: %APPDATA%\Claude\claude_desktop_config.json

{
  "mcpServers": {
    "registry-mcp": {
      "command": "uvx",
      "args": ["registry-mcp"],
      "env": { "REGISTRY_MCP_CONTACT_EMAIL": "you@example.com" }
    }
  }
}
npm en lugar de uvx — mismo servidor, lanzador Node
{
  "mcpServers": {
    "registry-mcp": { "command": "npx", "args": ["-y", "registry-mcp"] }
  }
}

npx registry-mcp recurre a uvx registry-mcp (con respaldo a pipx run registry-mcp), por lo que se requiere Python 3.12+ y uno de uv o pipx.

Alojado, sin instalación local — Streamable HTTP
{
  "mcpServers": {
    "registry-mcp": { "type": "http", "url": "https://api.foretak.dev/mcp" }
  }
}

Variables de entorno — todas opcionales:

VariableSignificado
REGISTRY_MCP_CONTACT_EMAILDirección de contacto enviada en el User-Agent al registro nacional, como solicita Brønnøysundregistrene a los clientes de API. Sin definir significa cliente anónimo, que puede ser limitado o bloqueado aguas arriba.
REGISTRY_MCP_CACHE_PATHRuta a la caché de respuestas SQLite local (TTL de 24 h). Por defecto es ./data/cache.sqlite3.
COMPANIES_HOUSE_API_KEYRequerida para el Reino Unido (GB). Una clave es gratuita e instantánea. Sin definir significa que las búsquedas de GB devuelven upstream_error con una pista que menciona esta variable — todos los demás países siguen funcionando.
BOLAGSVERKET_CLIENT_ID, BOLAGSVERKET_CLIENT_SECRETRequeridas para Suecia (SE). Un par de cliente OAuth 2 que Bolagsverket emite bajo solicitud; los datos en sí son gratuitos bajo el reglamento de conjuntos de datos de alto valor de la UE. Sin definir significa que las búsquedas de SE devuelven upstream_error mencionando ambas variables — todos los demás países siguen funcionando.

REST

Cada herramienta tiene un gemelo REST que devuelve el mismo documento JSON.

# One company by organisasjonsnummer
curl https://api.foretak.dev/v1/NO/company/923609016

# Search by name
curl "https://api.foretak.dev/v1/NO/search?q=equinor&limit=5"

# Statutory filing deadlines, from a date you choose
curl "https://api.foretak.dev/v1/NO/company/923609016/deadlines?today=2026-01-15"

# Checksum-validate an identifier — no upstream call, instant
curl https://api.foretak.dev/v1/NO/validate/923609016

# Which countries are live, and which need an API key
curl https://api.foretak.dev/v1/countries

# The same five routes for the United Kingdom — GB, never UK
curl https://api.foretak.dev/v1/GB/company/00445790
curl "https://api.foretak.dev/v1/GB/search?q=tesco&limit=5"
curl "https://api.foretak.dev/v1/GB/company/00445790/deadlines?today=2026-09-04"
curl https://api.foretak.dev/v1/GB/validate/445790

# Sweden — four of the five. /search returns 501 not_implemented: the free
# Bolagsverket API has no name index, and the error's hint says so.
curl https://api.foretak.dev/v1/SE/company/5560160680
curl "https://api.foretak.dev/v1/SE/company/5560160680/deadlines?today=2026-09-07"
curl https://api.foretak.dev/v1/SE/validate/556016-0680

Documentación legible por máquina: /llms.txt, /llms-full.txt, /openapi.json.

Añadir tu país

Noruega es una carpeta. También lo es el Reino Unido: registries/gb/ se añadió como cuatro archivos y una línea de importación, y GB apareció en list_countries, en cada herramienta, en /openapi.json y en registry://rules/GB por sí solo. También lo es Suecia — registries/se/ se lanzó en 0.3.0 con ningún cambio en core/, incluidas las partes de Suecia que peor encajan en la abstracción: un registro que no publica campo de estado, una operación que el proveedor no ofrece (search_company responde not_implemented), y un identificador que puede ser el ID nacional de una persona física.

Copia src/registry_mcp/registries/xx/ a registries/<cc>/, implementa cuatro métodos, añade una línea de importación — nada en core/ cambia, y ambas superficies más los manifiestos se activan automáticamente para el nuevo país.

CONTRIBUTING.md — "Añade tu país", y la plantilla de issue de new country para reclamar uno primero.

Desarrollo

uv sync --all-extras
uv run pytest          # `-m "not live"` to skip the tests that hit the real registry
uv run mypy .
uv run ruff check .

Estructura:

src/registry_mcp/core/        country-neutral models, Registry ABC, rules, date helpers
src/registry_mcp/registries/  one folder per country — no/ (Norway), gb/ (UK), se/ (Sweden), xx/ (template)
src/registry_mcp/api/         FastAPI REST surface
src/registry_mcp/mcp/         FastMCP server (stdio + Streamable HTTP at /mcp)

Documentos

Fuente de datos y licencia

Los datos noruegos provienen de Enhetsregisteret (Brønnøysundregistrene), publicados bajo NLOD 2.0 — se requiere atribución. Los datos del Reino Unido provienen del registro público de Companies House, copyright de la Corona, de reutilización gratuita sin condición de atribución; aun así lo citamos. Los datos suecos provienen de Bolagsverket, con Statistics Sweden (SCB) como segundo productor dentro del mismo payload, de reutilización gratuita como värdefull datamängd bajo el régimen de conjuntos de datos de alto valor de la UE — las propias palabras de Bolagsverket son "Det krävs inget avtal för att du ska få använda vårt API för värdefulla datamängder" y "Värdefulla datamängder är avgiftsfritt" — y Bolagsverket no nombra ninguna licencia, así que nosotros tampoco: la cadena license declara el permiso y declara claramente que no hay nombre de licencia que citar. Cada respuesta lleva source, source_url y license para que la atribución viaje con los datos. El código propio de este proyecto está bajo licencia MIT. No está afiliado ni respaldado por Brønnøysundregistrene, Companies House ni Bolagsverket.