Skip to main content
Glama
Meh-S-Eze

MCP YNAB Server

get_transactions_needing_attention

Identify YNAB budget transactions requiring action by filtering uncategorized, unapproved, or both types within a specified timeframe.

Instructions

List transactions that need attention based on specified filter type in a YNAB budget.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
budget_idYes
days_backNoNumber of days to look back (default 30, None for all)
filter_typeNoType of transactions to show. One of: 'uncategorized', 'unapproved', 'both'both

Implementation Reference

  • Main execution logic for the get_transactions_needing_attention tool. Fetches accounts and transactions from YNAB API, filters for those needing attention (uncategorized and/or unapproved), formats into a Markdown table, and returns it. Includes input schema via Annotated Fields.
    @mcp.tool()
    async def get_transactions_needing_attention(
        budget_id: str,
        filter_type: Annotated[
            str,
            Field(
                description="Type of transactions to show. One of: 'uncategorized', 'unapproved', 'both'"
            ),
        ] = "both",
        days_back: Annotated[
            Optional[int], Field(description="Number of days to look back (default 30, None for all)")
        ] = 30,
    ) -> str:
        """List transactions that need attention based on specified filter type in a YNAB budget."""
        filter_type = filter_type.lower()
        if filter_type not in ["uncategorized", "unapproved", "both"]:
            return "Error: Invalid filter_type. Must be 'uncategorized', 'unapproved', or 'both'"
    
        async with await get_ynab_client() as client:
            transactions_api = TransactionsApi(client)
            accounts_api = AccountsApi(client)
    
            accounts_response = accounts_api.get_accounts(budget_id)
            account_map = {
                account.id: account.name
                for account in accounts_response.data.accounts
                if not account.closed and not account.deleted
            }
    
            since_date = (datetime.now() - timedelta(days=days_back)).date() if days_back else None
            response = transactions_api.get_transactions(budget_id, since_date=since_date)
            needs_attention = _filter_transactions(response.data.transactions, filter_type)
    
            markdown = f"# Transactions Needing Attention ({filter_type.title()})\n\n"
            if not needs_attention:
                return markdown + "_No transactions need attention._"
    
            markdown += "**Filters Applied:**\n"
            markdown += f"- Filter type: {filter_type}\n"
            if days_back:
                markdown += f"- Looking back {days_back} days\n"
            markdown += "\n"
    
            headers = ["ID", "Date", "Account", "Amount", "Payee", "Status", "Memo"]
            align = ["left", "left", "left", "right", "left", "left", "left"]
            rows = [_get_transaction_row(txn, account_map, filter_type) for txn in needs_attention]
    
            markdown += _build_markdown_table(rows, headers, align)
            return markdown
  • Helper function to filter transactions that are uncategorized, unapproved, or both, based on the filter_type parameter.
    def _filter_transactions(
        transactions: List[TransactionDetail], filter_type: str
    ) -> List[TransactionDetail]:
        """Filter transactions based on the filter type."""
        needs_attention = []
        for txn in transactions:
            if isinstance(txn, TransactionDetail):
                needs_category = filter_type in ["uncategorized", "both"] and not txn.category_id
                needs_approval = filter_type in ["unapproved", "both"] and not txn.approved
                if needs_category or needs_approval:
                    needs_attention.append(txn)
        return needs_attention
  • Helper function to format a single transaction into a list for the Markdown table row, including status flags for uncategorized/unapproved.
    def _get_transaction_row(
        txn: TransactionDetail, account_map: Dict[str, str], filter_type: str
    ) -> List[str]:
        """Format a transaction into a row for the markdown table."""
        amount_dollars = float(txn.amount) / 1000
        amount_str = f"${abs(amount_dollars):,.2f}"
        if amount_dollars < 0:
            amount_str = f"-{amount_str}"
    
        status = []
        if not txn.category_id:
            status.append("Uncategorized")
        if not txn.approved:
            status.append("Unapproved")
    
        return [
            txn.id,
            txn.var_date.strftime("%Y-%m-%d"),
            account_map.get(txn.account_id, "Unknown"),
            amount_str,
            txn.payee_name or "N/A",
            ", ".join(status),
            txn.memo or "",
        ]

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/Meh-S-Eze/ynab-mcp-client2'

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