Skip to main content
Glama
dgalarza

YNAB MCP Server

by dgalarza

get_budget_summary

Retrieve budget summary for a specific month including income, budgeted amounts, and category details from your YNAB budget.

Instructions

Get budget summary for 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)

Returns:
    JSON string with budget summary including income, budgeted amounts, and category details

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
budget_idYes
monthYes

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Implementation Reference

  • MCP tool handler function for get_budget_summary. Registers the tool via @mcp.tool() decorator, validates inputs via type hints and docstring, delegates to YNABClient, and serializes response to JSON.
    @mcp.tool()
    async def get_budget_summary(budget_id: str, month: str) -> str:
        """Get budget summary for 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)
    
        Returns:
            JSON string with budget summary including income, budgeted amounts, and category details
        """
        client = get_ynab_client()
        result = await client.get_budget_summary(budget_id, month)
        return json.dumps(result, indent=2)
  • Core helper function in YNABClient that implements the business logic: validates inputs, fetches month data from YNAB API endpoint /budgets/{budget_id}/months/{month}, maps categories to groups, filters hidden/deleted, calculates aggregate totals (income, budgeted, activity, balance, to_be_budgeted), and returns structured dictionary with category details.
    async def get_budget_summary(self, budget_id: str, month: str) -> dict[str, Any]:
        """Get budget summary for a specific month.
    
        Uses direct API to get month-specific data since SDK doesn't support it.
    
        Args:
            budget_id: The budget ID or 'last-used'
            month: Month in YYYY-MM-DD format (e.g., 2025-01-01)
    
        Returns:
            Budget summary dictionary
    
        Raises:
            YNABValidationError: If parameters are invalid
            YNABAPIError: If API request fails
        """
        logger.debug(f"Getting budget summary for {budget_id}, month {month}")
    
        # Validate inputs
        budget_id = validate_budget_id(budget_id)
        month = validate_date(month, "month")
    
        # Use direct API call to get month-specific budget data
        url = f"{self.api_base_url}/budgets/{budget_id}/months/{month}"
        result = await self._make_request_with_retry("get", url)
    
        month_data = result["data"]["month"]
    
        # Debug: Check what keys are available
        if "categories" not in month_data:
            raise YNABAPIError(f"Month data keys: {list(month_data.keys())}")
    
        # Get category groups to map category IDs to group names
        categories_response = self.client.categories.get_categories(budget_id)
        category_group_map = {}
        for group in categories_response.data.category_groups:
            for cat in group.categories:
                category_group_map[cat.id] = group.name
    
        # Calculate totals and collect category details
        total_budgeted = 0
        total_activity = 0
        total_balance = 0
        categories = []
    
        # Month data has a flat list of categories, not grouped
        # Filter out hidden and deleted categories
        filtered_categories = self._filter_categories(month_data.get("categories", []))
    
        for category in filtered_categories:
            budgeted = category["budgeted"] / MILLIUNITS_FACTOR if category["budgeted"] else 0
            activity = category["activity"] / MILLIUNITS_FACTOR if category["activity"] else 0
            balance = category["balance"] / MILLIUNITS_FACTOR if category["balance"] else 0
    
            total_budgeted += budgeted
            total_activity += activity
            total_balance += balance
    
            category_group_name = category_group_map.get(category["id"], "Unknown")
    
            categories.append(
                {
                    "category_group": category_group_name,
                    "category_name": category["name"],
                    "budgeted": budgeted,
                    "activity": activity,
                    "balance": balance,
                }
            )
    
        return {
            "month": month,
            "income": month_data["income"] / MILLIUNITS_FACTOR if month_data.get("income") else 0,
            "budgeted": total_budgeted,
            "activity": total_activity,
            "balance": total_balance,
            "to_be_budgeted": month_data["to_be_budgeted"] / MILLIUNITS_FACTOR
            if month_data.get("to_be_budgeted")
            else 0,
            "categories": categories,
        }
  • The @mcp.tool() decorator registers the get_budget_summary function as an MCP tool with FastMCP, automatically generating schema from signature and docstring.
    @mcp.tool()
  • Docstring provides input schema description (budget_id str, month str in YYYY-MM-DD) and output format (JSON string with summary details). Type hints reinforce schema.
    """Get budget summary for 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)
    
    Returns:
        JSON string with budget summary including income, budgeted amounts, and category details
    """
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It implies a read operation ('Get') but doesn't specify permissions, rate limits, error handling, or whether it's idempotent. For a tool with zero annotation coverage, this leaves significant behavioral gaps.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is appropriately sized and front-loaded: the first sentence states the purpose clearly, followed by structured sections for Args and Returns. Every sentence adds value without redundancy, making it efficient and well-organized.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool has an output schema (which covers return values), the description provides good context with parameter details and a high-level return overview. However, as a read operation with no annotations, it could benefit from more behavioral transparency (e.g., error cases, data freshness) to be fully complete.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The description adds substantial meaning beyond the input schema, which has 0% description coverage. It explains that 'budget_id' can use 'last-used' for default budget and specifies the exact format for 'month' (YYYY-MM-DD with examples), compensating fully for the schema's lack of documentation.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb 'Get' and resource 'budget summary' with the scope 'for a specific month', making the purpose evident. However, it doesn't explicitly differentiate from sibling tools like 'get_category_spending_summary' or 'update_category_budget', which might handle similar budget-related data, so it misses full sibling differentiation.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives like 'get_category_spending_summary' or 'update_category_budget', nor does it mention prerequisites or exclusions. It only states what the tool does, without contextual usage advice.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/dgalarza/ynab-mcp-dgalarza'

If you have feedback or need assistance with the MCP directory API, please join our Discord server