Skip to content
Browse docsErrors and limits

Errors and limits

What each kind of failure looks like, and how to retry safely.

Connection errors#

ResponseMeaningWhat to do
HTTP 401 with WWW-AuthenticateNo token, or the token expired or was revokedLet your client refresh, or sign in again.
HTTP 401 for a member who left GravityAccess ended with their membershipNothing. The account can't be used.
HTTP 403 with error="insufficient_scope"The token lacks the read or edit permission for this operationContinue within the granted permissions, or authorize the scopes in the challenge if you want the additional capability.
HTTP 429 with error="rate_limit_exceeded"The member's read or write limit was exceededRespect Retry-After before retrying. No tool in the request ran.
HTTP 503 with "MCP authorization is temporarily unavailable."Gravity's sign-in service is downTry again later.

Tool errors#

Input validation failures return isError: true with text beginning Input validation error; nothing runs. Unknown tools produce a protocol error. These protocol failures do not use the application error envelope.

Executed-tool errors return { status: "error", code, message, recovery } as both structuredContent and JSON text, with isError: true. Conflicts include currentState when the owned goal is available. Known goal/run IDs may also be included. Messages explain the situation; codes and recovery values are stable.

CodeRecoveryMeaning and next step
unavailableresolve_idAn exact group or goal is missing or inaccessible. Resolve from current authorized lists; do not guess IDs.
version_conflictread_before_retryThe goal's scope or context revision changed. The edit was rejected without changing wording, private context, or audience. Read current state before preparing a revised action.
request_id_conflictnew_requestThe member already used this request ID with different arguments. Nothing changed. Recover the original action with its original arguments, or use a new ID for a new action.
clarification_requiredclarify_goalThe goal needs clarification before a search can start. Read its question and help answer it; no search started.
request_rejectedread_before_retryA goal or search rule rejected the request before changes. Use the message to correct the request after reading current state.
operation_failedretry_read for reads; read_before_retry for writesAn unexpected failure left the outcome unconfirmed. Reads can be retried. Read current state before considering another write.
invalid_responseretry_read for reads; read_before_retry for writesThe application's response did not meet the tool contract. No malformed/private payload is returned. The outcome is unconfirmed; use the same recovery as an unexpected failure.

An accessible empty list is successful. Missing and inaccessible exact resources both return unavailable, without disclosing which condition applies.

Example conflict:

json
{
  "status": "error",
  "code": "version_conflict",
  "message": "The goal has changed since this edit was prepared. Review its current state.",
  "recovery": "read_before_retry"
}

Retries and request IDs#

Use a fresh UUID requestId per new action. Request identity is scoped to the authenticated member and operation; reuse with different arguments returns request_id_conflict.

A goal save compares only supplied fields. If they already match current state, return no_change with current state and perform no write or search. If an already-applied request would now change the goal, return version_conflict and current state. A supplied stale version also rejects a new edit that would change state. Otherwise apply the patch atomically. There is no historical receipt replay.

An edit's expectedVersion is optional and checks the complete editable state. scopeVersion and contextRevisionId identify matching inputs and support optional narrower preconditions. Omitting a field preserves its current value, including when other actors edit concurrently.

Search requests capture current matching inputs atomically. Repeating the same request reuses its admitted run without another workflow, even if the first admission reused a different request's run. Changed arguments conflict; superseded goal inputs conflict. A separately authorized search retry is a new action.

Goal wording, private details, audience, and visibility commit together. Rejected edits change nothing. MCP saving starts no search, so search failure cannot turn a save into a partial save/search outcome.

Limits#

LimitValue
Goal text2,000 characters
Private details (additionalContext)4,000 characters
Groups per goal100
Running searches per goal1
MCP reads per member10 per second, shared across clients
MCP writes per member1 per second, shared across clients
Access token lifetime1 hour
Staying connected (offline_access)Until 90 days without use

Sign-in endpoints are rate limited. If you see HTTP 429 while signing in, wait a minute and try again.

MCP discovery and transport messages count toward the read limit. Each operation in a batch counts separately; a batch above either limit is rejected before any tool runs. MCP 429 responses include Retry-After: 1.

Each search does real work for every network it covers. Start one only when you're asked, and never in a loop. A full search on a goal that was already searched replaces matches nobody has acted on.

Results are plain JSON. get_goal returns goal state and versions; get_goal_matches returns saved matches. Reads reflect the current search lifecycle, including failed or cancelled background executions, without starting new matching work. If a request is rate limited, respect the returned retry guidance and do not start searches in a loop.

Private note changes#

save_person_notes requires the exact person's current expectedVersion and 1–12 changes. Each saved fact is one single-line claim of at most 280 characters. A rejected batch saves nothing. Notes stay private and saving starts no search. find_people requires a 2–200 character name or email query and returns at most 20 identities from your own Rolodex.

Note conflicts can include personId and noteState with the current owned identity, version, and note history. Re-read before preparing a new action. Reusing a request ID with different arguments returns request_id_conflict. An identical retry returns no_change only while its original effects still hold; an intervening correction or forget returns version_conflict. A new action needs a new ID and current version. Forget removes a fact from active use without restoring a predecessor; retained history is not erased.

Person saves#

get_person reads one exact owned person with an opaque version. save_person requires that version for an edit and uses a member-scoped UUID request ID. Create with a name and how the member knows them. Supplied sections replace whole sections; source basis is required. Email addresses are additive, up to 20 per call. Profile claim sections allow up to 40 single-line claims of 400 characters; summary allows 4,000 characters. Name allows 120 characters; LinkedIn URL 2,048; company and position 200 each; basis 500.

Identity conflicts reject the atomic save; an existing email on creation returns the owned current personState for review rather than merging. A stale version or changed original retry effect returns version_conflict. Changed arguments with an existing ID return request_id_conflict. Review current details and prepare a new action rather than restoring older values. See save_person for clearing and reset semantics.