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

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

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."
        )
Behavior2/5

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

No annotations are provided, so the description carries the full burden. It states the action ('Get historical balance snapshots') but lacks critical behavioral details such as time range coverage, pagination, rate limits, authentication needs, or what the snapshots include. This leaves significant gaps for an agent to understand how the tool behaves.

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

Conciseness4/5

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

The description is front-loaded with the core purpose in the first sentence, followed by a clear parameter explanation. It's efficient with no wasted words, though the structure is minimal and could benefit from more detailed guidance.

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

Completeness3/5

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

Given the tool's moderate complexity (historical data retrieval), no annotations, and an output schema present, the description is minimally adequate. It covers the basic purpose and parameter but lacks context on usage, behavioral traits, and output details, relying on the output schema to fill gaps.

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

Parameters4/5

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

The description adds meaningful context for the single parameter 'account_id' by explaining it's 'The ID of the account', which clarifies its purpose beyond the schema's basic type definition. With 0% schema description coverage and only one parameter, this compensation is adequate, though not exhaustive.

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 ('historical balance snapshots for an account'), making the purpose specific and understandable. It distinguishes from siblings like 'get_account_holdings' (current holdings) and 'get_recent_account_balances' (recent balances), though it doesn't explicitly mention these distinctions.

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?

No guidance is provided on when to use this tool versus alternatives. While the purpose implies it's for historical data, there's no mention of when to choose it over 'get_recent_account_balances' or 'get_account_snapshots_by_type', nor any prerequisites or exclusions.

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

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