Skip to content

MCP server

Let your AI agent work in the warehouse

Reolora has an MCP server, so Claude, ChatGPT, Codex, Cursor, Grok and other agents can see stock, order, move and count. They follow the same rules as your staff, and everything is in the event log under the agent’s name.

Addresshttps://mcp.reolora.dk/mcp
Transport
Streamable HTTP
Sign-in
OAuth 2.1 or API key
Tools
43

Connect

Pick your client. Interactive clients sign in with OAuth; bots and scripts use an API key.

Claude Code

  1. Add the server in your terminal.
  2. Type /mcp in Claude Code and pick reolora to sign in in the browser.
claude mcp add --transport http reolora https://mcp.reolora.dk/mcp

With an API key instead:

claude mcp add --transport http reolora https://mcp.reolora.dk/mcp \
  --header "Authorization: Bearer rk_live_…"

Claude.ai / Desktop

  1. Open Settings → Connectors → Add custom connector.
  2. Name: Reolora. URL: the address below. Click Add and sign in.
  3. Works in Claude.ai, Claude Desktop and Claude on mobile.
https://mcp.reolora.dk/mcp
Open Connectors in Claude

ChatGPT / Dots

  1. Settings → Apps & Connectors → Advanced → turn on Developer mode.
  2. Create a connector: name Reolora, the URL below, authentication OAuth.
  3. Needs a Business or Enterprise plan at OpenAI. Dots uses the same connectors; Deep Research uses the search and fetch tools.
https://mcp.reolora.dk/mcp

Codex

  1. Add the server and sign in (opens the browser).
codex mcp add reolora --url https://mcp.reolora.dk/mcp
codex mcp login reolora

With an API key instead: (~/.codex/config.toml)

[mcp_servers.reolora]
url = "https://mcp.reolora.dk/mcp"
bearer_token_env_var = "REOLORA_API_KEY"

Cursor

  1. Click the button, or put the block in ~/.cursor/mcp.json. Cursor asks you to sign in.
{
  "mcpServers": {
    "reolora": {
      "url": "https://mcp.reolora.dk/mcp"
    }
  }
}

With an API key instead:

{
  "mcpServers": {
    "reolora": {
      "url": "https://mcp.reolora.dk/mcp",
      "headers": {
        "Authorization": "Bearer rk_live_…"
      }
    }
  }
}
Add to Cursor

Grok

  1. grok.com → Connectors → New connector → Custom. The URL below, then sign in.
  2. Grok Build CLI is added like Claude Code. From the xAI API you use the MCP tool:
https://mcp.reolora.dk/mcp

xAI API

{
  "type": "mcp",
  "server_url": "https://mcp.reolora.dk/mcp",
  "server_label": "reolora",
  "authorization": "Bearer rk_live_…"
}
Open Grok connectors

VS Code

  1. Click the button, or put the block in .vscode/mcp.json. Copilot asks you to sign in.
{
  "servers": {
    "reolora": {
      "type": "http",
      "url": "https://mcp.reolora.dk/mcp"
    }
  }
}

Or in the terminal:

code --add-mcp '{"name":"reolora","type":"http","url":"https://mcp.reolora.dk/mcp"}'
Install in VS Code

Gemini CLI

  1. Add the server and sign in with /mcp auth reolora.
gemini mcp add --transport http reolora https://mcp.reolora.dk/mcp

With an API key instead: (~/.gemini/settings.json)

{
  "mcpServers": {
    "reolora": {
      "httpUrl": "https://mcp.reolora.dk/mcp",
      "headers": {
        "Authorization": "Bearer rk_live_…"
      }
    }
  }
}

Sign in

OAuth 2.1

For Claude.ai, ChatGPT, Dots, Grok, Cursor, VS Code and the CLIs with a login. The client finds the sign-in page itself; you sign in with your e-mail and approve. The app can then do what you can.

API key

For bots that run on their own and CLIs without a browser. A key belongs to an agent in Team, so the agent has its own name and role. Send it as Authorization: Bearer rk_live_…. The key is shown once; 120 calls a minute by default.

Create the key under Office → Team → Keys.

Roles

What an agent may do depends on its role. You pick it when you create the agent and can change it any time.

Read read

Reads everything on its sites. Changes nothing, proposes nothing.

Suggest suggest

Changes become proposals that a manager approves. A good place to start.

Work execute

Daily work: receive, ship transfers, count, move, orders and returns. Purchasing and the catalogue become proposals.

Manage manage

Like a manager: purchasing, min/max and the catalogue too.

Signed in with OAuth, the agent has your own role.

Tools 43

The list comes straight from the server. Every list takes limit and cursor; every change takes preview and request_id; site can be left out when you have one site.

NameWhat it doesKind
warehouse_statusStart here. Orders by status, items out/reorder/ok, open purchase orders and transfers, pending proposals, the latest events and cursor (the newest event n). Pass since (a cursor you kept) to also get summary_since: what happened after it, by kind and by who.{"since": 1520}reads
find_itemsFind items by SKU, EAN, supplier SKU or part of the name, with where they are on this site.{"query": "løbesko 42"}reads
stock_overviewStock per item: available (on hand minus reserved), on its way, min/max, sold in 30 days, days left and status (out, reorder, coming, over, ok, none = no min/max). Filter by status, group or text; most urgent first.{"status": "out"}reads
item_detailEverything about one item: master data, stock on every site, places here, min/max, what is on its way, 12 weeks of sales, recent history.{"sku": "SKU-1003"}reads
list_itemsThe catalogue (all sites) with group and supplier: filter by group name, items without a group, or text. For grouping and clean-up.{"without_group": true}reads
groups_and_suppliersThe item group tree (id, name, parent) and the suppliers (id, name, lead time in days, e-mail).{}reads
reorder_suggestionsWhat to buy now, per supplier: items below min (counting what is on its way), filled up to max in whole packs, with value and stock at other sites. Filter by supplier name.{"supplier": "FitGear"}reads
suggest_levelsMin/max from sales: daily mean and spread over days (default 60), lead time, 95 % service level, two-week review, whole packs. Compare with current_min/current_max.{"skus": ["SKU-1003"], "days": 90}reads
balance_suggestionsItems below min here that another site has more of than its own min: move them with create_transfer instead of buying.{}reads
purchase_ordersPurchase orders for this site with lines (ordered and received), supplier, expected date and value. Open ones only unless open_only is false.{"open_only": false}reads
transfersTransfers in and out of this site, with lines (asked, sent, received). Open ones only unless open_only is false.{}reads
count_suggestionsLocations worth counting now: ABC class, days since the last count, recent shortages, traffic.{"limit": 15}reads
reportKey figures over days (default 30): stock value, picks per day, short picks, orders shipped, best sellers, dead stock, ABC split, count differences.{"days": 7}reads
get_locationOne location (code or the customer alias) and what it holds.{"code": "A-01-02-1"}reads
list_ordersCustomer orders, newest first, with lines; optionally one status (new, allocated, picking, picked, production, produced, packing, packed, shipped, cancelled).{"status": "new"}reads
eventsThe event log in order. Pass since (the cursor you kept) for only new events, and kind for one area (move, adjust, receive, count, pick, short, order, status, purchase, transfer, return, levels, proposal). Keep the returned cursor for next time.{"since": 1520, "kind": "short"}reads
proposalsChanges agents have proposed for this site and their status (pending by default).{"status": "approved"}reads
set_stock_levelsSet min/max for items: levels [{sku, min, max}]; min and max null removes the level. source "suggested" when the numbers come from suggest_levels. Managers only; agents that may not, use propose.{"levels": [{"sku": "SKU-1003", "min": 20, "max": 60}]}changes
create_purchase_orderCreate a DRAFT purchase order for a supplier (name or id): lines [{sku, qty, cost?}]. Nothing is sent until send_purchase_order.{"supplier": "FitGear", "lines": [{"sku": "SKU-1003", "qty": 40}]}changes
update_purchase_orderChange a draft purchase order: replace its lines, expected date or note.{"po": "IK-0004", "lines": [{"sku": "SKU-1003", "qty": 50}]}changes
send_purchase_orderMark a draft purchase order as sent to the supplier; its quantities then count as on their way.{"po": "IK-0004"}changes
cancel_purchase_orderCancel a purchase order (a partly received one is closed for the rest).{"po": "IK-0004"}changes
receive_purchaseGoods in against a purchase order line: qty units to a location (or the best free place when left out).{"po": "IK-0004", "line": 1, "qty": 40}changes
create_transferCreate a DRAFT transfer between two sites of the company (codes or ids); from_site defaults to this site. Lines [{sku, qty}].{"to_site": "WH-02", "lines": [{"sku": "SKU-1002", "qty": 10}]}changes
ship_transferSend a draft transfer from this site; units are taken from the places holding most.{"transfer": "FL-0002"}changes
receive_transferReceive a transfer on its way to this site; units go to the best places.{"transfer": "FL-0002"}changes
register_returnA customer return: back on a shelf (restock true, the default) or written off. Say why.{"sku": "SKU-1003", "qty": 1, "reason": "Forkert størrelse"}changes
save_itemCreate or change an item by SKU; only the fields given change. group may be a path ("Sko / Løbesko", created when missing), supplier a name. Fields: sku, name, ean, group, supplier, supplier_sku, unit, pack_qty, cost, price, weight_grams, active, notes.{"item": {"sku": "SKU-1003", "price": 159}}changes
save_groupCreate an item group (optionally under a parent, by name or id), or rename one by id.{"name": "Kampagne", "parent": "Tilbehør"}changes
set_item_groupPut many items (SKUs) in one group (name or id); null takes them out of any group.{"skus": ["SKU-1002", "SKU-1003"], "group": "Kampagne"}changes
save_supplierCreate or change a supplier: name, contact, email, phone, lead_days, notes (id to change an existing one).{"supplier": {"name": "FitGear Europe", "lead_days": 10}}changes
move_stockMove units between two locations on this site; never mixes two items in one location.{"from": "A-01-02-1", "to": "B-03-01-2", "qty": 10, "reason": "Tættere på pakning"}changes
adjust_stockSet the quantity at a location (0 empties it). Give sku when the location is empty. Say why.{"location": "A-01-02-1", "qty": 12, "reason": "Optalt"}changes
countRecord a blind count at a location; returns the difference to the system quantity.{"location": "A-01-02-1", "qty": 11}changes
create_orderCreate a customer order. Lines [{sku, qty, location?}]; missing locations are allocated from stock.{"ref": "WEB-1042", "customer": "Mia Holm", "lines": [{"sku": "SKU-1003", "qty": 2}]}changes
set_order_statusMove an order forward (production, produced, packing, packed, shipped). Cancelling needs a manager.{"order": "WEB-1042", "status": "packed"}changes
proposeFor agents that may not change things themselves: propose a change for a manager to approve in Forslag, with the database command, its arguments and why. Commands: set_stock_levels {levels, source}, create_purchase_order {supplier_id, lines, expected_at?, note?}, send_purchase_order {po}, create_transfer {from_site?, to_site, lines} (site ids), save_item {item}, set_item_group {skus, group_id}, move_stock {from, to, qty, reason}, adjust_stock {location, qty, sku?, reason}, create_order, set_order_status.{"command": "move_stock", "args": {"from": "A-01-02-1", "to": "B-03-01-2", "qty": 10, "reason": "Fyld op"}, "reason": "Pladsen er næsten tom"}changes
whoamiWho you are signed in as: your name, role (and agent mode), company and the sites you can work on, with which one is used when you leave site out.{}reads
searchSearch the warehouse (items by SKU, EAN or name) and get ids for fetch. Returns {results: [{id, title, url}]}, the shape ChatGPT and Deep Research use.{"query": "drikkedunk"}reads
fetchThe full record behind a search id: an item with stock per site, places, min/max, what is on its way and recent sales. Returns {id, title, text, url, metadata}.{"id": "item:SKU-1003@WH-01"}reads
subscribeGet a POST to your https URL whenever events of these kinds happen on this site (empty: all): move, adjust, receive, count, pick, short, order, status, purchase, transfer, return, levels, proposal, layout. Signed with the returned secret; failed deliveries are retried.{"url": "https://example.com/hooks/reolora", "kinds": ["short", "proposal"]}changes
unsubscribeStop a webhook by its id (from subscribe or webhooks).{"webhook": "0b6d…"}changes
webhooksYour webhooks on this site (managers see all), with failures and the last answer.{}reads

For agents that run on their own

preview: true
Run a change and see the result without saving anything. The same checks as the real thing.
request_id
Give every change an id. If the agent retries with the same id, nothing happens twice.
Errors with a next step
Errors come as {code, message, hint, next}, e.g. not_found with next: find_items.
since and cursor
warehouse_status and events return a cursor. Next time: since = cursor, and summary_since tells what happened.
Webhooks
subscribe(url, kinds) sends a signed POST when, say, an item runs short or a proposal arrives. Failed calls are retried.
Resources and prompts
reolora://guide and status per site; prompts such as dagens-indkob (today’s purchasing) and ugens-optaelling (this week’s count).

Check a webhook’s signature:

import { createHmac, timingSafeEqual } from 'node:crypto';

// rawBody: the request body exactly as received (a string), secret: whsec_… from subscribe
const expected = 'sha256=' + createHmac('sha256', secret)
  .update(`${req.headers['x-reolora-timestamp']}.${rawBody}`)
  .digest('hex');
const ok = timingSafeEqual(Buffer.from(expected), Buffer.from(req.headers['x-reolora-signature']));

Try it

With an API key in REOLORA_API_KEY:

curl -s https://mcp.reolora.dk/mcp \
  -H "Authorization: Bearer $REOLORA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"1"}}}'
curl -s https://mcp.reolora.dk/mcp \
  -H "Authorization: Bearer $REOLORA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'

Three things to ask

  • “What should we order from Løbeland today? Make drafts, but send nothing.”
  • “What happened in the warehouse since yesterday, and is anything sold out?”
  • “Move 10 of SKU-1003 to the shop WH-02. Show me first what will happen.”