Skip to main content

How errors are returned

There are two kinds of errors. Problems with the HTTP request itself are returned as an HTTP error status before any tool runs. A tool call that fails is returned as a normal tools/call result with isError: true.

HTTP and protocol errors

These responses carry a JSON-RPC error body with "id": null, except the last two, which carry a small JSON object.

Tool errors

A failed tool call returns HTTP 200 with a JSON-RPC result, not a JSON-RPC error. The result has isError: true and one text block that explains what went wrong:
A call to a connector that is not connected yet returns the connect link, even when its arguments are invalid. What tools/list shows follows the same checks. Without a subscription, a connector endpoint lists only connect_account (CVR lists nothing), and the initialize result carries instructions that explain how to get access. A user without a seat still sees the tools, but every call is refused. A tool that is not enabled for your user, by the organization or by your access level, is not listed. See Authentication for the full access model. While a subscription’s payment is overdue, the connector’s tools are withdrawn and calls return the not-subscribed text. Do not buy the connector again. The stored connection is kept, and access returns without reconnecting once the payment goes through. An administrator manages the payment under Abonnement in the portal.
Because invalid arguments only return Tool invocation failed., validate arguments against the schemas in the API reference before calling, for example dates as YYYY-MM-DD and rowLimit within 1–25000 for Google Search Console.

Messages from the provider

Most provider failures return the fixed text Tool invocation failed., because a provider’s raw error can contain data that should not be passed on. That covers a provider error, a timeout and, on most connectors, a provider rate limit or a validation error from the provider. Some failures return an explanatory message instead:
  • Expired or rejected access: when a connection has expired or the provider rejects the stored access, the result usually says that the connector must be reconnected, for example Search Console rejected the access token (401); reconnect required. This applies to every connector except CVR, which has no connection of its own. Reconnect the connector in the portal.
  • e-conomic: a rate limit returns a message to wait and ask for fewer or smaller pages. Temporary unavailability returns a message to try again shortly; after a write, check in e-conomic whether it was applied before you repeat it. When e-conomic rejects a request as invalid (HTTP 400, 404 or 422, and 409 on the journal tools), the result summarizes what e-conomic rejected, such as the field, so the model can correct the call. See the e-conomic reference.
  • Uniconta, on the four daily-journal write tools: when Uniconta refuses a write (for example missing rights or an unknown account), the result is Uniconta refused <METHOD> <path>: <reason>. Nothing was changed. The connector’s own checks (unknown or blocked journal, a line that is not unposted, a posting preview that no longer matches) also return a message. See the Uniconta reference.
  • Ordrestyring: a rate limit that persists, and validation errors that name the field. See the Ordrestyring reference.
  • Business Central (early access): missing permissions (403), an unknown environment, a wrong company id (404), a rejected query (400) and a rate limit that persists. See the Business Central reference.
If a connector keeps returning Tool invocation failed. for calls that used to work, check the connector’s status in the portal and reconnect it there. The portal’s disconnect button applies only to the first portal; for an extra portal, call connect_account on that portal’s endpoint (for example /gsc-2/mcp) to get a new connect link. Shopify can only be connected in the portal. CVR has no connection of its own, so there is nothing to reconnect; if CVR calls keep failing, try again later or write to support@consile.dk.

Rate limits

Consile currently allows 20 requests per second per account and connector endpoint, with bursts of up to 60 requests. Every authenticated HTTP request counts: initialize, tools/list, tools/call and the GET stream. Each connector endpoint has its own budget, an extra portal endpoint such as /economic-2/mcp has its own as well, and the Concierge endpoint /mcp has one per account. Heavy use of one connector therefore does not slow down another. Over the limit you get HTTP 429 with Retry-After: 1 and the JSON-RPC error -32029 (Rate limit exceeded). Wait a second and retry. The limit is approximate. It is there to stop runaway loops and is not a monthly quota; for monthly usage, see Usage & fair use. The portal API, including GET /api/usage, has its own limits: currently about 10 requests per second per client IP address and 20 per second per account. Over the limit it returns 429 with Retry-After: 1 and {"error":"rate_limited"}.

Provider limits

Providers also limit requests. On some connectors Consile may briefly retry a provider’s rate-limit response before giving up. When the provider still refuses, e-conomic, Ordrestyring and Business Central return a message that tells you to wait, and the other connectors return Tool invocation failed.. Wait a moment, and ask for fewer or smaller pages, before you retry. Known provider limits: Dinero allows about 100 requests per minute per organization, HubSpot about 110 requests per 10 seconds per connected HubSpot account, and Business Central 6,000 requests per 5 minutes per Business Central user, shared with the user’s other Business Central clients. Shopify throttles by query cost, and Ordrestyring’s limit varies with the time of day.

Timeouts

Each request from Consile to a provider has a time limit, so a slow provider does not leave a call hanging. A call that times out returns Tool invocation failed.. Ask for a shorter period or fewer rows and try again. If book_journal_entries times out, the booking may still have completed in e-conomic, so check list_account_entries before you retry. The same applies to Uniconta’s post_journal_lines: check list_journal_lines before you retry.

Request limits

  • Request size: a request body may be at most 256 KiB. A larger body gets HTTP 400 with Parse error.
  • Headers: send Content-Type: application/json and Accept: application/json, text/event-stream on every POST.
  • Sessions: the endpoints are stateless. The server issues no Mcp-Session-Id, so every request carries its own bearer token. A POST may be answered as a Server-Sent Events stream.
  • Browser calls: the MCP endpoints send no CORS headers and refuse a foreign Origin with 403. Call them from a server-side process or a native MCP client.
  • Long-running calls: while a tool call is still running on an SSE response stream, the server sends an SSE comment line (: keepalive) about every 25 seconds to keep the connection alive. Clients should ignore it.

Row limits per connector

The main page sizes and caps per connector are listed below. Each connector’s API reference has the full details.

Google Search Console

  • Rows per request: up to 25,000 (limit on top_queries and top_pages, rowLimit on search_analytics_query).
  • Pagination: use startRow in search_analytics_query to fetch further rows.
  • Dates: always YYYY-MM-DD.
  • Properties: you can only reach properties that the authorized Google account already has access to. Use list_sites to see them.
See also Data freshness below and the Google Search Console reference.

CVR

  • size is 1–50 on soeg_virksomhed, find_produktionsenheder and find_virksomheder_for_person (default 10, or 50 for find_produktionsenheder). Values outside the range are rejected, not reduced, and there is no paging beyond the first 50 rows. find_ejere has no size and returns all relations.
See the CVR reference.

Uniconta

  • Rows per call: limit defaults to 50, max 1000.
  • Paging: list_inventory_items, list_inventory_transactions, list_journal_lines and query take offset; follow nextOffset in the result.
  • Aggregation: aggregate covers at most about 50,000 rows per call and returns truncated: true beyond that; narrow the filters or the date range. A grouping that produces more than 1,000 groups fails the call.
  • Journal batches: create_journal_lines, update_journal_lines and post_journal_lines take at most 50 lines per call; delete_journal_line deletes one line.
  • Write refusals: a write Uniconta refuses returns Uniconta refused <METHOD> <path>: <reason>. Nothing was changed.
  • Confirming: the confirming call of update_journal_lines applies your changes to the lines as they are at that moment. post_journal_lines refuses to post if a line changed after the preview.
See the Uniconta reference.

e-conomic

  • Page size: list tools take pagesize (default 20, max 1000) and skippages. Not every list tool accepts filter or sort.
  • Journal batches: create_journal_entries, update_journal_entries and book_journal_entries take at most 50 entries per call.
  • Journal filters: list_journal_entries cannot filter on text or amount.
  • Confirming: the confirming call of update_journal_entries applies your changes to the entries as they are at that moment. book_journal_entries refuses to book if an entry changed after the preview.
See the e-conomic reference.

Dinero

  • Rate limit: Dinero allows about 100 requests per minute per organization. A call Dinero keeps refusing returns Tool invocation failed..
  • Dinero Pro: the public API only works for organizations on Dinero Pro. A non-Pro organization gets 403 from Dinero on every call except list_organizations and validate_connection, and the call returns Tool invocation failed.. Use list_organizations to check isPro.
See the Dinero reference.

Billy

  • Page size: list tools take page and pageSize (default 50, 200 for list_currencies, max 1000).
See the Billy reference.

Ordrestyring

  • Page size: list_cases returns up to 200 rows per page (limit, default 50). list_case_hours and list_case_sales_invoices collect up to maxRows rows (default 500, max 2,000).
  • find_cases scans at most the 1,000 most recently updated cases.
  • Result size: graphql_query results over 100,000 characters, and introspect_schema or describe_type results over 40,000 characters, are refused with Tool invocation failed..
See the Ordrestyring reference.

Meta Ads

  • Rows per call: limit 1–5000 (default 100). A large limit can return fewer rows than requested. Use query with params.after to page further.
  • Budgets and bids on the write tools are in minor units of the account currency (5000 = 50.00).
See the Meta Ads reference.

LinkedIn Ads

  • Rows per call: list tools return up to limit rows (default 100, max 1000).
  • Analytics: get_ad_analytics and get_ad_statistics return one response without paging. LinkedIn caps it at 15,000 rows and accepts at most 20 metric fields.
  • Money: amounts are decimal strings in major units ("500.00"). currencyCode is required with any amount and must match the ad account’s currency.
  • 22 tools (Company Page, organic posts, comments and reactions, member profile) are not available yet; calls to them fail with Tool invocation failed.. They are listed under Write tools & guardrails.
See the LinkedIn Ads reference.

HubSpot CMS and HubSpot Marketing Email

  • Page size: list tools take limit (default 20, max 100) and the after cursor from paging.next.after.
  • Analytics (HubSpot CMS): get_traffic_analytics takes dates as YYYYMMDD and limit up to 1000.
See the HubSpot CMS reference and the HubSpot Marketing Email reference.

Shopify

  • Rows per list call: limit defaults to 50, max 250. There is no cursor argument; narrow the result with query where the tool takes one.
  • graphql_query: one read-only query per call, at most 64 KiB (65,536 characters) and 20,000 tokens.
See the Shopify reference.

Business Central

  • Page size: default 50, max 500 rows.
  • Result size: query_entity results over 100,000 characters and list_entity_metadata results over 40,000 characters are refused with Tool invocation failed..
See the Business Central reference.

Data freshness (Google Search Console)

Search Console data is not real-time. The most recent days may be incomplete or missing because Google is still collecting them.
  • Expect a delay of a couple of days on the newest numbers.
  • In search_analytics_query you can control this with dataState:
    • final: only fully collected data.
    • all: includes preliminary (fresh but unstable) data.
Empty numbers usually mean the period has no data yet, or the selected property has no traffic in the range. That is not necessarily an error.