Reliability, Errors, and Pagination
Handle errors, partial results, retries, and pagination in MCP integrations.
Use this guide when your integration needs to handle partial results, pagination, and failed calls.
Check errors before reading results
Inspect the transport outcome, any JSON-RPC error, the MCP result's isError flag, and the tool payload's error object. An outer success does not guarantee a successful query. Check all layers before consuming results.
If error is present, do not interpret an empty entities or rows array as a successful zero-result answer. Preserve error.code, error.message, any response_status, and request_id when available.
Clients and connectors can reject invalid arguments before they reach Crunchbase. These failures may have no server request ID.
A successful profile response does not establish that every requested field or card was retrieved. Unknown or unavailable selections can be omitted without an error. Validate selections against cb_reference and distinguish missing fields/cards from explicit empty results. Use supported positive limits; do not rely on out-of-range inputs being rejected or normalized consistently.
| Outcome | Recommended handling |
|---|---|
| Invalid request or HTTP 400 | Correct fields, operators, identifiers, or query structure before retrying. |
| Authentication failure | Renew the OAuth connection. If access remains denied, check MCP access with the workspace administrator. |
| HTTP 429 | Follow Retry-After when supplied. Check whether the error reports temporary rate limiting or an exhausted allowance. |
| Read timeout or HTTP 500/503 | Use a limited number of retries with increasing delays and jitter. A timeout can leave usage unknown. |
| Other processing error | Preserve the error details and request ID. Retry only when the error indicates a temporary failure. |
| Uncertain write | Inspect the destination before retrying. A timeout does not prove that the write failed. |
For data-token errors and usable partial results, use the handling below.
Handle current error codes
Use the machine-readable error.code to choose an action. HTTP status alone is not enough: a query timeout can arrive as HTTP 400, while HTTP 429 can mean either temporary throttling or an exhausted data-token allowance.
| Error code | Meaning and action |
|---|---|
SEARCH_VALIDATION_ERROR | The structured search was rejected as invalid. Check the field references, operators, values, and query structure before resubmitting. The message may be generic rather than identify the invalid field. |
SEARCH_QUERY_TIMEOUT | Narrow or simplify the search before retrying. This is a query execution limit, not a connection timeout. |
DOWNSTREAM_TIMEOUT | A service request timed out. Limit retries for reads; inspect destination state before retrying writes. Usage may be unknown. |
DOWNSTREAM_RATE_LIMITED | Temporary rate limiting. Reduce parallel requests and retry after a bounded delay. |
DOWNSTREAM_DATA_TOKENS_EXHAUSTED | A Crunchbase service reported an exhausted data-token allowance. Stop affected requests and follow any reset guidance in the message. This error does not include MCP exhausted_meters details and can occur while cb_metering_get_state reports an available balance. |
ENTITY_NOT_FOUND | The requested profile identifier did not resolve. Resolve the name again with autocomplete or entity resolution, then retry with the returned identifier. Do not repeatedly request the same missing entity. |
DOWNSTREAM_INVALID_RESPONSE | A service returned an invalid response. Preserve the request ID and error details; stop after a bounded recovery attempt and report a persistent failure. |
DOWNSTREAM_REQUEST_FAILED | The request failed without a more specific error code. Inspect the available status and message; do not assume every instance is retryable. |
These codes supplement the metering and access handling above. Other service error codes can also be returned. Preserve unknown codes and handle them without converting the response into an empty successful result.
Invalid searches can return a specific code such as CS109 instead of SEARCH_VALIDATION_ERROR. Check the field reference to correct the request and preserve the returned code for diagnostics.
Data-token errors and partial results
Preserve the raw result's _meta["cb/data_tokens"] alongside structuredContent. It reports the actual consumed deduction when confirmed, plus exhausted. These fields are outside the tool output schema. See Data-Token Metering for the full contract and examples.
| Metering outcome | What the client should do |
|---|---|
Usable response with exhausted: true | Keep the result, tell the user the allowance is used up, and stop further affected data requests. |
DATA_TOKENS_EXHAUSTED error | No usable data is served for that invocation. The deduction is zero and exhaustion is reported. Inspect error.exhausted_meters when supplied, or call cb_metering_get_state. |
DATA_TOKENS_DENIED error | Check the account's MCP entitlement. Waiting for an allowance reset will not resolve missing access. |
DATA_TOKENS_REFUSED error | Stop the affected workflow, preserve any reported deduction, and inspect the error. Contact support if the failure persists. |
Missing consumed or missing metering metadata | Record the deduction as unknown. Keep usable data and check that the connector preserves _meta. |
| Error with usable partial data | Inspect and label the partial data. It can be charged even when the payload has an error; the outer isError may remain false. |
When supplied, exhausted_meters uses the same meter-state format as cb_metering_get_state. Preserve it alongside code and message.
Do not automatically retry exhaustion, entitlement, or refusal errors. Resume when the allowance, access, or reported problem is resolved.
An ordinary tool error with no usable data has no data charge. A metering error can still report a deduction; preserve any returned consumed amount. An empty structured search uses zero tokens; an Expert answer with no matching rows can still incur charges.
After a timeout or disconnect, record unconfirmed usage as unknown. A retry is a new invocation and can consume more tokens. Inspect destination state before retrying a write.
Search pagination
cb_search_query returns entities and may include count. The count is the reported number of matches, not the number returned on this page.
Keep the collection, filters, fields, ordering, and limit unchanged between pages. Set after_id to the UUID of the last entity in the preceding page. Include identifier in selected fields.
Recommended loop:
- Check errors and validate the result shape.
- If the successful page is empty, end the traversal.
- Process entities, deduplicating by UUID.
- Read the last entity UUID and request the next page using that cursor.
- Stop and mark the traversal incomplete if a cursor repeats, a page makes no progress, a request fails, or your page/time budget is reached.
Do not infer completion solely because a page contains fewer rows than requested. Access-dependent caps may affect the effective page size. Use counts as a cross-check. Records and counts can change between requests.
Entity-card pagination
For cb_entity_get, scope card_ids to one card and pass field_ids=[] to minimize top-level fields. An identifier may still be included.
On the initial call, related_entity_limit guides distribution across selected lookup cards; it is not a strict total-row cap. The combined response can exceed the requested budget. Specify cards explicitly and enforce application-level row or payload safeguards. With after_id, the value requests a page size for exactly one card. A single card returns at most 100 entities per request; card and access limits can lower that number. Increasing the budget cannot override every card limit; use structured search or a reviewed compiled search when needed. Omitting card_ids selects one card per target collection, not every readable card. A card's has_more_entities indicates that a continuation may be needed, including when results were clipped to a budget; it is not a remaining-record count.
When has_more_entities=true, request the same single card with after_id set to the last related entity's identifier UUID. In the labeled response, find the property with field_id="identifier" and read value.uuid.
End on an explicit false flag or a successful empty page for the requested card. A missing card, missing flag, or repeated cursor is an unresolved traversal, not proof of completeness. Apply the same error, duplicate, and progress checks as search pagination.
Example: continue a funding-round card
First resolve the organization:
{"query":"Cohere","collection_ids":"organizations","limit":5}Select the intended organization from the autocomplete results and use its identifier. Resolve the example company again in your workflow rather than assuming its identifier.
Call cb_entity_get:
{"entity_id":"34b73a99-d4cb-4bc5-8641-6db4fd2782b8","entity_def_id":"organization","field_ids":[],"card_ids":["funding_rounds_list"],"related_entity_limit":2}Copy the last related entity's identifier UUID into the next request's after_id; preserve all other arguments. Do not reuse a cursor from another card or host entity.
Saved-list pagination
cb_list_get returns company_identifiers, an optional total_count, and an optional next_after_id. The current page size is 50; there is no caller-supplied page-size parameter.
- Call
cb_list_getwith the destinationlist_id. - Check transport, protocol, and payload errors before reading identifiers.
- Process the identifiers and deduplicate by UUID.
- If the successful page is empty or
next_after_idis absent, stop. - Otherwise, request the same list with
after_idset to the returnednext_after_id. - Stop and mark the traversal incomplete if a cursor repeats, a non-empty page makes no progress, a request fails, or the page/time budget is reached.
A returned cursor means another page may be available; that page can be empty. Do not calculate the next cursor from a list count, assume every list fits on one page, or interpret a missing total_count as zero. List membership can change between page requests.
The result contains identifiers rather than full profiles. Fetch additional data separately only for the members you need.
Verify an uncertain list write
cb_list_add_entities echoes submitted_entity_ids, including on some failures. That echo is not proof that each item was newly added. Check the response error and status, then read the destination list when membership confirmation is required. Do not assume the summary's submitted-item count is a count of newly created members.
For an uncertain cb_list_create, inspect existing lists before retrying; another create can make a duplicate list. Use your own operation log to reconcile writes without silently repeating the user's action.
Expert answers and previews
cb_expert_query_answer accepts one question. Its output includes columns, rows, row_count, and truncated. A non-null answered_question describes a narrower question that was answered; show that scope to the user.
If truncated=true, label the returned rows as partial. If explicitly false, the tool reports no truncation at its row limit; this does not prove that the question's interpretation or underlying coverage is exhaustive. If truncated is missing, treat its status as unknown. The current input does not expose a row limit, field selection, deduplication switch, or continuation cursor. Asking for “the next page” in a new natural-language question is not cursor pagination.
A build-search preview may be partial: preview_limit controls inline rows. Review the returned compiled search and use cb_search_query for subsequent pages. Preserve recursive query items rather than flattening them into predicates.
Resolution with an embedded profile
cb_expert_resolve_entity has separate resolution and profile outcomes. A successful disambiguation.result_type="match" does not establish that the optional profile fetch succeeded. Inspect the outer error, the disambiguation result, and any nested entity.error before rendering profile data.
When result_type="candidates", the ranked candidates need selection; do not treat the first item as a confirmed match. If profile retrieval was disabled with cb_entity_get: null, the missing profile is expected.
Continue embedded relationship cards through the standalone cb_entity_get tool. Use the matched host's identifier and entity type, a single card_id, and the related entity cursor; do not pass a cursor through the embedded options object.
Unexpected zero results
A successful zero-result search says no records matched that request under the caller's access. It does not establish that the real-world category is empty.
Check each predicate's field reference. Identifier-valued fields require valid UUIDs or permalinks, not display names. Loosen one filter at a time to diagnose the request; label the revised scope clearly instead of presenting broader results as satisfying the original filters.
For relationship filters, a related entity collection is not necessarily the relationship collection required by a subquery. Use a compiled, reviewed search or a relationship example from the reference. Do not construct a subquery by replacing a flat predicate's collection name.
Limits and support
Call cb_metering_get_state to inspect the current user’s Crunchbase data-token allowance: limit, used and available amounts, status, period, affected tools, warnings, and upcoming_meter_refresh when available. It does not enumerate all rate limits or access restrictions. Treat missing amounts and status="unknown" as unknown, not unlimited. A meter reading is not a reservation for future calls.
Log your own invocation ID and timestamp alongside the tool name, elapsed time, outcome, server request ID, and per-result consumed/exhausted fields when present. Record missing deductions explicitly as unknown. Do not rely on the server ID alone as your application's unique key. Keep credentials and unnecessary response data out of logs.
For persistent failures, contact your Crunchbase account team or Customer Success Manager with the timestamp, client/version, tool, redacted arguments, error details, and request ID. Specific limits and support commitments depend on your arrangement.
See Building a Crunchbase MCP Integration and Known MCP Limitations.
These instructions are for MCP tools. REST Entity Lookup parameters such as before_id, card_field_ids, and a REST API user key are not inputs to cb_entity_get. Use the connected tool’s schema, not REST examples, when forming an MCP call.
Updated about 11 hours ago

