move_category_funds
Transfer budgeted money between categories within a specific month to adjust your spending plan as financial needs change.
Instructions
Move funds from one category to another in a specific month.
Args:
budget_id: The ID of the budget (use 'last-used' for default budget)
month: Month in YYYY-MM-DD format (e.g., 2025-01-01 for January 2025)
from_category_id: Source category ID to move funds from
to_category_id: Destination category ID to move funds to
amount: Amount to move (positive value)
Returns:
JSON string with updated from and to categories
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| amount | Yes | ||
| budget_id | Yes | ||
| from_category_id | Yes | ||
| month | Yes | ||
| to_category_id | Yes |
Implementation Reference
- src/ynab_mcp/server.py:484-509 (registration)MCP tool registration and handler wrapper for move_category_funds. Delegates execution to YNABClient instance.@mcp.tool() async def move_category_funds( budget_id: str, month: str, from_category_id: str, to_category_id: str, amount: float, ) -> str: """Move funds from one category to another in a specific month. Args: budget_id: The ID of the budget (use 'last-used' for default budget) month: Month in YYYY-MM-DD format (e.g., 2025-01-01 for January 2025) from_category_id: Source category ID to move funds from to_category_id: Destination category ID to move funds to amount: Amount to move (positive value) Returns: JSON string with updated from and to categories """ client = get_ynab_client() result = await client.move_category_funds( budget_id, month, from_category_id, to_category_id, amount ) return json.dumps(result, indent=2)
- src/ynab_mcp/ynab_client.py:1353-1424 (handler)Core implementation executing the tool logic: retrieves current budgets, adjusts budgeted amounts for source and destination categories via YNAB API PATCH requests, and returns updated category details.async def move_category_funds( self, budget_id: str, month: str, from_category_id: str, to_category_id: str, amount: float, ) -> dict[str, Any]: """Move funds from one category to another in a specific month. Uses direct API calls since ynab-sdk is read-only. Args: budget_id: The budget ID or 'last-used' month: Month in YYYY-MM-DD format (e.g., 2025-01-01) from_category_id: Source category ID to_category_id: Destination category ID amount: Amount to move (positive value) Returns: Dictionary with updated from and to categories """ try: # Get current budgeted amounts categories_response = self.client.categories.get_categories(budget_id) categories = {} for group in categories_response.data.category_groups: for cat in group.categories: if cat.id in [from_category_id, to_category_id]: categories[cat.id] = {"budgeted": cat.budgeted, "name": cat.name} if from_category_id not in categories or to_category_id not in categories: raise ValueError("One or both category IDs not found") # Calculate new budgeted amounts from_budgeted = (categories[from_category_id]["budgeted"] / 1000) - amount to_budgeted = (categories[to_category_id]["budgeted"] / 1000) + amount # Update both categories using direct API calls base_url = f"{self.api_base_url}/budgets/{budget_id}/months/{month}/categories" # Update from_category from_url = f"{base_url}/{from_category_id}" from_data = {"category": {"budgeted": int(from_budgeted * MILLIUNITS_FACTOR)}} from_result = await self._make_request_with_retry("patch", from_url, json=from_data) # Update to_category to_url = f"{base_url}/{to_category_id}" to_data = {"category": {"budgeted": int(to_budgeted * MILLIUNITS_FACTOR)}} to_result = await self._make_request_with_retry("patch", to_url, json=to_data) from_cat = from_result["data"]["category"] to_cat = to_result["data"]["category"] return { "from_category": { "id": from_cat["id"], "name": from_cat["name"], "budgeted": from_cat["budgeted"] / 1000 if from_cat["budgeted"] else 0, "balance": from_cat["balance"] / 1000 if from_cat["balance"] else 0, }, "to_category": { "id": to_cat["id"], "name": to_cat["name"], "budgeted": to_cat["budgeted"] / 1000 if to_cat["budgeted"] else 0, "balance": to_cat["balance"] / 1000 if to_cat["balance"] else 0, }, "amount_moved": amount, } except Exception as e: raise Exception(f"Failed to move category funds: {e}") from e