ynab_move_money
Move money between YNAB categories: enter source and destination category IDs, the dollar amount to transfer, and an optional month for backdated changes.
Instructions
Move money from one category to another.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| params | Yes |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| result | Yes |
Implementation Reference
- src/ynab_mcp_server/server.py:218-256 (handler)The main handler function for the 'ynab_move_money' tool. It moves money (in dollars) from one YNAB category to another by fetching both categories, validating sufficient budgeted funds, then updating both category budgets via the API. Returns a summary table with before/after amounts.
async def ynab_move_money(params: MoveMoneyCategoryInput) -> str: """Move money from one category to another.""" try: month = params.month or get_current_month() amount_milliunits = dollars_to_milliunits(params.amount) async with YNABClient() as client: from_cat = await client.get_category(params.budget_id, params.from_category_id) to_cat = await client.get_category(params.budget_id, params.to_category_id) from_budgeted = from_cat.get("budgeted", 0) to_budgeted = to_cat.get("budgeted", 0) if from_budgeted < amount_milliunits: return ( f"Error: {from_cat['name']} only has {format_currency(from_budgeted)} budgeted. " f"Cannot move {format_currency(amount_milliunits)}." ) new_from = from_budgeted - amount_milliunits new_to = to_budgeted + amount_milliunits await client.update_category_budget( params.budget_id, params.from_category_id, month, new_from ) await client.update_category_budget( params.budget_id, params.to_category_id, month, new_to ) result = f"## Money Moved Successfully\n\n" result += f"**Moved {format_currency(amount_milliunits)}** from {from_cat['name']} to {to_cat['name']}\n\n" result += f"| Category | Before | After |\n" result += f"|----------|--------|-------|\n" result += f"| {from_cat['name']} | {format_currency(from_budgeted)} | {format_currency(new_from)} |\n" result += f"| {to_cat['name']} | {format_currency(to_budgeted)} | {format_currency(new_to)} |\n" return result except Exception as e: return format_error(e) - src/ynab_mcp_server/models.py:69-78 (schema)Pydantic input schema 'MoveMoneyCategoryInput' defining the required fields: from_category_id, to_category_id, amount (in dollars, >0), and optional month (YYYY-MM-01 format). Inherits budget_id from BudgetIdInput.
class MoveMoneyCategoryInput(BudgetIdInput): """Input for moving money between categories.""" from_category_id: str = Field(..., description="Category ID to move money FROM") to_category_id: str = Field(..., description="Category ID to move money TO") amount: float = Field(..., description="Amount in dollars to move (e.g., 50.00)", gt=0) month: Optional[str] = Field( default=None, description="Month in YYYY-MM-DD format (first of month). Defaults to current month.", pattern=r"^\d{4}-\d{2}-01$", ) - src/ynab_mcp_server/server.py:208-217 (registration)Registration of the tool via the @mcp.tool decorator with name='ynab_move_money', title 'Move Money Between Categories', with idempotentHint=False, destructiveHint=False, readOnlyHint=False.
@mcp.tool( name="ynab_move_money", annotations={ "title": "Move Money Between Categories", "readOnlyHint": False, "destructiveHint": False, "idempotentHint": False, "openWorldHint": False, } ) - src/ynab_mcp_server/server.py:40-42 (helper)Helper function 'dollars_to_milliunits' used by the handler to convert dollar amounts to YNAB's internal milliunit integer format (1000 milliunits = $1.00).
def dollars_to_milliunits(dollars: float) -> int: """Convert dollars to YNAB milliunits (1000 milliunits = $1.00).""" return int(round(dollars * 1000)) - src/ynab_mcp_server/api.py:236-249 (helper)The API helper 'update_category_budget' that sends the PATCH request to YNAB's API to update a category's budgeted amount for a specific month. Used by the handler to apply the money movement.
async def update_category_budget( self, budget_id: str, category_id: str, month: str, budgeted: int, ) -> Dict[str, Any]: """Update the budgeted amount for a category in a specific month.""" response = await self._request( "PATCH", f"/budgets/{budget_id}/months/{month}/categories/{category_id}", data={"category": {"budgeted": budgeted}}, ) return response["data"]["category"]