From 7a7140c76ca01e9a936f911695ee469a9145b07e Mon Sep 17 00:00:00 2001 From: b3nw Date: Tue, 5 May 2026 02:32:32 +0000 Subject: [PATCH] feat: add api_call pass-through tool and API reference resource - Add single pass-through tool following blueprint 'escape hatch' pattern - Add monarch://api-reference resource with available methods documentation - Fix dependency: use monarchmoney>=0.1.15 instead of monarchmoneycommunity - Add JSON error handling for malformed params --- pyproject.toml | 2 +- src/monarch_mcp_custom/server.py | 79 ++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 9d2ae5f..6405a5c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,7 +19,7 @@ requires-python = ">=3.12" dependencies = [ "mcp[cli]>=1.0.0", "fastmcp>=0.4.1", - "monarchmoneycommunity>=0.1.0", + "monarchmoney>=0.1.15", "gql>=4.0", "python-dotenv>=1.0.0", "pydantic>=2.0.0", diff --git a/src/monarch_mcp_custom/server.py b/src/monarch_mcp_custom/server.py index 9bd0f9d..f469392 100644 --- a/src/monarch_mcp_custom/server.py +++ b/src/monarch_mcp_custom/server.py @@ -191,6 +191,85 @@ async def refresh_accounts(reason: Optional[str] = None) -> str: return serialize_json(result) +# --- API Reference Resource --- + +API_REFERENCE = """ +# Monarch Money API Reference +Full method signatures: https://github.com/hammem/monarchmoney + +## Transaction Operations +- get_transactions(limit=100, offset=0, start_date=None, end_date=None, search='', category_ids=[], account_ids=[]) +- get_transaction_splits(transaction_id: str) +- update_transaction_splits(transaction_id: str, split_data: List[Dict]) +- create_transaction(date, account_id, amount, merchant_name, category_id, notes='', update_balance=False) +- update_transaction(transaction_id, category_id=None, merchant_name=None, amount=None, date=None, notes=None) +- delete_transaction(transaction_id: str) +- get_transaction_details(transaction_id: str) + +## Categories & Tags +- get_transaction_categories() +- get_transaction_category_groups() +- create_transaction_category(group_id, transaction_category_name, ...) +- create_transaction_tag(name, color) +- set_transaction_tags(transaction_id, tag_ids) +- get_transaction_tags() + +## Accounts +- get_accounts() +- get_account_holdings(account_id: int) +- create_manual_account(account_type, account_sub_type, is_in_net_worth, account_name, account_balance=0) +- update_account(account_id, account_name=None, account_balance=None, ...) + +## Budget & Cashflow +- get_budgets(start_date=None, end_date=None) +- get_cashflow(limit=100, start_date=None, end_date=None) +- get_recurring_transactions(start_date=None, end_date=None) + +## Sync +- request_accounts_refresh(account_ids: List[str]) +- is_accounts_refresh_complete(account_ids=None) +""" + + +@mcp.resource("monarch://api-reference") +def get_api_docs() -> str: + """Returns the API documentation for using the 'api_call' tool.""" + return API_REFERENCE + + +# --- Pass-through Tool --- + + +@mcp.tool() +@retry_on_auth_error() +async def api_call(method: str, params: str = "{}") -> str: + """ + Execute a raw method call to the Monarch Money API. + + Args: + method: The method name to call (e.g., 'get_transaction_splits', 'update_transaction_splits') + params: JSON string of parameters to pass to the method + + Returns: + JSON result from the API call + + Example: + api_call(method="get_transaction_categories", params="{}") + api_call(method="get_transaction_splits", params='{"transaction_id": "12345"}') + api_call(method="update_transaction_splits", params='{"transaction_id": "12345", "split_data": [{"amount": -50.00, "categoryId": "100", "merchantName": "Groceries"}]}') + """ + client = await get_authenticated_client() + method_func = getattr(client, method, None) + if not method_func: + return serialize_json({"error": f"Method '{method}' not found"}) + try: + parsed_params = json.loads(params) if params else {} + except json.JSONDecodeError as e: + return serialize_json({"error": f"Invalid JSON in params: {e}"}) + result = await method_func(**parsed_params) + return serialize_json(result) + + # --- Health Check Endpoint ---