Satchel MCP docs
MCP tools reference

satchel_move_money

The one write tool — refuses everywhere unless explicitly enabled.

satchel_move_money moves money between the customer's own Satchel accounts. It is the only write tool Satchel MCP has, and it comes with the strictest defaults in the whole server.

Where it's available

stdio only. The hosted remote MCP server never registers this tool — not gated behind a flag or a permission, simply not present in that server's tool list at all. If you're connected to the hosted server, satchel_move_money does not exist as far as your assistant is concerned. It only exists when you run the local stdio server (mcp/) yourself.

Off by default, everywhere

Even on the stdio server, and even with valid credentials, the tool refuses unless SATCHEL_ALLOW_WRITES=true is set in the server's own environment — in every mode, sandbox and live alike. Without it, calling the tool returns a polite refusal explaining that writes are off by default and how to turn them on (set the env var and ask again) — never a silent no-op and never an error that looks like something broke.

This is an explicit, opt-in gate on money movement, independent of read access: an assistant can always read your accounts (subject to the credentials it has), but it can only move money if a human deliberately flipped that specific switch in the server's environment ahead of time.

What it does

It calls the underlying POST /transfer/internal endpoint — an internal transfer between two of the customer's own accounts. It cannot pay external recipients, and it cannot initiate a payment to anyone else's account; account ids for both sides must belong to the same authenticated customer (get them from satchel_list_accounts).

Parameters:

NameTypeNotes
from_account_idintegerSource account id.
to_account_idintegerDestination account id.
amountnumber, positiveAmount to move.
currencystring, 3 letterse.g. EUR.
narrativestring, optionalMemo/description. Defaulted if omitted or too short (the real API requires 5+ characters).

structuredContent (on success):

{
  id: number;
  amount: number;
  currency: string;
  narrative: string;
  fee?: { amount: number; currency: string };
  balances: Array<{ id: number; name: string; balance: { amount: number; currency: string } }>;
}

The text response confirms the transfer and shows the updated balance of both accounts involved.

In the sandbox, it's real — the sandbox's ledger, at least

When writes are enabled against the sandbox, a successful transfer genuinely mutates sandbox account balances and prepends a matching sender/recipient pair of transactions to the ledger — a follow-up satchel_list_accounts or satchel_list_transactions reflects it immediately. This is the sandbox's "your agent can act, with your consent" demonstration: the mutation is real within the sandbox's own state, even though no real money exists behind it.

In live mode

The same SATCHEL_ALLOW_WRITES=true gate applies, with the same refusal behaviour when unset. Enabling it against live credentials is a deliberate choice to let this server initiate a real internal transfer — treat it accordingly. (The hosted remote pilot sidesteps this question entirely by never registering the tool in the first place; see Authentication & security.)

Widget

Like satchel_financial_summary, this tool advertises a ui:// HTML widget (see Widgets) — a confirmation/receipt view. The widget triggers the transfer only on an explicit user click; it never fires the write as a side effect of merely being displayed. As with every tool, the text + structuredContent result is always present regardless of whether a client renders the widget.

On this page