fix: add graceful error handling for get_budgets API errors
All checks were successful
Build and Push Monarch MCP Docker Image / build (push) Successful in 16s
All checks were successful
Build and Push Monarch MCP Docker Image / build (push) Successful in 16s
Returns informative error message when Monarch Money API fails, which may occur if budgets are not configured in the account.
This commit is contained in:
@@ -9,13 +9,14 @@ Classifier: Programming Language :: Python :: 3.12
|
|||||||
Requires-Python: >=3.12
|
Requires-Python: >=3.12
|
||||||
Description-Content-Type: text/markdown
|
Description-Content-Type: text/markdown
|
||||||
Requires-Dist: mcp[cli]>=1.0.0
|
Requires-Dist: mcp[cli]>=1.0.0
|
||||||
|
Requires-Dist: fastmcp>=0.4.1
|
||||||
Requires-Dist: monarchmoney>=0.1.15
|
Requires-Dist: monarchmoney>=0.1.15
|
||||||
Requires-Dist: gql<4.0,>=3.4
|
Requires-Dist: gql<4.0,>=3.4
|
||||||
Requires-Dist: keyring>=24.0.0
|
|
||||||
Requires-Dist: python-dotenv>=1.0.0
|
Requires-Dist: python-dotenv>=1.0.0
|
||||||
Requires-Dist: pydantic>=2.0.0
|
Requires-Dist: pydantic>=2.0.0
|
||||||
Requires-Dist: starlette>=0.35.0
|
Requires-Dist: starlette>=0.35.0
|
||||||
Requires-Dist: uvicorn>=0.27.0
|
Requires-Dist: uvicorn>=0.27.0
|
||||||
|
Requires-Dist: pyotp>=2.9.0
|
||||||
|
|
||||||
# Monarch Money Custom MCP Server
|
# Monarch Money Custom MCP Server
|
||||||
|
|
||||||
@@ -49,7 +50,7 @@ docker-compose up -d
|
|||||||
|
|
||||||
## 🔌 Connection
|
## 🔌 Connection
|
||||||
The server will be available at:
|
The server will be available at:
|
||||||
- **SSE Endpoint**: `http://localhost:8000/mcp/sse`
|
- **MCP Endpoint**: `http://localhost:8000/mcp`
|
||||||
- **Health Check**: `http://localhost:8000/health`
|
- **Health Check**: `http://localhost:8000/health`
|
||||||
|
|
||||||
## 🛠️ Tools Included
|
## 🛠️ Tools Included
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
mcp[cli]>=1.0.0
|
mcp[cli]>=1.0.0
|
||||||
|
fastmcp>=0.4.1
|
||||||
monarchmoney>=0.1.15
|
monarchmoney>=0.1.15
|
||||||
gql<4.0,>=3.4
|
gql<4.0,>=3.4
|
||||||
keyring>=24.0.0
|
|
||||||
python-dotenv>=1.0.0
|
python-dotenv>=1.0.0
|
||||||
pydantic>=2.0.0
|
pydantic>=2.0.0
|
||||||
starlette>=0.35.0
|
starlette>=0.35.0
|
||||||
uvicorn>=0.27.0
|
uvicorn>=0.27.0
|
||||||
|
pyotp>=2.9.0
|
||||||
|
|||||||
Binary file not shown.
@@ -110,7 +110,21 @@ async def get_transactions(
|
|||||||
async def get_budgets(reason: Optional[str] = None) -> str:
|
async def get_budgets(reason: Optional[str] = None) -> str:
|
||||||
"""Get current budget information."""
|
"""Get current budget information."""
|
||||||
client = await get_authenticated_client()
|
client = await get_authenticated_client()
|
||||||
|
|
||||||
|
try:
|
||||||
budgets = await client.get_budgets()
|
budgets = await client.get_budgets()
|
||||||
|
except Exception as e:
|
||||||
|
error_msg = str(e)
|
||||||
|
# Check if this is a Monarch API error about budgets not being set up
|
||||||
|
if "Something went wrong" in error_msg:
|
||||||
|
return serialize_json(
|
||||||
|
{
|
||||||
|
"error": "Budget data unavailable",
|
||||||
|
"detail": "The Monarch Money API returned an error. This may occur if budgets are not configured in your account.",
|
||||||
|
"raw_error": error_msg,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
raise
|
||||||
|
|
||||||
# Build a category lookup from categoryGroups
|
# Build a category lookup from categoryGroups
|
||||||
category_lookup = {}
|
category_lookup = {}
|
||||||
|
|||||||
56
test_token.py
Executable file
56
test_token.py
Executable file
@@ -0,0 +1,56 @@
|
|||||||
|
import asyncio
|
||||||
|
import os
|
||||||
|
from monarchmoney import MonarchMoney
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
|
||||||
|
async def test_token():
|
||||||
|
load_dotenv(override=True)
|
||||||
|
|
||||||
|
token = os.getenv("MONARCH_TOKEN")
|
||||||
|
|
||||||
|
email = os.getenv("MONARCH_EMAIL")
|
||||||
|
|
||||||
|
password = os.getenv("MONARCH_PASSWORD")
|
||||||
|
|
||||||
|
if token and token.strip():
|
||||||
|
# Strip potential prefix
|
||||||
|
|
||||||
|
if token.startswith("MONARCH_TOKEN="):
|
||||||
|
token = token.replace("MONARCH_TOKEN=", "")
|
||||||
|
|
||||||
|
print(f"Testing with TOKEN: {token[:10]}...")
|
||||||
|
|
||||||
|
mm = MonarchMoney(token=token)
|
||||||
|
|
||||||
|
elif email and password:
|
||||||
|
print(f"Testing with EMAIL: {email}")
|
||||||
|
|
||||||
|
mm = MonarchMoney()
|
||||||
|
|
||||||
|
try:
|
||||||
|
await mm.login(email, password)
|
||||||
|
|
||||||
|
print("✅ Login successful with email/password!")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Login failed: {e}")
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
else:
|
||||||
|
print("❌ No credentials found in .env")
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
accounts = await mm.get_accounts()
|
||||||
|
|
||||||
|
print(f"Success! Found {len(accounts.get('accounts', []))} accounts.")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error fetching accounts: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(test_token())
|
||||||
11
uv.lock
generated
11
uv.lock
generated
@@ -913,6 +913,7 @@ dependencies = [
|
|||||||
{ name = "mcp", extra = ["cli"] },
|
{ name = "mcp", extra = ["cli"] },
|
||||||
{ name = "monarchmoney" },
|
{ name = "monarchmoney" },
|
||||||
{ name = "pydantic" },
|
{ name = "pydantic" },
|
||||||
|
{ name = "pyotp" },
|
||||||
{ name = "python-dotenv" },
|
{ name = "python-dotenv" },
|
||||||
{ name = "starlette" },
|
{ name = "starlette" },
|
||||||
{ name = "uvicorn" },
|
{ name = "uvicorn" },
|
||||||
@@ -925,6 +926,7 @@ requires-dist = [
|
|||||||
{ name = "mcp", extras = ["cli"], specifier = ">=1.0.0" },
|
{ name = "mcp", extras = ["cli"], specifier = ">=1.0.0" },
|
||||||
{ name = "monarchmoney", specifier = ">=0.1.15" },
|
{ name = "monarchmoney", specifier = ">=0.1.15" },
|
||||||
{ name = "pydantic", specifier = ">=2.0.0" },
|
{ name = "pydantic", specifier = ">=2.0.0" },
|
||||||
|
{ name = "pyotp", specifier = ">=2.9.0" },
|
||||||
{ name = "python-dotenv", specifier = ">=1.0.0" },
|
{ name = "python-dotenv", specifier = ">=1.0.0" },
|
||||||
{ name = "starlette", specifier = ">=0.35.0" },
|
{ name = "starlette", specifier = ">=0.35.0" },
|
||||||
{ name = "uvicorn", specifier = ">=0.27.0" },
|
{ name = "uvicorn", specifier = ">=0.27.0" },
|
||||||
@@ -1485,6 +1487,15 @@ crypto = [
|
|||||||
{ name = "cryptography" },
|
{ name = "cryptography" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pyotp"
|
||||||
|
version = "2.9.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/f3/b2/1d5994ba2acde054a443bd5e2d384175449c7d2b6d1a0614dbca3a63abfc/pyotp-2.9.0.tar.gz", hash = "sha256:346b6642e0dbdde3b4ff5a930b664ca82abfa116356ed48cc42c7d6590d36f63", size = 17763, upload-time = "2023-07-27T23:41:03.295Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c3/c0/c33c8792c3e50193ef55adb95c1c3c2786fe281123291c2dbf0eaab95a6f/pyotp-2.9.0-py3-none-any.whl", hash = "sha256:81c2e5865b8ac55e825b0358e496e1d9387c811e85bb40e71a3b29b288963612", size = 13376, upload-time = "2023-07-27T23:41:01.685Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pyperclip"
|
name = "pyperclip"
|
||||||
version = "1.11.0"
|
version = "1.11.0"
|
||||||
|
|||||||
Reference in New Issue
Block a user