
Square gives an AI agent two ways into a seller's account: an official MCP server in beta that reaches 38 Square API services through three generic tools, and the REST API with OAuth permissions, webhooks and a sandbox. They overlap on nearly every resource. They diverge on how tools are shaped, which environment you can test in, how events reach you, and who holds the credential. This guide compares what each path lets an agent do, the credential each one puts you on, and how to serve thousands of small sellers in production.
Your agent needs to work inside your customers' Square accounts: summarize yesterday's sales for each location, find the refunds that went out without a note, answer a chargeback before its deadline, or check which items are about to run out. Those customers are small businesses. A coffee shop, a salon, a food truck, a boutique with two locations: each one is a separate Square seller with its own OAuth grant. Square ships an official Model Context Protocol (MCP) server that reaches almost every Square API, and it ships the REST API itself with webhooks and per-endpoint permissions. They overlap on nearly every resource. They diverge on how tools are shaped, which environment you can test in, how events reach you, and who holds the credential. Here's how to pick.
The Square MCP server is a bridge from AI clients to the Square REST API, and Square's docs state that it "is currently in Beta." It runs two ways. The hosted server at https://mcp.squareup.com/mcp, run by Block, signs users in with OAuth, so there are no access tokens to manage by hand. The local server runs with npx square-mcp-server start and reads a Square access token from ACCESS_TOKEN, with SANDBOX=true or PRODUCTION=true to pick an environment, DISALLOW_WRITES=true to restrict it to read-only operations, and SQUARE_VERSION to pin an API version. The GitHub README lists the hosted endpoint as https://mcp.squareup.com/sse for SSE clients.
The tool design is unusual. Instead of one tool per endpoint, the server exposes three: get_service_info to list a service's methods, get_type_info to read a method's parameters, and make_api_request to execute the call. The services behind them cover 38 areas, including payments, refunds, orders, catalog, inventory, customers, loyalty, gift cards, bookings, invoices, subscriptions, disputes, payouts, labor, team, terminal, devices, cash drawers, bank accounts, vendors, and webhook subscriptions. The code is generated from Square's OpenAPI specification. Square lists Claude.ai, Claude Desktop, Goose, Cursor, and Windsurf as supported clients and keeps an allowlist of MCP clients to guard against malicious registrations; anything else must request access on the developer forum.
The Square API is a set of REST APIs under https://connect.squareup.com/v2, with a separate sandbox at https://connect.squareupsandbox.com. It covers the same services the MCP server routes to: payments, refunds, orders, catalog, inventory, customers, loyalty, bookings, invoices, subscriptions, disputes, payouts, team and labor, terminal, and more. Every request carries a bearer token. Square offers two kinds: a personal access token, which "provides unrestricted Square API access to resources in a Square account" and only reaches the account that created it, and an OAuth access token, which a seller grants your app with specific permissions. Multi-tenant products use OAuth. The API is versioned by date through the Square-Version header, and Square releases new versions "typically on a monthly basis."
On raw coverage, Square MCP is close to the full API. It routes to almost every service Square offers, including several the Scalekit connector doesn't wrap as tools. The differences are in shape and in the edges: the hosted server runs only against live seller data, it can't receive events, and the webhook and Events endpoints sit behind a credential type it doesn't use.
Three tools is the smallest catalog in this series. A model holding get_service_info, get_type_info, and make_api_request carries a few hundred tokens of tool definitions, not tens of thousands, and it can still reach refunds, catalog, and bookings when a question needs them. For an exploratory question such as "which items sold out at the Mission Street location last weekend," the model can look up the inventory service, read the method's parameters, and make the call without anyone writing a schema. Writing the schema is the hard part. Not the API call. Square generated that layer from its OpenAPI specification, so the MCP server tracks the API as Square ships it.
The tradeoff is that the model does the schema work at run time. Every new operation is a three-step chain: discover the method, read its type, then build the request body by hand. That costs round trips, and the request body is assembled from a type description rather than a curated example, so a wrong field name or an amount in dollars instead of cents surfaces as a Square error, not a schema validation failure. The tool surface is also flat in a way that matters for safety. make_api_request is one tool whether it reads a payment or refunds one. You can't hand an agent "payments, read only" at the tool layer on the hosted server; you get whatever the OAuth grant allows. Locally, DISALLOW_WRITES=true is the only switch, and it is all or nothing.
On the MCP path, the hosted server signs the user in with their Square account through OAuth in the browser. Square's docs say remote OAuth lets users authorize only the scopes an application needs, and the session then acts inside that Square account. The local server skips OAuth entirely: it reads one token from ACCESS_TOKEN, which in practice is either a personal access token with unrestricted access to one account, or an OAuth token you obtained elsewhere. The client allowlist is the Square-specific catch. Off-the-shelf clients such as Claude and Cursor work immediately. A custom agent backend that wants to call the hosted server for your customers has to get on Square's allowlist first.
On the direct API path, a seller grants your app permissions through the OAuth code flow at https://connect.squareup.com/oauth2/authorize, and your server exchanges the code at POST /oauth2/token. The token lifecycle is long by industry standards: "Square OAuth access tokens expire after 30 days," and "refresh tokens obtained using the code flow don't expire." The PKCE flow, meant for public clients, issues single-use refresh tokens that expire after 90 days. Square's best practices say your app "should automatically renew OAuth access tokens every 7 days or less" and should raise an alert when a stored token is more than 8 days old.
Permissions are named per endpoint in the Permissions Reference: PAYMENTS_READ for ListPayments, PAYMENTS_WRITE for RefundPayment, ORDERS_READ for SearchOrders, DISPUTES_WRITE for submitting chargeback evidence, MERCHANT_PROFILE_READ for ListLocations, and so on. Square tells you to record the permissions you request, because you can't look them up later from an authorization code or token; RetrieveTokenStatus is the way to check a live token. You can narrow an existing grant by refreshing with a scopes array that is a subset of the original, and a 403 with INSUFFICIENT_SCOPES means the grant lacks a permission.
The credential types also split the work. OAuth tokens can't call the Webhook Subscriptions API or the Events API; those "require the developer's personal access token." Your webhook plumbing therefore runs on your own developer credential, configured once for your Square application, while every seller-facing call runs on that seller's OAuth grant. Each event carries a merchant_id, and mapping it back to the right customer is your job.
In a multi-tenant B2B agent, MCP gives you a credential per user and the direct API gives you a credential per user. In neither case does the path itself solve storage, rotation, or revocation; those are infrastructure problems regardless of which path you choose.
Square sharpens this because of who its sellers are. A Square grant covers a seller account, and most of your customers are one-owner businesses with a handful of staff. That makes the seller the natural unit: one connected account per business. It also means the long-lived refresh token from the code flow is effectively a standing key to that small business's payments, refunds, and customer list until someone revokes it. The agent acting for the coffee shop must never be able to reach the salon. What the user can't do, the agent can't do, and the only thing enforcing that on the API path is how you bind each grant to one customer.
Recommended reading: access control for multi-tenant AI agents
On the MCP path, Square hosts the server, generates the tool layer from its spec, and enforces the grant. You own each user's OAuth session inside a client you may not control, and the reconnect when it goes stale. You also own the gaps. The hosted server can't touch the sandbox, so every prompt you test against it runs on a live seller's data; Square itself recommends testing prompts against a sandbox account first, which means the local server. MCP tools only run when someone starts a conversation, so nothing happens when a chargeback arrives at 2 a.m. And because the server is in beta, its behavior may change without a release on your side.
On the API path, you own schemas, pagination, retries, versioning, and the token lifecycle. Square returns 429 Too Many Requests with a RATE_LIMITED code, publishes no numeric limits, notes that "Square API endpoints might enforce different rate limits," and recommends exponential backoff with jitter. In a July 22, 2026 developer forum answer, Square staff confirmed that "rate limits are at the application level and may vary by endpoint." For a product serving thousands of small sellers, that is the constraint that shapes your scheduler: nightly syncs for every seller compete for one budget, so you stagger them or a few large catalogs starve everyone else.
Versioning is another thing you own. Every app has a default API version pinned in the Developer Console, which applies to any request without a Square-Version header. Upgrading the default changes behavior for every seller at once, so pin the header in code and move it deliberately.
Webhooks carry their own rules. Your endpoint has 10 seconds to respond with a 2xx. Square retries failed deliveries for up to 24 hours with exponential backoff, then drops them. "Webhooks can be sent more than once," and there is "no guarantee of the delivery order of event notices," so you deduplicate on event_id. Each notification is signed with HMAC-SHA256 in the x-square-hmacsha256-signature header, computed over the notification URL and the raw request body with your subscription's signature key. Because the URL is part of the signature, a proxy or load balancer that rewrites the URL breaks validation. Missed events are recovered through the Events API, which again needs your personal access token.
Revocation arrives from the seller's side. A seller can disconnect your app from the Square Dashboard, which revokes every token for that seller, and the oauth.authorization.revoked webhook's revoker_type tells you whether the seller, your app, or Square did it. When a customer churns, POST /oauth2/revoke, authenticated with an Authorization: Client header carrying your application secret, revokes "the entire authorization" by default.
Use Square MCP when:
Use the Square API when:
Both paths hand you a Square credential per seller. Neither hands you a vault. A vertical SaaS product serving 2,000 salons holds 2,000 OAuth grants on the API path. Each has an access token that must be renewed at least every 7 days, and a code-flow refresh token that never expires, which makes it the most valuable thing in your database. Behind them sits your Square application secret, which signs refreshes and revocations for every seller at once. Every token must be encrypted at rest, kept out of logs and LLM context, refreshed on schedule rather than on the first ACCESS_TOKEN_EXPIRED, and cleaned up when the seller disconnects from their Square Dashboard.
The MCP path changes where the sessions live, not the problem. Each owner who connects through Claude or Cursor holds their own session, which matches Square's model, but you can't refresh, inspect, or revoke those sessions from your backend, and a custom backend can't use the hosted server at all until Square allowlists it. The tempting shortcut is the local server with a personal access token per customer. That is unrestricted, unscoped access to each customer's Square account, issued by them, pasted into your systems. Fewer moving parts, larger blast radius per secret.
Scalekit's square connector handles the Square OAuth flow, token storage, and refresh for every connected account, so the MCP vs API decision doesn't change your auth infrastructure. Your agent passes an identifier; credentials never touch the agent runtime or the LLM context.
Recommended reading: how to handle token refresh for AI agents
Scalekit's square connector is an API-path connector built by Scalekit with 118 tools: 69 read, 49 write, and 0 destructive. It covers payments, refunds, orders, catalog, inventory, customers, customer groups and segments, loyalty, gift cards, cards on file, bookings and booking profiles, invoices, payment links, subscriptions, disputes, payouts, locations, merchants, team members, wages, timecards, break types, and vendors. Write tools take an idempotency_key, so retries return the original result instead of acting twice. It authenticates with OAuth 2.0: each seller signs in to Square once, and Scalekit stores and refreshes the tokens.
In the Scalekit dashboard, go to AgentKit > Connections, create a Square connection, and copy its redirect URI. The name you give the connection is the connection_name your code passes, and the string must match the dashboard exactly. This is the most common integration error.
Square connections require your own OAuth app. In the Square Developer Console, create an application, add the Scalekit redirect URI on its production OAuth page, and paste the application's ID and secret into the Square connection. Then select the permissions your tools need on the connection; they apply to every connected account that uses it. For the examples below that means MERCHANT_PROFILE_READ, PAYMENTS_READ, ORDERS_READ, DISPUTES_READ, and DISPUTES_WRITE. Leave out PAYMENTS_WRITE unless an agent role genuinely issues refunds. Copy SCALEKIT_ENVIRONMENT_URL, SCALEKIT_CLIENT_ID, and SCALEKIT_CLIENT_SECRET from Developers > API Credentials into .env.
get_or_create_connected_account returns the connected account for an identifier. If it is not ACTIVE, get_authorization_link returns a link to Square's OAuth consent screen for your app. The seller approves once; Scalekit exchanges the code and stores the tokens, and the agent never sees them. Here the identifier is your customer's ID, because the grant covers the whole Square seller account. The last step records the seller's Square merchant_id, which you need later to route webhooks.
This is not a catalog load. The agent asks for the tools this connected account is authorized to call, then narrows them to the six a daily-close agent needs. Loading all 118 Square tools would put square_refund_create, square_dispute_accept, and square_payment_create in front of a model whose job is to summarize a day of sales. None of the six below changes anything in Square.
The loop runs until the model stops requesting tools. Every call executes with this seller's Square grant. The system prompt carries the two Square details models get wrong most often: amounts are in the smallest currency unit, and square_payments_list defaults to the main location unless you pass a location_id.
For pipelines, skip the model. execute_tool runs one tool with a fixed input and returns data plus an execution_id you can log. This handler runs when your webhook endpoint receives a dispute.created event. It verifies the signature with Square's SDK helper, drops duplicate deliveries, maps the event's merchant_id to your customer, then pulls the disputed payment and its order and attaches a text summary as evidence. It stops before square_dispute_evidence_submit, because evidence can't be added after submission and a person should read it first.
The webhook subscription itself is not a connector tool, and on Square it can't be one: subscriptions belong to your Square application and are created in the Developer Console or with your personal access token, not with a seller's OAuth grant. Subscribe once to dispute.created, which requires DISPUTES_READ on each seller's grant, and route every event by merchant_id. The Square MCP server has no equivalent for either step.
Two other writes show where the API path earns its place. square_refund_create refunds a completed payment and requires an idempotency_key, and square_dispute_accept concedes a chargeback. Neither belongs in a model's default tool set; both fit a pipeline with a human approval step in front of them.
The square connector has 118 tools. At roughly 200 tokens each, that is about 23,600 tokens of tool definitions before the agent does any work. Square's own MCP server avoids that cost with three generic tools, but it moves the problem rather than solving it: the model can still reach every service the grant allows, and the decision of what it may do lives in the prompt. A dispute agent that can reach square_refund_create or square_dispute_accept can refund or concede on a bad inference. The fix is not better prompting. It is surface reduction. A Scalekit virtual MCP server declares exactly which tools an agent role can see, and session tokens keep each run bound to one seller's connected accounts. Docs: set up a virtual MCP server.
One server definition serves every seller. Before each run, check that the seller's accounts are active and mint a short-lived session token scoped to them. Any MCP client that speaks Streamable HTTP can connect; this example uses langchain-mcp-adapters (pip install langchain-mcp-adapters) and passes the token as a Bearer header.
The agent sees six tools instead of 118, and none of them can move money. The endpoint is static; the identity is per seller. Unlike Square's own MCP server, this endpoint needs no client allowlisting, works from your own backend, and lets you give a refund role square_refund_create while every other role goes without it.
Every execute_tool call returns an execution_id, and every execution is attributed to a connected account, which maps to one of your customers. When a salon owner asks which agent run attached evidence to a chargeback, or why a refund went out on Sunday, the answer is a lookup, not an investigation. Store the execution_id next to the Square object it touched, such as the dispute ID or the refund ID, and you can trace any Square record back to the run and the prompt that produced it.
Attribution is also where the paths differ. On the MCP path, actions run inside the owner's own chat session and the record lives in their client. On the API path, every call runs under the seller-level grant your app holds, and Square has no field that says which of your users asked the agent to act; your execution log is the only place that record exists. A shared credential across sellers breaks even that: one token reaching several Square accounts means every action looks the same, and a leak exposes all of them. Shared credentials work for one user. They do not survive a second user.
Recommended reading: audit trails for agent auth
If your agent is a seller's assistant in Claude, Cursor, or another allowlisted client, answering questions about sales, customers, and stock with the owner watching, Square's official MCP server is a good fit: it is hosted, it reaches nearly every Square service through three tools, and Square keeps it in step with the API. Run it locally against a sandbox seller while you test. If your agent runs unattended across many sellers, reacts to dispute.created and payment webhooks, reconciles payouts, or needs to be barred from refunds by construction, build against the Square API, where you choose the permissions, the tools, and the schedule. Either way, you hold an OAuth grant per Square seller, with access tokens to renew every week and refresh tokens that never expire, and that's what needs production-grade infrastructure.
Yes, in beta. It runs hosted at https://mcp.squareup.com/mcp with OAuth sign-in, or locally with npx square-mcp-server start and an ACCESS_TOKEN. Instead of one tool per endpoint it exposes three, get_service_info, get_type_info, and make_api_request, which reach 38 Square API services generated from Square's OpenAPI specification. The hosted server only touches production data, and Square keeps an allowlist of MCP clients.
It cannot receive events, since there are no triggers, and it cannot call the Webhook Subscriptions API or the Events API, because Square requires a personal access token for those endpoints and an OAuth session cannot use them. The hosted server cannot touch the sandbox, so every test prompt runs on live seller data, and the only write restriction is the local server's all-or-nothing DISALLOW_WRITES flag.
Square OAuth access tokens expire after 30 days, and Square's best practices say to renew them every 7 days or less and to alert when a stored token is more than 8 days old. Refresh tokens obtained with the code flow do not expire. The PKCE flow for public clients issues single-use refresh tokens that expire after 90 days.
Square applies rate limits at the application level, not per seller, and publishes no numeric limits. A product serving thousands of sellers shares one budget across all of them, so nightly syncs compete and one seller's catalog backfill can slow down every other seller. Square returns 429 with a RATE_LIMITED code and recommends exponential backoff with jitter.
When it runs headless from a dispute.created or payment webhook, when it runs a deterministic nightly close across every connected seller, when it serves hundreds or thousands of sellers with per-seller connected accounts, or when it needs tool-level boundaries the MCP server cannot express, such as reading payments and adding dispute evidence without ever being able to call square_refund_create.
The square connector exposes 118 tools over the Square API and runs the OAuth flow, token storage, and refresh through your own Square app. Each seller approves once, Scalekit stores and renews the tokens, write tools take an idempotency_key, a virtual MCP server narrows the tools per agent role so a dispute desk never sees refunds, and every execution returns an execution_id attributed to that seller.
Browse the Scalekit Square connector and the Square connector docs with the full tool list. See Scalekit pricing, or talk to us.