Skip to main content
Glama

BORME API MCP connector

MCP Badge

Español: README.es.md

Connect Microsoft Copilot, Claude, ChatGPT, Cursor, VS Code or any MCP client to the hosted BORME API MCP server: Spanish commercial-registry data published in the BORME (Boletín Oficial del Registro Mercantil), with more than 9.6 million events since 2009, company histories, company search by name, NIF lookup, trademarks and trading names, and risk signals.

The server is hosted at mcp.bormeapi.com; there is nothing to install or run, and it is the recommended way to connect. This repository holds what you need around it: connection settings for each client, an agent skill, the event-type vocabulary, and a local stdio server that wraps the BORME API REST endpoints, for clients that only start servers over stdio.

The full guide, kept up to date, is at bormeapi.com/mcp. If this README and that page ever disagree, the page is right.

Two ways to connect

API key: https://mcp.bormeapi.com/mcp

  • Transport: Streamable HTTP. Each request gets a plain JSON response; no session is kept between calls.

  • Authentication: your API key in the X-API-Key header. Without a key, the free plan's limits apply.

  • For clients that can send a header: Microsoft Copilot Studio, Claude Code, Cursor, VS Code, Claude Desktop (through mcp-remote) and any other Streamable HTTP client.

OAuth: https://mcp.bormeapi.com/mcp/oauth

  • For assistants with custom connectors that sign in with OAuth, such as Claude.ai, ChatGPT or Copilot. There is no API key to paste anywhere: you sign in with your BORME API account, and the app uses the plan of the account that authorized it.

  • This endpoint requires a BORME API account and ignores the X-API-Key header. Its calls share your API key's daily quota with REST API and /mcp calls made with that key.

  • If your account has no active API key, the tools return an error directing you to your account page; they work again once your account has an active key, without reconnecting the app.

  • If the app does not use the connection for 30 days, connect it again. You can disconnect the app at any time under Connected apps on your account page.

  • For client developers: an unauthenticated call gets 401 with WWW-Authenticate: Bearer resource_metadata="https://mcp.bormeapi.com/.well-known/oauth-protected-resource/mcp/oauth". The authorization server is https://bormeapi.com (metadata at /.well-known/oauth-authorization-server), with dynamic client registration, PKCE (S256) and the scope mcp.

Get an API key on your account page.

Related MCP server: Mapa Societario

Set up your client

Claude.ai (OAuth)

  1. Go to Customize > Connectors > Add custom connector.

  2. Enter https://mcp.bormeapi.com/mcp/oauth as the server URL. Claude detects how to sign in and shows Sign in now and Register automatically; keep these options.

  3. Click Add. Our sign-in page opens.

  4. Sign in with the link we email you, then select Allow.

  5. Back in Claude, if the connector page says the connector has no tools, reload the page.

On Team and Enterprise plans an owner adds the connector under Organization settings.

To use your API key instead, enter https://mcp.bormeapi.com/mcp, choose No sign-in and add the x-api-key header with your key under Request headers. Anthropic offers request headers as a beta to a limited set of organizations; if you do not see that section, use the Claude Desktop setup below.

ChatGPT (OAuth)

ChatGPT's custom connectors cannot send an API-key header. Add a custom connector with https://mcp.bormeapi.com/mcp/oauth as the server URL and sign in with your BORME API account. The screens and their names may differ from Claude.ai's. Without OAuth, ChatGPT can use https://mcp.bormeapi.com/mcp only without a key, on the free plan.

Microsoft Copilot Studio and Microsoft 365 Copilot (API key)

These steps follow Microsoft's documentation. They may vary with your tenant and your data loss prevention (DLP) policies.

  1. In Copilot Studio, open the agent you want to use and go to Tools > Add a tool > New tool > Model Context Protocol.

  2. Enter a Server name (BORME API), a Server description and the Server URL: https://mcp.bormeapi.com/mcp

  3. For authentication, choose API key, set Type to Header and enter X-API-Key as the header name. Select Create, then Create a new connection, enter your key and select Add to agent.

  4. Test the agent in Copilot Studio first. Then publish it and set up the Teams and Microsoft 365 Copilot channel, subject to your organization's permissions and policies. If your organization has Power Platform data policies (DLP), an administrator may need to allow this connector.

Claude Code (API key)

claude mcp add --transport http --scope user \
  --header "X-API-Key: YOUR_KEY" \
  borme https://mcp.bormeapi.com/mcp

--scope user makes the server available in all your projects; leave it out to add it to the current project only.

Cursor (API key)

Add this to ~/.cursor/mcp.json (all projects) or .cursor/mcp.json (one project) and set BORME_API_KEY in your environment:

{
  "mcpServers": {
    "borme": {
      "url": "https://mcp.bormeapi.com/mcp",
      "headers": { "X-API-Key": "${env:BORME_API_KEY}" }
    }
  }
}

VS Code (API key)

Add this to .vscode/mcp.json in your workspace. VS Code asks for the key the first time the server starts:

{
  "inputs": [
    {
      "type": "promptString",
      "id": "borme-api-key",
      "description": "BORME API key",
      "password": true
    }
  ],
  "servers": {
    "borme": {
      "type": "http",
      "url": "https://mcp.bormeapi.com/mcp",
      "headers": { "X-API-Key": "${input:borme-api-key}" }
    }
  }
}

Claude Desktop (API key)

Add the server to claude_desktop_config.json through mcp-remote, a third-party bridge that needs Node.js:

{
  "mcpServers": {
    "borme": {
      "command": "npx",
      "args": ["mcp-remote", "https://mcp.bormeapi.com/mcp",
               "--header", "X-API-Key:${BORME_API_KEY}"],
      "env": { "BORME_API_KEY": "YOUR_KEY" }
    }
  }
}

Any other Streamable HTTP client (API key)

Send each JSON-RPC message as a POST to https://mcp.bormeapi.com/mcp with Content-Type: application/json, an Accept header that includes application/json, and your key in X-API-Key. For example, to list the tools:

curl -s https://mcp.bormeapi.com/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "X-API-Key: YOUR_KEY" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

Local stdio server

server.py is a local stdio server that wraps the BORME API REST endpoints; the hosted server at mcp.bormeapi.com is the recommended way. It offers the same tools, with the same names, titles, descriptions, parameters and annotations (all tools are read-only), as the hosted server: they are copied into tools.json. Each tool call makes one or more requests to https://api.bormeapi.com/v1/.... It holds no data; MCP directories build an image from its Dockerfile to list the tools.

  • Listing the tools needs no key and no network.

  • Calling a tool needs an API key for every tool except list_act_types and registry_stats: the REST API, unlike the hosted MCP server, has no keyless free plan. Your free key is in your account. Set it as BORME_API_KEY.

  • daily_digest and registry_stats return fewer fields than on the hosted server, because the REST API has no single endpoint for them: daily_digest returns the day's event count, its parse completeness and up to 200 insolvency notices, and registry_stats returns the latest publication date and, with a key, the parse completeness of the last 30 publication days.

  • It does not sign in with OAuth.

With Docker:

docker build -t borme-mcp .
docker run -i --rm -e BORME_API_KEY=YOUR_KEY borme-mcp

With Python 3.12:

pip install -r requirements.txt
BORME_API_KEY=YOUR_KEY python server.py

When the hosted server changes its tools, run python scripts/update_tools.py to regenerate tools.json and commit it. CI fails while tools.json and the hosted server differ.

Tools

  • search_companies - find companies by current or former name and get ranked company cards.

  • company_history - the registry timeline of one company: the published acts available under your plan, newest first.

  • search_events - search BORME notices by date, province, act type and company name.

  • daily_digest - one publication day in figures, with its insolvency notices.

  • company_by_nif - find a company by its NIF/CIF tax ID (Basic plan and above).

  • brand_owner - find the company a trademark or trading name is linked to (Basic plan and above).

  • company_brands - trademarks and trading names linked to one company (Basic plan and above).

  • recent_signals - the latest risk signals, such as insolvency filings and mass exits (Risk plan).

  • list_act_types - the act types, with their English labels and the original Spanish headings.

  • registry_stats - size and coverage of the registry data.

Each tool's description and parameter schema, as returned by tools/list, explain its parameters.

Prompts and resources

Besides tools, the hosted server and the local stdio server offer prompts, ready-made instructions that your client can offer you (in Claude, from the + menu; in other clients, wherever they list a server's prompts), and resources, reference data that your client can attach as context. A prompt only supplies the instructions: the tool calls it leads to count against your plan as usual.

  • company_due_diligence (company): a report on one company's identification, published history, officer appointments and insolvency notices, citing the BORME id of each act.

  • board_changes (company, since): appointments, re-elections, terminations and resignations, revocations and ex officio cancellations of appointments, optionally since a date.

  • new_companies_digest (province, date): companies whose incorporation notices were published in BORME on one day, for one province or autonomous community. If date is omitted, it uses the latest publication day.

  • check_nif (nif): which company a NIF/CIF is linked to in our data, and its latest published acts (Basic plan and above).

The prompts tell the model to cite BORME ids, to tell a name match from a confirmed identification or ownership, and not to treat a missing result as proof that something does not exist.

  • borme://act-types: the act types, as list_act_types returns them.

  • borme://provinces: the provinces and autonomous communities that the province filters accept. It needs BORME_API_KEY; without a key, reading the resource returns instructions for obtaining a free API key.

  • borme://coverage: data freshness, as registry_stats returns it on this server.

One resource template takes a company slug:

  • borme://company/{slug}: up to 20 of the most recent published events of one company, by slug (for example borme://company/vaz-metales-sl), as company_history returns them with limit 20 and order desc, under the same plan rules. On the hosted server without an API key, only events from the last 7 days are visible; the local server requires BORME_API_KEY. For more events, call company_history.

Plans and limits

  • No key or free key: 50 requests a day, events from the last 7 days, company search by name (first 5 results), company histories and daily digests within those 7 days, the act-type list and registry statistics.

  • Basic: 5,000 requests a day, 365 days of history, NIF lookup, the NIF on company search results, trademarks and trading names.

  • Pro: 50,000 requests a day and the full history since 2009.

  • Risk: 200,000 requests a day and the risk signals tool.

The MCP server uses the same key and the same daily quota as the REST API. Each tool call counts as one request against the daily quota of your key (or, without a key, of your IP address). Results are capped per call (for example, 200 events); page with offset where a tool offers it.

Plans and prices: bormeapi.com/#pricing.

Data

  • More than 9.6 million events since 2009 from BORME-A (acts registered in the Registro Mercantil), updated every publication day.

  • Results are based on published BORME notices and other public data. Associations involving trademarks or NIFs are data matches and do not constitute legal confirmation.

  • Not included: annual accounts, BORME-C notices (legal announcements), and notices published before 2009.

In this repository

  • skills/borme-registry - an Agent Skill that tells the agent which tool to call, how to chain them and how to report the answers. skills/borme-registry-es is the same skill in Spanish. Install one of the two, not both. For Claude Code:

    git clone https://github.com/bormeapi/borme-mcp.git
    mkdir -p ~/.claude/skills && cp -r borme-mcp/skills/borme-registry ~/.claude/skills/

    The skill needs the MCP server to be connected.

  • vocab/ - the act-type vocabulary: each enum with its Spanish heading and English label.

  • server.py, prompts.py, tools.json and the Dockerfile - the local stdio server described above, with its prompts, resources and resource template; scripts/update_tools.py regenerates tools.json from the hosted server.

License

The contents of this repository are under the MIT License.

The data served by BORME API contains public-sector information from the Agencia Estatal Boletín Oficial del Estado (BORME), reused under Law 18/2015 and RD 1495/2011. Not affiliated with or endorsed by BOE.

Available Tools

10 tools
brand_ownerFind a brand's companyA
Read-onlyIdempotent
Inspect

Find the Spanish company a trademark or trading name is linked to, in the Spanish patent office's (OEPM) trademark and commercial-name records we hold (the archive starts in 1987).

Use it when the user names a brand; for a company's own name use search_companies, for a known company's brands use company_brands.

Returns JSON {found, brand, matches: [{brand, kind, company_slug, company_name, company_status, file}], truncated, source, note}. kind commercial_name identifies a business; trademark distinguishes goods or services (NESCAFÉ is not another name for Nestlé): say which kind a hit is. Links come from holder-name matching (the office publishes no tax IDs); ambiguous holders stay unlinked: present a hit as a name match, not confirmed ownership. found false is not proof the brand is unused. On a hit, use company_history with the slug.

Read-only; one request per call. Needs the basic plan or higher: send your API key in the X-API-Key header (https://bormeapi.com/account).

NameRequiredDescriptionDefault
brandYesBrand or trading name, or part of it, at least 3 letters or digits after punctuation is removed, case-insensitive, e.g. "ZARA".
limitNoMaximum matches, integer 1-200, e.g. 10 (default 20).

TDQS

A4.6/5.0
Behavior5/5

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

Annotations already cover read-only/idempotent safety, but the description adds substantial context beyond them: the 1987 archive boundary, that links come from holder-name matching rather than tax IDs, that ambiguous holders remain unlinked, and above all the epistemic caveat that a hit is a name match not confirmed ownership and that found=false is not proof the brand is unused. Auth and plan requirements plus 'one request per call' are also disclosed.

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 purpose, then routing, then return shape and caveats, then auth. Dense but nearly every sentence carries decision-relevant information; the return-schema field enumeration is the one segment that runs long for a tool with no output schema.

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

Completeness5/5

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

With no output schema, the description supplies the return JSON shape including truncated, source and note, explains the kind discriminator semantics, and pre-empts the two most likely misinterpretations (name match vs ownership, found=false vs unused). Nothing needed to call or interpret it correctly is missing.

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

Parameters3/5

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

Schema description coverage is 100%, so the schema already documents both the brand string (minimum length, case-insensitivity, partial matching) and the limit range. The description adds no further parameter detail, which is acceptable at full coverage but leaves this at baseline.

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 ('find the Spanish company a trademark or trading name is linked to') and names the exact data source, OEPM trademark and commercial-name records since 1987. It explicitly differentiates itself from two named siblings by input type.

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

Usage Guidelines5/5

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

Gives an explicit trigger ('when the user names a brand') and routes two adjacent cases elsewhere: company's own name to search_companies, known company's brands to company_brands. It also adds a follow-up path ('On a hit, use company_history with the slug'), so the agent knows what to do next.

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

company_brandsA company's brandsA
Read-onlyIdempotent
Inspect

List the trademarks and trading names that the Spanish patent office (OEPM) records under a holder with this company's name.

Use it for a known company (a slug from search_companies or company_history); to go from a brand to its company use brand_owner.

Returns JSON {company_slug, commercial_names, trademarks (each {name, file, status, since}), counts, truncated, limit_per_kind, source, note}. The office publishes no tax IDs, so every link is a name match, not confirmed ownership. An empty result means none is linked in our data, not that the company holds none. limit applies to each kind separately, newest first; counts is what this answer lists, not the company's total, and truncated true for a kind means more are linked: raise limit.

Read-only; one request per call. Needs the basic plan or higher: send your API key in the X-API-Key header (https://bormeapi.com/account).

NameRequiredDescriptionDefault
limitNoMaximum results per kind (trademarks, trading names), integer 1-200, e.g. 10 (default 50).
companyYesCompany slug, as returned by search_companies or company_history, e.g. vaz-metales-sl.

TDQS

A4.9/5.0
Behavior5/5

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

Beyond the readOnly/idempotent annotations, it discloses the plan gate (basic or higher), the X-API-Key header, one request per call, and the critical caveat that links are name matches rather than confirmed ownership since OEPM publishes no tax IDs. It also explains empty-result semantics, per-kind limits, and what truncated means.

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

Conciseness5/5

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

Purpose is front-loaded, followed by usage, return shape, caveats, and access requirements. Every sentence carries information an agent would otherwise have to guess, with no filler or repetition of the schema.

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

Completeness5/5

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

There is no output schema, and the description fully enumerates the return shape including nested trademark fields. It also covers the truncation/limit interaction and the name-match reliability caveat, leaving no material gap for correct invocation or interpretation.

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 100%, so the schema already documents both parameters. The description still adds real meaning for limit: it applies per kind, newest first, and truncated=true means raise it. The company parameter gains only the reiteration of the slug source, already in the schema.

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: lists trademarks and trading names recorded by OEPM under a holder matching the company name. It immediately distinguishes itself from the sibling brand_owner by naming the reverse direction, so an agent can route without opening either schema.

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

Usage Guidelines5/5

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

Explicitly says to use it for a known company and where the slug comes from (search_companies or company_history), and names the alternative brand_owner for the opposite lookup. Both the entry condition and the exclusion are stated.

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

company_by_nifFind a company by NIFA
Read-onlyIdempotent
Inspect

Look up a Spanish company by its NIF/CIF tax ID. Use it when the user gives a tax ID (with a name use search_companies); on a hit, call company_history with the company_slug.

Returns JSON {found, company_slug, company_name, current_name, status, province, nif_source, nif_caveat, ...}; use current_name. BORME has no dedicated tax-ID field: there are more than 580,000 NIF mappings from public sources and the text of BORME notices, covering a minority of companies, so a miss (reason nif_unmapped) means "not matched yet", not "does not exist". invalid_input true: not a NIF/CIF. reason nif_check_character_failed: wrong check character; relay tell_the_user and the did_you_mean candidates. reason not_registry_entity: explain entity_type as the note does. ambiguous true: ask which candidate. nif_caveat present: say the link is not settled.

Read-only; one request per call. Needs the basic plan or higher: send your API key in the X-API-Key header (https://bormeapi.com/account).

NameRequiredDescriptionDefault
nifYesSpanish NIF/CIF, normally 9 characters, e.g. B12345674. Spaces, hyphens, dots and the ES VAT prefix (ESB12345674) are accepted; other country prefixes are not.

TDQS

A4.6/5.0
Behavior5/5

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

Annotations already declare readOnly/idempotent, and the description adds genuinely non-inferable context: one request per call, X-API-Key header plus plan requirement, and a coverage caveat (>580,000 mappings, minority of companies) with the crucial semantics that a miss means 'not matched yet', not 'does not exist'. It also decodes each failure reason (invalid_input, nif_check_character_failed, not_registry_entity, ambiguous, nif_caveat) and how to relay it.

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 purpose, then alternative, then return handling, then failure modes. It is dense rather than wasteful, though the single paragraph packs many clauses (reason codes, caveats, auth) that could be more cleanly separated.

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

Completeness5/5

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

No output schema exists, so the description must explain returns — and it does, listing the JSON fields, which field to prefer (current_name), and the meaning of each status/reason. For a single-param read tool, nothing an agent needs to call or interpret it correctly is missing.

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

Parameters3/5

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

Schema description coverage is 100% and already documents the NIF format, length, and accepted separators/prefixes, so the schema carries parameter semantics. The description adds no syntax detail beyond it; its value is in output interpretation, not the input parameter, so baseline 3 is right.

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 ('Look up a Spanish company by its NIF/CIF tax ID') and immediately distinguishes it from the sibling search_companies by input type. An agent can tell it apart without opening 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 Guidelines5/5

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

Explicit routing: use this when the user gives a tax ID, use search_companies when a name is given, and on a hit chain into company_history with the returned company_slug. Both the use case and the alternative are named.

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

company_historyCompany registry timelineA
Read-onlyIdempotent
Inspect

Get one company's BORME timeline: its published registry events within your plan's window.

Use it once the company is known (a slug from search_companies or company_by_nif); across many companies use search_events. A name instead of a slug is searched: several matches return {ambiguous: true, candidates}, none returns {error}.

Returns JSON {company_slug, total_events, first_seen, last_seen, truncated, next_offset, count, events} (as in search_events), with former_slugs for a merged company (an old slug returns the merged timeline) and plan_window on a limited plan. total_events, first_seen and last_seen cover the whole timeline in your window, not just this page. To page, keep limit and order and pass next_offset as offset (at most 10000) until it is null.

Read-only; one request per call. Without an API key (X-API-Key header) only the last 7 days; basic covers 365 days, pro and risk the full history back to 2009. If all its events are outside your window, the refusal counts them.

NameRequiredDescriptionDefault
limitNoEvents per page, integer 1-200, e.g. 20 (default 100).
orderNo"desc" (default, newest first) or "asc" (oldest first), e.g. "asc" to start from the earliest event in your plan's window.desc
offsetNoEvents to skip, integer 0-10000 (default 0); pass the previous page's next_offset, e.g. 100.
companyYesCompany slug, e.g. vaz-metales-sl (from search_companies), or a name of at least 3 letters or digits, e.g. "Mercadona", searched case-insensitively.

TDQS

A4.8/5.0
Behavior5/5

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

Annotations already declare readOnlyHint/idempotentHint, but the description goes beyond them: per-call request count, plan-tier windows (7 days anonymous, 365 basic, 2009+ pro/risk), merged-company former_slugs behavior, truncation, the 10000 offset ceiling, and the fact that refusals still count out-of-window events. That is exactly the context an agent needs and no annotation provides.

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 purpose, then usage routing, then return shape, then paging, then auth windows — a logical order with dense but information-bearing sentences. Minor redundancy with the schema (offset max 10000, limit/order kept stable) keeps it just short of maximal.

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

Completeness5/5

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

No output schema exists, so the description carries the return contract and does so fully: field list, the fact that total_events/first_seen/last_seen span the whole window rather than the page, truncated/next_offset paging, former_slugs, and plan_window. Combined with the auth tier explanation, an agent has everything needed to call and interpret it.

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 100%, so the baseline is 3, but the description adds real semantics: a name of at least 3 characters is searched case-insensitively and may return {ambiguous: true, candidates} or {error}, and paging requires keeping limit and order while passing next_offset as offset. It does not restate the limit range or enum-like order values, which is appropriate since the schema covers them.

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 — the BORME registry timeline for one company, events within the plan window — and immediately scopes it against search_events for the multi-company case. An agent can distinguish it from siblings like search_events and company_by_nif without opening 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 Guidelines5/5

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

Explicitly names the precondition ('once the company is known (a slug from search_companies or company_by_nif)') and the alternative ('across many companies use search_events'). It also covers the name-instead-of-slug fallback and what the ambiguous/no-match responses look like.

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

daily_digestDaily BORME digestA
Read-onlyIdempotent
Inspect

Summarise one BORME publication day: total events, counts by act type, the top 10 provinces and the day's insolvency-proceedings notices.

Use it for "what was published today" or a day's figures; to read the notices use search_events with date_from = date_to = that day.

Returns JSON {date, total_events, by_type, top_provinces, insolvencies: [{company, province}]}. insolvencies lists the events with INSOLVENCY_DECLARATION or INSOLVENCY_STATUS (not SUSPENSION_OF_PAYMENTS, BANKRUPTCY_LEGACY or PROVISIONAL_SHEET_CLOSURE_INSOLVENCY). An INSOLVENCY_STATUS notice can record any stage, from a request for a declaration to the conclusion: before saying a company was declared insolvent, read the act's payload with search_events. A day without a gazette (weekends, holidays) returns total_events 0.

Read-only; one request per call. Without an API key only days within the last 7 days; send your key in the X-API-Key header (https://bormeapi.com/account) for your plan's window.

NameRequiredDescriptionDefault
dateNoPublication day, YYYY-MM-DD, e.g. 2026-10-27; omit for the latest day in the database.

TDQS

A4.6/5.0
Behavior5/5

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

Goes well beyond the readOnly/idempotent annotations by disclosing the access model (one request per call; without an X-API-Key only the last 7 days, key URL provided) and the empty-day edge case (weekends/holidays return total_events 0). It also flags a real correctness trap: INSOLVENCY_STATUS can represent any stage, so the payload must be read before asserting a company was declared insolvent.

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 the alternative, then the return shape, then caveats — a sensible information hierarchy. It is on the long side and the parenthetical enumeration of excluded act types (SUSPENSION_OF_PAYMENTS, BANKRUPTCY_LEGACY, PROVISIONAL_SHEET_CLOSURE_INSOLVENCY) is verbose, though each clause carries real decision value.

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

Completeness5/5

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

There is no output schema, and the description compensates by spelling out the returned JSON shape (date, total_events, by_type, top_provinces, insolvencies[{company, province}]). Combined with the auth window, empty-day behavior, and the insolvency-interpretation warning, an agent has everything needed to call it and to interpret the result.

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

Parameters3/5

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

Schema coverage is 100% and the schema already documents the YYYY-MM-DD format and the omit-for-latest default, so the description needn't repeat it. What it adds is behavioral: a day without a gazette yields total_events 0, which helps interpret the parameter's edge cases but doesn't extend the format semantics.

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?

Opens with a specific verb and resource ("Summarise one BORME publication day") and immediately enumerates the exact contents: totals, counts by act type, top provinces, insolvency notices. It explicitly distinguishes itself from search_events, so an agent can route between the two without opening either schema.

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

Usage Guidelines5/5

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

Gives explicit when-to-use ("what was published today" or a day's figures) and names the alternative with the exact invocation pattern: to read the notices use search_events with date_from = date_to = that day. That is a concrete hand-off rule, not just a mention of a sibling.

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

list_act_typesList act typesA
Read-onlyIdempotent
Inspect

List every normalized BORME act type: the enum used by the act_types filter of search_events (act_type), its Spanish label (spanish) and its English label (english).

Use it to choose act_types values or to translate act types in an answer; it reads no registry data. Returns a JSON array of {act_type, spanish, english}, sorted by act_type. Read-only, open to everyone, no key needed and not counted against a quota. The same list is the resource borme://act-types.

NameRequiredDescriptionDefault

No parameters

TDQS

A4.6/5.0
Behavior4/5

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

Annotations already declare readOnly, idempotent, non-destructive and closed-world, and the description adds genuinely new operational facts: no key required, no quota consumption, and equivalence to the borme://act-types resource. The safety restatement ('Read-only, open to everyone') overlaps somewhat with the annotations but the quota and auth disclosures are real added value.

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 identity of the list and the return shape, with usage guidance second and access facts last. Slight redundancy in the 'Read-only, open to everyone, no key needed' cluster, but no sentence is wasted overall.

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

Completeness5/5

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

No output schema exists, and the description fully compensates by specifying the return container (JSON array), the field set of each element, and the sort order (by act_type). An agent can call this and use the result without further inference.

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?

The tool takes zero parameters, so there is nothing for the description to disambiguate; baseline for a no-param tool applies. The description correctly implies no filtering arguments are accepted.

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 ('List every normalized BORME act type') and pins down exactly what each entry contains (act_type, spanish, english). It also identifies the consumer relationship — this is the enum used by the act_types filter of search_events — which distinguishes it cleanly from every sibling.

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

Usage Guidelines5/5

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

Gives two explicit use cases ('choose act_types values' or 'translate act types in an answer') and an explicit non-use signal ('it reads no registry data'), which routes registry-data queries to search_events. The alternative is named directly.

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

recent_signalsRecent risk signalsA
Read-onlyIdempotent
Inspect

Get a sample of the latest risk signals derived from BORME and public sources: at most 10 rows dated within the last 7 days.

Use it for "what risk signals appeared this week"; not a per-company check (use company_history) and not the full feed (the hosted API's /v1/signals).

Returns JSON {count, window, sample_cap, signals: [{signal_type, date, company_slug, company_name, province, details}], full_feed}. AEAT_DEBTOR comes from the AEAT's yearly debtors list (art. 95 bis LGT): details carry listed_on, list_year, is_current_list (true for 12 months from listed_on) and debt_eur, the published total at 31 December of the prior year. Say the company was on the list published on that date; never say the debt is still outstanding. count 0 means none in the window, not that a company is risk-free; an unknown signal_type is refused with the valid list.

Read-only; one request per call. Needs the risk plan: send your API key in the X-API-Key header (https://bormeapi.com/account).

NameRequiredDescriptionDefault
signal_typeNoOptional, one of INSOLVENCY_FILED, ACCORDION, MASS_EXIT, OWNERSHIP_CHANGE, DISTRESS_COMBO, PHOENIX, ADDRESS_CLUSTER, AEAT_DEBTOR, PUBLIC_CONTRACT_AWARD, e.g. MASS_EXIT; omit for all types.

TDQS

A4.8/5.0
Behavior5/5

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

Beyond the readOnly/idempotent annotations, it discloses the sample cap, the 7-day window, the auth requirement (X-API-Key, risk plan), one-request-per-call, the exact return shape, and subtle semantics: count 0 does not mean risk-free, and an unknown signal_type is refused with the valid list. The AEAT_DEBTOR note adds an important interpretive constraint (report the historical listing, never say the debt is outstanding).

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?

It is front-loaded with purpose and scope before the alternatives and caveats, and every paragraph (return shape, AEAT handling, count-0 semantics, auth) carries information the agent needs. It runs long, but there is little true waste; a slightly tighter AEAT paragraph would be the only trim.

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

Completeness5/5

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

With no output schema, the description takes responsibility by listing the JSON return fields and explaining count/window/sample_cap/full_feed. Combined with the auth note and the AEAT interpretation caveat, an agent has everything needed to call and report results correctly.

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 100%, so the enum values are already documented in the schema and the baseline would be 3. The description adds value beyond it by explaining rejection behavior for an unknown signal_type, which the schema does not state, plus the omit-for-all-types default implied by the usage guidance.

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?

The description opens with a specific verb and resource ("Get a sample of the latest risk signals") and bounds it precisely: at most 10 rows within the last 7 days. It also names the sibling it is not (company_history) and distinguishes itself from the full hosted feed, so an agent can tell it apart from search_events and daily_digest without opening a schema.

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

Usage Guidelines5/5

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

It gives an explicit use case ("what risk signals appeared this week"), two explicit exclusions with the alternative named (per-company check -> company_history; full feed -> /v1/signals), and the plan/auth prerequisite. Virtually nothing about when to select this tool is left to inference.

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

registry_statsData coverage and freshnessA
Read-onlyIdempotent
Inspect

Report the coverage and freshness of the BORME data behind this server.

Use it to answer "how much data is there?", "how fresh is it?" and "can I trust date filters for period X?" before running searches; it says nothing about any one company.

Returns JSON {events_approx, companies_approx, coverage: {from, to}, parse_completeness_last_30d, source}: approximate event and company counts (planner estimates, not exact tallies), the first and latest publication day held (YYYY-MM-DD), and the event-weighted parse completeness over the 30 days up to the latest run (e.g. 0.9987). Takes no arguments. Read-only, open to everyone, no key needed and not counted against a quota. The same report is the resource borme://coverage.

NameRequiredDescriptionDefault

No parameters

TDQS

A4.8/5.0
Behavior5/5

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

Beyond the read-only/idempotent annotations it discloses non-obvious traits: counts are approximate planner estimates rather than exact tallies, the freshness field is event-weighted over the trailing 30 days, and there are no key or quota costs. It even points to the equivalent resource borme://coverage.

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 purpose, then usage, then return shape, then access notes — a sensible order with no filler. Slightly long for a single-purpose stats call, and the example value '(e.g. 0.9987)' is borderline unnecessary.

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

Completeness5/5

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

With no output schema, the description compensates by enumerating every returned field and its meaning, including the approximate nature of counts and the date format. Nothing an agent needs to interpret the result is missing.

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?

Zero parameters gives a baseline of 4; the description reinforces this with 'Takes no arguments,' which removes any doubt about whether a date range or filter can be supplied. No further parameter meaning is needed.

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+resource ('Report the coverage and freshness of the BORME data') and draws an explicit boundary against the sibling search tools: 'it says nothing about any one company.' An agent can place it among search_companies/search_events/company_* without ambiguity.

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

Usage Guidelines5/5

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

Gives concrete triggering questions ('how much data is there?', 'how fresh is it?', 'can I trust date filters for period X?') and a sequencing rule: call it before running searches. It also names what it is not for.

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

search_companiesSearch companies by nameA
Read-onlyIdempotent
Inspect

Find Spanish companies by name and return ranked company cards. Use it first when the user gives a company name, then company_history with its company_slug; with a tax ID use company_by_nif, with a brand use brand_owner.

Matches current names, former names and variants, ignoring accents, case, punctuation and the legal form. Returns JSON {query, count, total, total_is_at_least, truncated, limit, offset, companies: [{company_slug, name, legal_form, province, municipality, status, in_insolvency, last_act_date, match, matched_on}]}. match is exact, prefix, contains or fuzzy (a lead, not an identification; say so). Ranked by match, then active companies, then newest act.

Read-only; one request per call; not limited by the free plan's 7 days of history. The free plan shows at most the first 5 ranked cards; hidden_by_plan counts the rest: relay its note. The NIF is on the card from the basic plan up (X-API-Key header). An empty answer is not proof that a business does not exist.

NameRequiredDescriptionDefault
nameYesThe bare company name or part of it, at least 3 letters or digits and at most 200 characters, e.g. "inditex" or "Talleres Jarama": no city, parentheses or notes. Matching allows for case, accents and punctuation, and a legal form such as SL or SA can be left out. Do not repeat the same query unchanged after an empty answer: read note and hidden_by_plan if present.
limitNoCards per page, integer 1-50, e.g. 5 (default 10).
offsetNoCards to skip, integer 0-200 (default 0), e.g. 10. At most 200 cards are ranked; truncated true means a candidate cap was reached or a search step ran out of time, so add another word from the name.
statusNoOptional, one of active, dissolved, extinct, sheet_closed, e.g. active; applied like province.
provinceNoOptional province, accent-insensitive, e.g. MADRID or VIZCAYA, or an autonomous community for all of its provinces, e.g. Catalonia; several values separated by commas, e.g. BIZKAIA,GIPUZKOA. Applied to the candidates the search reads (2,000 with a filter), so a broad name can return fewer companies than match it.

TDQS

A4.4/5.0
Behavior3/5

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

Annotations already declare readOnly, idempotent, closed-world and non-destructive, so the safety profile is covered. The description goes well beyond that with free-plan caps (5 cards, hidden_by_plan counting), plan-gated NIF data, ranking order and the 'empty answer is not proof' caveat — but it omits rate-limit/error behavior beyond 'one request per call'. Wait — reassessing: the plan gating, ranking criteria and empty-result caveat are exactly the kind of non-obvious context annotations cannot express, so the score should reflect that added value.

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?

Purpose and routing are front-loaded in the first two sentences, then matching rules, then result shape and plan caveats. Dense but every clause carries information; the inline JSON return-shape block is the only part bordering on verbose.

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

Completeness5/5

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

For a 5-param search tool with no output schema, the description supplies the return shape, ranking logic, plan-driven truncation behavior, match-type interpretation and the failure caveat. An agent can call it and interpret the response correctly without further context.

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 100%, so the baseline is 3. The description still adds meaning the schema does not: match values are 'a lead, not an identification', ranking order (match, active, newest act), and the semantics of truncated. The hidden_by_plan / NIF-plan notes sit outside the parameters but explain result shape, not parameter use.

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 ('Find Spanish companies by name and return ranked company cards') and explicitly distinguishes itself from company_history, company_by_nif and brand_owner by naming each sibling and the input that routes to it.

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

Usage Guidelines5/5

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

Gives an explicit when-to-use rule ('Use it first when the user gives a company name') plus three named alternatives with the exact condition selecting each (slug, tax ID, brand). No inference required.

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

search_eventsSearch registry eventsA
Read-onlyIdempotent
Inspect

Search BORME registry events (since 2009) across companies by publication date, province, act type and company name, newest first.

Use it for questions about many companies ("insolvency notices in Valencia in September"). For one known company use company_history; to find a company use search_companies; for one day's totals use daily_digest.

Returns JSON {count, events: [{event_id, date, borme_id, province, company_name, company_slug, acts: [{act_type, act_type_raw, roles, payload}], registral}]}, plus company_name_match, plan_window and hidden_by_plan when they apply. No next page: when count equals limit, narrow the filters.

Read-only; one request per call against your daily quota. Without an API key (X-API-Key header, https://bormeapi.com/account) only the last 7 days are searched (plan_window). An empty page with hidden_by_plan means matches exist outside your plan's window: do not say none exist. A bad date, province or act type is refused with a message naming the fix.

NameRequiredDescriptionDefault
limitNoMaximum events returned, integer 1-200, e.g. 20 (default 50).
date_toNoLatest publication date, inclusive, YYYY-MM-DD, e.g. 2026-09-30. Optional; defaults to the latest day held.
act_typesNoOptional list of act type enums; an event matches if it has any of them, e.g. ["INCORPORATION"] or ["INSOLVENCY_DECLARATION", "INSOLVENCY_STATUS"]. Full list: list_act_types. Barcelona prints some acts as free text under "Otros conceptos": recognised wording gets its own act type (act_type_raw stays "Otros conceptos"; fields.shareholder names a sole shareholder when the text does), and a same-entry revocation and reappointment becomes RE_ELECTIONS. Reprocessed events keep their event_id, but their acts can change.
date_fromNoEarliest publication date, inclusive, YYYY-MM-DD, e.g. 2026-09-01. Optional; data starts on 2009-01-02. Without a key it is moved up to 7 days ago (plan_window says so).
provincesNoOptional list of BORME province names, accent- and case-insensitive, e.g. ["MADRID", "CADIZ", "VIZCAYA"]. An autonomous community stands for all of its provinces, e.g. ["Basque Country"] or ["Cataluña"]. Full list: the resource borme://provinces.
company_name_containsNoOptional part of the company name, case- and accent-insensitive, e.g. "mercadona"; use at least 3 letters or digits for a selective search. % and _ match literally. It filters events; to look a company up by name, call search_companies first.

TDQS

A4.9/5.0
Behavior5/5

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

Goes well beyond the readOnly/idempotent annotations: discloses one-request-per-call quota consumption, the X-API-Key requirement and its 7-day fallback window, the plan_window and hidden_by_plan fields, the absence of pagination, and that invalid dates/provinces/act types are refused with a corrective message. The warning not to report 'none exist' on a hidden_by_plan empty page is a genuinely important behavioral caveat that no annotation conveys.

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

Conciseness5/5

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

Front-loaded with purpose, then routing, then return shape, then operational caveats. Every sentence carries distinct information; the inline return-shape listing is not waste because no output schema exists and it is the only place those fields are documented.

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

Completeness5/5

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

Six optional parameters with 100% schema coverage plus annotations, and the description compensates for the missing output schema by documenting the return envelope and conditional fields. Auth requirements, quota cost, window limits, error behavior and empty-result interpretation are all covered, so an agent has everything needed to call and interpret this tool.

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 100%, so per-parameter meaning is already carried by the schema; the description still adds cross-cutting semantics the schema does not, notably 'newest first' ordering and the no-next-page rule tying `limit` to a narrowing strategy rather than paging. It does not restate per-parameter formats, which is appropriate given the schema's detail.

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 with scope: 'Search BORME registry events (since 2009) across companies by publication date, province, act type and company name, newest first.' It also explicitly distinguishes itself from three siblings by name, so an agent can route correctly without opening 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 Guidelines5/5

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

Gives an explicit when-to-use example ('questions about many companies') and then routes the other three cases: one known company -> company_history, find a company -> search_companies, one day's totals -> daily_digest. This is the strongest form of alternative-naming guidance.

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. 8 tool updatesv2.1.1
    • Changedbrand_owner2 fields changed
      • changedInput schema / properties / brand / description
        Previous value: -"Brand or trading name, or part of it."New value: +"Brand or trading name, or part of it, at least 3 letters or digits after punctuation is removed, case-insensitive, e.g. \"ZARA\"."
      • changedInput schema / properties / limit / description
        Previous value: -"Maximum results, 1-200 (default 20)."New value: +"Maximum matches, integer 1-200, e.g. 10 (default 20)."
    • Changedcompany_brands2 fields changed
      • changedInput schema / properties / company / description
        Previous value: -"Company slug, as returned by search_companies or company_history."New value: +"Company slug, as returned by search_companies or company_history, e.g. vaz-metales-sl."
      • changedInput schema / properties / limit / description
        Previous value: -"Maximum results per kind (trademarks, trading names), 1-200 (default 50)."New value: +"Maximum results per kind (trademarks, trading names), integer 1-200, e.g. 10 (default 50)."
    • Changedcompany_by_nif1 field changed
      • changedInput schema / properties / nif / description
        Previous value: -"NIF/CIF, e.g. B12345674. Spaces, hyphens, dots and the ES VAT prefix (ESB12345674) are accepted; other country prefixes are not."New value: +"Spanish NIF/CIF, normally 9 characters, e.g. B12345674. Spaces, hyphens, dots and the ES VAT prefix (ESB12345674) are accepted; other country prefixes are not."
    • Changedcompany_history4 fields changed
      • changedInput schema / properties / company / description
        Previous value: -"Company slug (e.g. vaz-metales-sl) or name; a name falls back to a case-insensitive search (at least 3 letters or digits)."New value: +"Company slug, e.g. vaz-metales-sl (from search_companies), or a name of at least 3 letters or digits, e.g. \"Mercadona\", searched case-insensitively."
      • changedInput schema / properties / limit / description
        Previous value: -"Events per page, 1-200 (default 100)."New value: +"Events per page, integer 1-200, e.g. 20 (default 100)."
      • changedInput schema / properties / offset / description
        Previous value: -"Events to skip, 0-10000, in steps of limit."New value: +"Events to skip, integer 0-10000 (default 0); pass the previous page's next_offset, e.g. 100."
      • changedInput schema / properties / order / description
        Previous value: -"\"desc\" (default, newest first) or \"asc\" (oldest first)."New value: +"\"desc\" (default, newest first) or \"asc\" (oldest first), e.g. \"asc\" to start from the earliest event in your plan's window."
    • Changeddaily_digest1 field changed
      • changedInput schema / properties / date / description
        Previous value: -"Publication day, YYYY-MM-DD; omit for the latest day in the database."New value: +"Publication day, YYYY-MM-DD, e.g. 2026-10-27; omit for the latest day in the database."
    • Changedrecent_signals1 field changed
      • changedInput schema / properties / signal_type / description
        Previous value: -"One signal type to filter by (see the tool description); omit for all types."New value: +"Optional, one of INSOLVENCY_FILED, ACCORDION, MASS_EXIT, OWNERSHIP_CHANGE, DISTRESS_COMBO, PHOENIX, ADDRESS_CLUSTER, AEAT_DEBTOR, PUBLIC_CONTRACT_AWARD, e.g. MASS_EXIT; omit for all types."
    • Changedsearch_companies5 fields changed
      • changedInput schema / properties / limit / description
        Previous value: -"Cards per page, 1-50 (default 10)."New value: +"Cards per page, integer 1-50, e.g. 5 (default 10)."
      • changedInput schema / properties / name / description
        Previous value: -"Company name or part of it, at least 3 letters or digits; accents, case, punctuation and legal form are ignored."New value: +"The bare company name or part of it, at least 3 letters or digits and at most 200 characters, e.g. \"inditex\" or \"Talleres Jarama\": no city, parentheses or notes. Matching allows for case, accents and punctuation, and a legal form such as SL or SA can be left out. Do not repeat the same query unchanged after an empty answer: read note and hidden_by_plan if present."
      • changedInput schema / properties / offset / description
        Previous value: -"Cards to skip. At most 200 cards are ranked; truncated true means more candidates existed, so add another word from the name."New value: +"Cards to skip, integer 0-200 (default 0), e.g. 10. At most 200 cards are ranked; truncated true means a candidate cap was reached or a search step ran out of time, so add another word from the name."
      • changedInput schema / properties / province / description
        Previous value: -"The company's province, accent-insensitive, e.g. MADRID, VIZCAYA, or an autonomous community for all of its provinces, e.g. Catalonia; several values can be separated by commas, e.g. BIZKAIA,GIPUZKOA. Applied to the candidates the search reads (2,000 with a filter), so a broad name can return fewer companies than match it."New value: +"Optional province, accent-insensitive, e.g. MADRID or VIZCAYA, or an autonomous community for all of its provinces, e.g. Catalonia; several values separated by commas, e.g. BIZKAIA,GIPUZKOA. Applied to the candidates the search reads (2,000 with a filter), so a broad name can return fewer companies than match it."
      • changedInput schema / properties / status / description
        Previous value: -"One of active, dissolved, extinct, sheet_closed; applied like province."New value: +"Optional, one of active, dissolved, extinct, sheet_closed, e.g. active; applied like province."
    • Changedsearch_events6 fields changed
      • changedInput schema / properties / act_types / description
        Previous value: -"Act types, e.g. INCORPORATION, APPOINTMENTS, TERMINATIONS, CAPITAL_INCREASE, DISSOLUTION, INSOLVENCY_STATUS (full list: list_act_types)."New value: +"Optional list of act type enums; an event matches if it has any of them, e.g. [\"INCORPORATION\"] or [\"INSOLVENCY_DECLARATION\", \"INSOLVENCY_STATUS\"]. Full list: list_act_types. Barcelona prints some acts as free text under \"Otros conceptos\": recognised wording gets its own act type (act_type_raw stays \"Otros conceptos\"; fields.shareholder names a sole shareholder when the text does), and a same-entry revocation and reappointment becomes RE_ELECTIONS. Reprocessed events keep their event_id, but their acts can change."
      • changedInput schema / properties / company_name_contains / description
        Previous value: -"Part of the company name, at least 3 letters or digits, case-insensitive; % and _ match literally."New value: +"Optional part of the company name, case- and accent-insensitive, e.g. \"mercadona\"; use at least 3 letters or digits for a selective search. % and _ match literally. It filters events; to look a company up by name, call search_companies first."
      • changedInput schema / properties / date_from / description
        Previous value: -"Earliest publication date, YYYY-MM-DD (data starts in 2009)."New value: +"Earliest publication date, inclusive, YYYY-MM-DD, e.g. 2026-09-01. Optional; data starts on 2009-01-02. Without a key it is moved up to 7 days ago (plan_window says so)."
      • changedInput schema / properties / date_to / description
        Previous value: -"Latest publication date, YYYY-MM-DD, inclusive."New value: +"Latest publication date, inclusive, YYYY-MM-DD, e.g. 2026-09-30. Optional; defaults to the latest day held."
      • changedInput schema / properties / limit / description
        Previous value: -"Maximum events returned, 1-200 (default 50)."New value: +"Maximum events returned, integer 1-200, e.g. 20 (default 50)."
      • changedInput schema / properties / provinces / description
        Previous value: -"BORME province names, accent- and case-insensitive, e.g. MADRID, CADIZ, VIZCAYA. An autonomous community stands for all of its provinces, e.g. Basque Country, Cataluña, Andalucía."New value: +"Optional list of BORME province names, accent- and case-insensitive, e.g. [\"MADRID\", \"CADIZ\", \"VIZCAYA\"]. An autonomous community stands for all of its provinces, e.g. [\"Basque Country\"] or [\"Cataluña\"]. Full list: the resource borme://provinces."
  2. 10 tool updatesv1.1.1
    • Addedbrand_owner
    • Addedcompany_brands
    • Changedcompany_by_nif2 fields changed
      • addedInput schema / properties / nif / description
        Added value: +"NIF/CIF, e.g. B12345674. Spaces, hyphens, dots and the ES VAT prefix (ESB12345674) are accepted; other country prefixes are not."
      • changedOutput schema / (root)
        Previous value: -{
        -  "properties": {
        -    "result": {
        -      "title": "Result",
        -      "type": "string"
        -    }
        -  },
        -  "required": [
        -    "result"
        -  ],
        -  "title": "company_by_nifOutput",
        -  "type": "object"
        -}New value: +null
    • Addedcompany_history
    • Addeddaily_digest
    • Changedlist_act_types1 field changed
      • changedOutput schema / (root)
        Previous value: -{
        -  "properties": {
        -    "result": {
        -      "title": "Result",
        -      "type": "string"
        -    }
        -  },
        -  "required": [
        -    "result"
        -  ],
        -  "title": "list_act_typesOutput",
        -  "type": "object"
        -}New value: +null
    • Changedrecent_signals5 fields changed
      • removedInput schema / properties / signal_type / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • removedInput schema / properties / signal_type / default
        Removed value: -null
      • addedInput schema / properties / signal_type / description
        Added value: +"One signal type to filter by (see the tool description); omit for all types."
      • addedInput schema / properties / signal_type / type
        Added value: +"string"
      • changedOutput schema / (root)
        Previous value: -{
        -  "properties": {
        -    "result": {
        -      "title": "Result",
        -      "type": "string"
        -    }
        -  },
        -  "required": [
        -    "result"
        -  ],
        -  "title": "recent_signalsOutput",
        -  "type": "object"
        -}New value: +null
    • Addedregistry_stats
    • Addedsearch_companies
    • Addedsearch_events
  3. 6 tool updatesv1.1.0
    • Addedcompany_by_nif
    • Removedcompany_history
    • Removeddaily_digest
    • Addedrecent_signals
    • Removedregistry_stats
    • Removedsearch_events
  4. 5 tool updatesv0.1.0
    • First observedcompany_history
    • First observeddaily_digest
    • First observedlist_act_types
    • First observedregistry_stats
    • First observedsearch_events

TDQS

A4.6/5.0

Scored across 10 tools

Disambiguation5/5

Each tool has a clearly distinct role: company search vs. event search vs. single-company history vs. NIF lookup vs. brand lookups in both directions. Overlaps such as search_events vs. daily_digest are explicitly differentiated by the descriptions, and the inverse brand_owner/company_brands pair is unambiguous.

Naming Consistency4/5

All names use snake_case and are readable, but the set mixes verb-first names (search_events, list_act_types) with entity-first names (company_history, brand_owner, daily_digest). The variation is minor and appropriate for resource-oriented lookup tools, so it is not confusing.

Tool Count5/5

Ten tools is well within a healthy range for a registry-data server and each tool covers a distinct user need: search, entity lookup, timelines, brands, metadata, digests, and signals. No tool feels extraneous.

Completeness4/5

The surface covers the main BORME workflows: finding companies, retrieving histories, searching events, resolving brands, checking coverage, and sampling risk signals. Minor gaps exist, such as no direct single-event lookup or full signal feed, but they are workaroundable through the available search and history tools.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    B
    maintenance
    Search Spanish companies, directors and corporate relationships from official BORME registry filings — ~3.2M companies since 2009. Read-only, anonymous.
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables searching and retrieving French official business-event notices (creations, insolvency, sales, modifications, etc.) for companies by SIREN or name, with filtering by event type, department, and date range, all via keyless access.
    216 npm
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables AI agents to perform due diligence, KYB, and supplier or client verification by querying Spanish company registry data cross-referenced with public grants and procurement awards, each fact linking to its official publication.
    MIT