Skip to main content
Glama
dgalarza

YNAB MCP Server

by dgalarza

get_transactions

Retrieve YNAB transactions with filtering options by date, account, or category. Use pagination to manage large datasets and analyze spending patterns effectively.

Instructions

Get transactions with optional filtering and pagination.

Args:
    budget_id: The ID of the budget (use 'last-used' for default budget)
    since_date: Only return transactions on or after this date (YYYY-MM-DD format)
    until_date: Only return transactions on or before this date (YYYY-MM-DD format)
    account_id: Filter by account ID (optional)
    category_id: Filter by category ID (optional)
    limit: Number of transactions per page (default: 100, max: 500)
    page: Page number for pagination (1-indexed, default: 1)

Returns:
    JSON string with transactions array and pagination metadata

Note:
    For large date ranges (>1 year), use get_category_spending_summary or
    compare_spending_by_year instead to avoid timeouts and reduce context usage.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
account_idNo
budget_idYes
category_idNo
limitNo
pageNo
since_dateNo
until_dateNo

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Implementation Reference

  • MCP tool handler implementation for get_transactions. Registers the tool via @mcp.tool() decorator, validates inputs via type hints/docstring, delegates to YNABClient, and serializes response to JSON.
    @mcp.tool()
    async def get_transactions(
        budget_id: str,
        since_date: str = None,
        until_date: str = None,
        account_id: str = None,
        category_id: str = None,
        limit: int = None,
        page: int = None,
    ) -> str:
        """Get transactions with optional filtering and pagination.
    
        Args:
            budget_id: The ID of the budget (use 'last-used' for default budget)
            since_date: Only return transactions on or after this date (YYYY-MM-DD format)
            until_date: Only return transactions on or before this date (YYYY-MM-DD format)
            account_id: Filter by account ID (optional)
            category_id: Filter by category ID (optional)
            limit: Number of transactions per page (default: 100, max: 500)
            page: Page number for pagination (1-indexed, default: 1)
    
        Returns:
            JSON string with transactions array and pagination metadata
    
        Note:
            For large date ranges (>1 year), use get_category_spending_summary or
            compare_spending_by_year instead to avoid timeouts and reduce context usage.
        """
        client = get_ynab_client()
        result = await client.get_transactions(
            budget_id, since_date, until_date, account_id, category_id, limit, page
        )
        return json.dumps(result, indent=2)
  • Supporting method in YNABClient class that performs the actual API request to YNAB, applies client-side filtering for category/until_date/pagination, formats transaction data, and handles errors.
    async def get_transactions(
        self,
        budget_id: str,
        since_date: str | None = None,
        until_date: str | None = None,
        account_id: str | None = None,
        category_id: str | None = None,
        limit: int | None = None,
        page: int | None = None,
    ) -> dict[str, Any]:
        """Get transactions with optional filtering and pagination.
    
        Args:
            budget_id: The budget ID or 'last-used'
            since_date: Only return transactions on or after this date (YYYY-MM-DD)
            until_date: Only return transactions on or before this date (YYYY-MM-DD)
            account_id: Filter by account ID
            category_id: Filter by category ID
            limit: Number of transactions per page (default: 100, max: 500)
            page: Page number for pagination (1-indexed, default: 1)
    
        Returns:
            Dictionary with transactions, pagination info, and total count
    
        Note:
            For large date ranges (>1 year), consider using get_category_spending_summary
            or compare_spending_by_year instead to avoid timeouts and reduce context usage.
        """
        try:
            # Use direct API call for better filtering support
            url = f"{self.api_base_url}/budgets/{budget_id}/transactions"
            params = {}
            if since_date:
                params["since_date"] = since_date
            if account_id:
                url = f"{self.api_base_url}/budgets/{budget_id}/accounts/{account_id}/transactions"
    
            result = await self._make_request_with_retry("get", url, params=params)
    
            txn_data = result["data"]["transactions"]
    
            # Apply filters
            filtered_transactions = []
            for txn in txn_data:
                # Filter by category_id if provided
                if category_id and txn.get("category_id") != category_id:
                    continue
    
                # Filter by until_date if provided (client-side filtering)
                if until_date and txn["date"] > until_date:
                    continue
    
                filtered_transactions.append(txn)
    
            # Pagination
            page_size = min(limit or 100, 500)  # Default 100, max 500
            page_num = max(page or 1, 1)  # Default to page 1, minimum 1
    
            total_count = len(filtered_transactions)
            total_pages = (total_count + page_size - 1) // page_size if total_count > 0 else 1
    
            start_idx = (page_num - 1) * page_size
            end_idx = start_idx + page_size
    
            paginated_txns = filtered_transactions[start_idx:end_idx]
    
            transactions = []
            for txn in paginated_txns:
                transactions.append(
                    {
                        "id": txn["id"],
                        "date": txn["date"],
                        "amount": txn["amount"] / 1000 if txn.get("amount") else 0,
                        "memo": txn.get("memo"),
                        "cleared": txn.get("cleared"),
                        "approved": txn.get("approved"),
                        "account_id": txn.get("account_id"),
                        "account_name": txn.get("account_name"),
                        "payee_id": txn.get("payee_id"),
                        "payee_name": txn.get("payee_name"),
                        "category_id": txn.get("category_id"),
                        "category_name": txn.get("category_name"),
                        "transfer_account_id": txn.get("transfer_account_id"),
                        "deleted": txn.get("deleted"),
                    }
                )
    
            return {
                "transactions": transactions,
                "pagination": {
                    "page": page_num,
                    "per_page": page_size,
                    "total_count": total_count,
                    "total_pages": total_pages,
                    "has_next_page": page_num < total_pages,
                    "has_prev_page": page_num > 1,
                },
            }
        except httpx.HTTPStatusError as e:
            raise Exception(
                f"Failed to get transactions: HTTP {e.response.status_code} - {e.response.text}"
            ) from e
        except Exception as e:
            raise Exception(f"Failed to get transactions: {type(e).__name__}: {e}") from e
Behavior4/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 effectively describes key behaviors: pagination support (with defaults for limit and page), date format requirements (YYYY-MM-DD), timeout risks for large date ranges, and the return format (JSON with array and metadata). It doesn't mention rate limits or authentication needs, but covers most operational aspects well.

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 well-structured and appropriately sized. It starts with a clear purpose statement, then organizes parameter details in a labeled 'Args' section, followed by return information and a practical note. Every sentence adds value, with no wasted words or redundancy.

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

Completeness5/5

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

Given the tool's complexity (7 parameters, filtering/pagination logic) and the presence of an output schema (which handles return values), the description is complete. It covers purpose, parameters, usage guidance, and behavioral context thoroughly. The Note section addresses performance considerations, making it well-rounded for agent use.

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 all 7 parameters clearly: purpose (e.g., 'filter by account ID'), special values ('last-used' for budget_id), formats (YYYY-MM-DD for dates), defaults (limit: 100, page: 1), constraints (max: 500 for limit), and optionality. This fully compensates for the schema's lack of descriptions.

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 tool's purpose: 'Get transactions with optional filtering and pagination.' It specifies the verb ('Get') and resource ('transactions'), and mentions key capabilities (filtering, pagination). However, it doesn't explicitly differentiate from sibling tools like 'search_transactions' or 'get_unapproved_transactions', which prevents a perfect score.

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

Usage Guidelines4/5

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

The description provides clear context for when to use alternatives: the Note section explicitly advises using 'get_category_spending_summary' or 'compare_spending_by_year' for large date ranges (>1 year) to avoid timeouts. This is helpful guidance, though it doesn't cover all sibling distinctions (e.g., vs. 'search_transactions').

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