feat(pushover): add cancel receipt, glance update, and limits tools

Add pushover_cancel_receipt for stopping emergency retries,
pushover_send_glance for widget data updates, and
pushover_get_limits for checking message usage.
This commit is contained in:
Timothy
2026-03-09 16:41:52 -07:00
parent 1c75100f59
commit 7b78f6c12f
@@ -225,3 +225,145 @@ def register_tools(
}
except Exception as e:
return {"error": f"Receipt check failed: {e!s}"}
@mcp.tool()
def pushover_cancel_receipt(
receipt: str,
) -> dict[str, Any]:
"""
Cancel emergency-priority notification retries for a receipt.
Stops Pushover from continuing to retry delivery of an emergency
notification before it expires or is acknowledged.
Args:
receipt: Receipt ID from an emergency-priority pushover_send response
Returns:
Dict with cancellation status
"""
token = _get_token(credentials)
if not token:
return _auth_error()
if not receipt:
return {"error": "receipt is required"}
try:
resp = httpx.post(
f"{PUSHOVER_API}/receipts/{receipt}/cancel.json",
data={"token": token},
timeout=30.0,
)
result = resp.json()
if result.get("status") != 1:
return {"error": f"Cancel failed: {resp.text[:300]}"}
return {"status": "cancelled", "receipt": receipt}
except httpx.TimeoutException:
return {"error": "Cancel request timed out"}
except Exception as e:
return {"error": f"Cancel failed: {e!s}"}
@mcp.tool()
def pushover_send_glance(
user_key: str,
title: str = "",
text: str = "",
subtext: str = "",
count: int | None = None,
percent: int | None = None,
device: str = "",
) -> dict[str, Any]:
"""
Update Pushover Glance data on a user's device widget.
Glances display small data updates on smartwatch/widget screens
without triggering a full notification.
Args:
user_key: Pushover user key
title: Glance title (max 100 chars)
text: Primary glance text (max 100 chars)
subtext: Secondary text line (max 100 chars)
count: Numeric count to display (-999 to 999)
percent: Percentage value (0-100)
device: Target device name (optional)
Returns:
Dict with glance update status
"""
token = _get_token(credentials)
if not token:
return _auth_error()
if not user_key:
return {"error": "user_key is required"}
if not any([title, text, subtext, count is not None, percent is not None]):
return {"error": "At least one of title, text, subtext, count, or percent is required"}
data: dict[str, Any] = {
"token": token,
"user": user_key,
}
if title:
data["title"] = title[:100]
if text:
data["text"] = text[:100]
if subtext:
data["subtext"] = subtext[:100]
if count is not None:
data["count"] = max(-999, min(count, 999))
if percent is not None:
data["percent"] = max(0, min(percent, 100))
if device:
data["device"] = device
try:
resp = httpx.post(
f"{PUSHOVER_API}/glances.json",
data=data,
timeout=30.0,
)
result = resp.json()
if result.get("status") != 1:
errors = result.get("errors", [])
return {
"error": f"Glance error: {', '.join(errors) if errors else resp.text[:300]}"
}
return {"status": "updated", "request": result.get("request", "")}
except httpx.TimeoutException:
return {"error": "Glance request timed out"}
except Exception as e:
return {"error": f"Glance update failed: {e!s}"}
@mcp.tool()
def pushover_get_limits() -> dict[str, Any]:
"""
Get Pushover application message limits and usage.
Returns the app's monthly message limit, number of messages sent
this month, and the reset timestamp.
Returns:
Dict with limit, remaining, and reset timestamp
"""
token = _get_token(credentials)
if not token:
return _auth_error()
try:
resp = httpx.get(
f"{PUSHOVER_API}/apps/limits.json",
params={"token": token},
timeout=30.0,
)
result = resp.json()
if result.get("status") != 1:
return {"error": f"Limits check failed: {resp.text[:300]}"}
return {
"limit": result.get("limit", 0),
"remaining": result.get("remaining", 0),
"reset": result.get("reset", 0),
}
except httpx.TimeoutException:
return {"error": "Limits request timed out"}
except Exception as e:
return {"error": f"Limits check failed: {e!s}"}