Mcp Borme

io.github.nubiia-devPublished by GitHub account nubiia-devv1.0.2Updated Oct 29, 2026

OpenMercantil (BORME): 37 read-only tools for Spanish company search, officers, sectors and tenders

Overview

AI-generated overview

Read-only MCP server for Spanish company registry data (BORME): search companies, officers, sectors, tenders and mercantile law.

What you can do
  • Search Spanish companies by name, alias or CIF and open a full registry report with KPIs, events, officers and activity timeline
  • Compare companies, list yearly registry acts, structured facts, relationships, group graph and similar peers
  • Search persons mentioned as officers and view their documentary company links
  • Browse the daily bulletin by section and province, and list companies or Banco de España ratios by CNAE sector
  • Search public procurement notices (PLACSP, TED) and per-company grants, CNMV listing and Wikidata identifiers
  • Look up mercantile-law norms, articles and which law governs each registry act type, plus dataset health and freshness
When to use it
Useful when an assistant needs factual, sourced information on Spanish companies: due diligence, supplier or competitor research, officer and registry-history questions, sector prospecting, public tender searches, or checking which law governs a registry act.
Requirements
Runs locally via npx with Node.js 22.14 or higher. No account needed: the anonymous OpenMercantil tier allows 60 requests/minute and 200/day per IP. An optional OPENMERCANTIL_API_KEY raises the quota; OPENMERCANTIL_MAX_REQUESTS_PER_MINUTE and OPENMERCANTIL_MAX_RESPONSE_CHARS tune local limits. Requires network access to the OpenMercantil API.
Before you install
OPENMERCANTIL_API_KEY is a secret sent in the X-API-Key header; keep it out of configs you share. All 37 tools are read-only, so nothing is written or deleted. Data is documentary and informational, not official certificates or legal advice, and empty results do not prove absence. Queries go to a third-party API and are rate-limited; heavy agent loops can exhaust the daily quota.

Installation

In SourceWeft

  1. Open Mcp Borme in the dashboard and add it to a workspace.
  2. Enable the server for the chats that should use its tools.

Desktop only via STDIO. STDIO servers start a local process, so they need the SourceWeft desktop host.

Other MCP clients

Follow the launch instructions in the repository.

README

MCP BORME

[CI] [npm version] [License: MIT] [by Nubiia]

A Model Context Protocol (MCP) server for the BORME (Boletín Oficial del Registro Mercantil, Spain's commercial-registry bulletin), built on the public OpenMercantil API. It lets AI assistants like Claude search Spanish companies, read their registry history and officers, browse the daily bulletin, map sectors by CNAE, look at public procurement and consult the mercantile-law norms behind each registry act.

Built and maintained by Nubiia — automatización e integraciones con IA para negocios (MCP, Holded, Pipedrive y más). ¿Quieres algo así para tu empresa? Escríbenos en nubiia.es.

Independent and informational. OpenMercantil is not the BOE, the BORME or the Registro Mercantil, and its data does not replace official certificates or registry extracts. BORME material is re-used under Ley 37/2007; the official version is on boe.es. Tool responses keep the source attribution (_attributions) and the tool descriptions repeat the documentary, not-legal-advice caveats.

No account needed

The OpenMercantil API is public: this server works out of the box on its anonymous free tier (60 requests/minute and 200 requests/day per IP). An optional API key (OPENMERCANTIL_API_KEY, omk_..., from openmercantil.es) selects your account's larger quota:

PlanPer minutePer day
Free (anonymous, per IP)60200
Profesional (API key)1205,000
MAX (API key)60050,000
Enterprise (contract)1,200500,000+

Plans change — see openmercantil.es and docs/api-notes.md. With 200 requests a day, the server is built to be frugal:

  • Every input is validated locally against the OpenAPI bounds, so a bad call never costs a request.
  • Result counts default to small numbers (10 results, 10 events, 10 acts per province) and big payloads are trimmed with an explicit notice (events_total, events_truncated, total_acts...) so the assistant knows what it did not see and which tool pages the rest. A full company report (~60 KB) arrives as ~6 KB; a full day of the bulletin (~340 KB) as a per-province summary.
  • Any response above OPENMERCANTIL_MAX_RESPONSE_CHARS (default 60,000) is replaced by a valid-JSON envelope that says it was cut.
  • Responses carry the API's rate-limit state; a 429 reports the plan, when to retry and how to get a larger quota. Short Retry-After values are honoured automatically; long ones (the daily quota) are reported immediately instead of blocking.

Features

37 read-only tools, all marked readOnlyHint: true — nothing in this server writes to OpenMercantil or anywhere else.

  • Companies (11): borme_search_companies, borme_get_company, borme_compare_companies, borme_get_company_events, borme_get_company_facts, borme_get_company_timeline, borme_get_company_officers, borme_get_company_relationships, borme_get_company_graph, borme_get_company_activity, borme_get_similar_companies
  • Other public sources per company (7): borme_get_company_contracts, borme_get_company_grants, borme_get_company_ted, borme_get_company_cnmv, borme_get_company_wikidata, borme_get_company_bde, borme_get_company_sources
  • Daily bulletin (1): borme_get_daily_summary
  • Persons (3): borme_search_persons, borme_get_person, borme_get_person_graph
  • Sectors / CNAE (4): borme_list_sector_companies, borme_get_sector_ratios, borme_get_cnae, borme_get_cnae_tree
  • Mercantile law (4): borme_list_legal_norms, borme_get_legal_norm, borme_get_legal_article, borme_get_act_map
  • Public procurement (4): borme_search_tenders, borme_get_tender, borme_get_tender_stats, borme_list_tender_suppliers
  • Service (3): borme_get_health, borme_get_stats, borme_get_sources_freshness

Deliberately out of scope

Everything that is not part of OpenMercantil's public read plane: user accounts, lists, notes, segments, API-credential and webhook management, billing, support tickets and the legal-report purchase flow (all of them write data or need a browser session). Also left out: the bulk export/* and CSV downloads, the legacy aliases, the aggregate dashboards (ccaa/stats, sectores/stats, datasets/public, integrations) and the per-company risk-signal endpoints (sanctions, embargoes, AEAT debtors, score), which are not part of the allowlisted credential scopes of the public API.

Installation

Prerequisites

  • Node.js 22.14 or higher
  • Optionally, an OpenMercantil API key from openmercantil.es

Install from npm

bash
npm install -g @nubiia/mcp-borme

Install from source

bash
git clone https://github.com/nubiia-dev/mcp-borme.gitcd mcp-bormenpm installnpm run build

Configuration

Environment Variables

VariableRequiredDescription
OPENMERCANTIL_API_KEYNoOpenMercantil API key (omk_...). Secret — never commit it. Without it the anonymous free tier is used. Sent in the X-API-Key header, never in a URL, and redacted from error messages.
OPENMERCANTIL_MAX_REQUESTS_PER_MINUTENoLocal cap on requests per minute across all tools. Default 60 (the anonymous limit); raise it with a paid plan.
OPENMERCANTIL_MAX_RESPONSE_CHARSNoMaximum size of one tool response. Default 60000; larger results are cut with a notice.
OPENMERCANTIL_BASE_URLNoOverride the API host (mirrors, local mocks). https only, except http://localhost.
bash
export OPENMERCANTIL_API_KEY=omk_your_key   # optional

Claude Desktop Configuration

Add to your Claude Desktop config file:

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

json
{  "mcpServers": {    "borme": {      "command": "npx",      "args": ["-y", "@nubiia/mcp-borme@latest"],      "env": {        "OPENMERCANTIL_API_KEY": "omk_your_key"      }    }  }}

Without a key, drop the env block entirely. Or if installed from source:

json
{  "mcpServers": {    "borme": {      "command": "node",      "args": ["/path/to/mcp-borme/dist/index.js"]    }  }}

Claude Code Configuration

bash
# anonymous free tierclaude mcp add borme -- npx -y @nubiia/mcp-borme@latest
# with an API keyclaude mcp add borme --env OPENMERCANTIL_API_KEY=omk_your_key -- npx -y @nubiia/mcp-borme@latest

Troubleshooting

  • sh: mcp-borme: command not found when launching from inside this repo. If you start Claude Code (or another MCP client) from the cloned repository directory, npx @nubiia/mcp-borme resolves the local package.json instead of the published package, and the mcp-borme binary is not on the PATH. Pin the registry version with @latest (as in the examples above), or launch the client from another directory.
  • A recent date or company seems to be missing. The OpenMercantil dataset is rebuilt periodically and can lag behind the official bulletin. Call borme_get_health (latest_borme_processed, status) to see how fresh it is.
  • 503 projection_unavailable on grants / TED / CNMV / Wikidata / sources. Those tools read an integrations projection that OpenMercantil can take offline; it is a server-side state, not evidence that the company has no such records.

Tools

The recommended flow: borme_search_companies → borme_get_company → detail tools. Company tools take the slug returned by the search (e.g. telefonica-de-espana-sa).

borme_search_companies · read-only

Search by name prefix, alias or exact CIF. Returns slug, CIF, province, CNAE, share capital (cents), first/last BORME appearance and number of acts. DNI/NIE never match.

json
{ "q": "Telefónica de España", "limit": 5 }

borme_get_company · read-only

The full BORME report: identity, KPIs, activity timeline, top event types, the most recent events (events_limit, default 10; the response reports events_total) and current and historical officers. Page the whole history with borme_get_company_events.

borme_get_company_events · read-only

BORME acts of one company for a calendar year (year, default current), paginated (page, page_size ≤ 100). Check total and pages.

json
{ "slug": "telefonica-de-espana-sa", "year": 2025, "page_size": 20 }

borme_get_company_facts, borme_get_company_timeline, borme_get_company_officers, borme_get_company_relationships, borme_get_company_graph, borme_get_company_activity, borme_get_similar_companies, borme_compare_companies

Structured facts per act type, a unified registry + procurement timeline, officers, documentary relationships (filter by type / confidence), group graph, monthly activity series, peers in the same province and CNAE division, and a two-company comparison. All documentary: a mention is not proof of current status.

borme_get_company_contracts, _grants, _ted, _cnmv, _wikidata, _bde, _sources

Public procurement (PLACSP), subsidies (BDNS), EU tenders (TED), stock-market listing (CNMV), Wikidata identifiers, Banco de España sector ratios and the coverage map of those sources. An empty result is not proof of absence.

borme_get_daily_summary · read-only

What the BORME published on a date, by section and province. Because a day can hold thousands of acts, the response gives exact counts plus the first limit acts per province (default 10). Narrow with province / section ("1" registered acts, "2" announcements). No bulletin is published on Sundays or holidays (404).

json
{ "date": "2026-07-07", "province": "Madrid", "limit": 20 }

borme_search_persons, borme_get_person, borme_get_person_graph

Persons appear only as documentary name mentions (usually officers). Homonyms share a slug, identity is never resolved, and no DNI, address or contact data is exposed.

borme_list_sector_companies, borme_get_sector_ratios, borme_get_cnae, borme_get_cnae_tree

Companies of a CNAE sector (optionally by province), Banco de España aggregate ratios per two-digit division, code metadata and the code hierarchy.

borme_list_legal_norms, borme_get_legal_norm, borme_get_legal_article, borme_get_act_map

The consolidated mercantile-law norms (BOE texts) and the bridge from each BORME act type to the law that governs it. Informational only, not legal advice.

borme_search_tenders, borme_get_tender, borme_get_tender_stats, borme_list_tender_suppliers

Public procurement notices with CPV / phase / province / buyer / supplier / amount / date filters and cursor pagination. The API rejects some filter combinations (free text with structured filters, cpv with anything but dates) with a 422 that is surfaced as-is.

borme_get_health, borme_get_stats, borme_get_sources_freshness

Dataset size and freshness — worth checking before asserting that something "was not published".

Rate limiting

A local guard stops runaway agent loops before they burn the daily quota:

ScopeLimit
All tools togetherOPENMERCANTIL_MAX_REQUESTS_PER_MINUTE (default 60/min)
Each tool30 req/min

429/502/503/504 responses and connection-refused/DNS errors are retried with backoff (3 attempts); timeouts and connection resets are not, to avoid wasting quota. Each attempt times out after 30 seconds.

Error messages

Errors say what to do: a 429 includes the plan, the retry time and the anonymous limits; 401/403 point to OPENMERCANTIL_API_KEY; a 404 on a company or person explains that OpenMercantil never confirms withheld or personal identities. The API key is redacted from every error message.

Development

bash
npm installnpm run buildnpm test              # runs entirely against mocks — no network, no API keynpm run test:coveragenpm run lintnode scripts/smoke.mjs   # live smoke test against the real API (about 10 requests)

See CONTRIBUTING.md for the full workflow and docs/api-notes.md for API behaviour verified against the live service.

License

MIT. The data served by OpenMercantil is subject to the source-specific terms published in each response and at openmercantil.es/terminos-de-uso.

Related

Source: README.md at commit fec7e44

Tools

37

borme_search_companies

Search companies

Search Spanish companies (BORME / Registro Mercantil) by name, alias or exact CIF. ALWAYS the first step: it returns the `slug` that every other company tool needs, plus CIF, province, CNAE code, share capital (cents), first/last BORME appearance and number of registry acts. Name search is by name prefix, so start with the distinctive start of the legal name (e.g. "Telefónica de España"), not a descriptive phrase. Only legal entities are returned; DNI/NIE never match. Paginate with offset (max 1000).

Parametersqrequiredlimitoffset

borme_get_company

Get company

Get the BORME report of one company by slug: identity (name, CIF, legal form, status, aliases), KPIs (number of acts, first/last seen), activity timeline by period, top event types and provinces, the most recent registry events, and current and historical officers. Use it for "tell me about company X". `events_limit` (default 10) bounds the event list; page the full history with borme_get_company_events. The report is documentary: it reflects BORME publications, not a certified registry extract.

Parametersslugrequiredevents_limit

borme_compare_companies

Compare companies

Compare exactly two companies side by side using the stable comparison projection (identity, province, CNAE, registry activity). Cheaper than fetching two full reports when the question is "which of these two ...". Both slugs must come from borme_search_companies.

Parametersslugsrequired

borme_get_company_events

Get company events

List the BORME events (registry acts) of a company for one calendar year, paginated: date, section, province, act type (Nombramientos, Ceses, Ampliación de capital, Disolución...) and the act text. Defaults to the current year, 20 per page; check `total` and `pages` and use `year` to walk back through the history (data from 2009).

Parameterspageslugrequiredyearpage_size

borme_get_company_facts

Get company facts

Structured facts extracted from the BORME acts of a company, grouped by type (appointments, removals, capital changes, mergers, registered-office moves...) with person name and role when applicable, plus a `summary` with the count per type. Use it to answer "who was appointed / what changed" without reading raw act text.

Parametersslugrequiredlimit

borme_get_company_timeline

Get company timeline

Unified chronological timeline of a company combining BORME registry acts and public procurement awards (PLACSP), newest first, each entry with date, category, source, source URL and confidence. The `limit` (default 30) bounds the list; the response reports `events_total`. Amounts are source-reported awards, not proof of payment.

Parametersslugrequiredlimit

borme_get_company_officers

Get company officers

Current and historical officers of a company as published in the BORME: administrators, attorneys (apoderados), auditors and similar roles with the date each was first seen. Documentary mentions only: no DNI, no contact data, and a mention does not prove the person still holds the role today. At most 500 mentions.

Parametersslugrequired

borme_get_company_relationships

Get company relationships

Documented relationships between a company and other entities (officers, domicile, contracts, grants, IP assets, corporate links, mentions), each with source, date, confidence and evidence URL. Filter with `type` and `confidence`. Documentary only: a relationship does not imply control, responsibility or current validity.

Parametersslugrequiredtypeconfidence

borme_get_company_graph

Get company graph

Corporate graph centred on a company: parents and children (group structure from GLEIF) with counts and coverage notes. Only entities that pass the OpenMercantil identity policy appear, so an empty graph does not mean the company has no group.

Parametersslugrequiredmax_children

borme_get_company_activity

Get company activity

Monthly time series of BORME activity for a company (number of registry acts per month, `series: [{period: "2024-05", count: 2}]`). Useful to spot dormant companies or bursts of corporate activity.

Parametersslugrequired

borme_get_similar_companies

Get similar companies

Companies in the same province and two-digit CNAE division, ranked by closeness of BORME act count. A documentary heuristic for finding peers or competitors, not a recommendation or a statement of any relationship.

Parametersslugrequiredlimit

borme_get_company_contracts

Get company contracts

Public procurement notices (PLACSP, contrataciondelestado.es) linked to the company by CIF: object, buyer, supplier, CPV codes, procedure, typed amounts (budget, estimated, award) and phase. The link is documentary and does not prove payment or executed spend; amounts of different kinds are never summed. Default 10, max 100.

Parametersslugrequiredlimit

borme_get_company_grants

Get company grants

Public grants and subsidies (BDNS) awarded to the company, in integer cents of the awarded amount (never payments). Up to 200 attested rows. May answer 503 `projection_unavailable` when the integrations projection is offline: that is not evidence of "no grants".

Parametersslugrequiredlimit

borme_get_company_ted

Get company TED

European public procurement notices (TED) linked to the company NIF: publication number and date, buyer and the official notice URL. Rows do not prove payment or current contractual status. May answer 503 when the integrations projection is offline.

Parametersslugrequiredlimit

borme_get_company_cnmv

Get company CNMV

Stock-market (CNMV) listing tuple of the company and its most recent regulatory events. Use it to check whether a company is listed. Empty coverage is not proof of non-listing. May answer 503 when the integrations projection is offline.

Parametersslugrequiredlimit

borme_get_company_wikidata

Get company wikidata

Wikidata identifiers of the company: Q-id, entity URL, ticker and inception date (CC0 subset only; no labels, logos or websites). Useful to link the company to other datasets. May answer 503 when the integrations projection is offline.

Parametersslugrequired

borme_get_company_bde

Get company BDE

Banco de España (Central de Balances) sector ratios for the company’s two-digit CNAE: sector benchmarking such as net margin, ROA and ROE. It is NOT the company’s own financial statements. `coverage_status` tells whether the sector is projected; when it is not, `metrics` is empty.

Parametersslugrequired

borme_get_company_sources

Get company sources

Coverage of the four external integrations for a company (BDNS grants, CNMV, TED, Wikidata): which are available or empty, with licence metadata. Call it before the individual integration tools to know which ones have data. May answer 503 when the integrations projection is offline.

Parametersslugrequired

borme_get_daily_summary

Get daily summary

What the BORME published on one date: every registry act grouped by BORME section and province (company, act type, company slug). The raw day can hold thousands of acts, so the response gives exact counts per section and province plus the first `limit` acts per province (default 10). Narrow with `province` and/or `section` before raising the limit. `province` ignores case and accents and accepts part of a name of 3+ characters ("alava" finds "Araba/Álava"); if nothing matches, the response lists `available_provinces`. The BORME is not published on Sundays or national holidays (404), and this dataset may lag behind today: check borme_get_health (`latest_borme_processed`) if a recent date is missing.

Parametersdaterequiredlimitsectionprovince

borme_search_persons

Search persons

Search people mentioned in the BORME by name (usually as officers: administrators, attorneys, auditors). Returns name mentions with `slug`, number of mentions and companies, and first/last seen. These are NOT identity profiles: two people with the same name share one slug. Use the slug with borme_get_person.

Parametersqrequiredlimit

borme_get_person

Get person

Documentary report of the BORME mentions of a person slug: the companies and roles where the name appears, with dates. Does not infer identity or whether the person still holds a role. Withheld, ambiguous or absent identities answer 404.

Parametersslugrequired

borme_get_person_graph

Get person graph

Person-to-company graph built only from BORME mentions of a person slug: the companies connected to that name. Does not infer control, identity or vigency.

Parametersslugrequiredlimit

borme_list_sector_companies

List sector companies

List companies of a CNAE sector (1-4 characters: section letter, 2-digit division such as "62" for IT programming/consulting, or a longer code), optionally within one province. Sorted by BORME activity by default; with `province` use sort=recent (default) or oldest. Use for prospecting and market mapping; 20 per page, offset up to 1000. Find codes with borme_get_cnae_tree.

Parameterscnaerequiredsortlimitoffsetprovince

borme_get_sector_ratios

Get sector ratios

Banco de España (Central de Balances) aggregate ratios for a two-digit CNAE division by year (net margin, ROA, ROE...). Sector benchmark only, never company-specific figures. `ratios` is empty when the sector is not in the reviewed aggregate.

Parameterscnaerequired

borme_get_cnae

Get CNAE

Metadata of a CNAE-2009 code: description, level, parent and number of companies. Works for section letters and two-digit divisions; longer codes may answer 404. Use it to confirm what a `cnae_code` from a company search means.

Parameterscoderequired

borme_get_cnae_tree

Get CNAE tree

The CNAE-2009 hierarchy (sections and divisions) with company counts, to look up the right sector code for borme_list_sector_companies or borme_get_sector_ratios. About 13 KB: call it once, not per question.

Takes no parameters.

borme_get_legal_article

Get legal article

Consolidated text (`body_html`) of one article of a norm, with its ELI anchor and version date. Article numbers join bis/ter with a hyphen ("160-bis"). Informational, not legal advice; the official text is on boe.es.

Parametersnrequirednormrequired

borme_get_act_map

Get act map

Which law governs which BORME act type: maps registry act types (constitución, nombramiento, ampliación de capital, disolución, concurso...) to the norm and articles that regulate them. Without `acto` returns the full map (about 11 KB); with `acto` one mapping. Use it to answer "what law governs this registry act". Not legal advice.

Parametersacto

borme_search_tenders

Search tenders

Search Spanish public procurement notices (PLACSP) by object/buyer text, CPV prefix, phase, province, buyer NIF, supplier CIF, open status, amount range (requires amount_kind) and publication dates. Cursor-paginated: pass back `cursor` for the next page. Constraints: free text cannot be combined with structured filters, and `cpv` combines only with the date filters (otherwise the API answers 422). Supplier names are not searchable; use supplier_cif.

Parametersqcpvlimitphasecursorprovincebuyer_nifopen_onlyamount_kindpublished_tosupplier_cifmax_amount_eur+2 more

borme_get_tender

Get tender

One procurement notice by `key` (from borme_search_tenders): buyer, supplier, lots, CPV codes, procedure, typed amounts and results. Monetary concepts (budget, estimated, award) are never mixed. Uncertain supplier identities are withheld.

Parameterskeyrequired

borme_get_tender_stats

Get tender stats

Coverage and freshness metrics of the procurement dataset (record counts, geography, documents). No monetary rollups. Use it to judge how complete tender data is.

Takes no parameters.

borme_list_tender_suppliers

List tender suppliers

Corporate suppliers ranked by number of public contract awards (only suppliers matched to a company by CIF; natural persons omitted; no monetary totals). Default 10, max 50.

Parameterslimit

borme_get_health

Get health

OpenMercantil service status and BORME freshness: `status` (ok/stale), `latest_borme_processed` (last bulletin date loaded), approximate company and event counts and degraded flags. Call it when a recent date or company seems missing, or before stating that something "has not been published yet".

Takes no parameters.

borme_get_stats

Get stats

Size of the public dataset: number of legal entities published and an approximate count of person mentions, with the build timestamp.

Takes no parameters.

borme_get_sources_freshness

Get sources freshness

Per-source freshness map (BORME, PLACSP, BDNS, CNMV, annual accounts...): last update time and status of each public source behind the data, including a global label. Use it to qualify how current an answer is. About 12 KB.

Takes no parameters.

Version history

1
  1. v1.0.2LatestOct 22, 2026

Score

90% of the applicable checks met

How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.

  • Reached in the last 30 days25 pts
  • Auth declared10 pts

    Declare the credential headers in the registry entry, or keep the endpoint answering the probe so its auth can be classified.

  • Tools listedRequired15 pts
  • DescriptionRequired15 pts
  • Logo10 pts
  • Documentation15 pts
  • License10 pts