AI Customer Service
Let your customer-service AI answer “where’s my order?” on its own, by reading live fulfilment data straight from Move Fresh.
Move Fresh publishes a small, read-only service that any AI assistant supporting the Model Context Protocol (MCP) can connect to — including Claude, ChatGPT and most agent frameworks. Your AI agent looks up an order at the moment a customer asks, instead of a person checking a portal.
At a glance
| Endpoint | https://mcp.movefresh.com/mcp |
|---|---|
| Protocol | Model Context Protocol, over streamable HTTP |
| Authentication | Bearer token — your MCP secret, issued by Move Fresh |
| Access | Read-only, limited to your brand’s orders |
| Tools | get_delivery_status, list_orders |
Getting access
MCP access is off until you switch it on for you. Ask your Move Fresh account manager for instructions on how to get your brand an MCP secret from our app.
Treat it like a password: keep it in your application’s backend, never in browser code or anywhere a customer could reach it. If it is exposed, switch MCP off and on again, to get a new secret.
Connecting your support agent
Point your MCP client at the endpoint and present your secret as the authorisation token. Here it is wired into the Claude API’s MCP connector:
client.beta.messages.create(
model="claude-opus-4-8",
max_tokens=1024,
betas=["mcp-client-2025-11-20"],
mcp_servers=[{
"type": "url",
"url": "https://mcp.movefresh.com/mcp",
"name": "move-fresh",
"authorization_token": "YOUR_MCP_SECRET",
}],
tools=[{"type": "mcp_toolset", "mcp_server_name": "move-fresh"}],
messages=[{"role": "user", "content": "Where is order TB-1234567?"}],
)
The tools
Two read-only tools. Your agent decides when to call them — get_delivery_status for a single order, list_orders for many.
get_delivery_status(order_reference)
order_reference is the order’s reference exactly as it appears on the order, including your brand prefix (for example TB-1234567). This is the most accurate answer available: once the parcel is moving it uses the courier’s own live tracking.
{
"found": true,
"status": "dispatched",
"message": "This order was dispatched yesterday at 4:02 PM. It is
estimated to be delivered on 23 September from
7:00 AM to 8:00 PM.",
"estimated_delivery_from": "2026-09-23T07:00:00+01:00",
"estimated_delivery_to": "2026-09-23T20:00:00+01:00",
"target_delivery_deadline": "2026-09-23T20:00:00+01:00",
"estimate_source": "move_fresh",
"courier_reference": "JD0002128900",
"courier_link": "https://track.dhlparcel.co.uk/JD0002128900"
}
If the reference isn’t recognised you get {"found": false, "message": "Order not found."}.
list_orders(status, created_after, created_before, updated_since, page)
Lists the delivery status of your orders, most recent first, up to 200 per page. All arguments are optional:
status— filter by status, e.g.doneorin_process.created_after/created_before— ISO dates (YYYY-MM-DD) on the order’s creation date.updated_since— an ISO timestamp. Returns only orders that have changed since then, whether they moved through the warehouse or were updated by the courier. This is the efficient way to poll for what has moved since you last looked.page— page number, starting at 1. Call again with the next page whilehas_next_pageis true.
Each order carries the same fields as get_delivery_status, alongside total_count and has_next_page.
One difference worth knowing. The estimates on the list method can be up to 15 minutes out of date, and will not include the 2-hour delivery window available on the day of delivery. When you need the fully up-to-date estimate for one order, including any delivery window, call get_delivery_status for it.
Response fields
| Field | Meaning |
|---|---|
found | Whether an order with that reference exists for your brand. |
status | Where the order is in fulfilment. See the list below. |
message | A ready-to-show sentence summarising the status and, where relevant, the estimate. Safe to relay to a customer as-is. |
estimated_delivery_fromwhen available | Start of the expected delivery window, ISO 8601 with time zone. |
estimated_delivery_towhen available | End of the expected delivery window, ISO 8601 with time zone. |
target_delivery_deadlineonce dispatched | The latest the order was expected to arrive, fixed when it shipped. Unlike the estimate above, it doesn’t move. See Is the order late? |
estimate_sourcewhen available | Where the estimate came from — the courier’s tracking, or Move Fresh. |
courier_referenceonce dispatched | The courier’s consignment / tracking number. |
courier_linkonce dispatched | A tracking URL on the courier’s own website. |
date_failed_deliveryfailed delivery only | When the courier attempted delivery and could not complete it. |
delivery_failure_typefailed delivery only | Why it failed, in a fixed form you can branch on. See When a delivery doesn’t happen. Absent if the courier recorded no reason. |
Order status values
Before dispatch, each carrying an estimate:
- pending
- waiting
- ready
- in_process
- packed
- deferred
After dispatch:
- dispatched
- in_transit
- delivered
Needs attention, and no estimate is given:
- on_hold
- cancelled
- rescheduled
- failed_delivery
Estimate accuracy
Every estimate is tagged with its source, so your assistant can pitch its confidence accordingly.
estimate_source | Meaning |
|---|---|
a courier name, e.g.dhl_parcel, yodel | A live estimate from the courier, available on the day of delivery. |
move_fresh | Our own calculation from the shipping deadline, service used, the courier’s usual transit time to that particular postcode, and taking account of any holidays. |
Is the order late?
A five-day-old order isn’t necessarily a problem — it depends what was expected. Once an order is dispatched, target_delivery_deadline records the latest it was expected to arrive, fixed at the moment it shipped. Compare it with estimated_delivery_to:
| Order | Deadline | Current estimate | Read as |
|---|---|---|---|
| Next-day service, now day five | 22 Sep | 26 Sep | Four days late. Worth apologising for and escalate. |
| Five-day service to a remote area | 26 Sep | 26 Sep | On track, just a long journey. Reassure the customer. |
The deadline doesn’t move, so the gap between the two is the slippage. If they agree, nothing has gone wrong however long the service takes. Before an order is dispatched there is no deadline to hold the courier to, so the field isn’t present.
When a delivery doesn’t happen
Two statuses mean the parcel’s arrival is no longer something we can predict, so no estimate is given at all and your agent should hand the customer to a person rather than offer a date:
| Status | What has happened |
|---|---|
rescheduled | The customer has arranged a new delivery time directly with the courier. Reported even if a delivery was attempted first, because it describes the current arrangement. |
failed_delivery | The courier attempted delivery and could not complete it. date_failed_delivery says when, and delivery_failure_type says why. |
The message already explains the failure in words you can relay. delivery_failure_type gives the same thing in a fixed form, so your agent can ask for the right thing rather than flag a generic problem:
delivery_failure_type | Suggested response |
|---|---|
carded | Nobody was in. Tell the customer the courier will make two attempts to deliver. Escalate if they need help. |
incorrect_address | Find out the correct address and then escalate. |
no_valid_id | Explain that the courier needs a passport, driving license or similar for certain high-value deliveries or where they need to prove age. |
refused, return_to_sender | The parcel is heading back to us. Escalate for a refund or reshipment. |
damaged | Escalate for a replacement. |
delayed, vehicle_breakdown, major_incident, weather | Outside anyone’s control. Apologise and escalate for an updated date. |
other | No detail given. Escalate. |
The field is absent when the courier recorded no reason, in which case the message says only that there has been a problem. Treat that the same as other.
Example assistant prompt
A starting point for your assistant’s system prompt, written against the two tools and the fields above. Adapt the tone to your brand and fill in the placeholders {{BRAND}}, {{PREFIX}}, {{ESCALATION_ROUTE}} and {{CONTACT_ROUTE}}.
Show the full example prompt
You are the customer-service assistant for {{BRAND}}. You help customers with
their orders — most often "where is my order?" — in a warm, concise,
professional tone.
TOOLS
On the "move-fresh" server you have two read-only tools:
- get_delivery_status(order_reference) — one order, in full detail. Use this
for any question about a specific order. It is the most accurate: once the
parcel is moving it uses the courier's own live tracking.
- list_orders(status, created_after, created_before, updated_since, page) —
many orders at once. Use it for questions across the account ("which orders
are running late?", "what shipped yesterday?"); updated_since is the
efficient way to see what has moved since you last looked. Every estimate in
a list is Move Fresh's own calculation, so before telling a customer
something precise about one order, confirm it with get_delivery_status.
FINDING THE ORDER
- The reference looks like {{PREFIX}}-1234567. If the customer gives only a
number, prefix it with "{{PREFIX}}-" before calling the tool.
- If you don't have a reference, ask for it first.
- Verify identity before sharing details: ask for the reference AND the email
or postcode on the order, and only continue if they match. Never read out
details for an order the customer can't confirm is theirs.
IS IT LATE, OR JUST SLOW? (do not skip this)
Once an order is dispatched the result includes target_delivery_deadline: the
latest it was expected to arrive, fixed when it shipped. Compare it with
estimated_delivery_to.
- Estimate LATER than the deadline -> genuinely late, by that difference. Say
so plainly, apologise, and offer {{ESCALATION_ROUTE}}.
- Estimate MATCHING the deadline -> ON TRACK, even if the journey is long. A
five-day service to a remote area is not a problem. Reassure the customer
and give the expected date; do not apologise as though something has gone
wrong.
- Both already in the past -> overdue. Apologise and escalate.
- Before dispatch there is no deadline, so never imply an order is late.
USING THE RESULT
- "message" is a ready-to-use sentence — relay it, or rephrase in our voice.
- Give estimated_delivery_from/to as a friendly local window (e.g. "Tuesday
23 September, 7am–8pm") and make clear it is an estimate.
- If courier_reference / courier_link are present, share the tracking link.
- Confidence: estimate_source "move_fresh" is our own projection made before
the courier has scanned the parcel — phrase it a little more tentatively
("currently expected"). A courier name (e.g. "dhl_parcel") is a live courier
estimate — speak with confidence.
BY STATUS
- Before dispatch (pending, waiting, ready, in_process, packed, deferred):
reassure them it is being prepared and give the estimated delivery.
- dispatched / in_transit: it is on its way — give the estimate, the tracking
link, and apply the late-or-slow check above.
- delivered: tell them when. If they say it hasn't arrived, apologise and
escalate.
- rescheduled: the customer has arranged a new time with the courier, so we
cannot say when it will arrive. Confirm that, do NOT offer a date, and hand
off via {{ESCALATION_ROUTE}}.
- failed_delivery: relay the message, which explains what happened, and use
delivery_failure_type to ask for the right thing — confirm the address for
incorrect_address, arrange a new time for carded, explain the ID needed for
no_valid_id. Never offer a new delivery date yourself; hand off via
{{ESCALATION_ROUTE}}.
- on_hold / cancelled: there is a problem and no estimate is given. Do NOT
invent a delivery date. Apologise and hand off via {{ESCALATION_ROUTE}}.
EDGE CASES
- "found": false means the reference wasn't recognised. Ask them to
double-check it. Never guess or invent an order.
- If a tool errors or is unreachable, apologise, don't make up a status, and
offer to escalate.
- list_orders returns up to 200 orders a page. If has_next_page is true and
you genuinely need more, request the next page — but prefer narrowing with
the filters.
GUARDRAILS
- State only facts the tools return. Never fabricate order numbers, dates,
tracking numbers, or statuses.
- The tools are read-only. You can look things up but cannot change, hold,
cancel, or refund an order — for those, direct the customer to
{{CONTACT_ROUTE}}.
Of everything here, the “Is it late, or just slow?” instruction is the one we’d least recommend dropping. Without it an assistant tends to apologise for any order still in transit — wrong for a five-day service on day three — and to under-react to a next-day order that is genuinely days overdue.
Keeping it secure
It’s read-only. The tools can look up order and delivery status and nothing else — no order can be created, changed, held, or cancelled through them. No personally identifying information is exposed.
It’s scoped to your brand, and can look up any order in your brand. Keep the secret in your own trusted systems; don’t embed it in a shopper-facing app or hand it to customers.
Rotate any time. If a secret might be exposed, switch the MCP service off and then on again to get a new secret.
Getting started
Ready to switch it on, or want to talk it through? Speak to your Move Fresh account manager.
