Assistant plugin docs

CabuTally for ChatGPT and Claude

Plan group events, split bills to the cent and keep track of who owes whom, from a chat with Claude or ChatGPT. Two tools work without an account; the rest act on your own CabuTally events.

Server URL
https://mcp.cabutally.com/mcp
Transport
Streamable HTTP
Sign-in
OAuth 2.1, only for account tools

Get started

  • Claude: Settings → Connectors → Add custom connector, and paste the server URL. Once it is listed in Claude’s connector directory, you can add it from there instead.
  • ChatGPT: Search for CabuTally in ChatGPT’s plugin directory once it is listed.

Any MCP client that supports remote servers over Streamable HTTP with OAuth can use the same URL.

What it can do

Without an account

  • “Plan a weekend in Ibiza with Luis and Marta, about €900.” You get a card with a link that opens CabuTally with the event filled in. Nothing is created until you tap Create in the app.
  • “We spent 84 on dinner, Ana paid 50 and I paid 34, four of us.” You get who pays whom, with the fewest payments, exact to the cent.

With your CabuTally account

  • Add expenses as you go, or from a pasted group chat, receipt or statement. From a paste, or more than three at once, you check every line before anything is added, and a line that looks already added is pointed out first.
  • Ask where things stand: who owes you, how the budget is going, what changed since yesterday.
  • Record payments and money into the kitty, and draft a friendly reminder to send yourself.
  • Create an event with its people and to-do list, and keep the to-dos moving.

Sign-in and permissions

The server connects without signing in. The first time you use an account tool, the assistant asks you to sign in to CabuTally (OAuth 2.1 with PKCE). You need a CabuTally account with an email address; the friends you invite still don’t.

It acts as you and sees only what you see in the app, other members’ names and amounts included. It adds expenses, payments, people and to-dos, and every entry it adds is marked as added through an assistant.

It never deletes anything, and never changes an expense or a payment: a mistake is fixed in the app, where your group sees it. Its one change to existing data is claiming or ticking a to-do. No tool is destructive, and Claude and ChatGPT ask before a tool that writes, unless you have let it run without asking.

Data and privacy

The server keeps no event data. Its one store is the sign-in grant (tokens as hashes, the session encrypted). Its logs name the tool and how each call ended, never the arguments.

What a tool reads goes to the assistant’s provider, which you chose, under that provider’s terms.

The Privacy Policy has the details.

Refusals and limits

A call that cannot be done is refused with a short reason and a code, such as (no_debt) or (possible_duplicate), and writes nothing, so the assistant can ask you what you meant. A batch that stops partway says which rows were added.

Account tools have per-user rate limits, set high enough that a person never meets them. A call over the limit is refused with (rate_limited).

Disconnect

In the app, open Profile → Assistants → Disconnect assistants. Every assistant you connected loses access within the hour. You can also remove CabuTally in the assistant’s own settings.

Tool reference

All 17 tools, as the server publishes them. This list is generated from the live server each time this site is built (last on 2026-11-02).

No account needed

plan_event Plan a group event

  • Read-only
  • No account

Use when the user is organising a trip, dinner, party or any group outing with other people and shared costs or a group budget ("organise a weekend in Ibiza with Luis and Marta, €900 between us", "organizar un viaje", "organiser un week-end entre amis"), even alongside an itinerary. Not for an itinerary alone, with no group money to track. Returns a link that opens CabuTally with the event filled in; nothing is created until the user taps Create. No account needed. With the account connected, create_event makes the event directly.

Parameters (4)
NameTypeRequiredDescription
namestringYesThe event name, e.g. "Ibiza weekend"
peoplestring[]NoThe OTHER people going, by first name. Never the user: the app asks for their name.
budgetnumberNoThe total budget for the whole group, if one was given
currencystringNoISO code; leave out if unknown

split_bill Split a bill

  • Read-only
  • No account

Use when the user wants to split a one-off bill that is not in a CabuTally event ("we spent 84 on dinner, Ana paid 50", "cenamos por 84, Ana pagó 50 y yo 34", "on a payé 84, qui doit combien à qui"). Works out who pays whom, exact to the cent, with the fewest payments, in equal shares. Also returns a link to keep it as a shared CabuTally event. For an event the user already has, add_expenses records the cost and get_event shows the balances. Not for recurring costs like rent.

Parameters (8)
NameTypeRequiredDescription
currencystringNo
paymentsobject[]Yes
payments[].paidBystringYesWho paid
payments[].amountnumberYesHow much they paid, in currency units (12.50). Read it as the user writes numbers: in Spanish "1.200" is 1200
payments[].sharedBystring[]NoWho shares this payment; leave out when everyone does
everyonestring[]NoEveryone in the split, including people who paid nothing
mestringNoThe name used for the user in payments, if they are in the split
eventNamestringNoWhat it was, e.g. "Dinner at Casa Pepe"

Account: reads

list_my_events List my events

  • Read-only
  • Account

Use when the user asks about their own CabuTally events ("my trips", "which events am I in?", "mis eventos", "mes événements"). Lists the 50 most recently active events their account is in, each with its eventId (which every other event tool takes), whether the user is square in it, and a link, plus the name saved on the user's account (create_event needs a name). Needs the user to connect their CabuTally account.

No parameters.

get_event Get an event

  • Read-only
  • Account

Use when the user asks where one event stands for them ("where are we?", "who owes me?", "¿cuánto debo?", "¿cómo va el bote?", "qui me doit quoi ?", "où en est la cagnotte ?"): the people (isMe marks the user), what the user owes and is owed (only their own lines: not what two others owe each other), the budget and what was spent, the kitty and its collector, and every to-do. Does not list the expenses (list_expenses does) and gives no share link.

Parameters (1)
NameTypeRequiredDescription
eventIduuidYesThe event, as list_my_events returns it (eventId). When the user names none and more than one could fit, ask which

draft_reminder Draft a reminder

  • Read-only
  • Account

Use when the user wants to nudge someone who owes them money ("remind Marta she owes me", "recuérdale a Luis lo que me debe", "rappelle à Luis ce qu’il me doit"). Drafts the app’s friendly reminder for the user to copy and send themselves; it sends nothing and has no link. Only for someone who owes the user, never for what the user owes.

Parameters (2)
NameTypeRequiredDescription
eventIduuidYesThe event, as list_my_events returns it (eventId). When the user names none and more than one could fit, ask which
personstringYesWho owes the user: a name as the user said it, or a guestId

list_expenses List expenses

  • Read-only
  • Account

Use when the user asks what the group spent or wants to find expenses in one event: "what did we spend on food?", "what did Marta pay for?", "¿cuánto gastamos en la cena?", "gastos del sábado", "combien on a dépensé au resto ?", "les dépenses de samedi". Lists the expenses newest first, at most 50, with the count and total of everything that matched, how much of it was taken home, and with paidBy what that person paid themselves; filter by who paid, words, a category or dates. Its totals count whole expenses, so for what the group shared or each share, event_recap is the answer. It does not say who owes whom (get_event does) and does not add anything (add_expenses does).

Parameters (7)
NameTypeRequiredDescription
eventIduuidYesThe event, as list_my_events returns it (eventId). When the user names none and more than one could fit, ask which
paidBystringNoOnly what this person paid (or helped pay): a name, "me", or a guestId
wordstringNoWords to find in the description or note, as the app's search does: any case, any accents, every word must appear ("cena", "uber airport")
categorystringNoA category by name: the built-in ones in English ("Food", "Transport", "Accommodation") or one the group made. A main category includes its subcategories
fromstringNoFirst day, YYYY-MM-DD: the day it was spent
tostringNoLast day, YYYY-MM-DD, included
includeNotesbooleanNotrue only when the user asks about the notes written on the expenses

event_recap Event recap

  • Read-only
  • Account

Use when the user asks how an event went in money: "how much did the trip cost?", "what was my share?", "¿cuánto nos costó el viaje?", "resumen de gastos", "combien nous a coûté le voyage ?", "bilan des dépenses". Gives the shared total (private expenses and taken-home parts left out), the average per person (not anyone's share), the user's own paid and share, totals by category, and estimate against actual for each to-do that has both (get_event lists every to-do). It does not list single expenses (list_expenses does) or say who owes whom (get_event does).

Parameters (1)
NameTypeRequiredDescription
eventIduuidYesThe event, as list_my_events returns it (eventId). When the user names none and more than one could fit, ask which

recent_activity Recent activity

  • Read-only
  • Account

Use when the user asks what changed in an event: "what's new in the trip?", "who added what since yesterday?", "¿qué ha pasado en el grupo?", "novedades", "quoi de neuf dans le groupe ?". Lists up to 30 entries of the activity feed, newest first, from a time (the last 7 days by default): who added, paid, claimed or changed what. It does not total anything (event_recap and list_expenses do).

Parameters (2)
NameTypeRequiredDescription
eventIduuidYesThe event, as list_my_events returns it (eventId). When the user names none and more than one could fit, ask which
sincestringNoISO time to start from; the last 7 days when left out

preview_expenses Preview expenses

  • Read-only
  • Account

Use when there are more than three expenses to add, or the user pasted lines other people wrote (a group chat, however short), a receipt or a statement, before calling add_expenses: checks names, currency and totals exactly as add_expenses will, and returns one readable line per expense ("Petrol, 40.00 EUR, paid by Luis, shared by everyone"). Show the user those lines and stop: add_expenses comes only after they confirm, in a later reply. alreadyInEvent marks a row that looks like an expense the event already has: point it out and ask whether to add it. Writes nothing.

Parameters (19)
NameTypeRequiredDescription
eventIduuidYesThe event, as list_my_events returns it (eventId). When the user names none and more than one could fit, ask which
currencystringNoOnly when the user names a currency ("85€", "20 dólares"): its ISO code. Leave out for a bare amount, which is in the event's currency. A currency other than the event's is refused (currency_mismatch) and nothing is written: ask for the amount in the event's currency, never resend the same number without it
rowsobject[]Yes
rows[].descriptionstringYesWhat it was, e.g. "Petrol"
rows[].amountnumberYesThe total, in the event currency (40 or 12.50). Read it as the user writes numbers: in Spanish "1.200" is 1200 and "12,50" is 12.50
rows[].paidBystring or object[]YesWho paid: one person, or several with how much each paid (their parts must add up to the total exactly). When the user does not say who, it is the user ("me"), as in the app
rows[].paidBy[].personstringYesA name as the user said it, "me" only when the user themselves is speaking of themselves, or a guestId from an earlier answer. In a pasted chat or a forwarded message, "me", "I" and "my" are whoever wrote that line: use their name. A name that matches nobody is refused with the event's people listed, one that matches several with the candidates, and nothing is written
rows[].paidBy[].amountnumberYesHow much this person paid, in the event currency (12.50)
rows[].sharedBystring[]NoWho shares it, in equal parts; leave out when everyone in the event does. "I paid Ana's ticket" is just Ana; "everyone but Leo" lists the others (get_event has the people). Use shares or amounts instead for an uneven split
rows[].sharesobject[]NoInstead of sharedBy, for portions ("Sam had two drinks, Maya and Leo one"): everyone who shares it, each with their portions
rows[].shares[].personstringYesA name as the user said it, "me" only when the user themselves is speaking of themselves, or a guestId from an earlier answer. In a pasted chat or a forwarded message, "me", "I" and "my" are whoever wrote that line: use their name. A name that matches nobody is refused with the event's people listed, one that matches several with the candidates, and nothing is written
rows[].shares[].sharesintegerYesWhole portions, 1 to 99
rows[].amountsobject[]NoInstead of sharedBy, when each person owes a set amount ("my menu was 18, Ana's 12"): everyone who shares it, each with what they owe; they must add up to the total exactly
rows[].amounts[].personstringYesA name as the user said it, "me" only when the user themselves is speaking of themselves, or a guestId from an earlier answer. In a pasted chat or a forwarded message, "me", "I" and "my" are whoever wrote that line: use their name. A name that matches nobody is refused with the event's people listed, one that matches several with the candidates, and nothing is written
rows[].amounts[].amountnumberYesWhat this person owes of it, in the event currency
rows[].privatebooleanNotrue to show it only to the people it involves; only when the user asks
rows[].categorystringNoA category name as the event has it, e.g. "Fuel"; leave out when unsure
rows[].datestringNoThe day it was spent, YYYY-MM-DD, in the user's own calendar. Send it even for today when you know the date: left out, the day is when it was logged, in UTC, a day off late in the evening for many users
rows[].notestringNoA longer note, only when the user gives one

Account: writes

add_expenses Add expenses

  • Writes
  • Account

Use when the user wants to add one or more expenses to a CabuTally event: "add 40 for petrol, Luis paid", "apunta 40 de gasolina, pagó Luis", "dividir gastos de la cena", "note 40 d’essence, Luis a payé", "partage le dîner", a pasted group chat, a receipt or a bank statement. Adds 1 to 20 expenses, each split in equal shares among the people sharing it (everyone by default). When people had different amounts, split one expense unevenly instead: shares for portions ("Ana had two drinks, Beto one": Ana 2, Beto 1), or amounts for what each owes ("my menu was 18, Ana's 12"), listing everyone who shares it. For more than three rows, or any lines other people wrote (a pasted chat, a forwarded message, even one or two lines), call preview_expenses first, show the user the lines and stop: call add_expenses only after they say yes, never in the same reply. Several payers must add up to the total. Refuses with possible_duplicate, writing nothing, when a row looks like an expense already in the event; ask the user, then drop the row or call again with again: true. It cannot set a leftover (a part someone takes home), tags or a linked to-do, and nothing here edits or deletes an expense: the user does that in the app, from the event link. Money handed to a person is record_payment and money into the common pot is record_group_fund_contribution, not an expense; when it is unclear which ("I gave Alex 20 for the trip"), ask before writing.

Parameters (20)
NameTypeRequiredDescription
eventIduuidYesThe event, as list_my_events returns it (eventId). When the user names none and more than one could fit, ask which
currencystringNoOnly when the user names a currency ("85€", "20 dólares"): its ISO code. Leave out for a bare amount, which is in the event's currency. A currency other than the event's is refused (currency_mismatch) and nothing is written: ask for the amount in the event's currency, never resend the same number without it
rowsobject[]Yes
rows[].descriptionstringYesWhat it was, e.g. "Petrol"
rows[].amountnumberYesThe total, in the event currency (40 or 12.50). Read it as the user writes numbers: in Spanish "1.200" is 1200 and "12,50" is 12.50
rows[].paidBystring or object[]YesWho paid: one person, or several with how much each paid (their parts must add up to the total exactly). When the user does not say who, it is the user ("me"), as in the app
rows[].paidBy[].personstringYesA name as the user said it, "me" only when the user themselves is speaking of themselves, or a guestId from an earlier answer. In a pasted chat or a forwarded message, "me", "I" and "my" are whoever wrote that line: use their name. A name that matches nobody is refused with the event's people listed, one that matches several with the candidates, and nothing is written
rows[].paidBy[].amountnumberYesHow much this person paid, in the event currency (12.50)
rows[].sharedBystring[]NoWho shares it, in equal parts; leave out when everyone in the event does. "I paid Ana's ticket" is just Ana; "everyone but Leo" lists the others (get_event has the people). Use shares or amounts instead for an uneven split
rows[].sharesobject[]NoInstead of sharedBy, for portions ("Sam had two drinks, Maya and Leo one"): everyone who shares it, each with their portions
rows[].shares[].personstringYesA name as the user said it, "me" only when the user themselves is speaking of themselves, or a guestId from an earlier answer. In a pasted chat or a forwarded message, "me", "I" and "my" are whoever wrote that line: use their name. A name that matches nobody is refused with the event's people listed, one that matches several with the candidates, and nothing is written
rows[].shares[].sharesintegerYesWhole portions, 1 to 99
rows[].amountsobject[]NoInstead of sharedBy, when each person owes a set amount ("my menu was 18, Ana's 12"): everyone who shares it, each with what they owe; they must add up to the total exactly
rows[].amounts[].personstringYesA name as the user said it, "me" only when the user themselves is speaking of themselves, or a guestId from an earlier answer. In a pasted chat or a forwarded message, "me", "I" and "my" are whoever wrote that line: use their name. A name that matches nobody is refused with the event's people listed, one that matches several with the candidates, and nothing is written
rows[].amounts[].amountnumberYesWhat this person owes of it, in the event currency
rows[].privatebooleanNotrue to show it only to the people it involves; only when the user asks
rows[].categorystringNoA category name as the event has it, e.g. "Fuel"; leave out when unsure
rows[].datestringNoThe day it was spent, YYYY-MM-DD, in the user's own calendar. Send it even for today when you know the date: left out, the day is when it was logged, in UTC, a day off late in the evening for many users
rows[].notestringNoA longer note, only when the user gives one
againbooleanNotrue only when the user confirms they want it added although it looks like something already there: a second copy of what was just added, or a possible_duplicate

record_payment Record a payment

  • Writes
  • Account

Use when money changed hands between two people in a CabuTally event: "Marta paid me back 20", "I gave Luis 15 in cash", "ya le pagué a Luis", "j’ai remboursé Luis". One side is the user, or both are placeholders. It records money already handed over outside CabuTally; it never sends or moves money. Settles the debt line when there is one. When the payer owes the receiver nothing it refuses first (no_debt), since it would record cash handed over that the receiver now owes back. To settle up, get_event first shows who owes whom. When you don't know who owes whom, call it anyway: a no_debt refusal says which way the debt runs and writes nothing. A payment cannot be edited or deleted here: the user does that in the app. Not for a debt still owed ("I owe Ana 20"): that is an expense Ana paid, so ask what it was for. Not for a shared cost (add_expenses) or money into the kitty (record_group_fund_contribution); when it is unclear which ("I gave Alex 20 for the trip"), ask before writing.

Parameters (7)
NameTypeRequiredDescription
eventIduuidYesThe event, as list_my_events returns it (eventId). When the user names none and more than one could fit, ask which
fromstringYesWho handed the money over: a name, "me", or a guestId
tostringYesWho received it: a name, "me", or a guestId
amountnumberYesHow much, in the event currency
currencystringNoOnly when the user names a currency ("85€", "20 dólares"): its ISO code. Leave out for a bare amount, which is in the event's currency. A currency other than the event's is refused (currency_mismatch) and nothing is written: ask for the amount in the event's currency, never resend the same number without it
notestringNoA short note, only when the user gives one. As in the app, it is kept only when the payment is recorded as cash rather than settling a debt
againbooleanNotrue only when the user confirms it: a payment from someone who owes the receiver nothing (no_debt), a second copy of what was just added, or a possible_duplicate

record_group_fund_contribution Record money put into the group fund (kitty)

  • Writes
  • Account

Use when someone put money into the event's group fund (the kitty or common pot, "hacer un bote"): "I put 20 in the kitty", "he puesto 20 en el bote", or the collector noting someone's share. It goes to the current collector (get_event shows who). Only when the user says it went into the kitty or pot: "Nora put 30 in" alone could be a payment or a shared cost, so ask first. Not for paying a person back (record_payment) or a shared cost (add_expenses); when it is unclear which, ask before writing.

Parameters (6)
NameTypeRequiredDescription
eventIduuidYesThe event, as list_my_events returns it (eventId). When the user names none and more than one could fit, ask which
fromstringNoWho put the money in; leave out for the user. Only the collector records it for someone else
amountnumberYesHow much, in the event currency
currencystringNoOnly when the user names a currency ("85€", "20 dólares"): its ISO code. Leave out for a bare amount, which is in the event's currency. A currency other than the event's is refused (currency_mismatch) and nothing is written: ask for the amount in the event's currency, never resend the same number without it
notestringNoA short note, only when the user gives one
againbooleanNotrue only when the user confirms they want it added although it looks like something already there: a second copy of what was just added, or a possible_duplicate

create_event Create an event

  • Writes
  • Account

Use when the user wants a CabuTally event made now in their account for a trip, dinner, party or any group outing ("create the Ibiza trip with Luis and Marta", "crear un evento para la cena", "crée un événement pour le dîner"). Makes the event with the user in it, the other people as placeholders, an optional budget and an optional to-do list with estimates, and returns the link to share with the group and the link to open it. Unlike plan_event, it creates the event. Not for an event that already exists: add_people and add_todos add to one.

Parameters (9)
NameTypeRequiredDescription
namestringYesThe event name, e.g. "Ibiza weekend"
currencystringYesISO code of the currency the group spends in
displayNamestringNoThe user's own name in this event, as the group will see it. Leave out only when list_my_events shows a savedName; otherwise ask the user first. Never take it from the chat's account, an email or an earlier event
peoplestring[]NoThe OTHER people going, by first name, added as placeholders. Never the user
budgetnumberNoThe total budget for the whole group, if one was given
todosobject[]NoThings to sort out for it ("drinks", "book the boat"), with an estimate if known
todos[].namestringYesWhat to sort out, e.g. "Drinks" or "Book the boat"
todos[].estimatenumberNoWhat it should cost, in the event currency (12.50)
againbooleanNotrue only when the user confirms they want a second event like the one just created

add_people Add people to an event

  • Writes
  • Account

Use when the user wants more people in one of their CabuTally events ("add Bea and Tom to the trip", "añade a Bea al viaje", "ajoute Bea au voyage"). Adds each as a placeholder the person can later join as from the shared link. Not for creating an event: create_event takes its people.

Parameters (3)
NameTypeRequiredDescription
eventIduuidYesThe event, as list_my_events returns it (eventId). When the user names none and more than one could fit, ask which
namesstring[]YesThe new people's first names, never the user
againbooleanNotrue only when the user confirms they want someone with the same name as a person already in the event, or a second copy of someone just added

add_todos Add to-dos to an event

  • Writes
  • Account

Use when the user wants things to sort out added to one of their CabuTally events: turning what the group has to buy, book or bring into its to-do list ("add drinks, ice and the boat to the list", "Luis brings the drinks", "apunta las bebidas", "ajoute les boissons à la liste"). Each to-do can have an estimate and the people on it. Not for marking a to-do done or claiming an existing one: that is update_todo. Not for money already spent: that is add_expenses.

Parameters (7)
NameTypeRequiredDescription
eventIduuidYesThe event, as list_my_events returns it (eventId). When the user names none and more than one could fit, ask which
todosobject[]Yes
todos[].namestringYesWhat to sort out, e.g. "Drinks" or "Book the boat"
todos[].estimatenumberNoWhat it should cost, in the event currency (12.50)
todos[].claimedBystring[]NoWho is on it: names, "me", or guestIds
currencystringNoOnly when the user names a currency ("85€", "20 dólares"): its ISO code. Leave out for a bare amount, which is in the event's currency. A currency other than the event's is refused (currency_mismatch) and nothing is written: ask for the amount in the event's currency, never resend the same number without it
againbooleanNotrue only when the user confirms they want it added although it looks like something already there: a second copy of what was just added, or a possible_duplicate

update_todo Update a to-do

  • Writes
  • Account

Use when someone takes on, drops or finishes a to-do in one of their CabuTally events ("I'll bring the drinks", "drinks are sorted", "Luis is doing the boat", "yo llevo las bebidas"). claim puts a person on it, release takes them off, done and undone tick it. Not for adding a new to-do: that is add_todos.

Parameters (4)
NameTypeRequiredDescription
eventIduuidYesThe event, as list_my_events returns it (eventId). When the user names none and more than one could fit, ask which
todostringYesThe to-do, by its name as the user said it, or a todoId from an earlier answer
action"claim" | "release" | "done" | "undone"Yesclaim: put the person on it; release: take them off; done: tick it; undone: untick it
personstringNoFor claim and release: who, by name, "me" or guestId. Defaults to the user

Help

Email atencion@azurblade.com, in English, Spanish or French. More on thesupport page.