Connecting over MCP
Bottle speaks the Model Context Protocol at /mcp, so an assistant can read a
business’s data and answer questions about it. Claude and ChatGPT both connect
this way.
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://api.bottle.example/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.
The flow is the standard one and needs no arrangement with us:
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.
| 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. |
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 |
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: how often, next due, what is already written. |
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: patch, payload, load space, usual driver. |
get_planning |
rounds:read |
How the day is reckoned: hours, loading, minutes a door. |
list_drivers |
drivers:read |
Each driver, the vehicle they take and their hours. |
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. |
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”The scope says what kind of thing; the role says how much of it. A driver’s
own connection holds rounds:read, and list_rounds and get_round answer
with their rounds only. Nothing about the other vehicle, nothing about the
planning. An owner’s or admin’s connection with the same scope sees every
round. Each stop carries what happened at that door: delivered, or the reason
it could not be, with whatever the driver added.
An assistant cannot mark a drop delivered. That is a person at a door, with a phone in their hand, and it is the one record where being wrong means a customer is billed for gas they never got.
What an assistant may change
Section titled “What an assistant may change”One thing: where a placed order is going, and the day, payment method and notes that go with it. That is the call that comes ten minutes after an order was taken, it corrects a record that already exists, and every change shows in the app immediately. An address must belong to the customer the order is for, and a delivered or cancelled order cannot be touched.
Everything else reads. Taking an order creates an obligation, changing a rate changes what somebody is charged, and merging two customers cannot be undone, so all three want a person looking at the screen. An assistant can list the duplicate pairs; it cannot merge them.
Grant orders:write only if you want that one change. A connection without it is not
offered the tool.