agentic-firmenbuch
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@agentic-firmenbuchFind active GmbHs in Vienna with revenue over 1 million."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
agentic-firmenbuch
Austria's entire company register, queryable by AI agents in plain language. Official master data, annual accounts and key ratios for every firm – served over MCP, answered on real numbers instead of hallucinations.
Try the playground · Get a free key · Quickstart ↓
A live, automated data product over the Austrian Firmenbuch (free EU HVD / High Value Datasets), served through a multi-tenant MCP server. A deterministic Azure pipeline pulls the published Jahresabschluss (annual financial statement) filings from the official register, parses them, consolidates per company, computes ratios/growth/trends, and serves the result to MCP clients. The whole register holds ~640k legal entities; the served slice is currently ~341k and grows as the backfill progresses. Version 1 = facts + clean derivations only (no scoring, no third-party enrichment, no NACE, no AI summaries).
Also available: Germany and the wider DACH region. Alongside this Austrian product, a unified
agentic-registerendpoint serves both the Austrian Firmenbuch and the German Handelsregister / Unternehmensregister over a single MCP. It is listed in the official MCP registry asio.github.jkbngb/handelsregister(spec:handelsregister.server.json) and reachable athttps://register.agentic-firmenbuch.at/mcpwith the same free API key. A search returns matches from both countries, tagged bycountry(AT/DE).
Quickstart
Use the hosted service – query official Firmenbuch data from an MCP client that accepts an HTTP header key (Claude Code, VS Code with GitHub Copilot, Cursor, …):
Get a free API key at agentic-firmenbuch.at – just a verified email.
Add the server. Claude Code (terminal), one line:
claude mcp add --scope user --transport http agentic-firmenbuch https://mcp.agentic-firmenbuch.at/mcp --header "X-API-Key: <your-key>"GitHub Copilot / VS Code:
code --add-mcp "{\"name\":\"agentic-firmenbuch\",\"type\":\"http\",\"url\":\"https://mcp.agentic-firmenbuch.at/mcp\",\"headers\":{\"X-API-Key\":\"<your-key>\"}}". Any other HTTP-MCP-Header client: URLhttps://mcp.agentic-firmenbuch.at/mcp, headerX-API-Key: <your-key>.Ask in natural language, e.g. "Aktive GmbHs in Oberösterreich mit Bilanzsumme über 5 Mio. €, sortiert nach Umsatz." The agent calls
search_companies/get_company_detailsand answers with official data – no SDK required.
Claude Cowork & claude.ai (sandboxed clients) don't take the API-key header – they connect via
Settings → Connectors → Add custom connectorwith the URLhttps://mcp.agentic-firmenbuch.at/mcpand a one-time email login (OAuth, no key). Step-by-step with screenshots: agentic-firmenbuch.at/cowork.html.
Prefer to try before signing up? Use the playground.
Or run the pipeline yourself – clone, uv sync, uv run pytest (offline, no Azure). See Develop.
Related MCP server: companylens-mcp
Available MCP tools
Tool | Purpose |
| Filter / rank Austrian companies by region, size, balance-sheet total, equity ratio, revenue, growth profile, management age, last filing year, status. Returns a compact result card per match. |
| Full served profile of one company: identity, location, founding/filing years, size class, multi-year balance sheet + P&L, 13 computed ratios, growth, management, list of filings. |
| Superset of |
| Filing-by-filing time series of every reported position for one company. |
| K-nearest peer set for a company within its size class / region. |
| Aggregate statistics (counts, percentiles, distributions) for a filtered cohort. |
| Per-Bundesland / per-Rechtsform / per-size-class coverage statistics for the served dataset. |
| Available legal-form ( |
| Self-describing field dictionary with type + null-rules + EBIT/EBITDA definition. |
| Fetch the URL/blob key for an original filed annual statement (XML or PDF). |
All tools return a processed derivative of official Austrian Firmenbuch data (source: BMJ – Justiz, CC BY 4.0). Concretely: we ingest the published filings from the register, parse and consolidate them, compute ratios, and serve that from our own database — no web scraping, no LLM-generated summaries, no third-party data mixed in (V1). Every response carries provenance.data_version + built_at and names the original source, so the agent can attribute it correctly; for the authoritative record, the official Firmenbuch always governs.
Currently served: ~341,000 active legal entities across all Rechtsformen (GmbH, AG, KG, OG, EU, Genossenschaft, Privatstiftung, SE …). The full register has ~640,000 entities; the gap is companies without a published Jahresabschluss plus inactive/deleted entries, which are added step by step.
Documentation
Full index with the versioning convention (shipped _v1 specs vs. the forward
ROADMAP.md + V2 design spec): docs/README.md.
The headline documents:
Doc | What it is |
File format + golden sample for every pipeline stage. | |
Served field dictionary – every field each MCP tool returns, with type + null rules. Public page: felder.html. | |
Forward plan – status/priorities and the V2 direction (banks/insurers, GISA, Ediktsdatei). | |
Full 317-entry canonical position taxonomy → copied into | |
Official source material (API reference, JAb 4.0 XSDs/Excel). |
Monorepo layout (agentic-first)
This repository is the agentic-first monorepo umbrella. It separates source-agnostic
shared code from per-source products, so another source-specific product can be added without
touching the Austrian pipeline:
agentic-first/ (this repo)
├── packages/ SHARED — source-agnostic, zero Firmenbuch/UGB knowledge
│ ├── core/ (fbl_core) lineage/meta + metric contracts, config, storage clients
│ └── auth/ (fbl_auth) signup, token issue/validate, metering, 00_accounts
└── products/
└── agentic-firmenbuch/ AUSTRIA product (live) — README below
├── packages/
│ ├── core_at/ (fbl_core_at) UGB taxonomy, Firmenbuch domain models, ÖNACE, FI dirs
│ ├── firmenbuch_client, 99_registry, 90_ingest, 70_parse,
│ │ 50_consolidate, 30_derive, 10_present, mcp_server, orchestration
│ └── …
└── tests/ AT integration tests + golden fixturesAdditional source-specific products are added in their own separate repositories that consume
packages/{core,auth} as a dependency (they are not scaffolded here). The precise
1:1 / adapt / product-local reuse boundary is the reuse table (Appendix R) of the technical spec, and the generic recipe is in
docs/monorepo/ADDING_A_PRODUCT.md.
Product READMEs: agentic-firmenbuch · shared core · auth
Pipeline (numbered layers, 90 → 10)
99_registry (foundation: all companies) → 90_raw (Blob) → 70_parsed (Blob) → 50_consolidated → 30_derived → 10_presentation → MCP
(Cosmos) (Cosmos) (Cosmos)
side: 00_accounts (MCP signup) · 00_directories (register-based FI flag, OeNB) reserved for v2: 40_enriched, 20_scored90_raw is the immutable source of truth (every downloaded XML/PDF, kept forever). 70_parsed
is a write-through cache of the per-filing ParsedFiling JSON – always re-derivable from raw,
so safe to drop/rebuild; it exists so a reprocess (re-consolidate/derive after a logic change)
skips re-parsing all filings, and so the lineage inputs[] in each consolidated doc resolve to a
real parsed document. 50/30/10 are the queryable Cosmos layers; 10_presentation is what the MCP
serves.
LAYER_MAP – which code owns which layer
Each pipeline-stage package directory is prefixed with its layer number so the
owner of every data layer is obvious. (Python module names can't start with a digit, so
the importable package keeps its fbl_* name; the number is also exposed as a LAYER
constant in each stage package.)
All AT stage packages live under products/agentic-firmenbuch/packages/ (abbreviated …/ below).
Layer | Package (dir) | import | Store / container | Pydantic model | Sample |
|
| Cosmos |
| §15a.0 doc | |
|
| Blob | raw | ||
|
| Blob |
| ||
|
| Cosmos |
| ||
|
| Cosmos |
| ||
|
| Cosmos |
|
Un-numbered. Shared (in packages/): core (fbl_core,
source-agnostic lineage/meta + metric contracts, config, storage) and
auth (fbl_auth, 00_accounts). AT-specific (in
products/agentic-firmenbuch/packages/): core_at
(fbl_core_at, UGB taxonomy + Firmenbuch domain models + ÖNACE + FI directories),
firmenbuch_client
(fbl_firmenbuch_client, HVD SOAP adapter),
orchestration
(fbl_orchestration, the --mode Job entrypoint),
mcp_server
(fbl_mcp_server, serving). Plus products/agentic-firmenbuch/tests/ (fixtures),
docs/ (incl. API probe findings).
Build status – Version 1 complete ✅
All ten §15 build stages are implemented, each committed in order, each with a passing
Definition of Done. ruff + mypy --strict + pytest (with an 80% coverage gate) are
green in CI. The HVD API was live-probed (§16 resolved) and the full chain
raw→present was verified on live data end-to-end.
Stage 10: an auth-restricted coverage tool (XML vs PDF-only vs none, by format/status – §11) and GitHub Actions CI (
uv sync→ ruff → ruff format →mypy --strict→ pytest with an 80% coverage gate, plus a Bicep-compile job).
What's left to operate (not code): provision Azure (infra/setup.sh, billable),
push the FIRMENBUCH_API_KEY to Key Vault, build/push images, then run the Initial Load
(sync-registry → backfill-ingest → backfill-process) and enable the daily cron.
Develop
uv sync # create the workspace venv
uv run pytest # all fixture/unit/integration tests (offline)
uv run mypy packages products # strict types (shared + products)
uv run ruff check packages products # lintTrue end-to-end (live): a separate, env-flag-guarded test runs a few real FNRs
through every layer (API → 90_raw → … → 10_presentation → MCP). Skipped by default.
FBL_E2E=1 uv run pytest products/agentic-firmenbuch/tests/e2e -q # needs FIRMENBUCH_API_KEYSee products/agentic-firmenbuch/tests/e2e/. It uses in-memory stores + a tiny real pull –
no Azure, no full backfill (deployment is manual after review).
License & data
Licensed under the MIT License (see LICENSE).
The data originates from the Austrian Firmenbuch (BMJ – Justiz), an EU High Value Dataset
licensed under CC BY 4.0. Any redistribution of the data must keep the attribution
"Quelle: Österreichisches Firmenbuch / BMJ – Justiz (CC BY 4.0)" (see NOTICE).
Disclaimer – no warranty, use at your own risk
This software and any data it produces are provided "AS IS", WITHOUT WARRANTY OF ANY KIND, express or implied (see the MIT License). The processed data is derived automatically from the public Firmenbuch and is provided without any guarantee of correctness, completeness, timeliness, or fitness for a particular purpose. It is not legal, tax, or financial advice and does not replace an official Firmenbuch extract – the official register always prevails.
Use of this software and the data is entirely at your own risk. To the maximum extent permitted by law, the authors and copyright holders accept no liability for any direct, indirect, incidental, or consequential damages arising from its use. You are responsible for complying with the CC BY 4.0 attribution requirement and all applicable data-protection, competition, and copyright law when using or redistributing the data.
Available Tools
18 toolsbenchmark_companyBenchmark a company vs peersARead-onlyIdempotentInspect
Where one company stands in its peer group — a composite over find_peers + the company's precomputed size-peer percentiles. Read-only. Pro.
Parameters:
- fnr (required): the company's Firmenbuchnummer, e.g. "123456a" (an "AT:" prefix is
tolerated).
- n (optional, default 10, clamped 1..50): how many peers to include.
Returns the company's headline metrics (bilanzsumme, revenue, equity_ratio, growth_profile),
its `percentiles` WITHIN its UGB size class (100 = top of the class; available for
bilanzsumme and equity_ratio), and the nearest peers (same size class, same ÖNACE section
preferred, recent filers only: last Jahresabschluss within 3 years, widened once to 5 when
too few exist, see `peer_recency` + `peers_note`; each peer carries `latest_year`). Use for
"how does X compare to its peers"; for the raw peer list use find_peers, for whole-cohort
aggregates use get_cohort_summary.
| Name | Required | Description | Default |
|---|---|---|---|
| n | No | ||
| fnr | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive), and the description layers on genuinely non-obvious behavior: 'Pro' tier gating, percentile semantics (100 = top of class, only for bilanzsumme and equity_ratio), and the peer recency rule including the 3→5 year widening and where it surfaces (peer_recency/peers_note). That is real disclosure beyond the structured fields.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the one-line purpose, then a compact Parameters block and a returns paragraph with a routing sentence at the end. Slightly dense in the returns section, but every clause carries information an agent needs to interpret percentiles and peer recency.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, yet the description still names the headline metrics and the percentiles/peers shape, and documents the Austrian-domain constraints (UGB size class, ÖNACE section, recent filers). For a two-parameter composite tool this is more than sufficient.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description carries the full burden and does: fnr format with example and the tolerated 'AT:' prefix, plus n's default (10) and clamp range (1..50). Nothing about either parameter is left ambiguous.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Where one company stands in its peer group') and defines the composite method (find_peers + precomputed size-peer percentiles). The sibling set is named explicitly, so an agent can separate it from find_peers and get_cohort_summary 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.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit triggering phrase ('Use for "how does X compare to its peers"') and names both alternatives with their selecting conditions: find_peers for the raw peer list, get_cohort_summary for whole-cohort aggregates.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
describe_fieldsDescribe available fieldsARead-onlyIdempotentInspect
Catalog of every field the server can return, by tool tier (search card -> full profile -> full record), with code tables and availability/null rules. Read-only, no parameters.
This describes the SCHEMA only (field names, types, code tables, null rules) so you can
pick the right tool and interpret its output. It returns no company data itself; for that
call search_companies (many) or get_company_details / get_full_record (one). Call this
once up front when unsure what a field means or which tool to use.
Human-readable version: https://www.agentic-firmenbuch.at/felder.html| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, so safety is covered; the description nonetheless adds the meaningful fact that the tool returns schema metadata only and no company data, plus the tier structure (search card -> full profile -> full record). It does not discuss any rate limits or output structure beyond that, but with strong annotation coverage this is solid added context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose and the schema-only constraint are front-loaded, and the alternative-routing sentence earns its place. The trailing documentation URL and the restated 'describes the SCHEMA only' phrasing add minor redundancy, keeping it just short of ideal.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a parameterless, read-only catalog tool with an output schema present, the description covers everything an agent needs: what it returns (field names, types, code tables, null rules), what it does not return, when to call it, and where to get real data instead. Return-value explanation is correctly deferred to the output schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Zero parameters, so the baseline is 4; the description explicitly confirms 'no parameters', which matches the empty schema and leaves no ambiguity about invocation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Catalog of every field the server can return') and immediately scopes it as schema-only with no company data, which cleanly separates it from the data-returning siblings it names (search_companies, get_company_details, get_full_record). An agent can distinguish it from all 17 siblings 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.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit trigger ('Call this once up front when unsure what a field means or which tool to use') and routes the agent to the correct alternatives for actual data, distinguishing the many-result tool from the single-result tools. When-not is implied by 'it returns no company data itself', which is sufficient to prevent misuse.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
export_companies_csvExport companies to CSVARead-onlyInspect
Export a whole search result set as ONE downloadable CSV file (a lead list) instead of paging through search_companies 25 rows at a time. Read-only over company data; each call writes a new short-lived export file (auto-deleted after ~1 day).
Use this when the user wants a list to open in Excel / import elsewhere ("exportiere",
"als CSV/Liste", "alle GmbHs in … herunterladen"). For browsing or ranking on screen use
search_companies; for one company's full profile use get_company_details.
Parameters:
- filters (optional): a SearchFilters object — EXACTLY the same filters as search_companies
(name; legal_form; bundesland/city/postal_code; near radius; oenace_division/group /
geschaeftszweig; size_gkl; bilanzsumme / revenue / equity_ratio / employees ranges
(equity_ratio as a fraction, 0.35 = 35 %; percent values auto-converted);
growth_profile; founded/last-filing years; gf_age_min; manager_name; status). AND-joined.
- sort (optional): {field, descending}, same fields as search_companies (default bilanzsumme
descending; "distance" with a near filter).
- max_rows (optional, default 1000, hard maximum 10000): row ceiling. Free plan is capped at
100 rows with basic columns only. For a set larger than 10000, refine the filters
(Bundesland/Branche/Größe) and export in parts.
CSV format: semicolon-separated, UTF-8 with BOM (opens cleanly in Excel-DE, umlauts intact).
Columns are exactly the search card fields: fnr, name, legal_form, street, postal_code,
city, bundesland, industry_section, oenace_division(+label), geschaeftszweig, size_gkl,
bilanzsumme_latest, equity_ratio_latest, revenue_latest, growth_profile, manager_name, and
distance_km when a near filter is used. Empty values are blank cells. No fields beyond the
card — the same personal-data gating applies.
Returns {rows, download_url, expires_minutes (60), columns, truncated, note}. The
download_url is a signed link valid for 60 minutes (3600 s; exact expiry in
`download.expires_at` — open it promptly, don't expect bytes inline); the underlying
file is deleted after about one day. When the result was capped (truncated=true), the
note says so and asks you to refine.
Field reference: https://www.agentic-firmenbuch.at/felder.html
| Name | Required | Description | Default |
|---|---|---|---|
| sort | No | ||
| filters | No | ||
| max_rows | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover the safety profile (readOnlyHint=true, destructiveHint=false), but the description adds substantial context beyond them: each call creates a new short-lived export file auto-deleted after ~1 day, the download_url is a signed link valid 60 minutes (with exact expiry in download.expires_at), bytes are not returned inline, the free plan is capped at 100 rows with basic columns, and truncated=true signals a capped result. It also reconciles the read-only hint with the file-writing side effect ("Read-only over company data; each call writes a new short-lived export file"), which is exactly the nuance idempotentHint=false implies.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Despite its length, the text is front-loaded (purpose and side effects first, then usage, parameters, CSV format, returns) and every block earns its place given the 0% schema coverage and the non-obvious signed-URL/expiry behavior. No filler or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Complete for a complex export tool: it documents filters, sort, row limits, plan caps, CSV encoding/columns, truncation behavior, and the download-link lifecycle, even though an output schema exists. It also notes the personal-data gating and provides a field-reference URL, leaving no material gap for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Top-level schema description coverage is 0%, so the description carries the full burden and does: filters is documented as an AND-joined SearchFilters with the same semantics as search_companies (including the equity_ratio-as-fraction rule and auto-conversion of percent values), sort is described with its default (bilanzsumme descending) and the "distance" option, and max_rows is given its default 1000, hard maximum 10000, and the free-plan 100-row cap. This adds meaning well beyond the bare object schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource+scope: exporting a whole search result set as ONE downloadable CSV instead of paging through search_companies. It explicitly contrasts itself with two named siblings (search_companies for browsing, get_company_details for a profile), so an agent can disambiguate without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use triggers, including multilingual user phrasings ("exportiere", "als CSV/Liste", "alle GmbHs in … herunterladen"), plus when-not: use search_companies for on-screen browsing/ranking, get_company_details for a single profile. Also states the workaround when the set exceeds 10,000 rows (refine filters and export in parts).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
find_peersFind peer companiesARead-onlyIdempotentInspect
Find the companies most similar in size to a given one. Read-only.
Parameters:
- fnr (required): the reference company's Firmenbuchnummer, e.g. "123456a".
- n (optional, default 10, clamped to 1..50): how many peers to return.
Returns up to `n` companies in the SAME size class (`gkl`) as the reference, preferring
the same ÖNACE industry as SPECIFICALLY as possible: the cascade class -> group ->
division -> section widens only when a level has too few companies, and any remaining
slots are filled with the nearest same-size companies from other industries — closest by
Bilanzsumme within the class and group levels; on broader levels a reference with a
registered activity text gets the most similar activities first. Each is a compact card
like search_companies. The response
carries `same_sector_level` ("class"/"group"/"division"/"section"/null: how specific the
industry match is), `same_sector_count`, and an explicit `note` when the match is only
section-wide or the list is (partly) a pure size-neighbourhood — so you never mistake
same-size-different-industry rows for a sector benchmark (e.g. holdings whose stated
industry differs from the group's). The reference company is excluded; an empty list means
the FNR is unknown or has no Bilanzsumme to rank against. Recency: only companies whose
last Jahresabschluss is from the current year minus 3 or later qualify; when fewer than
`n` class/group-level peers exist in that window it widens once to minus 5 and the `note`
says so (`peer_recency` = {years, min_year, widened}); every peer row carries
`latest_year`. For a strict industry benchmark, filter search_companies by oenace_* + size
instead; for group aggregates use get_cohort_summary.
| Name | Required | Description | Default |
|---|---|---|---|
| n | No | ||
| fnr | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only/idempotent, and the description adds substantial behavior beyond them: the sector cascade (class->group->division->section), the size-neighbour fallback, recency window (current year minus 3, widening once to minus 5), exclusion of the reference company, and the same_sector_level/note signals that guard against misreading rows as benchmarks.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well front-loaded (purpose, then parameters, then the long return/cascade explanation), but the returns paragraph is a dense run-on covering cascade, tie-breaking, recency, and note semantics in one block. Every sentence is informative, though it could be split for scanability.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with non-obvious matching logic, the description covers selection cascade, tie-breaking rules, recency widening, reference exclusion, and the caveat fields (same_sector_level, peer_recency, note). With an output schema present, it appropriately stops short of re-listing raw field types.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description carries the full burden and does: it explains fnr as the reference Firmenbuchnummer with a concrete format example ('123456a') and defines n's default (10) and clamp (1..50). Both parameters gain meaning unavailable in the bare schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
First sentence gives a precise verb+resource+scope: find companies most similar in size to a reference company. It is clearly distinguishable from siblings, and the closing sentences explicitly name search_companies and get_cohort_summary as the tools for different jobs.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes the agent: use find_peers for size-based peer discovery, search_companies with oenace_* + size for a strict industry benchmark, and get_cohort_summary for group aggregates. It also states the meaning of an empty result, which removes a common ambiguity.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_cohort_summaryCohort statisticsARead-onlyIdempotentInspect
Aggregate statistics for a cohort of companies. Read-only.
Parameters:
- dimension (required): which axis defines the cohort, one of "gkl" (size class),
"bundesland" (federal state), or "legal_form" (Rechtsform). The search-filter alias
"size_gkl" is accepted for "gkl".
- value (required): the cohort value on that axis, e.g. dimension="bundesland",
value="Wien" (full name or the code "W" both work); dimension="gkl", value="M".
Use list_sectors to see valid legal_form / gkl values.
Returns cohort counts plus distribution statistics (e.g. Bilanzsumme median; the exact
median is skipped for very large cohorts to keep the request fast), NOT per-company rows.
Use for "what does group X look like in aggregate"; for the individual companies use
search_companies, for one company use get_company_details.
| Name | Required | Description | Default |
|---|---|---|---|
| value | Yes | ||
| dimension | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds real context beyond the annotations (which already assert read-only, idempotent, non-destructive): it discloses the large-cohort median skip ('the exact median is skipped for very large cohorts to keep the request fast') and clarifies the return is aggregate stats, not rows. This is a meaningful behavioral disclosure not present in the structured fields.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads purpose, then parameter documentation, then routing guidance. The parameter list is necessarily detailed given 0% schema coverage, but the prose is tight and every sentence carries information. Could be marginally shorter but nothing is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With annotations, a 0% schema, and an output schema already present, the description supplies the only missing pieces: dimension/value semantics and routing. It even notes a behavioral caveat about large cohorts. An agent has everything needed to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must carry the full burden, and it does: it defines the 'dimension' axis with all valid values ('gkl', 'bundesland', 'legal_form' and the 'size_gkl' alias), explains 'value' semantics with examples and accepted forms (code 'W' or full name 'Wien'), and points to list_sectors for valid legal_form/gkl values.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a precise verb and resource ('Aggregate statistics for a cohort of companies') and immediately sets scope with 'NOT per-company rows'. It names the alternative siblings (search_companies, get_company_details) in context, so it is clearly distinguishable from them.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says when to use it ('what does group X look like in aggregate') and when to use alternatives ('for the individual companies use search_companies, for one company use get_company_details'), naming both siblings. It also points to list_sectors for valid values.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_company_detailsCompany profileARead-onlyIdempotentInspect
Full served profile for one company by FNR. Read-only.
Parameters:
- fnr (required): Firmenbuchnummer, e.g. "123456a" (the `fnr` from a search card).
- include (optional): which optional sections to serve, subset of
["bilanz", "guv", "ratios", "management", "events", "industry"]; omit for ALL sections
(the full profile). Identity, location, company, size, filings and the financials
scalars (latest values) are always included. Use this to keep the response small when
you only need part of the profile.
- history (optional, default true): false drops the per-metric year series (the latest
values stay) — use get_company_history when you later need a specific trend.
Null fields are omitted from the response (a missing key means "no data for this
company"; describe_fields documents every field that CAN exist). Returns one company's
identity, location, financials (per-year Bilanz + GuV), all computed ratios, growth,
employees, filings, and management. Use when you already know the company
(from search_companies); for the complete record (full position taxonomy, unknown-code
passthrough, per-year lineage) use get_full_record; for specific metric trends use
get_company_history.
Field reference: https://www.agentic-firmenbuch.at/felder.html
| Name | Required | Description | Default |
|---|---|---|---|
| fnr | Yes | ||
| history | No | ||
| include | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish read-only, idempotent, non-destructive behavior (the opening 'Read-only' merely repeats that). The description adds genuinely new traits: null fields are omitted so a missing key means no data, always-included sections, and that history=false drops year series while keeping latest values. Only the return format and size expectations are left thin, which the output schema likely covers.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the identity and read-only statement, then a clean parameter list, then routing guidance. Slightly verbose: the closing sentence re-enumerates the returned sections already listed in the include description ('Identity, location, company, size, filings...'), which is mild redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a three-parameter read with annotations and an output schema, this is complete: it covers routing, parameter semantics, null-omission behavior, and even links a field reference for field-level detail. No output-shape explanation is needed given the output schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must carry all parameter meaning, and it does: fnr format with a concrete example and provenance ('from a search card'), the exact include subset with omit-means-all semantics and its purpose, and history's default plus the effect of setting it false. Nothing about the three parameters is left ambiguous.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Full served profile for one company by FNR') plus the read-only nature and the lookup key. It explicitly names what it is not (get_full_record for the complete record, get_company_history for trends), so an agent can distinguish it from siblings 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.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use ('when you already know the company, from search_companies') and names two alternative tools with the precise conditions that select them. The include/history guidance adds tactical advice on when to trim the response.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_company_historyCompany financial historyARead-onlyIdempotentInspect
Per-metric multi-year time series for one company — or a whole cohort. Read-only.
Parameters:
- fnr: Firmenbuchnummer, e.g. "123456a" (the `fnr` from a search card) — one company.
- fnrs: list of up to 50 Firmenbuchnummern for a BATCH in one call (a Branchenradar
over a 30-200 cohort pages through this instead of one call per company). Unknown
numbers land in `result.not_found`; billing stays per company (1 credit each),
only companies actually returned are charged. Pass fnr OR fnrs.
- metrics (optional): list of metric names to return, e.g.
["bilanzsumme", "umsatzerloese", "eigenkapital"]; omit to get every available series.
The card alias "revenue" is accepted for "umsatzerloese".
Returns, per requested metric, the yearly values (year -> value) plus latest/latest_year
(batch: the same shape per company under `result.companies`). Use when you need the
trend of specific figures; for a full one-shot profile use get_company_details, for
the complete record (all positions) use get_full_record.
| Name | Required | Description | Default |
|---|---|---|---|
| fnr | No | ||
| fnrs | No | ||
| metrics | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the read-only/idempotent profile, but the description adds genuinely non-obvious behavior: unknown fnrs land in result.not_found, billing is 1 credit per company and only returned companies are charged, and batches cap at 50. This is exactly the operational context annotations cannot express.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded one-line summary, then a clean per-parameter block, then return shape. Dense but every sentence carries load — no filler or restatement of the tool name.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, yet the description still sketches the return shape (year -> value, latest/latest_year, batch nesting under result.companies), which resolves the ambiguity between the two invocation modes. Nothing needed to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must carry the load and does: fnr format example and provenance ('the fnr from a search card'), fnrs batch limit and mutual exclusion ('Pass fnr OR fnrs'), and metrics semantics including the 'revenue' -> 'umsatzerloese' alias and the omit-to-get-all default.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource with scope: 'Per-metric multi-year time series for one company — or a whole cohort.' It distinguishes the single-vs-batch modes and explicitly names the sibling tools it is not (get_company_details, get_full_record).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit routing: 'Use when you need the trend of specific figures; for a full one-shot profile use get_company_details, for the complete record (all positions) use get_full_record.' It also names the concrete cohort scenario (Branchenradar over 30-200 company pages) that selects the batch path.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_coverageDataset coverageARead-onlyIdempotentInspect
How much of the register we actually serve, as an aggregate dashboard. Read-only, no parameters.
Returns coverage counts broken down by data availability — companies with parsed XML
financials vs PDF-only (linked but not machine-readable) vs none — and by format/status, so
you can gauge what share of the universe has usable financials. It is a dataset-wide
overview (served O(1) from a precomputed stats doc), NOT per-company data, no filters. Use
for "how complete is the data"; for the valid filter values use list_sectors, for one
group's aggregate figures use get_cohort_summary.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive/no-open-world, so safety is covered. The description adds real context beyond that: it is dataset-wide, not per-company, accepts no filters, and is served O(1) from a precomputed stats doc, plus it sketches the return breakdown (XML vs PDF-only vs none).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core purpose and then the return breakdown and routing, with each sentence carrying weight. Slightly verbose in places ('as an aggregate dashboard'), but no wasted filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Complete for a parameterless, read-only aggregate tool. An output schema exists so return values are covered, and the description still adds scope, performance, and routing context that fully equips an agent to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Zero parameters, which is the baseline-4 case. The description reinforces this with 'no parameters' and 'no filters', leaving no ambiguity that no arguments are accepted.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource: an aggregate, dataset-wide coverage dashboard showing how much of the register is served. It explicitly distinguishes itself from siblings (list_sectors, get_cohort_summary) and from per-company data, so an agent can identify it immediately.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit use case ('how complete is the data') and names two alternatives with the conditions that select them: list_sectors for valid filter values, get_cohort_summary for one group's aggregate figures. Nothing 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.
get_documentDownload annual filingARead-onlyIdempotentInspect
Get a time-limited download link to a company's official Jahresabschluss document. Read-only.
Parameter:
- doc_key (required): a filing's `document_ref` ("{fnr}:{stichtag}") from
get_company_details, a bare FNR (-> latest filing), or a legacy doc_key.
Returns `download.url`, a signed link valid for 15 minutes (900 s; the exact expiry is
`download.expires_at` / `expires_in_seconds` in the response — open it promptly, don't
expect bytes inline), plus the `financial_institution` flag + caveat for banks/insurers,
whose figures live only in the PDF. If the PDF is not in the archive yet it is fetched
on demand from the register (the first call for a year can take up to ~1 minute);
`download` is null only when the register itself holds no document for that filing. Use to
fetch the original filing artifact; for the already-parsed figures use
get_company_details / get_full_record instead of downloading.| Name | Required | Description | Default |
|---|---|---|---|
| doc_key | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Read-only is already in annotations, but the description adds real behavioral context the annotations don't: 15-minute (900 s) signed-link expiry, the ~1 minute on-demand fetch from the register for the first call of a year, the financial_institution flag/caveat for banks and insurers, and the precise condition under which download is null (register holds no document).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the action, then parameter, then return semantics; nearly every sentence earns its place. It does re-enumerate output field names (download.url, expires_at, expires_in_seconds) that the output schema already carries, which is mild redundancy, but the accompanying expiry/latency semantics justify it.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given a one-parameter tool with an output schema and full annotations, the description supplies everything an agent needs: key format, the expiry window, the latency and null cases, the bank/insurer caveat, and the alternative tools. Nothing material is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0% and the single parameter is undocumented in the schema, so the description carries the full burden — and does: doc_key accepts a document_ref formatted '{fnr}:{stichtag}' from get_company_details, a bare FNR (meaning latest filing), or a legacy doc_key. That is exactly the syntax an agent needs.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence states a precise verb+resource+output: it returns a time-limited download link to a company's official Jahresabschluss. It also draws the line against get_company_details / get_full_record for already-parsed figures, so an agent can separate it from the parsing siblings without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit routing: 'Use to fetch the original filing artifact; for the already-parsed figures use get_company_details / get_full_record instead of downloading.' Plus an operational warning to open the link promptly rather than expect inline bytes. Clear when-to-use and named alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_document_textRead annual filing textARead-onlyIdempotentInspect
Return the TEXT of a company's official Jahresabschluss filing so you can read the Anhang, Lagebericht and positions directly (XML filings are flattened to "label: value" lines, PDF filings are text-extracted). Read-only.
Parameters:
- doc_key (required): a filing's `document_ref` ("{fnr}:{stichtag}") from
list_documents / get_company_details, or a bare FNR (-> latest filing).
- max_chars (optional, default 40000, max 120000): cap on the returned text;
`truncated` tells you when the document is longer.
Use for questions about the wording of a filing ("Was steht im Lagebericht zum
Ausblick?", "Welche Risiken nennt der Anhang?"). For the parsed figures use
get_company_details; for a download link use get_document. Cite the Stichtag.| Name | Required | Description | Default |
|---|---|---|---|
| doc_key | Yes | ||
| max_chars | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, destructiveHint=false and openWorldHint=false, so safety and idempotency are covered. The description adds genuinely useful format behavior — XML flattened to 'label: value' lines, PDF text-extracted — plus the `truncated` signal. It stops short of permission requirements or error behavior, so a 3 is appropriate for annotations-covered read tools.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded purpose sentence, then compact parameter block, then usage-and-alternatives block. Every sentence earns its place; the example questions clarify intent rather than pad.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return structure need not be explained, and the description still flags the `truncated` field. Combined with thorough parameter documentation and sibling routing, nothing an agent needs to invoke this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description carries full burden and does so well: doc_key format ('{fnr}:{stichtag}'), its source tools, and the bare-FNR fallback to the latest filing are all specified. max_chars documents default 40000, max 120000, and the linked `truncated` flag.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Return the TEXT of a company's official Jahresabschluss filing') and clarifies what content is exposed (Anhang, Lagebericht, positions). It explicitly distinguishes itself from get_company_details (parsed figures) and get_document (download link) without requiring schema inspection.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides an explicit when-to-use trigger with example questions ('Was steht im Lagebericht zum Ausblick?') and names the two alternatives with their differing conditions. An agent can route correctly between text reading, figures, and download.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_event_statsRegister change statisticsARead-onlyIdempotentInspect
Aggregate counts of register changes by type and by Bundesland over a window. Read-only. Pro. Use for market-watch dashboards ("how many capital increases in OÖ this month"); for the individual changes use list_events.
Parameters (all optional): since / until (default last 30 days); bundesland; oenace_section;
oenace_division; legal_form — same facets as list_events. Returns {since, until, total,
by_type, by_bundesland}. Forward-only from 2026-07-01.
| Name | Required | Description | Default |
|---|---|---|---|
| since | No | ||
| until | No | ||
| bundesland | No | ||
| legal_form | No | ||
| oenace_section | No | ||
| oenace_division | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover readOnly, idempotent, non-destructive, so safety is handled. The description adds useful traits beyond structured data: the 30-day default window and the 'Forward-only from 2026-07-01' coverage constraint, which materially affects whether results are trustworthy for older periods. Minor gap in not explaining aggregation semantics or pagination, but the coverage boundary is the important disclosure.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core purpose in the first sentence, then usage, then parameters and return shape. Every block earns its place, though the fragmentary 'Read-only. Pro.' and mixed paragraph/list formatting read slightly unpolished.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a six-parameter, all-optional aggregation tool with an output schema, the description supplies purpose, alternative routing, parameter defaults, and the coverage window. Nothing essential to calling it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate, and it mostly does: it labels all six parameters, marks them optional, gives the since/until default, and notes the facet parameters match list_events. It stops short of giving accepted formats or example values for since/until or coded values for oenace/legal_form.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Aggregate counts of register changes by type and by Bundesland over a window') and explicitly distinguishes itself from the sibling list_events, which handles individual changes. An agent can select 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.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit use case ('market-watch dashboards') with a concrete example and names the alternative tool plus the condition that selects it ('for the individual changes use list_events'). This is textbook when/when-not guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_full_recordFull company recordARead-onlyIdempotentInspect
Complete per-company record, the full superset we hold for one company. Read-only.
Parameter:
- fnr (required): Firmenbuchnummer, e.g. "123456a" (the `fnr` from a search card).
Returns everything: every position's full per-year history, unknown-code passthrough
(nothing dropped), completeness flags, guv_years, and lineage (§5.1). This is the heaviest
read. Use it when you need raw completeness; for the normal curated profile use
get_company_details, for a single metric's trend use get_company_history.
| Name | Required | Description | Default |
|---|---|---|---|
| fnr | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover read-only/idempotent/destructive=false, so the safety profile is handled. The description adds genuine behavioral context beyond that: it is 'the heaviest read', it passes through unknown codes ('nothing dropped'), and it includes completeness flags, guv_years and lineage. It does not mention rate limits or result size/pagination.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the identity of the tool, then the parameter, then the return contents and routing. Every sentence earns its place; no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter read tool with an output schema present, the description supplies everything needed: what it does, the parameter's meaning/format, what comes back at a high level, and when to prefer siblings. Nothing material is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description carries the burden. It explains that fnr is the Firmenbuchnummer, gives a concrete format example ('123456a'), and tells the agent its source (the fnr from a search card). That is meaningful added semantics for the single required parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource: 'Complete per-company record, the full superset we hold for one company.' It defines the scope (everything for one company) and explicitly distinguishes itself from get_company_details and get_company_history by naming both siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit routing: 'Use it when you need raw completeness; for the normal curated profile use get_company_details, for a single metric's trend use get_company_history.' Both alternatives and their selecting conditions are named.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_my_usageMy API usageARead-onlyIdempotentInspect
Your own API-key usage: call count and weighted compute-units, per tool. Read-only.
Parameter:
- window (optional, default "today"): one of "today", "yesterday", "month_to_date",
"last_30_days", "all".
Returns only the calling key's own usage (totals + per-tool breakdown) for that window,
plus `plan` (the plan in force). Credit-metered accounts additionally get `credits_used`
(credits charged in the window), `credits_remaining` (current balance) and the `credits`
block with per-lot detail — for them, Credits are the billing unit (calls/compute_units
are internal telemetry; failed attempts cost 0). Free-plan keys use this to check their
consumption against the monthly free quotas. Never another user's data and never the
e-mail behind the key.| Name | Required | Description | Default |
|---|---|---|---|
| window | No | today |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only/idempotent/non-destructive, yet the description adds substantial behavior beyond them: failed attempts cost 0, credits are the billing unit for metered accounts while calls/compute_units are internal telemetry, and the response never leaks another user's data or the e-mail behind the key.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core purpose and scope in the first sentence, with the parameter and return details following. Some return-field detail is verbose given an output schema exists, but it is organized and each sentence carries information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single optional parameter read-only tool with an output schema, the description supplies the enum values, default, scope guarantees, and billing semantics. Nothing needed to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0% and the enum list is absent from the schema, so the description fully compensates by enumerating all five allowed window values and restating the default 'today'. Without this text an agent could not know the valid inputs.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Your own API-key usage: call count and weighted compute-units, per tool') and explicitly frames the scope as the calling key only. This is trivially distinguishable from every sibling, which are all company/person/document tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives concrete usage context: free-plan keys use it to check consumption against monthly free quotas, and credit-metered accounts use it for balance/billing detail. It does not name explicit alternatives or when-not-to-use, but the sibling set makes mis-selection unlikely.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_documentsList company documentsARead-onlyIdempotentInspect
List a company's available official documents, newest first. Read-only, metadata only.
Parameter:
- fnr (required): Firmenbuchnummer, e.g. "123456a" (an "AT:" prefix is tolerated).
Returns ONE merged chronology, strictly newest-first: every entry is
{type, stichtag, financial_year, document_ref, format, parsed, note?}. Two types:
`annual_financial_statement` (a filed Jahresabschluss; `parsed=true` means figures are
served) and `abschluss_document_pdf` (an Abschluss-carrying PDF the register holds beyond
the plain filing — Konzernabschluss, HV-Protokoll m. Jahresabschluss, Lagebericht — with
its `dokumentart` label; always `parsed=false`). A Konzernabschluss next to the same
year's Jahresabschluss is a DIFFERENT document, not a duplicate. Years held only as PDF
appear with `parsed=false` + a `note` — no extracted figures, but the original stays
downloadable (an honest gap, never silent). Pass any entry's `document_ref`
("{fnr}:{stichtag}") to get_document for a signed download link. No download link and no
personal data here — use get_document for the file, get_company_details for the figures.
| Name | Required | Description | Default |
|---|---|---|---|
| fnr | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, and the description adds substantial behavior beyond that: strictly newest-first merged chronology, no download links, no personal data, the meaning of parsed=true/false, and that PDF-only years are surfaced honestly rather than silently dropped.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose, then parameter, then returns — a logical order with no filler sentences. It is dense however, and the detailed entry-shape enumeration partially duplicates what the output schema already provides, costing a little efficiency.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given a single required parameter, an output schema, and rich annotations, the description still covers the remaining ambiguities an agent needs: parameter format, ordering guarantee, type semantics, the document_ref handoff to get_document, and the honest-gap behavior.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0% and the single parameter would otherwise be opaque, but the description fully compensates: it names fnr as Firmenbuchnummer, gives a concrete example format ('123456a'), and states that an 'AT:' prefix is tolerated.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb + resource + ordering ('List a company's available official documents, newest first') with scope qualifiers ('read-only, metadata only'). It also implicitly distinguishes itself from get_document and get_company_details, which the description names explicitly later.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes the agent: this tool for the listing/metadata, get_document for download links, get_company_details for figures. It also tells when a year appears only as PDF and that this is an intentional gap rather than an error, and clarifies that a Konzernabschluss is not a duplicate of the year's Jahresabschluss.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_eventsRegister change feedARead-onlyIdempotentInspect
Cross-company feed of register CHANGES (Vollzuege), newest first — the market-watch / deal-sourcing surface. Read-only. Pro.
Answers "which companies changed X, where, since when" in one call — e.g. management
changes, capital increases, relocations across a region or industry, or a watchlist of FNs.
For the change history of ONE known company, use get_company_details (its `events[]`).
Parameters (all optional, AND-combined):
- types: DETAILED (with before/after values), forward from 2026-07-01: "name_change",
"seat_change", "legal_form_change", "capital_change", "management_change". COARSE
historical (type + date only, source=change_feed, back to ~2020): "founding", "deletion",
"merger",
"split", "conversion", "contribution", "consolidation", "division",
"shareholder_capital_change", "management_join", "management_leave". Omit for all. The
M&A/restructuring types (merger/split/conversion/…) + capital_change + deletion are the
deal- and distress-signal surface.
- since / until: ISO dates ("2024-01-01"). Default window: the last 30 days.
- bundesland: full name ("Wien") or code; oenace_section (letter) / oenace_division
(2-digit); legal_form ("GmbH" or a Firmenbuch code) — same facets as search_companies.
- fnrs: restrict to these Firmenbuchnummern (a watchlist).
- page (1), page_size (25, max 100).
Returns {total, page, page_size, since, until, events:[{fnr, name, date, type, description,
source, capital_from, capital_to, managers_added, managers_removed, bundesland,
industry_section}]}. `source` is "change_feed" for the coarse historical events (no
before/after values) vs the detailed daily-diff events. An empty result means no matching
change in the window (not missing data).
Field reference: https://www.agentic-firmenbuch.at/felder.html
| Name | Required | Description | Default |
|---|---|---|---|
| fnrs | No | ||
| page | No | ||
| since | No | ||
| types | No | ||
| until | No | ||
| page_size | No | ||
| bundesland | No | ||
| legal_form | No | ||
| oenace_section | No | ||
| oenace_division | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover safety (readOnly, idempotent, non-destructive), yet the description adds tier gating ('Pro'), data provenance semantics for `source` (change_feed coarse vs detailed daily-diff), the critical interpretation that an empty result means no matching change rather than missing data, and the default 30-day window. This is substantial context beyond the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose and the sibling alternative are front-loaded, and the parameter block is bulleted and scannable. It is long, but the length is largely justified by ten undocumented parameters; only the extended type enumeration feels slightly dense.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 10-param, no-required-field query tool with an output schema, the description covers scope, ordering, filtering, defaults, return shape, field semantics, and the empty-result edge case, plus a field reference link. Nothing an agent needs to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description carries the full burden and does so well: it enumerates the valid `types` values split by detailed vs coarse, explains their date coverage and source, documents date formats and defaults, facet formats for bundesland/oenace/legal_form, fnrs as a watchlist, and pagination defaults/limits. This fully compensates for the empty schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('cross-company feed of register CHANGES'), its ordering ('newest first'), and its intended use case ('market-watch / deal-sourcing surface'). It explicitly distinguishes itself from the sibling get_company_details by naming the single-company alternative, so an agent can route correctly 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.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use framing ('which companies changed X, where, since when'), concrete example queries, and an explicit when-not-to-use clause routing single-company history to get_company_details. Also flags the M&A/restructuring types as the deal/distress surface, which helps an agent pick the right filter.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_sectorsList sectors & legal formsARead-onlyIdempotentInspect
Valid filter values for search_companies, with company counts. Read-only.
Optional `query`: a German category word or phrase ("Brauereien", "Steuerberater",
"Softwarefirma") -> `matches` with the ÖNACE level, code, official label, an activity
concept and the search_companies filter to use (oenace_section/division/group). Use this
instead of guessing a code; a concept-only match means "use filters.query".
Returns the legal-form (Rechtsform) codes and the size-class (`gkl`: W/K/M/G) values
present in the served dataset, each with its count. Call this first to discover the real
`legal_form` / `size_gkl` values to pass to search_companies or get_cohort_summary, instead
of guessing codes. For region/format coverage instead, use get_coverage.
| Name | Required | Description | Default |
|---|---|---|---|
| query | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare readOnlyHint=true, idempotentHint=true, and openWorldHint=false. The description adds valuable behavioral context beyond these: it discloses return structure (matches with ONACE level, code, label, activity concept, filter), explains the concept-only match semantics, and clarifies that counts reflect the served dataset. This is substantive transparency beyond annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Reasonably structured with front-loaded purpose and clear sections, but notably lengthy for a single-parameter tool. Every sentence serves a purpose, yet the density and use of parentheses/arrows may reduce scannability. The core value is present without excessive waste.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite having only one optional parameter, the description configures how to interpret results (concept-only matches), when to call it (first, before guessing), and where to go for complementary coverage. Given the tool's discovery role and an output schema present, the description provides sufficient context without needing to explain return values in detail.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must carry parameter meaning. It does so thoroughly: the optional query parameter accepts 'a German category word or phrase' with concrete examples (Brauereien, Steuerberater, Softwarefirma), and explains the match structure returned. It also documents the enum-like values for size-class (W/K/M/G). This fully compensates for the schema gap.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific purpose -- valid filter values for search_companies with counts -- and names the sibling it serves. Distinguishes itself from get_coverage explicitly for region/format coverage. An agent can identify its role in the tooling ecosystem without reading the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly instructs to 'call this first to discover real legal_form/size_gkl values' before using search_companies or get_cohort_summary, and directs to get_coverage for region/format coverage instead. Provides clear when-to-use and alternative-routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_companiesSearch Austrian companiesARead-onlyIdempotentInspect
Find or look up Austrian companies by name — START HERE for any company lookup.
This is the primary entry point: search/find/look up companies by NAME (substring) or
filter by location, industry, legal form, size or financials, ranked. Whenever the user
names a company or wants a list of companies, call THIS tool first (you do not need the
Firmenbuchnummer/FNR to search by name). Read-only.
Parameters:
- filters (optional): a SearchFilters object; every field is optional and AND-combined
(name substring; legal_form; bundesland; oenace_section/division/group and the
4-digit oenace_class for one exact activity (11.05 = breweries; list_sectors(query=…)
resolves a category word to the code); size_gkl W/K/M/G; bilanzsumme / anlagevermoegen
/ revenue / equity_ratio / employees min+max ranges; growth_profile; has_guv;
last_filing_year_min;
founded_year_min/max; gf_age_min; status active/inactive/all). Omit for an unfiltered
list. Full-name inputs like "Wien" or "GmbH" are mapped to stored codes automatically.
equity_ratio_min/max are FRACTIONS of the Bilanzsumme (0.35 = 35 % Eigenkapitalquote);
percent-style values (>1.5, up to 100) are auto-converted /100, so 35 and 0.35 both
mean 35 %.
- sort (optional): {field, descending}; the sort field for the founding year is
"founded_year" (never founded_year_min); an unknown field is rejected with the list
of valid ones. field in {bilanzsumme, anlagevermoegen, revenue, equity_ratio,
employees, last_filing_year, founded_year, revenue_growth_1y, revenue_growth_3y,
revenue_growth_5y}
(Umsatzwachstum: 1y YoY, 3y/5y CAGR; only companies with a multi-year GuV have them, the
rest sort last) (or "distance" with a near filter); default bilanzsumme
descending. Companies missing the sort field sort last. An unknown sort field is
rejected with the list of valid ones. With a `query`, the matched companies are
relevance-ranked by DEFAULT; pass an explicit sort to order them by that metric instead
(e.g. "die größten Medienhäuser" -> query + sort bilanzsumme). For an exhaustive
"largest in sector X" ranking prefer a structured filter (oenace_*) over query, since a
query returns a relevance shortlist, not the whole sector.
- page (optional, default 1) and page_size (optional, default 25, clamped to 1..100).
- after (optional): KEYSET paging for bulk extraction — pass "" to start, then feed the
response's `next_after` back here for each next page (FNR-ordered, no offset ceiling); an
empty page means done. Not combinable with `query`/`near` (ranking has no stable cursor).
Prefer this over deep `page` for exporting a whole segment. Credit-metered accounts:
keyset pages are EXTRACTION and cost 1 credit per returned company (same rate as
export_companies_csv); normal `page` browsing costs 1 credit per started 25 rows.
- exact_count (optional, default false): force an exact `total` in keyset mode (a full COUNT
scan). In normal (offset) mode `total` is always exact already; `total_semantics` reports
"exact" vs "page_only".
Returns the total match count plus a COMPACT summary card per company on the page (name,
legal_form, bundesland, size, Bilanzsumme, equity ratio, revenue, growth, has_guv, industry)
— NOT the full record. Use to find/rank companies; for one company's full profile call
get_company_details, for the complete record call get_full_record, for aggregates over a
whole group call get_cohort_summary.
Query recipes (pick ONE primary strategy per user intent):
- Specific company by name: filters={"name": "<name>"} — substring, case-insensitive.
Results are relevance-ordered (exact/prefix matches first) when the hit set is small
(≤200); a broader name acts as a market screen and keeps the numeric sort.
- Industry as a CONCEPT ("tech companies", "Metallverarbeiter"): use oenace_division /
oenace_group (codes + German labels via describe_fields), NOT geschaeftszweig.
- Industry by literal ACTIVITY TEXT: geschaeftszweig matches the Firmenbuch free-text
description as substring ("anlagenbau" works; "technisch" won't — it's not semantic).
- Free-text query: filters={"query": "<text>"} searches name + activity and combines with
all structured filters; cards carry match_reason. Semantic activity recall is live — a
concept query surfaces companies by what they DO even without the literal words, and the
matched pool is relevance-ranked by default (pass an explicit sort to override).
- Region: bundesland (broad) > city (exact town) > postal_code prefix. Radius: use
near={"place":"Gmunden","radius_km":25} or near={"postal_code":"4810","radius_km":25};
cards get distance_km and sort by distance. An ambiguous town name is rejected with the
candidate PLZs.
- Recent corporate EVENT ("companies that raised capital / changed management / were
acquired / changed owners"): add event_signal + event_since to filters, e.g.
filters={"oenace_division":"41","bilanzsumme_min":5000000,"event_signal":["capital_raise"],
"event_since":"2024-01-01"}. Signal groups: "ownership_change" (Gesellschafter-
Kapitaländerung, often a share transfer), "leadership_change", "capital_raise",
"restructuring" (Verschmelzung/Spaltung/…), "new_company", "closure", "rebrand",
"relocation". Combines with EVERY financial/profile filter; each returned card gains
`events` (the triggering register changes, rich values on forward events) +
latest_event_date. Default window 365 days. This is the deal-sourcing / sales-trigger
surface. Pro. (For the raw cross-company event log use list_events; for counts
get_event_stats.)
- Zero hits? Read `relaxations` in the response and adjust THAT filter; do not retry
blind variations. `applied_filters` echoes how your inputs were normalized.
The response also carries has_more (another page exists) and, when total==0 with ≥2
filters, relaxations (which single filter to drop, most-permissive first).
Field reference: https://www.agentic-firmenbuch.at/felder.html
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | ||
| sort | No | ||
| after | No | ||
| filters | No | ||
| page_size | No | ||
| exact_count | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent, so the description's added depth is real value: it discloses credit metering (keyset = 1 credit per company vs 1 per 25 rows), that keyset is 'not combinable with query/near', that unknown sort fields are rejected, that missing-metric companies sort last, and that cards are compact rather than full records.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The critical routing statement is front-loaded and the parameter/recipe blocks are scannable, but there is internal duplication — the 'unknown sort field is rejected with the list of valid ones' rule appears twice in the same bullet — and the parameter bullet for sort is dense enough to be hard to parse in one pass.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 6-param tool with a rich nested filter object, an output schema (so return values needn't be spelled out), and heavy sibling overlap, the description covers strategy selection, paging modes, cost model, and error recovery. Nothing an agent needs to invoke it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 0% top-level schema coverage the description carries the full burden and does so: equity_ratio is defined as a fraction with percent auto-conversion, the sort field must be 'founded_year' not 'founded_year_min', 'after' is keyset paging with a ''-to-start protocol, and event_signal groups are enumerated. This adds meaning far beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening sentence states a specific verb+resource ('Find or look up Austrian companies by name') and declares itself the primary entry point, explicitly contrasting with named siblings (get_company_details, get_full_record, get_cohort_summary). An agent can distinguish this from every other lookup tool 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.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit when-to-use ('START HERE', 'call THIS tool first'), a battery of named query strategies with selection rules, and routes to alternatives for events (list_events), aggregates (get_cohort_summary), and full records. The 'pick ONE primary strategy per user intent' plus the 'Zero hits? Read relaxations' guidance is unusually complete.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_personsSearch companies by representativeARead-onlyIdempotentInspect
Find the companies a person represents (Geschäftsführung, Vorstand, Prokura, Aufsichtsrat) by NAME over the official register roster. Read-only, public data only.
Parameters:
- name (required, min. 3 characters): part of the person's name, case-insensitive
("Pöpperl", "Christian Pöpperl").
- limit (optional, default 50, max 200): maximum companies scanned.
Returns `persons[]` grouped by the exact name found, each with `companies[]`
({fnr, name, city, role}). Name equality is not identity: say so when several people
share a name. Use for "Welche Firmen führt X?"; for a company's own officers use
get_company_details.| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | ||
| limit | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only/idempotent/destructive, and the description adds genuinely new behavioral facts: the 3-character minimum, case-insensitive matching, that limit caps companies scanned, that results are grouped by exact name found, and the important caveat that name equality is not identity and should be disclosed to users.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded purpose sentence, then a compact parameter block, then return shape, then routing. The German legal-form terms and the identity caveat each earn their space; no filler sentences.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a two-parameter read tool this covers everything an agent needs: input semantics, the shape of the returned persons[]/companies[] structure, the identity caveat, and the sibling routing. Output schema exists, yet the description's return summary adds grouping/equality nuance rather than duplicating field lists.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description carries the full burden and does: name is required, min 3 characters, case-insensitive, with concrete examples; limit is optional, default 50, max 200 and means maximum companies scanned. Both parameters gain meaning found nowhere in the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific action (find the companies a person represents) with the register roles covered (Geschäftsführung, Vorstand, Prokura, Aufsichtsrat) and the data source (official register roster). It is clearly distinguishable from sibling get_company_details, which it explicitly names as the inverse lookup.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit routing: use this for 'Welche Firmen führt X?' and use get_company_details when the direction is a company's own officers. It also includes a worked query example, so the when-to-use and when-to-use-the-alternative conditions are both covered.
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.
18 tool updates
v1.0.0- First observed
benchmark_company - First observed
describe_fields - First observed
export_companies_csv - First observed
find_peers - First observed
get_cohort_summary - First observed
get_company_details - First observed
get_company_history - First observed
get_coverage - First observed
get_document - First observed
get_document_text - First observed
get_event_stats - First observed
get_full_record - First observed
get_my_usage - First observed
list_documents - First observed
list_events - First observed
list_sectors - First observed
search_companies - First observed
search_persons
TDQS
Scored across 18 tools
The set covers distinct operations (search, profile, history, documents, events, peers, aggregates), but the three company-record tools get_full_record, get_company_details, and get_company_history overlap in scope, requiring careful reading to choose correctly. The descriptions explicitly disambiguate, so an attentive agent can avoid misselection.
All 18 tools use snake_case with a predictable verb_noun pattern (get_, list_, search_, find_, export_, describe_, benchmark_). No camelCase or mixed conventions; the naming is consistent throughout.
18 tools for a rich read-only register API with search, profile, documents, events, persons, benchmarks, and meta endpoints is slightly above the typical 3–15 range but each tool appears to serve a distinct capability. No obvious redundant tools, though the number is on the heavy side.
The surface covers company lookup, detailed profiles, full records, multi-year histories, document metadata, text extraction, download links, person search, sector filters, cohort aggregates, peer benchmarks, event feeds/stats, coverage, and usage. For a read-only Firmenbuch API, this is comprehensive with no obvious dead ends.
Maintenance
Related MCP Connectors
CompanyLens is a remote MCP server giving AI agents instant access to official company registry data across 19 jurisdictions in Europe, the Americas, and Asia-Pacific. Eighteen read-only tools let you search companies and people, look up officers and beneficial owners, map corporate networks through shared directors, screen names against the UK disqualified directors register, find every company at a registered address, and pull filing history — all from a single connector. Visit our website: https://companylens.io
Let AI agents query data and act across all your business apps via MCP.
Agent-native API for Finnish public company data via YTJ. Pay-per-call $0.01 USDC over x402.
KYB for AI agents: verify business registrations from MCP clients.
Related MCP Servers
- AlicenseAqualityDmaintenanceMCP server for Slovak business registers (RPO) — AI agents can query 1.4M+ Slovak legal entities via Slovakia's official Statistical Office API. Search companies by name, IČO, or get full entity details including legal form, address, and statutory representatives.21MIT
- AlicenseAqualityCmaintenanceCompanyLens MCP gives your AI assistant access to real corporate data from official government sources. No web scraping, no hallucinations — verified data from SEC EDGAR, UK Companies House, OpenSanctions, and USAspending.gov.5201 npm4MIT
- AlicenseNot gradedqualityDmaintenanceGives any MCP-compatible AI agent instant access to the Australian Business Register (ABR) — plus AI-powered business intelligence. Search 8M+ registered Australian entities by name or ABN, get full profiles, check GST status, and get an AI-generated opportunity assessment for any business.38 npmMIT
- FlicenseAqualityDmaintenanceAn MCP server that gives AI agents access to US business entity data, enabling searches across 9 state registries, SEC EDGAR filings, federal contracts, and lobbying disclosures.61-