Leadgen MCP
Summary: Leadgen MCP gives you search and enrichment over Romania's official business registry (4.2M ONRC firms), ANAF fiscal data, and 18 years of Ministry of Finance financial statements.
Look up companies by name, CUI/tax code, batch CUI (up to 100), website domain, or director/representative name.
Find firms by activity: curated topics, plain words, or CAEN codes, filterable by county, revenue, headcount, VAT status, legal form, and website presence.
Bulk-match up to 500 records (name, county, domain, CUI) to firms with confidence scores.
Extract contacts (emails, phones, socials) by crawling a company website.
Enrich a company in one call: registry record plus website contacts with confidence and source.
Profile a domain: WHOIS, DNS records, and SPF/DMARC email-security audit.
Get financials: multi-year statements (revenue, profit, headcount, balance sheet, ratios) since 2008.
Get financial intelligence: trends, CAGRs, health score, red flags, peer percentiles, and a growing/stable/distressed verdict.
Monitor changes: watch a company or CAEN activity code and poll for updates (new directors, status changes, ANAF inactivity, new registrations).
Check your allowance (plan, daily limit, remaining lookups) and report data gaps or errors.
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., "@Leadgen MCPFind companies associated with director Maria Ionescu"
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.
Leadgen MCP — Romanian company data (ONRC, ANAF, financial statements)
A remote Model Context Protocol server for Romania's official business registry: 4.2M firms from ONRC, the ANAF fiscal layer (VAT, e-Factura, fiscal inactivity, phone) and 18 years of financial statements (Ministry of Finance, 2008–2025) with ratios and peer benchmarks.
Endpoint:
https://leadgen-mcp.adrianhomelab.com/mcp(Streamable HTTP)Free: 30 lookups a day without a key, 50 a day with a free key from https://leadgen.adrianhomelab.com/start — send it as
Authorization: Bearer <key>(orX-API-Key).REST API and docs: https://leadgen.adrianhomelab.com/docs · for LLMs: https://leadgen.adrianhomelab.com/llms.txt
Server card: https://leadgen-mcp.adrianhomelab.com/.well-known/mcp/server-card.json · official MCP registry:
com.adrianhomelab/leadgen-onrc
This repository holds the public description of the server and an open-source local MCP client (below). The hosted server's source is not public.
Connect
Claude Code
claude mcp add --transport http leadgen https://leadgen-mcp.adrianhomelab.com/mcp --header "Authorization: Bearer <your key>"or in .mcp.json:
{
"mcpServers": {
"leadgen": {
"type": "http",
"url": "https://leadgen-mcp.adrianhomelab.com/mcp",
"headers": { "Authorization": "Bearer <your key>" }
}
}
}Claude (claude.ai and Claude Desktop): Customize → Connectors → Add custom connector →
URL https://leadgen-mcp.adrianhomelab.com/mcp, no sign-in; add the Authorization header with your key if your plan allows custom headers.
Cursor (~/.cursor/mcp.json or .cursor/mcp.json):
{ "mcpServers": { "leadgen": { "url": "https://leadgen-mcp.adrianhomelab.com/mcp", "headers": { "Authorization": "Bearer <your key>" } } } }VS Code (.vscode/mcp.json):
{ "servers": { "leadgen": { "type": "http", "url": "https://leadgen-mcp.adrianhomelab.com/mcp", "headers": { "Authorization": "Bearer <your key>" } } } }Without a key every client works for 30 calls a day; get_usage tells you what is left. Current limits:
https://leadgen.adrianhomelab.com/en/docs.
Related MCP server: openregistry
Run locally (open client)
The hosted endpoint above is the main product and the simplest way in. If your client only speaks
stdio, or you want to run the MCP server yourself, this repository also ships leadgen-mcp: a small
open-source (MIT) local MCP server with the same 17 tools. It holds no data: every tool calls Leadgen's
public REST API (https://leadgen.adrianhomelab.com/docs), so answers, limits and keys are the same as
on the hosted server. Tool names, descriptions and schemas are a snapshot of the hosted server's
tools/list (leadgen_mcp/tools.json, refreshed with scripts/sync_tools.py).
It is on PyPI as leadgen-mcp (Python 3.10 or newer):
uvx leadgen-mcpor install it:
pip install leadgen-mcp
leadgen-mcpTo run the latest commit on main instead of the release:
uvx --from git+https://github.com/darksider4all/leadgen-mcp leadgen-mcp.
or run it in Docker: docker build -t leadgen-mcp . then docker run -i --rm -e LEADGEN_API_KEY leadgen-mcp.
Variable | Default | What it does |
| none | Your free key from https://leadgen.adrianhomelab.com/start (50 lookups a day instead of the REST API's 5). Optional; sent only when set. |
|
| A channel tag sent with each request ( |
|
| REST API base URL. |
|
| Seconds to wait for an answer (website crawls can take a while). |
Claude Desktop (claude_desktop_config.json):
{
"mcpServers": {
"leadgen": {
"command": "uvx",
"args": ["leadgen-mcp"],
"env": { "LEADGEN_API_KEY": "<your key>", "LEADGEN_SOURCE": "claude-desktop" }
}
}
}Cursor (~/.cursor/mcp.json or .cursor/mcp.json):
{
"mcpServers": {
"leadgen": {
"command": "uvx",
"args": ["leadgen-mcp"],
"env": { "LEADGEN_API_KEY": "<your key>", "LEADGEN_SOURCE": "cursor" }
}
}
}Leave LEADGEN_API_KEY out to use the REST API's 5 anonymous lookups a day.
How it relates to the hosted server: same tools and same data. This client calls the REST API,
whose anonymous allowance is smaller than the MCP endpoint's (5 a day against 30, counted per door
and per IP); a free key gives 50 a day. A refusal (no key, daily limit, suspended key) comes back as a tool
error that keeps the server's message and the link to a free key; for the daily limit it says when it
resets (00:00 UTC). The key is sent as the X-API-Key header, only when it is set. Watches need a key.
Development: pip install -e ".[test]" && pytest (no network); LEADGEN_LIVE=1 pytest tests/test_live.py
makes one real anonymous lookup; LEADGEN_DRIFT=1 pytest tests/test_drift.py compares tools.json
with the live server card; python scripts/check_public.py checks that nothing private is committed.
Tools
Tool | What it does |
| Look up a Romanian company by name or CUI (tax code) in the official ONRC registry of 4.2M firms. |
| Look up many Romanian companies by CUI in one call (up to 100): one result per input, in input order, each with found true/false and the company record. |
| Find the Romanian firm behind a website domain (dedeman.ro). |
| Match a list of up to 500 records (name, optional county, domain or CUI) to Romanian firms: each row gets match {cui, companyName, confidence, matchedOn} and the record, or no_match with up to 3 candidates. |
| Find companies by what they do, not by name: a curated topic ('software', 'retail'), plain words ('dentists', a CAEN class title; see matched) or CAEN codes ('4321,4322'; 6201 also finds Rev.3 6210). |
| Find Romanian companies by the name of a director or legal representative (ONRC). |
| Crawl a company website and extract emails, phone numbers and social profiles. |
| A whole-firm profile in one call: the ONRC registry record plus the contacts discovered on that firm's website, each labelled with a confidence and a source. |
| WHOIS plus DNS records (A, MX, NS, TXT) and an SPF/DMARC email-security audit for a domain. |
| Annual financial statements for a Romanian company from Ministry of Finance filings, every fiscal year on record since 2008: revenue, profit, headcount and balance-sheet lines in RON with each year's ratios (growth, margins, equity ratio, liquidity), plus a summary (3/5/10-year CAGR, loss years, health score). |
| Derived financial intelligence for a Romanian company: multi-year revenue trend (YoY, 3/5/10-year CAGR), margins, headcount, solvency and liquidity ratios, a 0-100 health score with its rule-by-rule breakdown, red flags, and peer percentiles within the same CAEN activity and county. |
| Register a company (by CUI) to monitor. |
| Watch a CAEN activity code, optionally scoped to one county, for newly registered firms. |
| Collect everything the watch tools have found: call it to drain the changeset for every watch owned by your API key, most severe first. |
| Stop watching a firm ( |
| Show your own allowance: plan, daily limit, lookups used today, how many remain, when it resets (00:00 UTC) and any credit balance. |
| Tell the Leadgen founder what is missing or wrong: a missing field, firm or source (kind 'gap'), a wrong company record ('wrong_record', pass its cui), a bug, an idea. |
Every company-bearing answer carries asOf (registry snapshot, financial year, ANAF load date) — cite it.
Data and credit
Registry and financial statements: ONRC and the Ministry of Finance via data.gov.ro, licensed CC BY 4.0; fiscal data: ANAF. When you publish data obtained through Leadgen, credit it as: "Sursa: ONRC și Ministerul Finanțelor (data.gov.ro, CC BY 4.0) și ANAF, prin Leadgen".
Romanian
Server MCP pentru registrul oficial al firmelor din România (ONRC, ANAF, bilanțuri 2008–2025). Gratuit: 30 de interogări pe zi fără cheie (5 prin API-ul REST), 50 pe zi cu o cheie gratuită de la https://leadgen.adrianhomelab.com/start. Documentație: https://leadgen.adrianhomelab.com/docs.
Contact
Prices: https://leadgen-checkout.adrianhomelab.com/ · questions: through the website's contact link.
Available Tools
17 toolsenrich_companyCompany profile with website contactsARead-onlyIdempotentInspect
A whole-firm profile in one call: the ONRC registry record plus the contacts discovered on that firm's website, each labelled with a confidence and a source. Prefer this over lookup_business followed by extract_contacts when you want everything about one company. cui is its tax code; website overrides the registered one; max_pages bounds the crawl; refresh=true crawls now instead of answering from the cache.
| Name | Required | Description | Default |
|---|---|---|---|
| cui | Yes | Romanian tax identification number (CUI), e.g. '2816464'; 'RO' and leading zeros are accepted. | |
| refresh | No | true crawls now even if a cached result exists (default false: answer from the cache when there is one). | |
| website | No | Optional website override (domain or URL). When omitted, the firm's registered website is used (an error if none is on file). | |
| max_pages | No | Maximum number of pages to crawl (1-20, default 5). |
Output Schema
| Name | Required | Description |
|---|---|---|
| cui | No | The firm's CUI. |
| asOf | No | What to cite: registry (ONRC snapshot date), financialYear (fiscal year of the figures), anaf (day of the ANAF data), snapshot, published, source. |
| error | No | Set only when there is no answer (empty_query, invalid_cui, data_unavailable, plan_required ...); such a call is not counted. |
| company | No | A company record: companyName, cui, registrationCode, registrationDate (DD/MM/YYYY), legalForm, euid, address, county, city, website, phone, caenActivities [{code, activity (RO), activityEn}], directors, representatives [{name, role}], status [{code, name}], latestFinancials {year, revenue, netResult, employees; RON}, anaf {mainCaen, vatPayer, eFactura, inactive}, risk {level, label, reasons, isLead}, source, asOf, url (the firm's public record page to share with the user; null for sole traders and other natural persons), and score/match on name searches. With fields or compact, only the requested keys (compact keeps url). |
| crawled | No | true when the site was crawled for this answer. |
| message | No | A sentence for the caller. |
| website | No | The website crawled. |
| cacheHit | No | true when answered from the cache. |
| contacts | No | Contacts found, each with type, value, confidence and source. |
| crawlError | No | Why the crawl failed, if it did. |
| pagesCrawled | No | Pages read. |
| websiteSource | No | Where the website came from: registry or override. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/openWorld/non-destructive, and the description goes further by disclosing cache-vs-live behavior ('refresh=true crawls now instead of answering from the cache') and that outputs carry confidence and source labels. It stops short of covering crawl cost, latency, or failure/partial-result behavior, so it is strong but not exhaustive.
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 value proposition and the sibling routing rule, then compresses all four parameters into one dense clause each. No sentence is redundant or padded.
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 values need not be explained; the description still notes the confidence/source annotation on discovered contacts. With schema and annotations covering the rest, an agent has everything needed to call this 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 description coverage is 100%, so all four parameters are already documented with types, defaults and constraints (1-20 pages, RO-prefix acceptance). The description restates 'cui is its tax code', the website override, the crawl bound and refresh semantics without adding syntax or examples 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?
States a specific composite verb/resource ('whole-firm profile in one call: the ONRC registry record plus the contacts discovered on that firm's website') and explicitly names the two siblings it replaces. An agent can distinguish it from lookup_business and extract_contacts 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 when-to-use rule and names the alternatives: 'Prefer this over lookup_business followed by extract_contacts when you want everything about one company.' Both the condition and the competing tools are stated, leaving nothing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
extract_contactsExtract contacts from a websiteARead-onlyIdempotentInspect
Crawl a company website and extract emails, phone numbers and social profiles. Accepts a bare domain or a full URL; max_pages (1-20, default 5) bounds the crawl.
| Name | Required | Description | Default |
|---|---|---|---|
| website | Yes | The website to crawl: a bare domain ('example.com') or a full URL ('https://example.com'). | |
| max_pages | No | Maximum number of pages to crawl (1-20, default 5). |
Output Schema
| Name | Required | Description |
|---|---|---|
| url | No | The start URL crawled. |
| error | No | Set only when there is no answer (empty_query, invalid_cui, data_unavailable, plan_required ...); such a call is not counted. |
| domain | No | The site's registrable domain. |
| emails | No | Addresses on the site's own domain. |
| github | No | GitHub profile. |
| phones | No | Phone numbers found. |
| message | No | A sentence for the caller. |
| No | X / Twitter profile. | |
| youtube | No | YouTube channel. |
| No | Facebook profile. | |
| No | LinkedIn page. | |
| No | Instagram profile. | |
| otherEmails | No | Other addresses found on the site. |
| socialLinks | No | Every social link found, best first. |
| pagesCrawled | No | Pages read. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, openWorldHint=true, idempotentHint=true and destructiveHint=false, so safety is covered. The description adds that this is a bounded crawl (max_pages controls scope), which usefully implies runtime/cost characteristics, but says nothing about latency, rate limits, or whether results are cached.
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?
Two tight sentences with the capability front-loaded and the input constraints trailing. The second sentence is largely a paraphrase of the schema, which is the only minor 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?
An output schema exists, so return values need no explanation, and annotations cover the safety profile. The description is nearly complete for this tool; only crawl-dynamics details (scope of crawling, subdomain behavior, expected duration) are absent.
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 100% and both parameters already document the domain/URL format and the 1-20 default-5 range. The description simply restates that same information, adding no syntax, format, or edge-case guidance beyond the schema, so the baseline of 3 applies.
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 description states a concrete verb+resource ('Crawl a company website') plus the extracted artifacts (emails, phone numbers, social profiles), so an agent knows exactly what it produces. It is clearly distinct from the lookup_* siblings in mechanism, but it never clarifies its relationship to overlapping tools like enrich_company, which could also surface contact data.
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?
Usage is only implied: the agent can infer 'use this when you need contact details from a live site.' There is no explicit when-to-use trigger, no when-not, and no routing to or from alternatives such as enrich_company or lookup_domain.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
find_company_by_domainFind the company behind a websiteARead-onlyIdempotentInspect
Find the Romanian firm behind a website domain (dedeman.ro). Uses the registry's website field, else reads the site's home and legal/contact pages for the CUI or registration number it shows (matchedOn: registry_website, site_cui). Without one, it says so and offers name candidates from the page title or the domain name, each with a confidence (at most 0.7, never a match). One lookup.
| Name | Required | Description | Default |
|---|---|---|---|
| domain | Yes | The website's domain ('dedeman.ro'); a URL or a www. host is reduced to it. Public domains only. | |
| fields | No | Optional: keep only these company fields in each row, comma-separated (companyName,cui,county,risk; dotted paths such as risk.level work). Without it the full record is returned. | |
| compact | No | Optional: true keeps a short preset per row (name, CUI, county, city, legal form, risk level and what it did not check, phone, website, latest revenue and headcount, record url). |
Output Schema
| Name | Required | Description |
|---|---|---|
| asOf | No | What to cite: registry (ONRC snapshot date), financialYear (fiscal year of the figures), anaf (day of the ANAF data), snapshot, published, source. |
| site | No | What was read from the site: url, pagesRead, title, cuis, registrationCodes, error. |
| error | No | Set only when there is no answer (empty_query, invalid_cui, data_unavailable, plan_required ...); such a call is not counted. |
| found | No | Whether a firm was identified. |
| match | No | The identified firm: cui, companyName, matchedOn. |
| total | No | Number of company records returned (at most 5). |
| domain | No | The normalised domain. |
| fields | No | The company fields kept when fields or compact trimmed the rows. |
| reason | No | When not found: no_cui_on_site or site_unreachable. |
| message | No | A sentence for the caller. |
| results | No | The company records, best first. |
| warnings | No | Notes on how the request was read (a clamped limit, a widened CAEN code, an ignored field). |
| matchedOn | No | registry_website, site_cui or site_registration_code. |
| candidates | No | When not found (also when the site cannot be read): up to 3 firms whose name matches the page title or the domain name, each with a confidence (at most 0.7). |
| attribution | No | The credit line to keep when redistributing the data (CC BY 4.0). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: it discloses the two lookup paths (registry website field vs. reading home/legal/contact pages), the matchedOn values, that name candidates are capped at 0.7 confidence and are 'never a match', and that it is a single lookup. This is exactly the behavioral detail annotations cannot convey.
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?
Dense and front-loaded with the core purpose first, then method, then fallback behavior. The middle sentence is packed but not redundant; a slightly shorter phrasing would improve scannability.
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 an output schema present and annotations covering the safety profile, the description supplies everything remaining an agent needs: input shape, resolution strategy, confidence semantics, and the fact that a non-match is reported rather than fabricated.
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 100%, so the domain, fields, and compact parameters are already fully documented in the schema. The description adds no parameter syntax or format detail of its own, so the baseline 3 applies.
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 ('Find the Romanian firm behind a website domain') with a concrete example (dedeman.ro) and names the matching method used. It is clearly distinguishable in substance from lookup/enrich siblings, though it never names an alternative tool to contrast against.
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?
Usage context is implied (you have a domain, you want the company) and the fallback chain tells the agent what will happen, but there is no explicit 'use this when X, use lookup_domain/lookup_business when Y' guidance despite many closely named siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_usageShow my daily allowanceARead-onlyIdempotentInspect
Show your own allowance: plan, daily limit, lookups used today, how many remain, when it resets (00:00 UTC) and any credit balance. Free and never counted as a lookup. Limits: 5 lookups a day anonymously, 25 with a free API key from https://leadgen.adrianhomelab.com/start (an email address, no payment).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| plan | No | Plan name (free, pro, business). |
| error | No | Set only when there is no answer (empty_query, invalid_cui, data_unavailable, plan_required ...); such a call is not counted. |
| links | No | get_a_key, pricing, docs. |
| counted | No | Always false: this call is not counted. |
| message | No | A sentence for the caller. |
| identity | No | Who is counted: kind (key or anonymous) and counted_as. |
| remaining | No | Lookups left today. |
| resets_at | No | When the allowance resets (ISO 8601, 00:00 UTC). |
| suspended | No | true when the key is suspended. |
| used_today | No | Lookups used today. |
| daily_limit | No | Lookups allowed per UTC day. |
| entitlements | No | What the plan includes. |
| resets_in_seconds | No | Seconds until the reset. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and destructiveHint=false, but the description adds real behavioral context beyond them: it is free, never counted against the quota, reports both anonymous (5/day) and keyed (25/day) ceilings, and points to the key signup. Auth requirements and rate limits are disclosed, which is exactly what the annotations cannot convey.
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?
Two sentences, output contents front-loaded before the quota/auth caveats, with no filler. The trailing signup URL and parenthetical are slightly dense but genuinely actionable, so the trade-off is acceptable.
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-value detail is optional; the description going further and enumerating the fields is a bonus. Auth needs, quota tiers, reset timing, and cost are all covered, leaving no gap an agent would need to guess at for this parameterless read tool.
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?
The tool takes zero parameters, so the baseline is 4 and there is nothing further for the description to disambiguate. The statement that it costs no lookup is a useful semantic note about invocation but is not a parameter concern.
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 ('Show your own allowance') followed by an enumerated list of what is returned: plan, daily limit, lookups used today, remaining, reset time, credit balance. It is unmistakably distinct from the lookup/enrich siblings, which all consume allowance rather than report it.
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 clear context for when to call it (checking your allowance) and states the free/unmetered condition plus the anonymous-vs-key limits that shape usage. It does not explicitly name an alternative tool or a 'do not use when' case, but the sibling set contains no near-equivalent, so routing risk is low.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
lookup_businessLook up a Romanian companyARead-onlyIdempotentInspect
Look up a Romanian company by name or CUI (tax code) in the official ONRC registry of 4.2M firms. Diacritic-insensitive ('paval' finds 'PAVAL'); a CUI matches exactly. The first call for a named Romanian company. Ranked with a score: live firms first (exact name, then words), closed ones after; county lifts. For 'firms that do X in Y', use lookup_by_category (an empty result may carry a hint naming it).
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Company name or CUI (tax ID) to search for. Names are diacritic-insensitive ('paval' finds PAVĂL); a CUI ('2816464', 'RO2816464') matches exactly. | |
| county | No | Optional county hint (diacritic-insensitive): firms registered there rank higher. Not a filter. | |
| fields | No | Optional: keep only these company fields in each row, comma-separated (companyName,cui,county,risk; dotted paths such as risk.level work). Without it the full record is returned. | |
| compact | No | Optional: true keeps a short preset per row (name, CUI, county, city, legal form, risk level and what it did not check, phone, website, latest revenue and headcount, record url). | |
| max_results | No | Maximum number of companies to return (1-100, default 10). |
Output Schema
| Name | Required | Description |
|---|---|---|
| asOf | No | What to cite: registry (ONRC snapshot date), financialYear (fiscal year of the figures), anaf (day of the ANAF data), snapshot, published, source. |
| hint | No | When a name search finds nothing but reads like a category question: the lookup_by_category call that answers it. |
| error | No | Set only when there is no answer (empty_query, invalid_cui, data_unavailable, plan_required ...); such a call is not counted. |
| found | No | false when a well-formed CUI is not in the snapshot. |
| query | No | The query as given. |
| total | No | Rows returned in this answer (at most max_results), not the number of firms that match. |
| county | No | The county hint, if one was given. |
| fields | No | The company fields kept when fields or compact trimmed the rows. |
| reason | No | Why nothing was found (not_found). |
| source | No | Data source: onrc (registry) or mfp (Ministry of Finance filings). |
| message | No | A sentence for the caller. |
| results | No | The company records, best first. |
| warnings | No | Notes on how the request was read (a clamped limit, a widened CAEN code, an ignored field). |
| attribution | No | The credit line to keep when redistributing the data (CC BY 4.0). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, non-destructive and closed-world, so the safety profile is covered. The description adds genuinely non-derivable behavior: diacritic-insensitive matching, CUI exact-match semantics, live-before-closed ranking with county lift, and the empty-result hint. It stops short of stating result limits or pagination, but that is minor against the annotation coverage.
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, then ranking rules, then the sibling redirect. Dense but every clause carries information; the parenthetical examples are compact. Slightly packed with semicolon-separated ranking detail, 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 an output schema present, return values need no explanation, and the description covers matching rules, ranking order and the alternative path. A complex, highly-ranked lookup tool is adequately described; only the max_results/truncation boundary behavior is left implicit.
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 100% and the parameter descriptions already cover diacritic-insensitivity, the county-as-hint-not-filter nuance, fields/compact behavior and the 1-100 bounds. The description largely restates the query semantics, so baseline 3 is correct – it adds little the schema does not already say.
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 ('Look up a Romanian company by name or CUI') and pins the data source ('official ONRC registry of 4.2M firms'). It also positions itself among siblings with 'The first call for a named Romanian company', so an agent can separate it from lookup_companies, lookup_by_category and match_companies 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?
Explicitly routes the disambiguating case: 'For firms that do X in Y, use lookup_by_category', and even explains the redirect an empty result may carry. Combined with the 'first call for a named Romanian company' framing, both when-to-use and when-to-use-something-else are stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
lookup_by_categoryFind companies by activityARead-onlyIdempotentInspect
Find companies by what they do, not by name: a curated topic ('software', 'retail'), plain words ('dentists', a CAEN class title; see matched) or CAEN codes ('4321,4322'; 6201 also finds Rev.3 6210). Narrow by county; qualify by revenue, headcount, VAT, main activity. active_only (default) drops dead and ANAF-inactive firms.
| Name | Required | Description | Default |
|---|---|---|---|
| sort | No | Order of the results: 'newest' registrations first (default), 'revenue' (latest filing's turnover, biggest first) or 'employees' (headcount, biggest first); firms without a filing come last. | newest |
| topic | Yes | What the firms do: a curated topic ('software', 'retail'), plain words for a trade ('dentists', 'stomatologie'), a CAEN class title in Romanian or English, or CAEN codes ('6201' or '4321,4322'). Case-, space- and diacritic-insensitive. A number that names another activity in each revision takes a suffix: '4781r3' (Rev.3) or '4781r2' (Rev.2). | |
| county | No | Optional county to narrow to (diacritic-insensitive: 'bucuresti', 'cluj'; a county town such as 'Cluj-Napoca' or a Bucharest sector is read as its county); omit for nationwide. An unknown county is an error (unknown_county) with suggestions, not 0 firms. | |
| fields | No | Optional: keep only these company fields in each row, comma-separated (companyName,cui,county,risk; dotted paths such as risk.level work). Without it the full record is returned. | |
| compact | No | Optional: true keeps a short preset per row (name, CUI, county, city, legal form, risk level and what it did not check, phone, website, latest revenue and headcount, record url). | |
| vat_payer | No | Optional: true keeps VAT-registered firms only, false only non-VAT payers (ANAF data). Omit for both. | |
| legal_form | No | Optional legal form(s) to keep, comma-separated, case-insensitive: 'SRL', 'SA', 'PFA', 'II', or 'SRL,SA' (companies, no sole traders). Default: any form. | |
| active_only | No | Default true: drop firms that are not a lead (struck off, dissolving, in liquidation, insolvent or bankrupt, activity suspended, or ANAF fiscally inactive). false returns every firm. | |
| has_website | No | true keeps only firms with a website on file in the registry (default false). | |
| max_results | No | Maximum number of companies to return (1-100, default 10). | |
| max_revenue | No | Optional maximum net turnover in RON on the latest filing. | |
| min_revenue | No | Optional minimum net turnover in RON on the latest filing (FY2025, else FY2024). Firms without a filing never match a band. | |
| max_employees | No | Optional maximum average headcount on the latest filing. | |
| min_employees | No | Optional minimum average headcount on the latest filing. | |
| main_activity_only | No | Default false: a firm matches when the code is ANY of its authorised activities (ONRC lists a dozen per firm, most never practised). true keeps only firms whose DECLARED main activity is one of the codes (ANAF main CAEN, else the CAEN on the latest filing): fewer, more relevant firms. The Leadgen app's lists use true by default. |
Output Schema
| Name | Required | Description |
|---|---|---|
| asOf | No | What to cite: registry (ONRC snapshot date), financialYear (fiscal year of the figures), anaf (day of the ANAF data), snapshot, published, source. |
| sort | No | The order of results: newest, revenue or employees. |
| error | No | Set only when there is no answer (empty_query, invalid_cui, data_unavailable, plan_required ...); such a call is not counted. |
| label | No | Human label of what was matched. |
| query | No | The topic as given. |
| topic | No | The curated topic matched, if any. |
| total | No | Rows returned in this answer (at most max_results), not the size of the match set: a full page (total == max_results) may have more; narrow the filters or raise max_results. |
| appUrl | No | The same list opened in the Leadgen app (CAEN codes, county, legal form, active and main-activity filters), to share with the user; null when the app cannot open it (more than 10 codes, a legal form it does not offer). |
| county | No | The county filter, if any. |
| fields | No | The company fields kept when fields or compact trimmed the rows. |
| source | No | Data source: onrc (registry) or mfp (Ministry of Finance filings). |
| filters | No | The filters applied (legalForm, activeOnly, revenue and headcount bands, vatPayer, mainActivityOnly ...). |
| matched | No | How plain words were read: by, niche or class title, codes. |
| message | No | A sentence for the caller. |
| results | No | The company records, best first. |
| warnings | No | Notes on how the request was read (a clamped limit, a widened CAEN code, an ignored field). |
| caenCodes | No | The CAEN codes searched, when given or derived as codes. |
| caenNames | No | The CAEN codes as asked, named: [{code, title (Romanian), titleEn}]. |
| truncated | No | true when max_results was cut to the list cap (and the list is full). |
| candidates | No | When the words fit several activities (ambiguous_topic): the ones to choose from. |
| codesAdded | No | CAEN Rev.2/Rev.3 counterparts added to the search. |
| matchTotal | No | How many firms the whole list holds with every filter (active_only on; null when off): exact, or estimated when matchTotalApproximate is true. |
| attribution | No | The credit line to keep when redistributing the data (CC BY 4.0). |
| availableTopics | No | The curated topic ids, when the topic is unknown or ambiguous. |
| matchTotalMargin | No | The 99% margin of an estimated matchTotal. |
| availableTopicNames | No | Each curated topic id with its name, e.g. {"agriculture": "Agriculture & Food"}, next to availableTopics. |
| inactiveFilteredOut | No | Firms removed by active_only (null when off). |
| matchTotalApproximate | No | true when matchTotal is estimated (matchTotalMargin: its 99% margin). |
| inactiveFilteredOutApproximate | No | true when that count is estimated. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive/openWorld=false, so the safety profile is covered. The description adds real behavioral context beyond that: the default active_only filter meaningfully changes result sets by dropping struck-off, dissolving, insolvent, suspended and ANAF-inactive firms, and it discloses that codes match ANY authorised activity unless main_activity_only narrows it. Return shape is left to the output schema, which is fine.
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 differentiator ('not by name') before the accepted input formats and filters; dense but every clause carries information. Minor waste and ambiguity in fragments like 'see matched' and the parenthetical CAEN examples.
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 15-parameter tool with a full output schema, the description covers the essential decision points: what 'topic' accepts, the scoping/qualifying filters, and the default filtering behavior. It is slightly thin on how this tool relates to its closest siblings, but 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 100%, so the schema already documents all 15 parameters, and the baseline is 3. The description mostly restates the filter categories rather than extending them, though the cross-revision note ('6201 also finds Rev.3 6210') and the 'a CAEN class title; see matched' hint add a little semantics the schema states only for the topic param.
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?
A concrete verb+resource ('Find companies by what they do') with an explicit negative qualifier ('not by name') that separates it from name/domain lookups. However, it never names the close siblings (lookup_companies, match_companies) that an agent must choose between, so differentiation is by implication rather than by reference.
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?
Usage context is implied through the accepted topic formats and the filter list ('narrow by county; qualify by revenue, headcount, VAT, main activity'), which tells the agent when the tool fits. But there are no explicit when-not conditions, prerequisites, or named alternatives among the many lookup_* siblings, and the fragment 'a CAEN class title; see matched' is puzzling rather than instructive.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
lookup_companiesLook up many companies by CUIARead-onlyIdempotentInspect
Look up many Romanian companies by CUI in one call (up to 100): one result per input, in input order, each with found true/false and the company record. Each row counts as one lookup; a batch larger than what is left today is refused whole. fields or compact trims each record.
| Name | Required | Description | Default |
|---|---|---|---|
| cuis | Yes | Up to 100 CUIs, as a list or one comma-separated string ('RO', spaces and leading zeros accepted, as in lookup_business). | |
| fields | No | Optional: keep only these company fields in each row, comma-separated (companyName,cui,county,risk; dotted paths such as risk.level work). Without it the full record is returned. | |
| compact | No | Optional: true keeps a short preset per row (name, CUI, county, city, legal form, risk level and what it did not check, phone, website, latest revenue and headcount, record url). |
Output Schema
| Name | Required | Description |
|---|---|---|
| asOf | No | What to cite: registry (ONRC snapshot date), financialYear (fiscal year of the figures), anaf (day of the ANAF data), snapshot, published, source. |
| error | No | Set only when there is no answer (empty_query, invalid_cui, data_unavailable, plan_required ...); such a call is not counted. |
| found | No | Rows that matched a firm. |
| total | No | Number of input rows. |
| errors | No | Rows that are input errors (empty, not a CUI, wrong control digit). |
| fields | No | The company fields kept when fields or compact trimmed the rows. |
| source | No | Data source: onrc (registry) or mfp (Ministry of Finance filings). |
| message | No | A sentence for the caller. |
| results | No | Per input: input, cui, found, and company (the record) or error/reason. |
| metering | No | What the batch cost: rows, counted, notCounted (input-error rows are not counted) and the rule. |
| notFound | No | Well-formed CUIs not in the snapshot. |
| warnings | No | Notes on how the request was read (a clamped limit, a widened CAEN code, an ignored field). |
| attribution | No | The credit line to keep when redistributing the data (CC BY 4.0). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover readOnly/idempotent/non-destructive, so the description's added value is the quota accounting ('each row counts as one lookup'), the atomic whole-batch refusal, the per-row found flag, and the input-order guarantee — real operational context beyond the schema. It doesn't say whether refused batches surface as an error vs a partial result.
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?
Dense but front-loaded: batch scope, per-row semantics, quota rule, and trimming flags in order of importance, with 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?
An output schema exists so return shapes need no explanation, and the description covers ordering, the found flag, and quota failure. The one gap is what happens on invalid or unknown CUIs within the batch, and how the whole-batch refusal is reported.
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 100%, so cuis, fields, and compact are already fully documented, including accepted CUI formats and dotted paths. The description only echoes that fields/compact trim each record, adding no syntax beyond the schema; baseline 3 applies.
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 (look up), resource (Romanian companies by CUI), and batch scope (up to 100, one result per input) that clearly separates it from the singular lookup_business sibling it references.
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?
The 'many ... in one call' framing and the pointer to lookup_business for CUI formatting imply the batch-vs-single choice, and the quota/refusal rule tells the agent when a call will fail. It stops short of explicitly naming when to prefer this over match_companies or other siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
lookup_directorFind companies by directorARead-onlyIdempotentInspect
Find Romanian companies by the name of a director or legal representative (ONRC). Diacritic-insensitive. Whole words: 'pop maria' finds POP MARIA, not POPA MARIANA; prefix=true matches prefixes. The registry has no personal ID, so one name can be several people: homonyms and byCounty say so. Use this when you know a person rather than a firm.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | Director / representative name to search for (e.g. 'Ion Popescu'); diacritic-insensitive, each word a whole word of the name. | |
| fields | No | Optional: keep only these company fields in each row, comma-separated (companyName,cui,county,risk; dotted paths such as risk.level work). Without it the full record is returned. | |
| prefix | No | true matches each word as a prefix ('pop' also finds POPA, POPESCU); default false (whole words). | |
| compact | No | Optional: true keeps a short preset per row (name, CUI, county, city, legal form, risk level and what it did not check, phone, website, latest revenue and headcount, record url). | |
| max_results | No | Maximum number of companies to return (1-100, default 10). |
Output Schema
| Name | Required | Description |
|---|---|---|
| asOf | No | What to cite: registry (ONRC snapshot date), financialYear (fiscal year of the figures), anaf (day of the ANAF data), snapshot, published, source. |
| note | No | What homonyms means for this name. |
| error | No | Set only when there is no answer (empty_query, invalid_cui, data_unavailable, plan_required ...); such a call is not counted. |
| match | No | words (whole words) or prefix. |
| query | No | The name as given. |
| total | No | Every matching firm, not just the rows returned. |
| fields | No | The company fields kept when fields or compact trimmed the rows. |
| source | No | Data source: onrc (registry) or mfp (Ministry of Finance filings). |
| message | No | A sentence for the caller. |
| results | No | The company records, best first. |
| byCounty | No | Matching firms per county. |
| homonyms | No | true when the matches span several counties (likely several people). |
| returned | No | Number of companies returned. |
| warnings | No | Notes on how the request was read (a clamped limit, a widened CAEN code, an ignored field). |
| attribution | No | The credit line to keep when redistributing the data (CC BY 4.0). |
| distinctCounties | No | Number of counties the matches are in. |
| totalIsLowerBound | No | true when the scan stopped early and total is a minimum. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive, closed-world), and the description usefully adds matching semantics (diacritic-insensitive, whole-word, prefix option) plus the key ambiguity that one name can map to several people due to no personal ID. It does not mention pagination or result-count behavior beyond the schema's max_results.
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 matching rules, and nearly every sentence carries distinct information. The dangling reference to 'byCounty' as a signal for homonyms is slightly confusing since no such parameter appears in the schema, costing a point.
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 an output schema present, return-value details are rightly omitted, and the description covers the tricky parts an agent needs: matching semantics, diacritics, prefix behavior, and the one-name-to-many-people caveat. Nothing essential for correct invocation 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 100%, so the schema already carries parameter meaning and the baseline would be 3. The description earns a point by reinforcing matching behavior with a concrete example ('pop maria' finds POP MARIA, not POPA MARIANA) and explaining the homonym ambiguity that no schema field conveys.
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 with its scope: 'Find Romanian companies by the name of a director or legal representative (ONRC).' This clearly separates it from sibling firm-oriented tools such as find_company_by_domain, lookup_companies, and match_companies.
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?
'Use this when you know a person rather than a firm' gives a clear selection condition and implicitly excludes firm/domain-based siblings. It does not name a specific alternative tool to switch to, so it stops short of full when/when-not routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
lookup_domainDomain WHOIS, DNS and email auditARead-onlyIdempotentInspect
WHOIS plus DNS records (A, MX, NS, TXT) and an SPF/DMARC email-security audit for a domain. Use it to profile a company's web estate or check its email posture. include_dns and include_security toggle the two halves.
| Name | Required | Description | Default |
|---|---|---|---|
| domain | Yes | Domain name to look up (e.g. 'example.com'); a URL is reduced to its host. | |
| include_dns | No | Include DNS records (A, AAAA, MX, NS, TXT, SOA); default true. | |
| include_security | No | Include the SPF/DMARC email-security check; default true. |
Output Schema
| Name | Required | Description |
|---|---|---|
| dns | No | Records by type: A, AAAA, MX, NS, TXT, SOA. |
| error | No | Set only when there is no answer (empty_query, invalid_cui, data_unavailable, plan_required ...); such a call is not counted. |
| whois | No | registrar, creationDate, expirationDate, updatedDate, nameServers, registrantOrg, registrantCountry. |
| domain | No | The normalised domain. |
| message | No | A sentence for the caller. |
| security | No | hasSPF, spf, hasDMARC, dmarc. |
| resolvedIP | No | An address the domain resolves to. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare this a read-only, idempotent, open-world, non-destructive operation, so the safety profile is covered. The description adds that the lookup is split into DNS and email-security halves, but discloses nothing about rate limits, failures on non-existent domains, or external source variability that an agent would find useful.
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?
Three tight sentences with the payload list front-loaded and the toggles noted last. Nothing is padded, though the final toggle sentence is largely redundant with the schema.
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 values need no explanation here, and the description covers scope, toggles, and intended use. A note on behavior for non-existent or malformed domains would complete it, but it is otherwise sufficient 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?
Schema coverage is 100%, so all three parameters are fully documented in the schema, including defaults and the URL-to-host normalization. The description's note that include_dns/include_security toggle the two halves restates what the schema already conveys, so the baseline 3 applies.
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 (lookup) and resource (domain) and enumerates the concrete payloads: WHOIS, DNS records, and an SPF/DMARC email audit. This distinguishes it from the sibling company-lookup tools, which fetch entity data rather than domain infrastructure.
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?
"Use it to profile a company's web estate or check its email posture" gives clear context for when to reach for this tool. It stops short of naming an alternative or exclusion (e.g., when to prefer find_company_by_domain or enrich_company instead), so it is not a full when/when-not statement.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
lookup_financial_ratiosFinancial ratios and health scoreARead-onlyIdempotentInspect
Derived financial intelligence for a Romanian company: multi-year revenue trend (YoY, 3/5/10-year CAGR), margins, headcount, solvency and liquidity ratios, a 0-100 health score with its rule-by-rule breakdown, red flags, and peer percentiles within the same CAEN activity and county. Verdict: 'growing', 'stable' or 'distressed'. Use lookup_financials for the raw figures.
| Name | Required | Description | Default |
|---|---|---|---|
| cui | Yes | Romanian tax identification number (CUI), e.g. '2816464'; 'RO' and leading zeros are accepted. |
Output Schema
| Name | Required | Description |
|---|---|---|
| cui | No | The firm's CUI. |
| asOf | No | What to cite: registry (ONRC snapshot date), financialYear (fiscal year of the figures), anaf (day of the ANAF data), snapshot, published, source. |
| error | No | Set only when there is no answer (empty_query, invalid_cui, data_unavailable, plan_required ...); such a call is not counted. |
| flags | No | Red flags. |
| found | No | Whether any filing is on record. |
| peers | No | Percentiles within the same CAEN activity and county. |
| total | No | Number of fiscal years used. |
| years | No | Per fiscal year figures and margins. |
| ratios | No | Margins, equity ratio, debt to equity, liquidity, returns. |
| source | No | Data source: onrc (registry) or mfp (Ministry of Finance filings). |
| history | No | Years on record, loss years, revenue peak. |
| message | No | A sentence for the caller. |
| signals | No | The distress signals found. |
| verdict | No | growing, stable or distressed. |
| distress | No | true when the distress signals fire. |
| headcount | No | Latest headcount and its change. |
| attribution | No | The credit line to keep when redistributing the data (CC BY 4.0). |
| healthScore | No | 0-100 score, band and its rule-by-rule components. |
| revenueTrend | No | Latest revenue, YoY growth, 3/5/10-year CAGR, trend label. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive/non-open-world, so safety is covered. The description adds real behavioral value beyond that: the discrete verdict enum ('growing'/'stable'/'distressed'), the presence of a rule-by-rule health-score breakdown, red flags and peer-percentile benchmarking. It omits any note on data freshness or what happens for companies with sparse filings.
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: the payload of the tool is stated first, with the sibling routing instruction last. The opening sentence is a long comma-separated enumeration, but each item is a distinct returned artifact rather than filler, so it stays efficient.
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 values need not be restated, yet the description still gives the agent the semantic shape (verdict enum, health-score breakdown, peer grouping by CAEN and county) plus scope and the alternative tool. Nothing needed to select or call 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?
Only one parameter and schema coverage is 100%, with the schema itself documenting the CUI format and the 'RO'/leading-zero tolerance. The description adds no further meaning about the identifier, so the baseline 3 for schema-covered params applies.
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+resource and enumerates exactly what 'derived financial intelligence' means: YoY/3-5-10y CAGR, margins, headcount, solvency/liquidity ratios, a 0-100 health score, red flags, peer percentiles. It explicitly distinguishes itself from the sibling lookup_financials ('raw figures'), so an agent can separate 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?
Names the alternative (lookup_financials) and the condition that selects it ('for the raw figures'), and scopes the tool to Romanian companies via the CUI input. It does not state prerequisites, failure modes (e.g. company with no filed statements), or exclusions beyond that one routing sentence, so it stops short of a full when/when-not map.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
lookup_financialsAnnual financial statementsARead-onlyIdempotentInspect
Annual financial statements for a Romanian company from Ministry of Finance filings, every fiscal year on record since 2008: revenue, profit, headcount and balance-sheet lines in RON with each year's ratios (growth, margins, equity ratio, liquidity), plus a summary (3/5/10-year CAGR, loss years, health score). Resolve the firm with lookup_business first if you only have a name.
| Name | Required | Description | Default |
|---|---|---|---|
| cui | Yes | Romanian tax identification number (CUI), e.g. '2816464'; 'RO' and leading zeros are accepted. |
Output Schema
| Name | Required | Description |
|---|---|---|
| cui | No | The firm's CUI. |
| asOf | No | What to cite: registry (ONRC snapshot date), financialYear (fiscal year of the figures), anaf (day of the ANAF data), snapshot, published, source. |
| error | No | Set only when there is no answer (empty_query, invalid_cui, data_unavailable, plan_required ...); such a call is not counted. |
| found | No | Whether any filing is on record. |
| total | No | Number of fiscal years returned. |
| years | No | Per fiscal year: revenue, profit, loss, netResult, employees, assets, debt, equity (RON) and that year's ratios. |
| source | No | Data source: onrc (registry) or mfp (Ministry of Finance filings). |
| message | No | A sentence for the caller. |
| summary | No | History, revenue growth (3/5/10-year CAGR), latest ratios, health score and band, flags. |
| attribution | No | The credit line to keep when redistributing the data (CC BY 4.0). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, destructiveHint=false and a closed world, so the safety profile is covered. The description adds genuine value beyond that: the data source (Ministry of Finance filings), historical depth (every fiscal year since 2008), currency (RON), and the name-resolution prerequisite. Rate limits, auth, and coverage gaps (e.g. missing years, firms never filing) are unmentioned.
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 payload is front-loaded into one dense sentence and the routing rule is a short second sentence, so nothing is buried. The enumerated field list is long but each item is informative rather than 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?
With an output schema present, the return format need not be explained, and annotations cover the safety profile; the description still supplies source, currency, and historical coverage. The remaining gap is the unresolved overlap with lookup_financial_ratios, which an agent facing both tools would need to disambiguate.
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?
There is a single parameter and the schema description coverage is 100%, with the schema itself documenting the CUI format, examples, and acceptance of 'RO' and leading zeros. The description adds no parameter-level meaning, so the baseline 3 applies.
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 unusually concrete scope: annual statements for a Romanian company sourced from Ministry of Finance filings, every fiscal year since 2008, including named line items in RON. It stops short of drawing the boundary against the sibling lookup_financial_ratios, whose territory (ratios) this description also claims, so an agent must guess which to call for ratio-only needs.
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 gives the prerequisite path: resolve the firm with lookup_business first when only a name is available, which is real routing guidance. It offers no when-to-use versus lookup_financial_ratios or the other lookup_* siblings, so selection among overlapping tools 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.
match_companiesMatch a list of records to firmsARead-onlyIdempotentInspect
Match a list of up to 500 records (name, optional county, domain or CUI) to Romanian firms: each row gets match {cui, companyName, confidence, matchedOn} and the record, or no_match with up to 3 candidates. A valid CUI wins (confidence 1.0). Each row counts as one lookup; a batch larger than what is left today is refused whole.
| Name | Required | Description | Default |
|---|---|---|---|
| rows | Yes | Up to 500 records, each {name, county, domain, cui, ref} (any of them; ref is your own id, echoed back), or a bare string (a CUI, a domain or a name). | |
| fields | No | Optional: keep only these company fields in each row, comma-separated (companyName,cui,county,risk; dotted paths such as risk.level work). Without it the full record is returned. | |
| compact | No | Optional: true keeps a short preset per row (name, CUI, county, city, legal form, risk level and what it did not check, phone, website, latest revenue and headcount, record url). |
Output Schema
| Name | Required | Description |
|---|---|---|
| asOf | No | What to cite: registry (ONRC snapshot date), financialYear (fiscal year of the figures), anaf (day of the ANAF data), snapshot, published, source. |
| error | No | Set only when there is no answer (empty_query, invalid_cui, data_unavailable, plan_required ...); such a call is not counted. |
| total | No | Number of input rows. |
| errors | No | Rows that are input errors (nothing to match on). |
| fields | No | The company fields kept when fields or compact trimmed the rows. |
| source | No | Data source: onrc (registry) or mfp (Ministry of Finance filings). |
| matched | No | Rows matched to a firm. |
| message | No | A sentence for the caller. |
| noMatch | No | Rows with no match above the threshold. |
| results | No | Per row: row, input, status (matched or no_match), match {cui, companyName, confidence, matchedOn}, company, or candidates. |
| metering | No | What the batch cost: rows, counted, notCounted (input-error rows are not counted) and the rule. |
| warnings | No | Notes on how the request was read (a clamped limit, a widened CAEN code, an ignored field). |
| threshold | No | Confidence a row needs to be matched (0-1). |
| attribution | No | The credit line to keep when redistributing the data (CC BY 4.0). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover safety (readOnly, idempotent, non-destructive, closed-world), so the bar is lower, yet the description adds real operational context: each row consumes one lookup, an over-quota batch is refused atomically, and a valid CUI forces confidence 1.0. It stops short of covering rate limits or partial-failure behavior in detail.
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?
Three dense sentences, front-loaded with the core action and the 500-row cap. The inline {cui, companyName, confidence, matchedOn} output spec is slightly heavy but 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?
Given a 3-parameter tool with a full schema and an output schema, the description covers the matching rules, quota cost, and all-or-nothing batch refusal. The main gap is sibling routing, which contextual completeness does not fully resolve.
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 100%, so the schema already documents rows, fields, and compact fully. The description's field list and CUI rule largely restate schema content, earning the baseline 3 rather than adding new parameter meaning.
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 (match) and resource (a list of up to 500 records) against Romanian firms, and makes the batch nature explicit. It is clearly distinguishable from single-record siblings like find_company_by_domain or lookup_companies.
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?
The batch use case is implied and the row-quota mechanics are explained, but the description never states when to choose this tool over siblings such as lookup_companies or enrich_company. Usage is inferable rather than guided.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
poll_watchlistCollect watchlist changesAInspect
Collect everything the watch tools have found: call it to drain the changeset for every watch owned by your API key, most severe first. Company watches return an 'updated' entry with the changed fields and risk; CAEN and county watches return the 'new' firms registered since the last poll (200 a poll, the rest next).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | No | true when the poll ran. |
| asOf | No | What to cite: registry (ONRC snapshot date), financialYear (fiscal year of the figures), anaf (day of the ANAF data), snapshot, published, source. |
| error | No | Set only when there is no answer (empty_query, invalid_cui, data_unavailable, plan_required ...); such a call is not counted. |
| owner | No | Whose watches these are (key prefix or IP). |
| total | No | Number of watches with news. |
| active | No | Every watch you hold, changed or not: kind (company or caen), target (CUI or code), county, since, name. Remove one with unwatch. |
| message | No | A sentence for the caller. |
| watches | No | Per watch: an 'updated' company with its changed fields and risk, or the 'new' firms registered in a watched activity. |
| attribution | No | The credit line to keep when redistributing the data (CC BY 4.0). |
| email_alerts | No | How to get the same changes by email. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare readOnlyHint=false, idempotentHint=false and destructiveHint=false, and the description explains exactly why: 'drain the changeset' discloses that collection consumes/mutates the pending changeset state, and 'since the last poll (200 a poll, the rest next)' discloses the non-idempotent pagination cap. It also describes ordering ('most severe first') and the differing output shapes for company vs CAEN/county watches, which is well beyond what the annotations convey.
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?
Two sentences, tightly front-loaded with what the tool does and why, followed by the output and pagination details. Every clause earns its place with no filler or repetition of the title.
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 values need not be explained, yet the description still summarizes the two result shapes ('updated' entries with fields and risk, 'new' firms for CAEN/county) and the 200-per-poll limit. For a zero-parameter polling tool, 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?
The tool takes zero parameters, so per the baseline the description carries no parameter burden beyond baseline 4. Schema coverage is 100% (empty object), and there is nothing in the parameter surface for the description to compensate for.
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 description uses a specific verb ('Collect... drain the changeset') and resource ('every watch owned by your API key'), and it explicitly frames itself against the sibling watch tools that create the watches. An agent can distinguish this from watch_company/watch_caen/unwatch 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?
It clearly establishes the context of use: call this to drain what the watch tools have found for your API key. It implies the setup/consume relationship with the watch_* siblings, but it never states when not to call it or names an explicit alternative (e.g., unwatch to stop collection).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
report_issueReport missing or wrong dataAInspect
Tell the Leadgen founder what is missing or wrong: a missing field, firm or source (kind 'gap'), a wrong company record ('wrong_record', pass its cui), a bug, an idea. Free, never counted as a lookup. contact is optional (an address for a reply); nothing is mailed to it automatically. Registry records are corrected at the source (ONRC) and arrive with the next snapshot.
| Name | Required | Description | Default |
|---|---|---|---|
| cui | No | Optional CUI of the firm the report is about (for 'wrong_record'). | |
| kind | No | One of 'gap' (a missing field, firm or source; the default), 'wrong_record' (pass its cui), 'bug', 'idea', 'other'. | gap |
| contact | No | Optional email address for a reply; nothing is mailed to it automatically. | |
| message | Yes | The report, in plain words: what is missing or wrong. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | The report's id. |
| kind | No | The kind filed. |
| note | No | For wrong_record: how registry records get corrected. |
| error | No | Set only when there is no answer (empty_query, invalid_cui, data_unavailable, plan_required ...); such a call is not counted. |
| status | No | received. |
| message | No | A sentence for the caller. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations (readOnlyHint=false, destructiveHint=false, idempotentHint=false) by disclosing cost (free, not counted as a lookup), notification behavior ('nothing is mailed to it automatically'), and downstream latency/workflow ('Registry records are corrected at the source (ONRC) and arrive with the next snapshot'). These are exactly the side-effect and expectation-setting details an agent cannot infer from 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 core action, then compresses the kind taxonomy, the cost guarantee, the contact caveat and the correction cadence into minimal prose. Every clause earns its place with no 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?
An output schema exists, so return values need no explanation. For a free-text report submission tool the description covers what to send, how to classify it, what it costs and what happens afterward, 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?
Schema description coverage is 100%, so the schema already documents cui, kind, contact and message. The description restates the kind taxonomy and cui usage and adds only the 'nothing is mailed automatically' clause, which is behavioral rather than semantic. Baseline 3 is appropriate when the schema carries the parameter burden.
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 ('Tell the Leadgen founder what is missing or wrong') and immediately enumerates the report categories, making it unmistakable against the sibling lookup/enrichment tools. An agent can tell this is a feedback channel, not a data-retrieval call, without opening 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?
Gives clear per-case routing: 'gap' for missing field/firm/source, 'wrong_record' plus its cui for a bad company record, plus bug and idea. It also supplies the incentive condition ('Free, never counted as a lookup'), which steers an agent away from treating it as a billable lookup. No explicit when-not-to-use or named alternative, so it falls short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
unwatchStop watching a company or activityAIdempotentInspect
Stop watching a company (cui) or a CAEN activity code (code, plus the county it was watched in, if any), on your API key: the watch and its baseline are removed. Unwatching something you do not watch changes nothing (removed: 0). poll_watchlist lists your active watches.
| Name | Required | Description | Default |
|---|---|---|---|
| cui | No | CUI of a watched firm (e.g. '2816464'); give this or code. | |
| code | No | A watched CAEN activity code (e.g. '6210'); give this or cui. | |
| county | No | With code: the county the code was watched in (diacritic-insensitive); omit for a nationwide watch. |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | No | true when the request was valid. |
| asOf | No | What to cite: registry (ONRC snapshot date), financialYear (fiscal year of the figures), anaf (day of the ANAF data), snapshot, published, source. |
| kind | No | company or caen. |
| error | No | Set only when there is no answer (empty_query, invalid_cui, data_unavailable, plan_required ...); such a call is not counted. |
| owner | No | Whose watches these are (key prefix or IP). |
| active | No | The watches you still hold (as in poll_watchlist). |
| county | No | The CAEN watch's county; null for nationwide or a company. |
| target | No | The CUI or CAEN code. |
| message | No | A sentence for the caller. |
| removed | No | 1 when the watch was removed, 0 when you did not hold it. |
| attribution | No | The credit line to keep when redistributing the data (CC BY 4.0). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description contradicts the destructiveHint: false annotation by stating that "the watch and its baseline are removed." Removing state is not an additive update, so the annotation and description are inconsistent. It also adds useful idempotence context ("removed: 0"), but the contradiction forces a 1 under the rules.
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?
It is front-loaded with the core action, packs relevant scope and behavior into three short sentences, and none of the text 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?
Given an output schema exists, the description need not explain return values. It covers the key inputs, removal semantics, idempotence, API key scope, and the related poll_watchlist alternative, so an agent has enough context 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 description coverage is 100%, so the schema already documents all three parameters. The description adds only a light mapping (cui=company, code=CAEN activity code, county conditional), which does not go meaningfully 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 description states a specific verb ("Stop watching") and resources ("a company (cui) or a CAEN activity code (code, plus the county...)"), and distinguishes itself from the opposite watch_* siblings and from poll_watchlist. An agent can identify the tool's scope without opening 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?
It gives clear context: stop watching a company or activity, on your API key, with a no-op if not watched, and points to poll_watchlist for active watches. It does not explicitly state when to use this versus watch_company/watch_caen, so it stops short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
watch_caenWatch an activity for new firmsAIdempotentInspect
Watch a CAEN activity code, optionally scoped to one county, for newly registered firms. A registration-date cutoff is the baseline: only firms registered after it are reported, and poll_watchlist slides the cutoff forward so each new firm surfaces once. A retired CAEN Rev.2 code (6201) also watches its Rev.3 successor (6210), with a warning.
| Name | Required | Description | Default |
|---|---|---|---|
| code | Yes | CAEN activity code to watch (e.g. '6210'); a retired Rev.2 code also watches its Rev.3 successor. | |
| county | No | Optional county name to scope the watch to (diacritic-insensitive); omit to watch nationwide. |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | No | true when the watch is in place. |
| asOf | No | What to cite: registry (ONRC snapshot date), financialYear (fiscal year of the figures), anaf (day of the ANAF data), snapshot, published, source. |
| error | No | Set only when there is no answer (empty_query, invalid_cui, data_unavailable, plan_required ...); such a call is not counted. |
| watch | No | kind, target, owner (key prefix), county, baseline. |
| message | No | A sentence for the caller. |
| warnings | No | Notes on how the request was read (a clamped limit, a widened CAEN code, an ignored field). |
| attribution | No | The credit line to keep when redistributing the data (CC BY 4.0). |
| alreadyWatching | No | true when you already held this watch (nothing changed). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover the safety profile (readOnlyHint=false, destructiveHint=false, idempotentHint=true), so the bar is lower. The description still adds real behavior beyond them: the registration-date baseline cutoff, the dedup guarantee that each firm surfaces once, and the retired Rev.2 → Rev.3 alias with a warning. It doesn't cover watch lifetime or how to remove the watch, hence not a 5.
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?
Three tight sentences: purpose first, then the cutoff/polling mechanics, then the edge case alias. No filler and the most important information is front-loaded.
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 values need not be described, and annotations carry the safety profile. The description covers scope, cutoff semantics, dedup, and the alias edge case; only watch lifecycle/auth requirements are unaddressed, which is a minor gap.
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 100% — both 'code' and 'county' are documented, including diacritic-insensitivity and nationwide default. The description's note about retired Rev.2 codes restates what the schema already says, adding no new parameter semantics, so the baseline 3 applies.
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 ('Watch a CAEN activity code') plus the scope ('for newly registered firms'), which cleanly separates it from watch_company (single firm) and unwatch. An agent can identify what is being created without opening 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?
The description explains the workflow relationship to poll_watchlist ('slides the cutoff forward so each new firm surfaces once'), which tells the agent when this tool's output will be consumed. It stops short of an explicit when-not/exclusion rule against the sibling watch tools, so it lands at clear context without routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
watch_companyWatch a company for changesAIdempotentInspect
Register a company (by CUI) to monitor. Stores a fingerprint of its current registry record as the baseline; poll_watchlist then reports changes between monthly ONRC snapshots - a new director, a new CAEN activity, an address or status change - and when ANAF declares it fiscally inactive or its VAT status flips.
| Name | Required | Description | Default |
|---|---|---|---|
| cui | Yes | Romanian tax identification number (CUI) of the firm to watch, e.g. '2816464'. Watching a firm you already watch changes nothing. |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | No | true when the watch is in place. |
| asOf | No | What to cite: registry (ONRC snapshot date), financialYear (fiscal year of the figures), anaf (day of the ANAF data), snapshot, published, source. |
| error | No | Set only when there is no answer (empty_query, invalid_cui, data_unavailable, plan_required ...); such a call is not counted. |
| watch | No | kind, target, owner (key prefix), county, baseline. |
| message | No | A sentence for the caller. |
| attribution | No | The credit line to keep when redistributing the data (CC BY 4.0). |
| alreadyWatching | No | true when you already held this watch (nothing changed). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds substantial behavior beyond the annotations: it stores a fingerprint of the current registry record as a baseline, changes are computed between monthly ONRC snapshots, and it enumerates the change classes detected (director, CAEN activity, address, status, ANAF fiscal-inactivity, VAT flip). It also reinforces idempotency ('watching a firm you already watch changes nothing'), consistent with idempotentHint=true.
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?
A single dense sentence, front-loaded with the action, then the baseline mechanism, then the reported outcomes and cadence. No filler sentences and nothing repeated from the schema.
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 one required parameter, full schema coverage, an output schema, and annotations covering the safety profile, the description supplies everything else an agent needs: what registration stores, when results appear (monthly snapshots), and via which sibling.
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 100% and the schema already defines CUI with an example plus the idempotency note. The description only restates 'by CUI', adding no format or constraint detail beyond the schema, so the baseline 3 applies.
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 concrete verb+resource ('Register a company ... to monitor') and immediately names the downstream consumer (poll_watchlist), which separates it from siblings like watch_caen and unwatch. An agent can pick it without opening 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?
Explains the workflow context clearly: register here, then poll_watchlist reports changes. It does not state exclusions or explicitly contrast with watch_caen (CAEN-specific watching) or unwatch, so it stops short of full 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.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
11 tool updates
v0.1.3- Changed
enrich_company1 field changed- changed
Output schema / properties / company / descriptionPrevious value: -"A company record: companyName, cui, registrationCode, registrationDate (DD/MM/YYYY), legalForm, euid, address, county, city, website, phone, caenActivities [{code, activity}], directors, status [{code, name}], latestFinancials {year, revenue, netResult, employees; RON}, anaf {mainCaen, vatPayer, eFactura, inactive}, risk {level, label, reasons, isLead}, source, asOf, and score/match on name searches. With fields or compact, only the requested keys."New value: +"A company record: companyName, cui, registrationCode, registrationDate (DD/MM/YYYY), legalForm, euid, address, county, city, website, phone, caenActivities [{code, activity (RO), activityEn}], directors, representatives [{name, role}], status [{code, name}], latestFinancials {year, revenue, netResult, employees; RON}, anaf {mainCaen, vatPayer, eFactura, inactive}, risk {level, label, reasons, isLead}, source, asOf, url (the firm's public record page to share with the user; null for sole traders and other natural persons), and score/match on name searches. With fields or compact, only the requested keys (compact keeps url)."
- Changed
find_company_by_domain3 fields changed- changed
Input schema / properties / compact / descriptionPrevious value: -"Optional: true keeps a short preset per row (name, CUI, county, city, legal form, risk level, phone, website, latest revenue and headcount)."New value: +"Optional: true keeps a short preset per row (name, CUI, county, city, legal form, risk level and what it did not check, phone, website, latest revenue and headcount, record url)." - changed
Output schema / properties / candidates / descriptionPrevious value: -"When not found: up to 3 firms whose name matches the page title."New value: +"When not found (also when the site cannot be read): up to 3 firms whose name matches the page title or the domain name, each with a confidence (at most 0.7)." - changed
Output schema / properties / results / items / descriptionPrevious value: -"A company record: companyName, cui, registrationCode, registrationDate (DD/MM/YYYY), legalForm, euid, address, county, city, website, phone, caenActivities [{code, activity}], directors, status [{code, name}], latestFinancials {year, revenue, netResult, employees; RON}, anaf {mainCaen, vatPayer, eFactura, inactive}, risk {level, label, reasons, isLead}, source, asOf, and score/match on name searches. With fields or compact, only the requested keys."New value: +"A company record: companyName, cui, registrationCode, registrationDate (DD/MM/YYYY), legalForm, euid, address, county, city, website, phone, caenActivities [{code, activity (RO), activityEn}], directors, representatives [{name, role}], status [{code, name}], latestFinancials {year, revenue, netResult, employees; RON}, anaf {mainCaen, vatPayer, eFactura, inactive}, risk {level, label, reasons, isLead}, source, asOf, url (the firm's public record page to share with the user; null for sole traders and other natural persons), and score/match on name searches. With fields or compact, only the requested keys (compact keeps url)."
- Changed
lookup_business3 fields changed- changed
Input schema / properties / compact / descriptionPrevious value: -"Optional: true keeps a short preset per row (name, CUI, county, city, legal form, risk level, phone, website, latest revenue and headcount)."New value: +"Optional: true keeps a short preset per row (name, CUI, county, city, legal form, risk level and what it did not check, phone, website, latest revenue and headcount, record url)." - changed
Output schema / properties / results / items / descriptionPrevious value: -"A company record: companyName, cui, registrationCode, registrationDate (DD/MM/YYYY), legalForm, euid, address, county, city, website, phone, caenActivities [{code, activity}], directors, status [{code, name}], latestFinancials {year, revenue, netResult, employees; RON}, anaf {mainCaen, vatPayer, eFactura, inactive}, risk {level, label, reasons, isLead}, source, asOf, and score/match on name searches. With fields or compact, only the requested keys."New value: +"A company record: companyName, cui, registrationCode, registrationDate (DD/MM/YYYY), legalForm, euid, address, county, city, website, phone, caenActivities [{code, activity (RO), activityEn}], directors, representatives [{name, role}], status [{code, name}], latestFinancials {year, revenue, netResult, employees; RON}, anaf {mainCaen, vatPayer, eFactura, inactive}, risk {level, label, reasons, isLead}, source, asOf, url (the firm's public record page to share with the user; null for sole traders and other natural persons), and score/match on name searches. With fields or compact, only the requested keys (compact keeps url)." - changed
Output schema / properties / total / descriptionPrevious value: -"Number of companies returned."New value: +"Rows returned in this answer (at most max_results), not the number of firms that match."
- Changed
lookup_by_category16 fields changed- changed
Input schema / properties / compact / descriptionPrevious value: -"Optional: true keeps a short preset per row (name, CUI, county, city, legal form, risk level, phone, website, latest revenue and headcount)."New value: +"Optional: true keeps a short preset per row (name, CUI, county, city, legal form, risk level and what it did not check, phone, website, latest revenue and headcount, record url)." - changed
Input schema / properties / county / descriptionPrevious value: -"Optional county name to narrow to (diacritic-insensitive: 'bucuresti', 'cluj'); omit for nationwide."New value: +"Optional county to narrow to (diacritic-insensitive: 'bucuresti', 'cluj'; a county town such as 'Cluj-Napoca' or a Bucharest sector is read as its county); omit for nationwide. An unknown county is an error (unknown_county) with suggestions, not 0 firms." - changed
Input schema / properties / main_activity_only / descriptionPrevious value: -"true keeps firms whose declared main activity (ANAF main CAEN, else the CAEN on the latest filing) is one of the codes, instead of any authorised activity (default false)."New value: +"Default false: a firm matches when the code is ANY of its authorised activities (ONRC lists a dozen per firm, most never practised). true keeps only firms whose DECLARED main activity is one of the codes (ANAF main CAEN, else the CAEN on the latest filing): fewer, more relevant firms. The Leadgen app's lists use true by default." - added
Input schema / properties / sortAdded value: +{ + "default": "newest", + "description": "Order of the results: 'newest' registrations first (default), 'revenue' (latest filing's turnover, biggest first) or 'employees' (headcount, biggest first); firms without a filing come last.", + "enum": [ + "newest", + "revenue", + "employees" + ], + "title": "Sort", + "type": "string" +} - changed
Output schema / descriptionPrevious value: -"A lead list: firms in an activity, newest registration first."New value: +"A lead list: firms in an activity, newest registration first (or by turnover / headcount: sort)." - added
Output schema / properties / appUrlAdded value: +{ + "description": "The same list opened in the Leadgen app (CAEN codes, county, legal form, active and main-activity filters), to share with the user; null when the app cannot open it (more than 10 codes, a legal form it does not offer).", + "type": [ + "string", + "null" + ] +} - added
Output schema / properties / availableTopicNamesAdded value: +{ + "description": "Each curated topic id with its name, e.g. {\"agriculture\": \"Agriculture & Food\"}, next to availableTopics.", + "type": [ + "object", + "null" + ] +} - changed
Output schema / properties / availableTopics / descriptionPrevious value: -"The curated topics, when the topic is unknown."New value: +"The curated topic ids, when the topic is unknown or ambiguous." - added
Output schema / properties / caenNamesAdded value: +{ + "description": "The CAEN codes as asked, named: [{code, title (Romanian), titleEn}].", + "type": [ + "array", + "null" + ] +} - added
Output schema / properties / matchTotalAdded value: +{ + "description": "How many firms the whole list holds with every filter (active_only on; null when off): exact, or estimated when matchTotalApproximate is true.", + "type": [ + "integer", + "null" + ] +} - added
Output schema / properties / matchTotalApproximateAdded value: +{ + "description": "true when matchTotal is estimated (matchTotalMargin: its 99% margin).", + "type": [ + "boolean", + "null" + ] +} - added
Output schema / properties / matchTotalMarginAdded value: +{ + "description": "The 99% margin of an estimated matchTotal.", + "type": [ + "integer", + "null" + ] +} - changed
Output schema / properties / results / items / descriptionPrevious value: -"A company record: companyName, cui, registrationCode, registrationDate (DD/MM/YYYY), legalForm, euid, address, county, city, website, phone, caenActivities [{code, activity}], directors, status [{code, name}], latestFinancials {year, revenue, netResult, employees; RON}, anaf {mainCaen, vatPayer, eFactura, inactive}, risk {level, label, reasons, isLead}, source, asOf, and score/match on name searches. With fields or compact, only the requested keys."New value: +"A company record: companyName, cui, registrationCode, registrationDate (DD/MM/YYYY), legalForm, euid, address, county, city, website, phone, caenActivities [{code, activity (RO), activityEn}], directors, representatives [{name, role}], status [{code, name}], latestFinancials {year, revenue, netResult, employees; RON}, anaf {mainCaen, vatPayer, eFactura, inactive}, risk {level, label, reasons, isLead}, source, asOf, url (the firm's public record page to share with the user; null for sole traders and other natural persons), and score/match on name searches. With fields or compact, only the requested keys (compact keeps url)." - added
Output schema / properties / sortAdded value: +{ + "description": "The order of results: newest, revenue or employees.", + "type": [ + "string", + "null" + ] +} - changed
Output schema / properties / total / descriptionPrevious value: -"Number of companies returned."New value: +"Rows returned in this answer (at most max_results), not the size of the match set: a full page (total == max_results) may have more; narrow the filters or raise max_results." - changed
Output schema / properties / truncated / descriptionPrevious value: -"true when more firms match than were returned."New value: +"true when max_results was cut to the list cap (and the list is full)."
- Changed
lookup_companies2 fields changed- changed
Input schema / properties / compact / descriptionPrevious value: -"Optional: true keeps a short preset per row (name, CUI, county, city, legal form, risk level, phone, website, latest revenue and headcount)."New value: +"Optional: true keeps a short preset per row (name, CUI, county, city, legal form, risk level and what it did not check, phone, website, latest revenue and headcount, record url)." - changed
Output schema / properties / results / items / properties / company / descriptionPrevious value: -"A company record: companyName, cui, registrationCode, registrationDate (DD/MM/YYYY), legalForm, euid, address, county, city, website, phone, caenActivities [{code, activity}], directors, status [{code, name}], latestFinancials {year, revenue, netResult, employees; RON}, anaf {mainCaen, vatPayer, eFactura, inactive}, risk {level, label, reasons, isLead}, source, asOf, and score/match on name searches. With fields or compact, only the requested keys."New value: +"A company record: companyName, cui, registrationCode, registrationDate (DD/MM/YYYY), legalForm, euid, address, county, city, website, phone, caenActivities [{code, activity (RO), activityEn}], directors, representatives [{name, role}], status [{code, name}], latestFinancials {year, revenue, netResult, employees; RON}, anaf {mainCaen, vatPayer, eFactura, inactive}, risk {level, label, reasons, isLead}, source, asOf, url (the firm's public record page to share with the user; null for sole traders and other natural persons), and score/match on name searches. With fields or compact, only the requested keys (compact keeps url)."
- Changed
lookup_director2 fields changed- changed
Input schema / properties / compact / descriptionPrevious value: -"Optional: true keeps a short preset per row (name, CUI, county, city, legal form, risk level, phone, website, latest revenue and headcount)."New value: +"Optional: true keeps a short preset per row (name, CUI, county, city, legal form, risk level and what it did not check, phone, website, latest revenue and headcount, record url)." - changed
Output schema / properties / results / items / descriptionPrevious value: -"A company record: companyName, cui, registrationCode, registrationDate (DD/MM/YYYY), legalForm, euid, address, county, city, website, phone, caenActivities [{code, activity}], directors, status [{code, name}], latestFinancials {year, revenue, netResult, employees; RON}, anaf {mainCaen, vatPayer, eFactura, inactive}, risk {level, label, reasons, isLead}, source, asOf, and score/match on name searches. With fields or compact, only the requested keys."New value: +"A company record: companyName, cui, registrationCode, registrationDate (DD/MM/YYYY), legalForm, euid, address, county, city, website, phone, caenActivities [{code, activity (RO), activityEn}], directors, representatives [{name, role}], status [{code, name}], latestFinancials {year, revenue, netResult, employees; RON}, anaf {mainCaen, vatPayer, eFactura, inactive}, risk {level, label, reasons, isLead}, source, asOf, url (the firm's public record page to share with the user; null for sole traders and other natural persons), and score/match on name searches. With fields or compact, only the requested keys (compact keeps url)."
- Changed
match_companies2 fields changed- changed
Input schema / properties / compact / descriptionPrevious value: -"Optional: true keeps a short preset per row (name, CUI, county, city, legal form, risk level, phone, website, latest revenue and headcount)."New value: +"Optional: true keeps a short preset per row (name, CUI, county, city, legal form, risk level and what it did not check, phone, website, latest revenue and headcount, record url)." - changed
Output schema / properties / results / items / properties / company / descriptionPrevious value: -"A company record: companyName, cui, registrationCode, registrationDate (DD/MM/YYYY), legalForm, euid, address, county, city, website, phone, caenActivities [{code, activity}], directors, status [{code, name}], latestFinancials {year, revenue, netResult, employees; RON}, anaf {mainCaen, vatPayer, eFactura, inactive}, risk {level, label, reasons, isLead}, source, asOf, and score/match on name searches. With fields or compact, only the requested keys."New value: +"A company record: companyName, cui, registrationCode, registrationDate (DD/MM/YYYY), legalForm, euid, address, county, city, website, phone, caenActivities [{code, activity (RO), activityEn}], directors, representatives [{name, role}], status [{code, name}], latestFinancials {year, revenue, netResult, employees; RON}, anaf {mainCaen, vatPayer, eFactura, inactive}, risk {level, label, reasons, isLead}, source, asOf, url (the firm's public record page to share with the user; null for sole traders and other natural persons), and score/match on name searches. With fields or compact, only the requested keys (compact keeps url)."
- Changed
poll_watchlist2 fields changed- added
Output schema / properties / activeAdded value: +{ + "description": "Every watch you hold, changed or not: kind (company or caen), target (CUI or code), county, since, name. Remove one with unwatch.", + "type": [ + "array", + "null" + ] +} - added
Output schema / properties / attributionAdded value: +{ + "description": "The credit line to keep when redistributing the data (CC BY 4.0).", + "type": [ + "string", + "null" + ] +}
- Added
unwatch - Changed
watch_caen1 field changed- added
Output schema / properties / attributionAdded value: +{ + "description": "The credit line to keep when redistributing the data (CC BY 4.0).", + "type": [ + "string", + "null" + ] +}
- Changed
watch_company1 field changed- added
Output schema / properties / attributionAdded value: +{ + "description": "The credit line to keep when redistributing the data (CC BY 4.0).", + "type": [ + "string", + "null" + ] +}
16 tool updates
v0.1.0- First observed
enrich_company - First observed
extract_contacts - First observed
find_company_by_domain - First observed
get_usage - First observed
lookup_business - First observed
lookup_by_category - First observed
lookup_companies - First observed
lookup_director - First observed
lookup_domain - First observed
lookup_financial_ratios - First observed
lookup_financials - First observed
match_companies - First observed
poll_watchlist - First observed
report_issue - First observed
watch_caen - First observed
watch_company
TDQS
Scored across 17 tools
Most tools target distinct resources or actions, and the detailed descriptions clarify boundaries well. However, lookup_business vs enrich_company, lookup_financials vs lookup_financial_ratios, and lookup_companies vs match_companies have adjacent purposes that could occasionally cause misselection.
All tool names use snake_case with clear verb/object structure, making the set predictable. Minor deviations exist, such as lookup_by_category and find_company_by_domain using prepositions, and unwatch lacking an explicit object.
17 tools is slightly above the ideal 3–15 range, but the server covers a broad leadgen domain including lookup, matching, enrichment, financials, monitoring, and utilities. Each tool has a plausible role, though a few adjacent lookup tools could be consolidated.
The surface covers core Romanian company workflows: search by category/name/director/domain, batch lookup and matching, enrichment, financial statements and ratios, contact extraction, domain profiling, monitoring, usage, and issue reporting. Minor gaps remain, such as no explicit address/phone search or bulk financial retrieval, but there are no major dead ends.
Maintenance
Related MCP Connectors
AI-agent marketplace: agent templates, web search & crawl, SEO audit, RO company data, city info.
Lead enrichment for AI agents: email finder, company enrichment, people data, firmographics.
Global B2B intelligence for AI agents: 35M+ companies, 1.6M sanctions, KYB pack. 78 tools.
Search companies, enrich contacts, and reveal emails and phones from your AI agent.
Related MCP Servers
- AlicenseAqualityCmaintenanceStructured business intelligence for AI agents. 11.3M verified entities, 40.3M BORME mercantile acts, EU VAT validation (VIES), GLEIF LEI and healthcare registries. 12 tools.61MIT
- AlicenseAqualityAmaintenanceOpenRegistry - the world's first MCP and API for live company filings directly from official government registries worldwide. 90+ countries.1022Apache 2.0
- AlicenseCqualityCmaintenanceEnables querying the Polish National Court Register (KRS) to retrieve current and historical entity data.241 npm4MIT
- AlicenseAqualityDmaintenanceEnables AI agents to research companies and find contacts with structured data from multiple free sources, including company info, tech stack, and email addresses.3MIT