Skip to main content

One connection, account-resolved tools

v2 chooses a persona through the URL. v3 connects to one URL and resolves its catalog from the account kinds you can reach. A person who can administer an organisation, sell from a Seller Account, and buy through multiple Buyer accounts can move between them without registering multiple MCP servers, by naming the account on each call. A call that names its account is scoped to that call and neither reads nor changes the connection’s stored selection, which stays only as a fallback for calls that omit accountId until removal. Begin with get_status with no accountId: it lists the accounts you can reach. Then name the account you work in with accountId on every call. See Name the account on every call.

Name the account on every call

Every v3 tool takes accountId, the account the call runs in, and your tool list marks it required (except on save_account and save_directed_campaign_subscription, where it stays optional until the old shape is removed). Send it on every call, reads included, with the accountId from get_status. get_status is the one tool where it is optional: with it, get_status reports that account; without it, it lists the accounts you can reach. The call runs in that account for that call only: nothing about the connection changes, so another conversation on the same connection is never moved. This is the way to work in more than one account at once. Five inputs used accountId for something else before: member reads in get (now memberAccountId), save_account (now id), save_directed_campaign_subscription (now providerAccountId), the map_account action of buyer_sellers_page (now providerAccountId) and the connection account on the Media Partners Page (now connectionAccountId on open_media_partners_page). On the first four, accountId names the call’s account only when you also send the new input. Without it, accountId keeps its earlier meaning for now, except on a save_account call that creates an account (it carries accountType), where accountId always names the account the call runs in. open_media_partners_page has no such fallback: its accountId always names the account the call runs in. It takes the connection account to open as connectionAccountId, from the connection’s accounts[].id, and the seller to open as sellerAccountId, the seller’s Account id. A call that still sends sellerId is refused with an error that names sellerAccountId. V3 no longer has open_connections_page, the tool’s earlier name: a call to it is refused as an unknown tool. Use open_media_partners_page. The server checks that you can work in the account you name: a membership in it, or an administrator role on its parent organization. Naming an account never grants access you do not already have. A Scope3 staff member who names an account they are not a member of gets the platform support access that applies to it and nothing more. For now, a call that names no account still runs in the account the connection last switched to, or in your credential’s home account, and its result ends with a line asking you to send accountId. switch_account is retired: it is in no tool list, and it still runs from tool lists that hosts cached earlier, with a result that says so. expectedAccountId is no longer listed either, and the server still accepts it. The removal date will be announced in advance. Send accountId instead. Credentials fixed to one account (WorkOS user and organization API keys, machine credentials, buyer agents) can name only that account. The v3 HTTP API names its account with accountId in the request too; its X-SCOPE3-CUSTOMER-ID header is deprecated, and if both are sent they must name the same account.

Writes that omit the account

An account switch used to move every conversation on a connection, not just the one that asked. That is why a write has to say which account it is for. A write names it with accountId, which never grants access and never changes any selection. While the transition runs, a write that omits accountId is still checked. If your connection can be switched to another account, the write fails with ACCOUNT_CONFIRMATION_REQUIRED. That covers people signed in to a connector and personal (legacy) Scope3 API keys. WorkOS user and organization API keys and machine credentials are fixed to one account, and so is the v3 HTTP API, so no switch can move them and an omitted accountId runs in their account. The server enforces this whatever tool list your client has cached. expectedAccountId is no longer listed. The server still accepts it, and it must agree with accountId when both are sent. ACCOUNT_CONFIRMATION_REQUIRED names the company of the account the connection is in, and gives no accountId, so take it from what the conversation established or from get_status, and confirm it with the person before you resend.

Orientation is always available

get_status returns:
  • the account you named and its account kind, or, when you name none, the accounts you can reach;
  • readiness and transaction state when available;
  • blockers and typed next actions;
  • ready buyer destinations where applicable; and
  • a bounded list of reachable accounts that says when it is truncated.
get_status remains available in an unclassified account. This is a navigation contract, not access to buyer or seller account data. A Developer account (account kind developer) is an account that owns agents. It has no buyer or seller nouns in v3, so it lists only get_status, and get_status describes it with the unclassified orientation state while reporting kind: developer. Developer accounts are in a closed preview.

Nouns and verbs

v3 uses a small verb vocabulary over account-owned nouns: Reads can share a safe envelope. Writes cannot: each save_<noun> has its own schema so a model does not choose an operation name and then guess the body.

Tool discovery is part of the contract

The catalog may differ by:
  • account kind;
  • permissions;
  • feature rollout; and
  • MCP App support in the host.
Treat tools/list as the source of truth for names and JSON Schemas for the account kinds you can reach. If your principal can reach both a Buyer Account and a Seller Account, it lists the deduplicated union of both catalogs at connection time. Those tools are still authorized only in the account a call names: get_status lists the accounts you can reach and the kinds represented in the listed catalog. The tool catalog explains the stable families and intended workflows; it does not replace runtime discovery. A call from a cached tool list that still runs switch_account makes v3 emit notifications/tools/list_changed. Hosts can cache their initial tool list, so they must not rely on that notification: a dual-access principal already sees both account kinds, and a wrong-account call returns a typed error that names the account the call ran in, the required account kind, and the accounts you can reach that can run the tool. It tells you to name one of them with accountId. Confirm with the person which account they mean.

Tasks, Pages, and model visibility

Some work should not be represented as model-authored fields. OAuth grants, credentials, payout destinations, legal acceptance, and certain review actions belong in a human-facing Page.
  • A model-facing tool may return a Page as the next action.
  • open_page opens a named Page with bounded focus parameters.
  • Resource-bound MCP App tools may be present on the wire but hidden from model context by their visibility metadata.
  • A Page stays in the account it opened in. Its calls name that account with accountId, so they keep running there whatever another conversation does. In the Apostra web app, a Page whose browser tab has since moved to another account is refused with ACCOUNT_MISMATCH, and a Page in an account you can no longer reach is refused with ACCOUNT_NOT_REACHABLE. Nothing is read or written either way; reopen the Page in the account you want.
Do not bypass a Page by placing credentials, bank details, or authorization decisions in another tool’s free text.

Declarative writes

A save_<noun> call states the desired noun state. Responses distinguish:
  • created or updated — a write occurred;
  • unchanged — the current state already matched;
  • pending_approval — a governed or seller-applied change was staged, not committed; the object keeps its live state, and a media buy’s pendingChange describes the waiting change;
  • a *_requested action (cancellation_requested, pause_requested, resume_requested) — the seller accepted the change and is still applying it, so the object keeps its live state until the seller confirms; and
  • an error or partial-write result — the response explains what did and did not persist.
Nothing is reported as done before it is. Send patches, not reconstructed whole objects, unless a schema explicitly asks for replacement. Preserve returned identifiers exactly. Qualified product and proposal IDs encode seller routing and must not be shortened or rebuilt.

Concurrency and idempotency

These mechanisms answer different questions:
  • expectedRevision prevents overwriting a newer object state. Re-read after a REVISION_CONFLICT and decide whether the intended change still applies.
  • idempotencyKey deduplicates one logical attempt where the tool promises it. Reusing a key for different intent is an error; inventing a new key for every retry can duplicate work.
  • correlationId, where offered, is a tracing handle and is not necessarily an idempotency key.
Use the exact semantics in each tool’s runtime schema and workflow guide.

Includes keep diagnostics attached to the object

Health, sync history, and capability evidence are facts about a resource, so they are generally requested through get.include:
Successful facts remain available when another requested include cannot be resolved. A response marks unsupported or partial detail instead of presenting it as an empty result.

Pagination and completeness

Pass the returned opaque nextCursor back to the same query while hasMore is true. Do not edit, reuse across kinds, or interpret a cursor. A partial response must say what was not reached; an empty items array alone is not evidence that the underlying system contained no results.