Skip to content

Connect an AI agent

Enterprise plan

An AI agent can answer questions about your warehouse and do work for you: “which orders are stuck, and why?”, “where is order #1042?”, “start the morning’s batches”. It connects to Floormode’s MCP server, signs in as you, and can never do more than you can.

  • What you need
  • Connect
  • What you approve
  • Taking access back
  • What the agent can do
  • How the agent finds its way
  • Three examples
  • When something goes wrong
  • See also
  • The Enterprise plan.
  • A Floormode person whose role includes Use the API and AI agents (REST, MCP). Administrators have it.
  • An AI client that can add a remote MCP server. Claude calls it a connector, other clients a custom integration or an MCP server. Floormode speaks the current MCP version, 2026-07-28, and the earlier 2025-06-18, so newer and older clients both connect.
  1. In your AI client, add a remote MCP server with this address:

    https://prod.floormode.app/mcp
  2. The client opens Floormode’s sign-in in your browser. Sign in with the email of your Floormode account. If you belong to more than one workspace, choose your store’s.

  3. Approve the client. The next section says what the approval screen asks for.

  4. Ask your question in the chat.

The approval screen comes from the sign-in page of your P&H account, not from Floormode’s own pages, and its words are general. What you grant is narrower than it may sound:

  • Floormode’s API for the workspace you chose: that one store’s Floormode, not your Shopify admin or any other app.
  • As you, within your role. The client reads and changes what your role allows, nothing more, and every call is checked against your role as it is at that moment. A change it makes shows in the history under your name.
  • For as long as you leave it connected. The screen asks to keep access: the client stays signed in without asking you each time, until you take the access back.

The screen may call the client unverified and warn about it. Most AI clients register themselves with the sign-in page when you add the server, and nobody can vouch for the publisher of a client that registered itself, so the page says so. The warning is about the client app, not about Floormode, and it changes nothing about what the client may do. Approve it only when you have just added the server yourself, in a client you trust.

  • In your AI client: remove the server (the connector). The client stops calling Floormode.
  • In Floormode, at once: open the person the agent signs in as under Settings → Team and choose Deactivate, or take Use the API and AI agents (REST, MCP) out of their role. The agent’s next call is refused, whatever the client still holds.

That is why a person of its own suits an agent (see below): deactivating it takes the agent’s access back without touching yours.

  • It works as you. Every read and every change is checked against your role, as in the app. A change it makes shows in the history under your name.
  • It can change data. Holds, stock adjustments and pick batches are writes. Ask the agent to say what it will do before it does it.
  • An agent of its own. To give an agent less than your own access, invite a person for it in Settings → Team (for example agent@yourshop.com), give that person a role with only what the agent needs plus Use the API and AI agents (REST, MCP), and sign in as that person when you connect.
  • Limits. Your store can make 60 calls a minute through the API, agents included. One agent request stops after 30 seconds or 200 calls.

This part is for the curious and for developers; the agent does it by itself.

The server offers two tools:

  • describe_api answers the index of everything the agent can call: each area (orders, inventory, picking, …) with its reads and its writes. Asked for an area, describe_api({ namespaces: ["orders"] }), it answers the area’s methods with their inputs and answers as TypeScript. Asked for words, describe_api({ search: "short stock" }), it answers the methods whose name or description holds every word.
  • run runs the JavaScript the agent writes, in a sandbox with no network. The agent calls app.<area>.<method>(input) and returns what it found. Several calls fit in one run.

A method’s name is the operation’s name in the API explorer with its first _ turned into a dot: orders_work_queue is app.orders.work_queue, and pick_profiles_list is app.pick.profiles_list.

What the agent writes for three questions, and what the answer looks like. You never write this code yourself.

const { groups } = await app.dashboard.needs_attention();
const short = await app.orders.work_queue({ allocationState: "short", limit: 5 });
const missing = await Promise.all(
short.rows.map(async (order) => {
const { gaps } = await app.orders.allocation_gaps({ shopifyOrderId: order.shopifyOrderId });
return {
order: order.name,
missing: gaps.map((gap) => `${gap.missingQty} × ${gap.sku ?? gap.title}`),
};
}),
);
return {
attention: groups.map(({ kind, reason, count }) => ({ kind, reason, count })),
missing,
};
{
"attention": [
{ "kind": "on_hold", "reason": "address_issue", "count": 2 },
{ "kind": "short_allocation", "reason": null, "count": 3 }
],
"missing": [
{ "order": "#1038", "missing": ["2 × MUG-BLUE"] },
{ "order": "#1041", "missing": ["1 × TEE-M-BLACK", "1 × TOTE-NAT"] }
]
}
const { hits } = await app.search.global({ query: "#1042" });
const order = hits.find((hit) => hit.type === "order" && hit.label === "#1042");
if (!order) return "No order #1042.";
const { entries } = await app.orders.journey({ shopifyOrderId: order.id });
return entries.slice(-4).map(({ atMs, kind, subject, detail }) => ({
at: new Date(atMs).toISOString(),
kind,
subject,
detail,
}));

The journey lists every step oldest first: reserved, picked, packed, label bought, shipped in Shopify, the carrier’s tracking. The last steps say where the order stands.

[
{ "at": "2026-10-21T09:12:40.000Z", "kind": "packed", "subject": "PACK-1", "detail": null },
{ "at": "2026-10-21T09:13:05.000Z", "kind": "label_bought", "subject": null, "detail": "00340434161094042557" },
{ "at": "2026-10-21T09:13:09.000Z", "kind": "shipped_in_shopify", "subject": "DHL", "detail": null },
{ "at": "2026-10-21T16:40:00.000Z", "kind": "tracking", "subject": "in_transit", "detail": "Hamburg" }
]
const { rows, totalShortfallUnits } = await app.inventory.backlog_shortfall({ limit: 10 });
return {
totalShortfallUnits,
items: rows.map(({ sku, title, demand, available, shortfall, incoming, suggestedOrderQty }) => ({
sku,
title,
demand,
available,
shortfall,
incoming,
suggestedOrderQty,
})),
};

demand is what open orders owe and available what the bins hold; shortfall is the difference. incoming is already on its way, so suggestedOrderQty is what is left to order.

{
"totalShortfallUnits": 9,
"items": [
{ "sku": "MUG-BLUE", "title": "Mug, blue", "demand": 12, "available": 6, "shortfall": 6, "incoming": 2, "suggestedOrderQty": 4 },
{ "sku": "TOTE-NAT", "title": "Tote bag, natural", "demand": 5, "available": 2, "shortfall": 3, "incoming": 0, "suggestedOrderQty": 3 }
]
}
The agent saysMeansDo
It has to sign in again and againThe sign-in did not reach your store’s workspaceSign in with the email of your Floormode account, and choose your store’s workspace if asked
The approval screen calls it unverifiedThe client registered itself when you added the serverApprove it if you added the server yourself just now; see What you approve
plan_requiredYour plan does not include the APIChoose the Enterprise plan in Settings → Billing
permission_requiredYour role does not include the APIAsk an administrator to add Use the API and AI agents (REST, MCP) to your role
RATE_LIMITEDThe store’s 60 calls for this minute are used upWait a minute. The refused call did not run, but the calls before it in the same request did: check what was already done before asking again
INVALID_INPUT or CONFLICTFloormode refused the call and said whyThe agent reads the reason and can correct the call
... is not a functionThe agent guessed a method nameAsk it to look the name up with describe_api