# Creditsafe MCP - beta test report

> [!NOTE]
> Thank you for the beta access. This report describes what we tested, how, and what we observed, with suggestions meant to help make the MCP server even better for AI agents. Findings are observations from one tester's point of view, not judgements.

| | |
|---|---|
| Date | 2026-10-22 09:10 |
| Server | `creditsafe-mcp 1022346` |
| Tools | 18 exposed, 16 called at least once |
| Test cases | 98 (95 executed, 3 skipped) |
| Result | 🟢 PASS **55** &nbsp; 🟠 WARN **37** &nbsp; 🔴 FAIL **3** |

🟢 PASS = behaves as expected &nbsp;|&nbsp; 🟠 WARN = works, worth improving (clarity, size, speed, wording) &nbsp;|&nbsp; 🔴 FAIL = wrong, missing, or unusable by an agent

## Executive summary

> [!IMPORTANT]
> The server is reachable and usable: **55 of 95** executed scenarios behave as expected, 37 work but can be improved and 3 fail. Most opportunities concern being **LLM-agent friendly**, in order of impact:
>
> - 🔴 **Functional behaviour differing from expectations** (3)
> - 🔴 **Responses too large for an LLM context window** (3)
> - 🟠 **Errors returned as successful results** (26)
> - 🟠 **Tool and parameter documentation gaps** (21)
> - 🟠 **Missing MCP metadata (annotations, outputSchema)** (18)

## 1. What was tested

Two complementary angles, applied to every tool:

1. **Functional**: does each tool return correct, complete data for realistic requests (search by name / SIREN / VAT / safe number, France, United Kingdom, Germany with legal `reason_code`, directors, group structure, beneficial owners, events, adverse information, financials, payment behaviour)?
2. **MCP / LLM-agent oriented**: is the server pleasant for an AI agent? Size of results versus context window, error contract (`isError`), actionable error messages, quality of tool definitions (descriptions, parameter docs, annotations, output schema), latency, noise in payloads, behaviour on invalid or hostile input.

| Category | Cases | 🟢 PASS | 🟠 WARN | 🔴 FAIL | ⚪ SKIP |
|---|---|---|---|---|---|
| Account and metadata | 11 | 8 | 2 | 1 | 0 |
| Company search | 19 | 16 | 3 | 0 | 0 |
| Company reports - France | 22 | 13 | 7 | 2 | 0 |
| Company reports - United Kingdom | 15 | 10 | 5 | 0 | 0 |
| Company reports - Germany (reason_code) | 7 | 1 | 6 | 0 | 0 |
| Directors | 8 | 5 | 3 | 0 | 0 |
| Robustness and error handling | 13 | 2 | 11 | 0 | 0 |
| Paid calls (--paid) | 3 | 0 | 0 | 0 | 3 |

## 2. How it was tested

- Black-box: a Python client speaks the real MCP protocol (Streamable HTTP) to the beta endpoint, exactly like an agent would. No access to server internals.
- Sequence mimics a human tester: discovery (`list_tools`), then searches, then every company tool on FR / GB / DE, directors, then edge cases (empty, very long, special characters, wrong types, unknown tool, invalid country / `reason_code`).
- Test company without stake: BearingPoint France (SIREN 443021241); UK and DE examples taken from Creditsafe's own tool descriptions.
- Each case opens a fresh session so a transport failure only affects that case.
- Each response is evaluated automatically against: expected outcome (success / error / not found), `isError` flag, presence of an actionable hint, size in characters and estimated tokens, share of empty fields, duration, JSON validity, raw technical text leaks.
- Credit-consuming calls (`refresh=True`, PDF, director report) are skipped unless explicitly enabled.
- Full requests/responses are kept in `verbose.log` and `raw.jsonl`; the API key is redacted everywhere.

## 3. Results in general

### What works well

<details><summary>🟢 PASS <b>Account and metadata</b> (8)</summary>

- 1.01 Account access and entitlements
- 1.02 Supported countries
- 1.03 Search fields for France
- 1.04 Search fields for several countries
- 1.06 Report languages, France
- 1.07 Report languages, UK
- 1.08 Report schema, France (summary)
- 1.09 Report schema, UK (summary)

</details>

<details><summary>🟢 PASS <b>Company search</b> (16)</summary>

- 2.01 Search by name, France
- 2.02 Search by registration number (SIREN)
- 2.03 Search by VAT number
- 2.04 Search by safe number, UK
- 2.05 Search by name, UK large company
- 2.06 Search, exact match
- 2.07 Search, multi-country
- 2.08 Search, city filter
- 2.09 Search, postcode filter
- 2.10 Search, status filter
- 2.11 Search, page_size=1
- 2.12 Search, page 2
- 2.14 Search with typo
- 2.15 Search with accents
- 2.18 Search, lowercase country
- 2.19 Search, unknown company

</details>

<details><summary>🟢 PASS <b>Company reports - France</b> (13)</summary>

- 3.01 get_company_overview, French company
- 3.02 get_company_financials, French company
- 3.03 get_company_payment_behaviour, French company
- 3.05 get_company_adverse_information, French company
- 3.06 get_company_group_structure, French company
- 3.07 get_company_beneficial_owners, French company
- 3.08 get_company_directors, French company
- 3.13 Overview without country
- 3.14 Overview repeated (cache check)
- 3.15 Financials, years=1
- 3.16 Financials, years=5
- 3.17 Financials, global basis
- 3.18 Financials, English

</details>

<details><summary>🟢 PASS <b>Company reports - United Kingdom</b> (10)</summary>

- 4.01 get_company_overview, UK company
- 4.02 get_company_financials, UK company
- 4.03 get_company_payment_behaviour, UK company
- 4.04 get_company_events, UK company
- 4.05 get_company_adverse_information, UK company
- 4.06 get_company_group_structure, UK company
- 4.08 get_company_directors, UK company
- 4.09 get_company_directorships, UK company
- 4.12 Overview by registration number
- 4.13 Financials with global basis

</details>

<details><summary>🟢 PASS <b>Company reports - Germany (reason_code)</b> (1)</summary>

- 5.06 FR overview with reason_code (should be ignored)

</details>

<details><summary>🟢 PASS <b>Directors</b> (5)</summary>

- 6.01 Search directors, UK
- 6.02 Search directors, France
- 6.03 Search directors, multi-country
- 6.04 Search directors with date of birth
- 6.05 Search directors, malformed date

</details>

<details><summary>🟢 PASS <b>Robustness and error handling</b> (2)</summary>

- 7.10 Unknown extra argument
- 7.11 Unknown tool

</details>

## 4. Points of attention (MCP / LLM-agent perspective)

### 🔴 Functional behaviour differing from expectations

**Why it matters**: The tool does not return what a user would expect for a valid request.

> [!TIP]
> **Suggestion**: See each case below.

<details><summary>Observed in 3 place(s)</summary>

- 🔴 FAIL - 3.11 `get_company_overview`: Unexpected error: { "error": { "code": "ambiguous", "message": "Multiple companies match '443021241'.", "hint": "Use the Creditsafe ID, safe number, registration number, VAT, or add postcode/city.", "candidates": [ { "
- 🔴 FAIL - 3.12 `get_company_overview`: Unexpected error: { "error": { "code": "not_found", "message": "No company found for 'FR96443021241'.", "hint": "Try safe number, registration number, VAT number, or name plus postcode." } }
- 🟠 WARN - 5.01 `get_company_overview`: Expected 'reason' in the response

</details>

### 🔴 Responses too large for an LLM context window

**Why it matters**: An agent pastes every tool result into its context. Huge payloads crowd out the conversation, cost money on every following turn, or exceed the window entirely.

> [!TIP]
> **Suggestion**: Return a compact view by default; add a `fields`/`sections` parameter and pagination; announce truncation explicitly; keep raw payloads behind a separate opt-in tool.

<details><summary>Observed in 3 place(s)</summary>

- 🔴 FAIL - 1.11 `get_company_report_schema`: Response of 870,747 chars (~248,785 tokens) exceeds typical LLM context windows (100,000 tokens): the tool is unusable by an agent in this mode
- 🟠 WARN - 3.04 `get_company_events`: Very large response (83,199 chars, ~23,771 tokens): consumes a large share of an LLM context
- 🟠 WARN - definition of `(all tools)`: Tool definitions alone weigh ~11,122 tokens, paid on every LLM turn

</details>

### 🟠 Errors returned as successful results

**Why it matters**: MCP clients and agent frameworks rely on `isError=true` to trigger retry/repair logic. An `error` body inside a normal result looks like a success.

> [!TIP]
> **Suggestion**: Set `isError=true` on every failure, keeping the structured error body.

<details><summary>Observed in 26 place(s)</summary>

- 🟠 WARN - 1.05 `get_company_search_fields`: Error returned as a normal result (isError=false) with an 'error' JSON body: clients cannot detect the failure from the MCP flag
- 🟠 WARN - 1.10 `get_company_report_schema`: Error returned as a normal result (isError=false) with an 'error' JSON body: clients cannot detect the failure from the MCP flag
- 🟠 WARN - 2.16 `search_companies`: Error returned as a normal result (isError=false) with an 'error' JSON body: clients cannot detect the failure from the MCP flag
- 🟠 WARN - 2.17 `search_companies`: Error returned as a normal result (isError=false) with an 'error' JSON body: clients cannot detect the failure from the MCP flag
- 🟠 WARN - 3.09 `get_company_directorships`: Error returned as a normal result (isError=false) with an 'error' JSON body: clients cannot detect the failure from the MCP flag
- 🟠 WARN - 3.10 `get_company_overview`: Error returned as a normal result (isError=false) with an 'error' JSON body: clients cannot detect the failure from the MCP flag
- 🟠 WARN - 3.11 `get_company_overview`: Error returned as a normal result (isError=false) with an 'error' JSON body: clients cannot detect the failure from the MCP flag
- 🟠 WARN - 3.12 `get_company_overview`: Error returned as a normal result (isError=false) with an 'error' JSON body: clients cannot detect the failure from the MCP flag
- 🟠 WARN - 3.22 `get_company_directorships`: Error returned as a normal result (isError=false) with an 'error' JSON body: clients cannot detect the failure from the MCP flag
- 🟠 WARN - 4.07 `get_company_beneficial_owners`: Error returned as a normal result (isError=false) with an 'error' JSON body: clients cannot detect the failure from the MCP flag
- 🟠 WARN - 4.10 `get_company_overview`: Error returned as a normal result (isError=false) with an 'error' JSON body: clients cannot detect the failure from the MCP flag
- 🟠 WARN - 4.11 `get_company_overview`: Error returned as a normal result (isError=false) with an 'error' JSON body: clients cannot detect the failure from the MCP flag
- ... and 14 more (see appendix / results.xlsx)

</details>

### 🟠 Tool and parameter documentation gaps

**Why it matters**: The LLM chooses tools and fills arguments only from names and descriptions. Missing descriptions or valid values cause wrong calls.

> [!TIP]
> **Suggestion**: Describe every parameter (format, example, allowed values), use enums/patterns in the JSON schema.

<details><summary>Observed in 21 place(s)</summary>

- 🟠 WARN - 3.09 `get_company_directorships`: Product not available for this country: the refusal is clear and free of charge (good), but this is only discoverable by calling the tool; expose per-country availability in the tool description or in the supported-countries tool
- 🟠 WARN - 3.22 `get_company_directorships`: Product not available for this country: the refusal is clear and free of charge (good), but this is only discoverable by calling the tool; expose per-country availability in the tool description or in the supported-countries tool
- 🟠 WARN - 4.07 `get_company_beneficial_owners`: Product not available for this country: the refusal is clear and free of charge (good), but this is only discoverable by calling the tool; expose per-country availability in the tool description or in the supported-countries tool
- 🟠 WARN - definition of `get_company_search_fields`: Parameter 'countries' is a free string without enum/pattern: valid values are only discoverable by trial and error
- 🟠 WARN - definition of `get_report_languages`: Parameter 'country' is a free string without enum/pattern: valid values are only discoverable by trial and error
- 🟠 WARN - definition of `get_company_report_schema`: Parameter 'country' is a free string without enum/pattern: valid values are only discoverable by trial and error
- 🟠 WARN - definition of `get_company_overview`: Parameter 'language' has no description
- 🟠 WARN - definition of `get_company_financials`: Parameter 'years' has no description
- 🟠 WARN - definition of `get_company_financials`: Parameter 'language' has no description
- 🟠 WARN - definition of `get_company_payment_behaviour`: Parameter 'language' has no description
- 🟠 WARN - definition of `get_company_events`: Parameter 'language' has no description
- 🟠 WARN - definition of `get_company_adverse_information`: Parameter 'language' has no description
- ... and 9 more (see appendix / results.xlsx)

</details>

### 🟠 Missing MCP metadata (annotations, outputSchema)

**Why it matters**: Annotations let clients auto-approve read-only calls and warn on costly ones; outputSchema helps downstream parsing.

> [!TIP]
> **Suggestion**: Declare readOnlyHint / idempotentHint, flag credit-consuming tools, publish outputSchema.

<details><summary>Observed in 18 place(s)</summary>

- 🟠 WARN - definition of `get_my_creditsafe_access`: No outputSchema: the shape of the result is undocumented
- 🟠 WARN - definition of `get_supported_countries`: No outputSchema: the shape of the result is undocumented
- 🟠 WARN - definition of `get_company_search_fields`: No outputSchema: the shape of the result is undocumented
- 🟠 WARN - definition of `get_report_languages`: No outputSchema: the shape of the result is undocumented
- 🟠 WARN - definition of `get_company_report_schema`: No outputSchema: the shape of the result is undocumented
- 🟠 WARN - definition of `search_companies`: No outputSchema: the shape of the result is undocumented
- 🟠 WARN - definition of `get_company_overview`: No outputSchema: the shape of the result is undocumented
- 🟠 WARN - definition of `get_company_financials`: No outputSchema: the shape of the result is undocumented
- 🟠 WARN - definition of `get_company_payment_behaviour`: No outputSchema: the shape of the result is undocumented
- 🟠 WARN - definition of `get_company_events`: No outputSchema: the shape of the result is undocumented
- 🟠 WARN - definition of `get_company_adverse_information`: No outputSchema: the shape of the result is undocumented
- 🟠 WARN - definition of `get_company_group_structure`: No outputSchema: the shape of the result is undocumented
- ... and 6 more (see appendix / results.xlsx)

</details>

### 🟠 Raw framework / validation errors exposed

**Why it matters**: Stack-like or pydantic texts are noisy, hard for a model to act on, and leak implementation details.

> [!TIP]
> **Suggestion**: Map validation failures to short, friendly messages naming the field and the allowed range.

<details><summary>Observed in 9 place(s)</summary>

- 🟠 WARN - 2.13 `search_companies`: Message exposes raw technical details (framework validation text / traceback / 5xx)
- 🟠 WARN - 3.19 `get_company_financials`: Message exposes raw technical details (framework validation text / traceback / 5xx)
- 🟠 WARN - 3.20 `get_company_financials`: Message exposes raw technical details (framework validation text / traceback / 5xx)
- 🟠 WARN - 3.21 `get_company_financials`: Message exposes raw technical details (framework validation text / traceback / 5xx)
- 🟠 WARN - 5.04 `get_company_overview`: Message exposes raw technical details (framework validation text / traceback / 5xx)
- 🟠 WARN - 5.05 `get_company_overview`: Message exposes raw technical details (framework validation text / traceback / 5xx)
- 🟠 WARN - 6.07 `search_directors`: Message exposes raw technical details (framework validation text / traceback / 5xx)
- 🟠 WARN - 7.08 `get_company_overview`: Message exposes raw technical details (framework validation text / traceback / 5xx)
- 🟠 WARN - 7.09 `get_company_financials`: Message exposes raw technical details (framework validation text / traceback / 5xx)

</details>

### 🟠 Errors that do not tell the model how to recover

**Why it matters**: A good MCP error says what was wrong and what to do next, so the LLM can self-correct without a human.

> [!TIP]
> **Suggestion**: Always return code + message + hint (valid values, expected format, next tool to call).

<details><summary>Observed in 3 place(s)</summary>

- 🟠 WARN - 2.16 `search_companies`: Error has no 'hint': an LLM cannot tell how to retry
- 🟠 WARN - 2.17 `search_companies`: Error has no 'hint': an LLM cannot tell how to retry
- 🟠 WARN - 6.08 `search_directors`: No explicit 'not found' message for an unknown entity

</details>

### 🟠 Calls rejected or failing at transport level

**Why it matters**: The client gets an HTTP/protocol exception instead of a tool result and cannot show a useful message to the model.

> [!TIP]
> **Suggestion**: Return a tool-level error for unusual inputs; check that WAF rules do not block legitimate text.

<details><summary>Observed in 2 place(s)</summary>

- 🟠 WARN - 7.06 `get_company_overview`: Call raised at protocol level instead of returning a tool result: HTTP 403 Forbidden (transport level)
- 🟠 WARN - 7.07 `search_companies`: Call raised at protocol level instead of returning a tool result: HTTP 403 Forbidden (transport level)

</details>

## 5. What did not work, and why

### 🔴 FAIL - 1.11 Report schema, include_raw

| | |
|---|---|
| Tool | `get_company_report_schema` |
| Arguments | `{"country": "GB", "include_raw": true}` |
| Expected | Raw schema; flag if enormous |

> [!CAUTION]
> Response of 870,747 chars (~248,785 tokens) exceeds typical LLM context windows (100,000 tokens): the tool is unusable by an agent in this mode

<details><summary>Response excerpt</summary>

```
{
  "schema": [
    {
      "title": "CompanyReportResponse",
      "$schema": "http://json-schema.org/draft-04/schema#",
      "type": "object",
      "properties": {
        "chargeReference": {
          "type": "string"
        },
        "messages": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "type": {
             ... [+870,347 chars]
```

</details>

### 🔴 FAIL - 3.11 Overview by SIREN

| | |
|---|---|
| Tool | `get_company_overview` |
| Arguments | `{"company": "443021241", "country": "FR"}` |
| Expected | SIREN as the company argument |

> [!CAUTION]
> Server error code: ambiguous - Multiple companies match '443021241'.; Error returned as a normal result (isError=false) with an 'error' JSON body: clients cannot detect the failure from the MCP flag; Unexpected error: { "error": { "code": "ambiguous", "message": "Multiple companies match '443021241'.", "hint": "Use the Creditsafe ID, safe number, registration number, VAT, or add postcode/city.", "candidates": [ { "

<details><summary>Response excerpt</summary>

```
{
  "error": {
    "code": "ambiguous",
    "message": "Multiple companies match '443021241'.",
    "hint": "Use the Creditsafe ID, safe number, registration number, VAT, or add postcode/city.",
    "candidates": [
      {
        "creditsafe_id": "FR-X-44302124100072",
        "safe_no": "FR22340418",
        "registration_number": "44302124100072",
        "vat_numbers": [
          "FR964430212... [+3,741 chars]
```

</details>

### 🔴 FAIL - 3.12 Overview by VAT number

| | |
|---|---|
| Tool | `get_company_overview` |
| Arguments | `{"company": "FR96443021241", "country": "FR"}` |
| Expected | VAT as the company argument |

> [!CAUTION]
> Server error code: not_found - No company found for 'FR96443021241'.; Error returned as a normal result (isError=false) with an 'error' JSON body: clients cannot detect the failure from the MCP flag; Unexpected error: { "error": { "code": "not_found", "message": "No company found for 'FR96443021241'.", "hint": "Try safe number, registration number, VAT number, or name plus postcode." } }

<details><summary>Response excerpt</summary>

```
{
  "error": {
    "code": "not_found",
    "message": "No company found for 'FR96443021241'.",
    "hint": "Try safe number, registration number, VAT number, or name plus postcode."
  }
}
```

</details>

## 6. Tool definitions review

What an LLM client sees when it discovers the tools (descriptions, parameter documentation, metadata).

- `get_my_creditsafe_access`: No outputSchema: the shape of the result is undocumented
- `get_supported_countries`: No outputSchema: the shape of the result is undocumented
- `get_company_search_fields`: No outputSchema: the shape of the result is undocumented
- `get_company_search_fields`: Parameter 'countries' is a free string without enum/pattern: valid values are only discoverable by trial and error
- `get_report_languages`: No outputSchema: the shape of the result is undocumented
- `get_report_languages`: Parameter 'country' is a free string without enum/pattern: valid values are only discoverable by trial and error
- `get_company_report_schema`: No outputSchema: the shape of the result is undocumented
- `get_company_report_schema`: Parameter 'country' is a free string without enum/pattern: valid values are only discoverable by trial and error
- `search_companies`: No outputSchema: the shape of the result is undocumented
- `get_company_overview`: No outputSchema: the shape of the result is undocumented
- `get_company_overview`: Parameter 'language' has no description
- `get_company_financials`: No outputSchema: the shape of the result is undocumented
- `get_company_financials`: Parameter 'years' has no description
- `get_company_financials`: Parameter 'language' has no description
- `get_company_payment_behaviour`: No outputSchema: the shape of the result is undocumented
- `get_company_payment_behaviour`: Parameter 'language' has no description
- `get_company_events`: No outputSchema: the shape of the result is undocumented
- `get_company_events`: Parameter 'language' has no description
- `get_company_adverse_information`: No outputSchema: the shape of the result is undocumented
- `get_company_adverse_information`: Parameter 'language' has no description
- `get_company_group_structure`: No outputSchema: the shape of the result is undocumented
- `get_company_group_structure`: Parameter 'language' has no description
- `get_company_beneficial_owners`: No outputSchema: the shape of the result is undocumented
- `get_company_beneficial_owners`: Parameter 'language' has no description
- `get_company_directors`: No outputSchema: the shape of the result is undocumented
- `get_company_directors`: Parameter 'language' has no description
- `get_company_directors`: Parameter 'limit' has no description
- `get_company_directorships`: No outputSchema: the shape of the result is undocumented
- `get_company_directorships`: Parameter 'language' has no description
- `get_company_directorships`: Parameter 'limit' has no description
- `get_company_report_pdf`: No outputSchema: the shape of the result is undocumented
- `get_company_report_pdf`: Parameter 'language' has no description
- `search_directors`: No outputSchema: the shape of the result is undocumented
- `search_directors`: Parameter 'countries' is a free string without enum/pattern: valid values are only discoverable by trial and error
- `get_director_report`: No outputSchema: the shape of the result is undocumented
- `get_director_report`: Parameter 'language' has no description
- `(all tools)`: Tool definitions alone weigh ~11,122 tokens, paid on every LLM turn

## 7. Per-tool statistics

| Tool | Calls | PASS | WARN | FAIL | Avg s | Max s | Max response (chars) |
|---|---|---|---|---|---|---|---|
| `get_my_creditsafe_access` | 1 | 1 | 0 | 0 | 2.4 | 2.4 | 5,327 |
| `get_supported_countries` | 1 | 1 | 0 | 0 | 1.6 | 1.6 | 8,118 |
| `get_company_search_fields` | 3 | 2 | 1 | 0 | 1.7 | 1.8 | 4,152 |
| `get_report_languages` | 2 | 2 | 0 | 0 | 1.6 | 1.6 | 192 |
| `get_company_report_schema` | 4 | 2 | 1 | 1 | 1.9 | 2.0 | 870,747 |
| `search_companies` | 20 | 16 | 4 | 0 | 1.6 | 2.4 | 5,315 |
| `get_company_overview` | 24 | 7 | 15 | 2 | 2.1 | 3.5 | 10,600 |
| `get_company_financials` | 12 | 7 | 5 | 0 | 2.0 | 4.3 | 28,669 |
| `get_company_payment_behaviour` | 2 | 2 | 0 | 0 | 2.4 | 2.6 | 3,818 |
| `get_company_events` | 2 | 1 | 1 | 0 | 3.3 | 3.8 | 83,199 |
| `get_company_adverse_information` | 3 | 2 | 1 | 0 | 2.0 | 2.5 | 14,683 |
| `get_company_group_structure` | 3 | 2 | 1 | 0 | 3.3 | 3.9 | 25,542 |
| `get_company_beneficial_owners` | 3 | 1 | 2 | 0 | 2.3 | 3.0 | 5,191 |
| `get_company_directors` | 3 | 2 | 1 | 0 | 2.7 | 3.3 | 14,530 |
| `get_company_directorships` | 3 | 1 | 2 | 0 | 2.4 | 3.1 | 10,191 |
| `get_company_report_pdf` | 0 | - | - | - | - | - | - |
| `search_directors` | 8 | 5 | 3 | 0 | 1.9 | 2.3 | 3,970 |
| `get_director_report` | 0 | - | - | - | - | - | - |

## 8. Appendix - all test cases

| ID | Title | Tool | Verdict | Time (s) | Chars |
|---|---|---|---|---|---|
| 1.01 | Account access and entitlements | `get_my_creditsafe_access` | 🟢 PASS | 2.4 | 5,327 |
| 1.02 | Supported countries | `get_supported_countries` | 🟢 PASS | 1.6 | 8,118 |
| 1.03 | Search fields for France | `get_company_search_fields` | 🟢 PASS | 1.8 | 4,152 |
| 1.04 | Search fields for several countries | `get_company_search_fields` | 🟢 PASS | 1.7 | 974 |
| 1.05 | Search fields, invalid country | `get_company_search_fields` | 🟠 WARN | 1.7 | 154 |
| 1.06 | Report languages, France | `get_report_languages` | 🟢 PASS | 1.6 | 192 |
| 1.07 | Report languages, UK | `get_report_languages` | 🟢 PASS | 1.6 | 180 |
| 1.08 | Report schema, France (summary) | `get_company_report_schema` | 🟢 PASS | 1.9 | 686 |
| 1.09 | Report schema, UK (summary) | `get_company_report_schema` | 🟢 PASS | 1.8 | 686 |
| 1.10 | Report schema, unknown template | `get_company_report_schema` | 🟠 WARN | 1.7 | 142 |
| 1.11 | Report schema, include_raw | `get_company_report_schema` | 🔴 FAIL | 2.0 | 870,747 |
| 2.01 | Search by name, France | `search_companies` | 🟢 PASS | 1.8 | 4,324 |
| 2.02 | Search by registration number (SIREN) | `search_companies` | 🟢 PASS | 1.6 | 3,803 |
| 2.03 | Search by VAT number | `search_companies` | 🟢 PASS | 1.6 | 3,803 |
| 2.04 | Search by safe number, UK | `search_companies` | 🟢 PASS | 1.7 | 620 |
| 2.05 | Search by name, UK large company | `search_companies` | 🟢 PASS | 1.6 | 4,431 |
| 2.06 | Search, exact match | `search_companies` | 🟢 PASS | 1.6 | 621 |
| 2.07 | Search, multi-country | `search_companies` | 🟢 PASS | 1.7 | 4,766 |
| 2.08 | Search, city filter | `search_companies` | 🟢 PASS | 1.6 | 5,037 |
| 2.09 | Search, postcode filter | `search_companies` | 🟢 PASS | 2.4 | 5,049 |
| 2.10 | Search, status filter | `search_companies` | 🟢 PASS | 1.6 | 4,431 |
| 2.11 | Search, page_size=1 | `search_companies` | 🟢 PASS | 1.6 | 560 |
| 2.12 | Search, page 2 | `search_companies` | 🟢 PASS | 1.9 | 2,296 |
| 2.13 | Search, page_size above cap | `search_companies` | 🟠 WARN | 0.6 | 281 |
| 2.14 | Search with typo | `search_companies` | 🟢 PASS | 1.9 | 5,300 |
| 2.15 | Search with accents | `search_companies` | 🟢 PASS | 2.3 | 5,171 |
| 2.16 | Search without any criterion | `search_companies` | 🟠 WARN | 0.9 | 218 |
| 2.17 | Search by name without country | `search_companies` | 🟠 WARN | 0.9 | 218 |
| 2.18 | Search, lowercase country | `search_companies` | 🟢 PASS | 1.5 | 4,324 |
| 2.19 | Search, unknown company | `search_companies` | 🟢 PASS | 2.2 | 5,315 |
| 3.01 | get_company_overview, French company | `get_company_overview` | 🟢 PASS | 2.8 | 2,292 |
| 3.02 | get_company_financials, French company | `get_company_financials` | 🟢 PASS | 2.7 | 28,340 |
| 3.03 | get_company_payment_behaviour, French company | `get_company_payment_behaviour` | 🟢 PASS | 2.2 | 3,818 |
| 3.04 | get_company_events, French company | `get_company_events` | 🟠 WARN | 2.7 | 83,199 |
| 3.05 | get_company_adverse_information, French company | `get_company_adverse_information` | 🟢 PASS | 2.5 | 14,683 |
| 3.06 | get_company_group_structure, French company | `get_company_group_structure` | 🟢 PASS | 2.7 | 25,542 |
| 3.07 | get_company_beneficial_owners, French company | `get_company_beneficial_owners` | 🟢 PASS | 3.0 | 1,061 |
| 3.08 | get_company_directors, French company | `get_company_directors` | 🟢 PASS | 2.5 | 14,530 |
| 3.09 | get_company_directorships, French company | `get_company_directorships` | 🟠 WARN | 3.1 | 421 |
| 3.10 | Overview by company name | `get_company_overview` | 🟠 WARN | 2.8 | 4,151 |
| 3.11 | Overview by SIREN | `get_company_overview` | 🔴 FAIL | 2.3 | 4,141 |
| 3.12 | Overview by VAT number | `get_company_overview` | 🔴 FAIL | 2.2 | 188 |
| 3.13 | Overview without country | `get_company_overview` | 🟢 PASS | 3.4 | 2,292 |
| 3.14 | Overview repeated (cache check) | `get_company_overview` | 🟢 PASS | 2.7 | 2,292 |
| 3.15 | Financials, years=1 | `get_company_financials` | 🟢 PASS | 2.3 | 6,835 |
| 3.16 | Financials, years=5 | `get_company_financials` | 🟢 PASS | 2.2 | 28,340 |
| 3.17 | Financials, global basis | `get_company_financials` | 🟢 PASS | 3.2 | 28,669 |
| 3.18 | Financials, English | `get_company_financials` | 🟢 PASS | 4.3 | 28,340 |
| 3.19 | Financials, invalid basis | `get_company_financials` | 🟠 WARN | 0.5 | 316 |
| 3.20 | Financials, years=0 | `get_company_financials` | 🟠 WARN | 0.7 | 295 |
| 3.21 | Financials, years=-3 | `get_company_financials` | 🟠 WARN | 0.6 | 296 |
| 3.22 | Directorships, limit=1 | `get_company_directorships` | 🟠 WARN | 1.8 | 421 |
| 4.01 | get_company_overview, UK company | `get_company_overview` | 🟢 PASS | 2.2 | 2,243 |
| 4.02 | get_company_financials, UK company | `get_company_financials` | 🟢 PASS | 2.3 | 14,291 |
| 4.03 | get_company_payment_behaviour, UK company | `get_company_payment_behaviour` | 🟢 PASS | 2.6 | 1,954 |
| 4.04 | get_company_events, UK company | `get_company_events` | 🟢 PASS | 3.8 | 9,373 |
| 4.05 | get_company_adverse_information, UK company | `get_company_adverse_information` | 🟢 PASS | 2.1 | 980 |
| 4.06 | get_company_group_structure, UK company | `get_company_group_structure` | 🟢 PASS | 3.9 | 854 |
| 4.07 | get_company_beneficial_owners, UK company | `get_company_beneficial_owners` | 🟠 WARN | 1.9 | 421 |
| 4.08 | get_company_directors, UK company | `get_company_directors` | 🟢 PASS | 2.2 | 8,511 |
| 4.09 | get_company_directorships, UK company | `get_company_directorships` | 🟢 PASS | 2.4 | 10,191 |
| 4.10 | Overview by name (ambiguous) | `get_company_overview` | 🟠 WARN | 1.7 | 4,810 |
| 4.11 | Overview by exact legal name | `get_company_overview` | 🟠 WARN | 1.6 | 5,191 |
| 4.12 | Overview by registration number | `get_company_overview` | 🟢 PASS | 2.5 | 2,340 |
| 4.13 | Financials with global basis | `get_company_financials` | 🟢 PASS | 2.8 | 9,165 |
| 4.14 | Group structure of a large group | `get_company_group_structure` | 🟠 WARN | 3.3 | 5,191 |
| 4.15 | Beneficial owners of a large group | `get_company_beneficial_owners` | 🟠 WARN | 2.0 | 5,191 |
| 5.01 | DE overview without reason_code | `get_company_overview` | 🟠 WARN | 3.5 | 4,578 |
| 5.02 | DE overview with reason_code=1 | `get_company_overview` | 🟠 WARN | 3.3 | 4,578 |
| 5.03 | DE financials with reason_code=2 | `get_company_financials` | 🟠 WARN | 1.5 | 4,578 |
| 5.04 | DE overview with invalid reason_code=9 | `get_company_overview` | 🟠 WARN | 0.8 | 304 |
| 5.05 | DE overview with reason_code='abc' | `get_company_overview` | 🟠 WARN | 0.6 | 306 |
| 5.06 | FR overview with reason_code (should be ignored) | `get_company_overview` | 🟢 PASS | 2.5 | 2,292 |
| 5.07 | DE directors without reason_code | `get_company_directors` | 🟠 WARN | 3.3 | 4,578 |
| 6.01 | Search directors, UK | `search_directors` | 🟢 PASS | 1.6 | 3,717 |
| 6.02 | Search directors, France | `search_directors` | 🟢 PASS | 2.3 | 2,906 |
| 6.03 | Search directors, multi-country | `search_directors` | 🟢 PASS | 2.0 | 3,970 |
| 6.04 | Search directors with date of birth | `search_directors` | 🟢 PASS | 1.9 | 3,816 |
| 6.05 | Search directors, malformed date | `search_directors` | 🟢 PASS | 2.3 | 316 |
| 6.06 | Search directors, countries only | `search_directors` | 🟠 WARN | 2.2 | 160 |
| 6.07 | Search directors, missing countries | `search_directors` | 🟠 WARN | 0.7 | 259 |
| 6.08 | Search directors, unknown people_id | `search_directors` | 🟠 WARN | 2.3 | 316 |
| 7.01 | Unknown company | `get_company_overview` | 🟠 WARN | 1.8 | 5,777 |
| 7.02 | Invalid country code | `get_company_overview` | 🟠 WARN | 2.3 | 187 |
| 7.03 | Empty company | `get_company_overview` | 🟠 WARN | 1.4 | 279 |
| 7.04 | Blank company | `get_company_overview` | 🟠 WARN | 1.4 | 279 |
| 7.05 | Very long company string | `get_company_overview` | 🟠 WARN | 2.0 | 10,600 |
| 7.06 | Special characters and HTML | `get_company_overview` | 🟠 WARN | 0.0 | 0 |
| 7.07 | SQL-like input | `search_companies` | 🟠 WARN | 0.0 | 0 |
| 7.08 | Missing required argument | `get_company_overview` | 🟠 WARN | 0.6 | 260 |
| 7.09 | Wrong argument type | `get_company_financials` | 🟠 WARN | 0.5 | 314 |
| 7.10 | Unknown extra argument | `get_company_overview` | 🟢 PASS | 2.6 | 2,292 |
| 7.11 | Unknown tool | `get_company_horoscope` | 🟢 PASS | 0.6 | 35 |
| 7.12 | Company in insolvency | `get_company_overview` | 🟠 WARN | 3.4 | 5,132 |
| 7.13 | Adverse info on a company in insolvency | `get_company_adverse_information` | 🟠 WARN | 1.6 | 5,132 |
| 8.01 | Company PDF report | `get_company_report_pdf` | ⚪ SKIP | 0.0 | 0 |
| 8.02 | Financials with refresh=True | `get_company_financials` | ⚪ SKIP | 0.0 | 0 |
| 8.03 | Director report | `get_director_report` | ⚪ SKIP | 0.0 | 0 |

Full requests and responses: `verbose.log`, `raw.jsonl`. Spreadsheet: `results.csv` / `results.xlsx`.
