Connecting over MCP
Bottle provides a Model Context Protocol endpoint at /mcp. Claude, ChatGPT
and other compatible clients can use it to read business data and make supported
changes with the user’s permission.
For the person connecting
Section titled “For the person connecting”Add the address as a connector in your assistant, sign in when it asks, and choose the business and the permissions. See Connecting an assistant.
https://my.getbottle.app/api/mcpFor whoever is building a client
Section titled “For whoever is building a client”Authentication is OAuth 2.1 with PKCE. An API key will not work here: the MCP endpoint wants a person’s grant, not a business credential.
Clients can register and connect using this flow:
GET /.well-known/oauth-protected-resourcenames the authorisation server. An unauthenticated request to/mcpreturns a 401 pointing at it.GET /.well-known/oauth-authorization-servergives the endpoints.POST /oauth/registerregisters your client. Anyone may; it grants nothing.- Send the person to the authorisation endpoint. They choose the business and the permissions.
- Exchange the code at
/oauth/tokenwith your verifier.S256only.
Access tokens last an hour; refresh tokens are single use and rotate.
The tools
Section titled “The tools”Which tools appear depends on what was granted, so a connection that may only read customers is not offered anything else.
Tools for a part of Bottle the business’s plan does not open are left out too: on Shop there are no rounds, planning, vehicles, drivers, regular orders or transfers to read. See Plans.
API tools
Section titled “API tools”The MCP catalogue includes the delegated API operations for products and prices,
customers and addresses, orders and regular orders, rounds and vehicle records,
rota, stock and suppliers, cash, invoices, setup, reporting and your shop. Delivery
partners are included too: they need the rounds scopes and a plan with delivery partners.
Each operation has its own tool and input schema. Use tools/list to discover
what your connection can access; the API reference describes the underlying operations.
Names start with api_, followed by the HTTP method and route. For example:
| Tool | Use |
|---|---|
api_get_products_by_id_charges |
Read one product’s cylinder charges |
api_get_invoices |
List invoices, with the API’s filters and pagination |
api_get_vehicles_by_id_record |
Read a vehicle’s mileage, maintenance and round details |
api_get_reports_overview |
Read business reporting for the selected period |
api_post_orders |
Create an order, with orders:write |
api_patch_products_by_id |
Change a product, with products:write |
Put route identifiers in path, filters in query, and a change’s fields in
body. Only use fields listed in the tool’s schema. For example:
{ "name": "api_get_products_by_id_charges", "arguments": { "path": { "id": "019205d1-6e7a-7c3b-9f6e-3a2b1c0d9e8f" } }}Use identifiers returned by a previous read, not guessed identifiers. Lists may be paginated: use the returned totals and next-page information rather than treating the first page as the whole business.
Write tools are offered only when their permission was granted. Explain the
change and get the user’s approval before calling one. Every API write requires an
idempotencyKey and reuse it if retrying the same change; use a new key for a
different change. The API enforces the same validation, plan limits, billing
rules and permissions as the app. Deleting, archiving, cancelling and publishing
can have lasting effects: do not treat a tool’s availability as user approval.
Session-only controls, API-key management, connection management, subscription changes, erasure, support approvals and Bottle staff endpoints are not exposed. An assistant cannot widen its own access. Files can be returned where the API supports them, up to 2 MB; download larger files in Bottle.
Flame AI is different: the in-app assistant receives only approved read-only tools. It cannot use these write tools, even for an owner.
Summary and shop-draft tools
Section titled “Summary and shop-draft tools”| Tool | Needs | What it does |
|---|---|---|
get_business |
tenant:read |
Which business this connection is for. |
list_customers |
customers:read |
Every customer, optionally filtered. |
get_customer |
customers:read |
One customer in full. |
get_marketing_consent |
customers:read |
One customer’s marketing consent on each channel, and every change to it. Read only. |
list_delivery_addresses |
customers:read |
Where one customer takes delivery, with the driver notes. |
list_merge_suggestions |
customers:read |
Customers that look like duplicates, each pair once. |
list_products |
products:read |
What the business sells, with list prices in pence. |
get_customer_prices |
products:read and customers:read |
What one customer pays, with the list price beside it. |
list_orders |
orders:read |
Orders, filtered by the day they are wanted. |
get_order |
orders:read |
One order with its lines, what was delivered, and any refund due. |
list_standing_orders |
orders:read |
Regular deliveries and collections, their frequency and generated orders. |
get_subscription |
billing:read |
The plan this business is on, and what happens next. |
list_bottle_invoices |
billing:read |
What Bottle has billed them, each with a link. |
get_card_payments_account |
billing:read |
Their own Stripe account: money in it, the next payout, and anything Stripe needs from them. Read only. |
list_rounds |
rounds:read |
A day’s rounds, each with its fit and stop times. |
get_round |
rounds:read |
One round in full, every stop with a time of day. |
list_locations |
rounds:read |
The bases rounds start from and end at. |
list_vehicles |
rounds:read |
The fleet: yard, patch, payload, load space, usual driver. |
get_planning |
rounds:read |
Planning settings: working hours, loading time and time per stop. |
list_drivers |
drivers:read |
Each driver, their yard, the vehicle they take and their hours. |
get_stock |
stock:read |
Full and empty cylinders in each yard and on each vehicle, optionally for one yard. |
list_low_stock |
stock:read |
What is at or under its minimum, naming the yard, and how many products each yard has low. |
list_transfers |
stock:read |
Stock moving between yards: its stage, who is carrying it (for one on a round, the round, day, driver and vehicle), and its history. Read only. |
list_supplier_orders |
stock:read |
Orders from suppliers: due day, late, the supplier’s reference, and per product the fulls ordered, empties to go back, what came and what is short. Read only. |
list_suppliers |
stock:read |
Suppliers with address, account number, open orders, last ordered and contacts with their roles: main, billing, orders and deliveries. Read only. |
list_members |
members:read |
Who works there, and their roles. |
search |
tenant:read |
Finds anything the connection may read, by name, postcode, phone or number. See Search. |
fetch |
tenant:read |
One customer, order or invoice in full, by an id search returned. |
get_shop_building_guide |
storefront:read |
How to build the whole shop from a description of the business, step by step. |
get_shop |
storefront:read |
Whether the shop is set up and published, its address, and changes not yet published. |
get_shop_look_and_settings |
storefront:read |
The draft’s look (template, colours, fonts, logo), words, checkout settings, search details, terms and privacy, and the top bar, header and footer. |
list_section_kinds |
storefront:read |
Every kind of section: its fields as JSON Schema, an example, the widths it allows, and whether pages can have it. |
list_home_sections |
storefront:read |
The draft home page’s sections, top to bottom, with ids and widths. |
list_pages |
storefront:read |
The shop’s own pages, published or not, with changes waiting. search and status (published, draft or bin) narrow it. |
get_page |
storefront:read |
One page with its sections and its draft. |
list_blog_posts |
storefront:read |
The blog posts, draft or published, newest first. search and status (published, draft or bin) narrow it. |
get_blog_post |
storefront:read |
One blog post with its words. |
get_menus |
storefront:read |
The draft’s menus and which shows in the header and footer. |
get_filters |
storefront:read |
How product lists sort and filter, and the filters the products allow. |
list_link_targets |
storefront:read |
The products, categories, pages and built-in pages a link or button can go to, as targets. |
start_shop |
storefront:drafts |
Sets up a shop that is not set up yet, as a private draft. Does nothing to one already set up. |
update_shop_look |
storefront:drafts |
Changes the draft’s template and theme. |
update_shop_settings |
storefront:drafts |
Changes the draft’s words, checkout settings, search details, terms of sale and privacy policy. |
update_shop_frame |
storefront:drafts |
Changes the top bar, header and footer on every page, in the draft. |
update_shop_tracking |
storefront:drafts |
Switches analytics and advert services on or off by their IDs, in the draft. IDs only, checked against each service’s format. |
add_home_section |
storefront:drafts |
Adds a section to the draft home page, at a place and a width. |
update_home_section |
storefront:drafts |
Changes a section’s fields. |
remove_home_section |
storefront:drafts |
Takes a section off the draft home page. |
move_home_section |
storefront:drafts |
Moves a section to after another, or to the top. |
set_home_section_width |
storefront:drafts |
Sets a section’s width, from those its kind allows. |
create_page |
storefront:drafts |
Writes a new page, as a draft. |
update_page_draft |
storefront:drafts |
Changes a page’s draft: title, address, search words, menu choice and sections. |
delete_page |
storefront:drafts |
Moves a page that has never been published to the Bin, where the owner can restore it for 90 days. |
create_blog_post |
storefront:drafts |
Writes a blog post, as a draft. |
update_blog_post |
storefront:drafts |
Changes a blog post that is still a draft. |
save_menu |
storefront:drafts |
Writes a menu, new or replacing one, in the draft. |
delete_menu |
storefront:drafts |
Deletes a menu from the draft. |
place_menu |
storefront:drafts |
Shows a menu in the header or footer, or none. |
update_filters |
storefront:drafts |
Changes how product lists sort and filter, in the draft. |
upload_picture |
storefront:drafts |
Stores a picture sent as base64 (JPEG, PNG, WebP, AVIF or GIF, up to 5 MB) and answers with its key. For small pictures the assistant made. |
upload_picture_from_url |
storefront:drafts |
Fetches a picture from a public https address on port 443 (up to 5 MB, 10 seconds, 3 redirects, each checked) and answers with its key. For pictures already online. |
search and fetch exist because deep research connectors look for exactly
those two names. search is also the quickest way for any assistant to get
from “the Kingston fish bar” or “invoice 42” to a record: it covers every kind
the connection’s scopes can read, and its ids (customer:<uuid>,
order:<uuid>, invoice:<uuid>) work with fetch and, without the prefix,
with the other tools.
What a driver’s assistant sees
Section titled “What a driver’s assistant sees”A driver’s connection can read only their assigned rounds, including delivery
outcomes and notes. Owners and admins with rounds:read can read all rounds.
Drivers are not offered office-wide API tools. Their assistant can read their own day and cash, alongside their existing assigned-round tools. Drivers record delivery outcomes in the app.
What an assistant may change
Section titled “What an assistant may change”With orders:write, an assistant can update a placed order’s delivery address,
date, payment method and notes. The address must belong to the order’s customer.
Delivered and cancelled orders cannot be edited.
The API-backed tools also support other changes where the corresponding write permission was granted. A read-only connection cannot create orders, change rates or merge customers. Customer exports follow the API’s permissions and audit records; Flame AI does not receive file-export tools.
Building a shop
Section titled “Building a shop”With storefront:read and storefront:drafts, an assistant can build the
business’s whole shop: its look, home page sections, pages, blog posts, menus,
filters and pictures. It works only on drafts. Nothing it writes reaches
shoppers until a person presses Publish in the office, and no tool can
publish, discard changes, take the shop down or change its addresses. These
tools are offered to owners and admins, on a plan with Bottle Shop.
That draft-only restriction applies to storefront:drafts. A connection also
granted storefront:write can use the API-backed shop tools to publish and make
other supported shop changes. Grant draft-only access when you want to review
everything before it goes live.
- The look and the words go into the shop’s draft settings, the same draft the office’s Design and Settings tabs edit. Each tool reads the draft, changes the part it is about and saves it through the same checks as the office: the settings schema, the sanitiser for rich text, and that every product, page and picture named is the business’s own.
- Home page sections come from the section library.
list_section_kindsgives each kind’s fields as JSON Schema, with an example, and the widths it allows. The page has twelve columns; a section can befull,threeQuarters,twoThirds,half,thirdorquarterwhere its kind allows, and sections share a row while they fit. - Pages are written as drafts. A published page’s changes go into its draft, and shoppers see the published page until a person publishes the draft. Only a page never published can be deleted here.
- Blog posts are written as drafts. A post that is published is not changed here, since a post’s changes show as soon as they are saved; the assistant says so and suggests writing a new draft.
- Pictures come from the web or as data.
upload_picture_from_urlfetches an https address on the standard port (443): the name must resolve only to a public website. Links requiring sign-in and private network addresses are not supported. The limit is 5 MB, 10 seconds and three redirects. The request does not send your credentials to the picture’s website.upload_picturetakes the file as base64, and says plainly when the base64 has characters base64 does not use, is the wrong length, or is a picture that cannot be read, which is what base64 copied by hand usually comes to. Either way, up to 5 MB, and the type is read from the bytes, not from what anyone says it is. Recommend the address for a picture already online, and base64 for a small one the assistant made.
Every change answers with what it did and the office link where the owner reviews it.
- Only the draft read is changed. Each tool reads the draft and writes its change only over that same draft: if the office changed it meanwhile, the tool is refused and says to read it again.
- Publishing names what was looked at.
POST /storefront/publishandPOST /storefront/pages/{id}/publishtakebase: thedraftVersion(or the page’sversion) the person publishing was looking at. A draft changed since, by the assistant or anyone else, answers 409 (draft_changed) and nothing is published. The office always sends it.PUT /storefront/draftandPUT /storefront/pages/{id}/drafttakebasethe same way, and the check is applied before the change is saved. - One change back. Before each change, Bottle keeps what was there: the
shop’s draft, a page’s draft, a draft post, or a page it is about to delete.
GET /storefront/assistant-changesays what the last change was, andPOST /storefront/assistant-change/undoputs it back, once (storefront:readandstorefront:write, owners and admins). A page or post the assistant wrote is removed; a page it deleted comes back. Only the last change can be put back, and only while what it changed is still exactly as the assistant left it: once anyone has changed it since, or published it, nothing is put back and the answer is 409, so the later change is never written over. Two requests at once put it back once. A shop set up withstart_shopand uploaded pictures are not undone. - Addresses must be lower-case letters, digits and single dashes, and not one of the shop’s own; this is checked by the tools, the routes and again when a page is saved or published, and the shop never links an address that is not one.
- Pictures: up to 50 a day for one shop over MCP, both upload tools together.
start_shopsets up a shop never set up before. A shop its owner published and then switched off is refused: the owner switches it back on.storefront:draftscan be granted to a connected assistant only. An API key cannot hold it.
An office tab open on the shop is told when the assistant changes a draft and says so, with a way to put back the assistant’s last change.