Skip to main content
Glama
vargahis

monarch-mcp

get_account_history

Retrieve historical balance snapshots for a Monarch Money account to track financial changes over time.

Instructions

Get historical balance snapshots for an account.

Args: account_id: The ID of the account

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
account_idYes

Implementation Reference

  • The main handler function for the 'get_account_history' tool. It's decorated with @mcp.tool() to register it as an MCP tool, and uses @_handle_mcp_errors for error handling. The function takes an account_id parameter, creates an async client, calls client.get_account_history(), and returns the result as JSON.
    @mcp.tool()
    @_handle_mcp_errors("getting account history")
    def get_account_history(account_id: str) -> str:
        """
        Get historical balance snapshots for an account.
    
        Args:
            account_id: The ID of the account
        """
    
        async def _get_account_history():
            client = await get_monarch_client()
            return await client.get_account_history(account_id)
    
        history = run_async(_get_account_history())
    
        return json.dumps(history, indent=2, default=str)
  • The @mcp.tool() decorator registers the get_account_history function as an MCP tool with the FastMCP framework. The tool name is derived from the function name.
    @mcp.tool()
  • Error handling decorator that wraps the tool handler. It catches specific exceptions (RuntimeError, TransportServerError, TransportQueryError, TransportError) and returns user-friendly error messages, ensuring the MCP tool never crashes.
    def _handle_mcp_errors(operation: str):
        """Decorator providing granular exception handling for MCP tool functions.
    
        Catches specific known exception types with appropriate log messages,
        with a catch-all for anything unexpected.  Every path returns a
        user-readable error string so the MCP tool never crashes.
        """
        def decorator(func):
            @functools.wraps(func)
            def wrapper(*args, **kwargs):
                try:
                    return func(*args, **kwargs)
                except RuntimeError as exc:
                    logger.error("Runtime error %s: %s", operation, exc)
                    return f"Error {operation}: {exc}"
                except TransportServerError as exc:
                    code = getattr(exc, "code", "unknown")
                    logger.error(
                        "Monarch API HTTP %s error %s: %s", code, operation, exc,
                    )
                    return f"Error {operation}: Monarch API returned HTTP {code}: {exc}"
                except TransportQueryError as exc:
                    logger.error("Monarch API query error %s: %s", operation, exc)
                    return f"Error {operation}: API query failed: {exc}"
                except TransportError as exc:
                    logger.error(
                        "Monarch API connection error %s: %s", operation, exc,
                    )
                    return f"Error {operation}: connection error: {exc}"
                except Exception as exc:  # pylint: disable=broad-exception-caught
                    logger.error(
                        "Unexpected error %s: %s (%s)",
                        operation, exc, type(exc).__name__,
                    )
                    return f"Error {operation}: {exc}"
            return wrapper
        return decorator
  • Helper function that runs async coroutines in a thread pool with proper event loop handling. Also handles authentication errors by clearing expired tokens and triggering re-authentication flow.
    def run_async(coro):
        """Run async function in a new thread with its own event loop.
    
        If the coroutine raises an authentication error (expired token,
        invalid credentials), the stale token is cleared from the keyring,
        the browser-based auth flow is re-triggered, and a RuntimeError is
        raised so the calling tool can inform the user.
    
        Only catches the two exception types that ``is_auth_error`` can
        recognise; everything else propagates unchanged to the caller.
        """
        with ThreadPoolExecutor() as executor:
            future = executor.submit(_run_sync, coro)
            try:
                return future.result()
            except (TransportServerError, LoginFailedException) as exc:
                if is_auth_error(exc):
                    logger.warning("Token appears expired — clearing and triggering re-auth")
                    secure_session.delete_token()
                    trigger_auth_flow()
                    raise RuntimeError(
                        "Your session has expired. A login page has been opened in "
                        "your browser — please sign in and try again."
                    ) from exc
                raise
  • Helper function that retrieves or creates a MonarchMoney client instance. It checks secure session storage first, then falls back to environment credentials, and finally triggers browser-based authentication if needed.
    async def get_monarch_client() -> MonarchMoney:
        """Get or create MonarchMoney client instance using secure session storage."""
        # Try to get authenticated client from secure session
        client = secure_session.get_authenticated_client()
    
        if client is not None:
            logger.info("Using authenticated client from secure keyring storage")
            return client
    
        # If no secure session, try environment credentials
        email = os.getenv("MONARCH_EMAIL")
        password = os.getenv("MONARCH_PASSWORD")
    
        if email and password:
            try:
                client = MonarchMoney()
                await client.login(email, password)
                logger.info(
                    "Successfully logged into Monarch Money with environment credentials"
                )
    
                # Save the session securely
                secure_session.save_authenticated_session(client)
    
                return client
            except Exception as e:
                logger.error("Failed to login to Monarch Money: %s", e)
                raise
    
        # No credentials anywhere — open browser login and tell the user
        trigger_auth_flow()
        raise RuntimeError(
            "Authentication needed! A login page has been opened in your "
            "browser — please sign in and try again."
        )

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/vargahis/monarch-mcp'

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