feat: add automatic re-authentication with MFA support
All checks were successful
Build and Push Monarch MCP Docker Image / build (push) Successful in 8s
All checks were successful
Build and Push Monarch MCP Docker Image / build (push) Successful in 8s
Implement automatic token refresh using stored credentials and TOTP MFA secret. When an API call fails with a 401/unauthorized error, the system now transparently re-authenticates using MONARCH_EMAIL, MONARCH_PASSWORD, and MONARCH_MFA_SECRET, then retries the original request. Changes: - Add refresh_authentication() function in auth.py for credential-based login - Create @retry_on_auth_error decorator to handle and retry failed auth calls - Apply decorator to all MCP tools (get_accounts, get_transactions, etc.) - Add MONARCH_MFA_SECRET to .env.example with documentation - Update login_setup.py to instruct users about required env vars - Replace PROBLEM.md with PLAN.md documenting the implementation
This commit is contained in:
@@ -2,7 +2,6 @@
|
||||
Monarch Money MCP Server - Custom SSE Implementation.
|
||||
"""
|
||||
|
||||
import os
|
||||
import logging
|
||||
import json
|
||||
from typing import Optional, Any
|
||||
@@ -13,7 +12,7 @@ from starlette.applications import Starlette
|
||||
from starlette.responses import JSONResponse
|
||||
from starlette.routing import Route, Mount
|
||||
|
||||
from monarch_mcp_custom.auth import get_authenticated_client
|
||||
from monarch_mcp_custom.auth import get_authenticated_client, retry_on_auth_error
|
||||
|
||||
# Load environment variables
|
||||
load_dotenv()
|
||||
@@ -39,6 +38,7 @@ def serialize_json(data: Any) -> str:
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
@retry_on_auth_error()
|
||||
async def get_accounts(reason: Optional[str] = None) -> str:
|
||||
"""Get all financial accounts from Monarch Money."""
|
||||
try:
|
||||
@@ -64,6 +64,7 @@ async def get_accounts(reason: Optional[str] = None) -> str:
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
@retry_on_auth_error()
|
||||
async def get_transactions(
|
||||
limit: int = 50,
|
||||
offset: int = 0,
|
||||
@@ -112,6 +113,7 @@ async def get_transactions(
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
@retry_on_auth_error()
|
||||
async def get_budgets(reason: Optional[str] = None) -> str:
|
||||
"""Get current budget information."""
|
||||
try:
|
||||
@@ -137,6 +139,7 @@ async def get_budgets(reason: Optional[str] = None) -> str:
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
@retry_on_auth_error()
|
||||
async def get_account_holdings(account_id: str, reason: Optional[str] = None) -> str:
|
||||
"""Get investment holdings for a specific account."""
|
||||
try:
|
||||
@@ -150,6 +153,7 @@ async def get_account_holdings(account_id: str, reason: Optional[str] = None) ->
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
@retry_on_auth_error()
|
||||
async def refresh_accounts(reason: Optional[str] = None) -> str:
|
||||
"""Request a refresh of account data from financial institutions."""
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user