MCP server over the BORME events database. Tools for AI agents: search normalized registry events, pull a company's history, get a daily digest. Requires BORME_DSN (postgresql://...).
borme-mcp has 7 tools with visible definitions in server.py. All tools are READ_ONLY and have descriptions, which is good. However, there are consistent gaps: (1) Most parameter descriptions are minimal and lack format/constraint details (e.g., 'date_from' says 'Start date in YYYY-MM-DD format' but no validation guidance); (2) No output schemas documented, tools return JSON strings with implicit field structures; (3) No error handling patterns visible, tools return generic JSON with 'error' or 'found': false, but no recovery guidance; (4) Parameter descriptions are brief (averaging ~40-50 chars), below the 72-char baseline; (5) Tool names lack action verbs consistently (e.g., 'recent_signals' is noun-heavy, 'registry_stats' is noun-only). Positives: All tools have substantive docstrings (100-200 chars), parameter types are declared in function signatures, all tools are marked READ_ONLY, tools accept natural identifiers (company names, not just slugs), and the server includes sensible defaults (limit capping, accent-insensitive province matching).
Look up a Spanish company by its NIF/CIF tax ID. BORME itself prints no tax IDs — this mapping is cross-referenced from open official sources and covers a growing subset (~560k companies, 17% of the corpus, up from 232k when this tool shipped). A miss means "not matched yet", not "does not exist". On a hit, follow up with company_history using the returned slug.
Full registry timeline for one company, oldest first. `company` is a company slug (e.g. vaz-metales-sl) or an exact-ish name; if no slug matches, falls back to case-insensitive name search and, when several companies match, returns the list of candidate slugs instead.
Digest of one BORME publication day (default: latest in the database): totals by event type, top provinces, and all insolvency declarations.
All normalized event types (English enum + original Spanish label).
Sample of the latest derived risk signals (last 7 publication days, max 10 rows). Types: INSOLVENCY_FILED, ACCORDION, MASS_EXIT, OWNERSHIP_CHANGE, DISTRESS_COMBO, PHOENIX, ADDRESS_CLUSTER, AEAT_DEBTOR. This is a teaser feed — the full historical signals firehose lives in the hosted API's risk tier (https://bormeapi.com/#pricing).
No output schemas documented. Tools return JSON strings, but the agent cannot know what fields to expect without parsing examples or trial calls. E.g., search_events returns {count, events: [{event_id, date, borme_id, ...}]}, but this structure is implicit in the docstring, not declared as a formal return type.
Parameter descriptions lack actionable constraints. E.g., 'date_from' description is 'Start date in YYYY-MM-DD format', which states the format but does not mention valid range (coverage starts 2009), whether dates are inclusive, or what happens if date_from > date_to. Compare to baseline: 'parameter description must include expected format, range, and allowed values.'
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | D | 51 | 2026-07-28+ | v2 |
Coverage and freshness report for the BORME dataset behind this server. Returns a JSON object with: total_events (approximate count, planner estimate), total_companies, date_range (first and latest publication day covered, YYYY-MM-DD), and recent parse completeness (share of gazette text successful...
Search Spanish commercial-registry (BORME) events. All filters optional. Dates are YYYY-MM-DD (coverage starts 2009). provinces: BORME province names, accent-insensitive (MADRID, CADIZ...). act_types: normalized enums, e.g. INCORPORATION, APPOINTMENTS, TERMINATIONS, CAPITAL_INCREASE, DISSOLUTION, INSOLVENCY_STATUS (see list_act_types). Returns newest first, at most `limit` (<=200) events as JSON.
Tool names lack action verbs or are noun-heavy. 'recent_signals', 'daily_digest', 'registry_stats', and 'list_act_types' do not start with typical action verbs (get_, search_, list_). LLM parsing of tool intent relies on verb recognition. Recommend: get_recent_signals, get_daily_digest, get_registry_stats, list_act_types (already OK).
Error handling is implicit and not recovery-guided. company_by_nif returns {found: false, note: '...'} and company_history returns {error: '...', ambiguous: true, candidates: [...]}. These have recovery hints in the note/docstring, but the pattern is not systematic, no status codes, no categorization (retryable vs user-fixable), and no consistent error structure. A malformed NIF or invalid date range would silently fail or throw an unhandled exception.
Parameters accept enum-like values but are not formally constrained. E.g., 'provinces' description says 'BORME province names, accent-insensitive (MADRID, CADIZ...)', which provides examples but not an enum. 'act_types' references list_act_types but does not enforce the constraint. An LLM could pass 'MADRID ' (with whitespace) or 'ACME_INVALID' without validation feedback.
No pagination metadata in responses. search_events accepts a limit parameter but does not return a next_cursor, total count (only 'count' of returned items), or indication whether more results exist. An agent cannot know if it has fetched all matching events or should paginate. Baseline: tools returning lists should include pagination indicators.
Tool annotations (readOnlyHint, destructiveHint, idempotentHint) are not present in the FastMCP definitions. All tools are marked READ_ONLY in metadata, but this is not reflected in tool registration. Modern MCP servers should declare tool properties via annotations for proper agent planning.