https://api.platformdtc.com/mcp. Agent tools
put your app in that assistant’s hands. A merchant who installed your loyalty app can say
“give Maria 500 points for the late delivery”, and the assistant calls your award_points tool.
You never share your database. You declare what the assistant may ask your app to do, and your
server does it. Apps plug in two ways:
Coming from Shopify? Agent tools are the PlatformDTC version of Sidekick app extensions. The
declaration is the same idea (a name, a description and a JSON Schema input, 20 per app, shipped
with an app version). The difference is where the tool runs: on Shopify it runs in the admin’s
browser sandbox; here the merchant’s agent is outside any browser, so the platform calls your
server with a signed request, like a webhook.
1. Declare tools on a version
Tools belong to an app version, next to its scopes and extensions. Send them asagent_tools when you create the version:
version.json
Limits: 20 tools per version. Skill and built-in apps cannot declare tools (they have no
server to call). A version is fixed once created: to change a tool, create a new version and
submit it for review, exactly like a scope change.
When you submit the version, review sends each tool’s
url one call signed with the wrong
secret (shop app-review.invalid, empty arguments). Every tool must answer 401, or the
agent_tools_reject_invalid_signature requirement fails. The review team reads your tools with the rest of the version. Keep each tool inside what your
app does and what your listing says, and never use a tool to promote other products or ask for
reviews.
2. What the assistant sees
On a store where your app is installed, the assistant’s tool list gains your tools, named"<App name>: <title>". If that name would pass 64 characters (the limit most AI
clients enforce), the handle is shortened and given a 6-character suffix; your test call shows the
exact name.
A tool is listed only when all of these hold, checked on every list and every call:
- your app is installed on that store and not suspended, and the tool is on the version that install approved;
- the merchant granted every one of the tool’s
required_scopesto your app (a declined optional scope hides the tool); - the merchant’s assistant also holds every one of those scopes. An assistant the merchant connected read-only never sees your write tools, so your app can never give an assistant more power than the merchant gave it;
- the caller is the merchant’s assistant or the merchant, not another app. Apps do not call each other’s tools.
3. Handle the call
Each call is aPOST to the tool’s url:
actor.type is agent when the merchant’s assistant made the call and merchant when the
merchant made it from the dashboard. shop and store_id tell you which store to act on; use the
access token your app got when that store installed it.
Verify it
The signature is the same algorithm and the sameclient_secret as your
webhooks: HMAC-SHA256(client_secret, raw_body),
hex, prefixed sha256=. Compute it over the raw request bytes, compare in constant time, then:
- Answer
401on a bad signature. - Refuse a
timestampmore than 5 minutes old (replay protection). - De-duplicate on
idempotency_key. A retried call carries the same key: do the work once and answer the saved result again.
Answer it
Answer within 10 seconds with JSON. What you return is what the assistant reads, so keep it small and plain: the facts it needs to answer the merchant, not your whole record.
Use
4xx for anything the assistant can fix: a customer that does not exist, a value out of range.
A clear message such as {"message": "Customer c_81f has no loyalty account yet"} lets it correct
the call or explain the problem to the merchant. Redirects are not followed: answer at the URL
you declared.
Before calling you, the platform checks that arguments is a JSON object (at most 256 KiB) with
every top-level required property of your input_schema. Validate the rest yourself and answer
422 with a message when it is wrong.
4. Tools that need the merchant’s approval
A tool withrequires_approval: true, or any tool needing a scope that moves money or contacts
customers (write_discounts, write_gift_cards, marketing:send, ads:write,
checkout:recover, store:publish, publish_themes), never runs straight from the assistant:
- The assistant’s call comes back as
pending_approvalwith a job id. Your server is not called yet. - The merchant sees the request in their dashboard (Agents, under Waiting for you) as “App action”, with your app name and the tool’s title, and approves or denies it.
- On approval, the platform checks again that your app is still installed with those scopes, then calls your tool exactly as above. The assistant reads your result from the job.
5. Limits and reliability
- 60 calls per minute per store for each installed app. Past that the assistant gets
RATE_LIMIT_EXCEEDEDwith aRetry-After. - Circuit breaker. After 5 failures in a row (
5xx, network errors, timeouts; not4xx), calls to your app stop for 30 seconds and fail at once withAPP_UNAVAILABLE, then one call is let through to test you. A slow or down app cannot slow the merchant’s assistant down. - Every call is recorded in the merchant’s agent audit log with your app, the tool and the outcome.
6. Test a tool
In the Partner dashboard, open your app → Versions, expand a version and choose Test next to a tool. Pick one of your development stores, enter arguments, and the platform sends the exact production request (same envelope, signature and limits) to your URL. You see the status, the time it took, the name the assistant will see, and your response or the error it would get. The same test is available over the API (10 calls a minute per app; you must be an owner, admin or developer of the app’s partner organization):"ok": false and error: {code, message} with the same codes as the table
above.
7. Declare tools with the CLI
With the CLI, agent tools live in an extension folder, like Shopify’stools.json:
extensions/assistant/platformdtc.extension.toml
tools.json is the agent_tools array from step 1. A tool’s url may also be a path such as
"/agent/award_points", resolved against your application_url. dtc app deploy (and
dtc app config push) checks every rule above before sending, and puts the array on the new
version. An app has at most one agent_tools folder. See App configuration.
Share data with the assistant
Some things are better read than called. Write them into custom data your app owns, and the merchant’s assistant reads them with the tools it already has. Nobody else can change them.
Use your app’s access token (the
sq_agt_… key your app got at install). The platform stores
$app as app--<your app id> and $app:<sub> as app--<your app id>--<sub>, and returns the
stored form in responses. Writing an app--… namespace or type that is not yours is refused
(403), and $app from anything but an app token is a 400. The merchant’s dashboard shows your
data read-only.
When a merchant uninstalls your app, your data stays for 48 hours, the same window as
shop/redact. If they reinstall inside it, nothing is lost.
After it, the platform deletes your metafields and metaobjects on that store, just before it sends
shop/redact. Your metafield definitions go once your app is installed on none of the merchant’s stores.
Metafields (reference, scopes read_metafields / write_metafields):
store:read / store:write; writes need an
Idempotency-Key):
metaobject_id in the same body; list yours with
GET /api/v1/agent/v1/metaobjects?type=$app:reward. The merchant’s assistant finds them with
dtc_list_metaobjects and dtc_get_metaobject.