Skip to content

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.

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/mcp

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:

  1. GET /.well-known/oauth-protected-resource names the authorisation server. An unauthenticated request to /mcp returns a 401 pointing at it.
  2. GET /.well-known/oauth-authorization-server gives the endpoints.
  3. POST /oauth/register registers your client. Anyone may; it grants nothing.
  4. Send the person to the authorisation endpoint. They choose the business and the permissions.
  5. Exchange the code at /oauth/token with your verifier. S256 only.

Access tokens last an hour; refresh tokens are single use and rotate.

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.

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.

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.

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.

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.

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_kinds gives each kind’s fields as JSON Schema, with an example, and the widths it allows. The page has twelve columns; a section can be full, threeQuarters, twoThirds, half, third or quarter where 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_url fetches 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_picture takes 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/publish and POST /storefront/pages/{id}/publish take base: the draftVersion (or the page’s version) 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/draft and PUT /storefront/pages/{id}/draft take base the 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-change says what the last change was, and POST /storefront/assistant-change/undo puts it back, once (storefront:read and storefront: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 with start_shop and 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_shop sets 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:drafts can 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.