Skip to main content

Build an MCP integration

ARC exposes a remote Model Context Protocol server for AI clients and agents:

https://<arc-host>/mcp

MCP is the right surface when a user wants an agent to operate ARC with consent and the user's current permissions. It is not a replacement for the deterministic GraphQL/service APIs in a data pipeline.

Connect a client​

A generic MCP client configuration looks like:

{
"mcpServers": {
"growmax-arc": {
"url": "https://<arc-host>/mcp"
}
}
}

The client should:

  1. send an unauthenticated request to discover the protected-resource metadata;
  2. discover the authorization server for the same host;
  3. dynamically register with POST /register when supported;
  4. use authorization code + PKCE (S256);
  5. open the ARC consent page so the seller can sign in and approve the organization;
  6. exchange the code at /token and call /mcp with the access token.

ARC also publishes:

GET /.well-known/oauth-authorization-server
GET /.well-known/oauth-protected-resource/mcp
GET /.well-known/oauth-protected-resource
GET /mcp/info
GET /mcp/icon.png

Use the metadata returned by the host you connected to. Do not hardcode a global issuer or move a token between tenant hosts.

Token and origin rules​

  • Access tokens live for one hour.
  • Refresh tokens are long-lived, rotate on every use, and must replace the old refresh token in storage.
  • Authorization codes are single-use and short-lived.
  • A token is bound to one user, one active organization, and the exact /mcp audience.
  • Disabling the user or organization invalidates the retained grant.
  • MCP tokens are not ARC API keys and are not accepted as GraphQL credentials.

The catalogue is permission-filtered​

tools/list is the set of tools allowed by all of these layers:

  1. requested OAuth scope (read and/or write);
  2. the signed-in user's current ARC permissions;
  3. the tenant's plan features;
  4. the MCP tool registry.

The list is a capability hint. ARC re-checks authorization again during tools/call. Do not cache a tool as permanently available.

Tools are backed by the same catalog-copilot registry used by ARC's own assistant. The authoritative input and output JSON Schemas are the schemas returned by tools/list, not a hand-copied table in your application.

Read data​

Read tools cover catalog, pricing, customers, suppliers, inventory, sales documents, purchasing documents, invoices, payments, and analytics. A read is always tenant-scoped from the token; there is no tenant argument.

List tools use cursors where supported. Persist nextCursor, check hasMore, and use the output schema's content key. ARC's MCP result contract does not put every list under a generic items property.

Writes are three-phase​

MCP writes are intentionally not a single model-generated command:

propose_* → human approves the ARC proposal card → apply_proposal with confirm: true
  1. Call a propose_* tool. It returns a persisted proposal envelope, usually with proposalId, sessionId, status, payload, and approvalUrl.
  2. Open approvalUrl and have the operator approve the current proposal in ARC. A sentence such as “yes, do it” in chat is not human approval.
  3. Call apply_proposal with the proposalId, the sessionId, and confirm: true. It applies an approved proposal of any kind, with the same permission, plan and approval checks. idempotencyKey is optional: reuse the same key verbatim to retry an apply after a timeout, and ARC replays the original result instead of applying again. To learn whether the operator has approved, call get_proposal with the same ids.

The per-kind apply_* tools still work but are deprecated. Their tools/list entries carry _meta.deprecated and the removal date, 2027-01-14. Use apply_proposal in new integrations.

A proposal can require more input, become stale, or already be applied. Handle HUMAN_APPROVAL_REQUIRED, PROPOSAL_STALE, and PROPOSAL_ALREADY_APPLIED as explicit workflow states.

Result handling​

Read results are egress-clamped to the projection ARC's copilot is allowed to expose. Use the returned outputSchema; do not assume the full GraphQL object is present. Proposal and apply results have separate envelopes.

A tool call can fail because of:

  • missing user permission or plan access;
  • missing required input or a server-side question;
  • a stale proposal/document;
  • a rate limit (429 with retry metadata);
  • a business rule such as no price in the requested currency or insufficient stock.

MCP-specific production rules​

  • Keep refresh tokens in an encrypted server-side store.
  • Reconnect using the same tenant host that minted the grant.
  • Treat tools/list as dynamic and refresh after reauthorization.
  • Send an idempotencyKey with apply_proposal so a retry after a timeout replays the original result.
  • Never add a tenant id to tool arguments to “make isolation explicit”; ARC derives it from OAuth.
  • Use GraphQL/service REST for deterministic bulk synchronization; use MCP for user-directed agent work.

The repository maintains a deeper connector contract for internal development, but the live tools/list schemas and initialize instructions remain authoritative for external clients. Ask your Growmax account manager for access to the full connector pack when your integration needs a complete tool-by-tool contract.