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:
@@ -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}"}
|
||||
|
||||
Reference in New Issue
Block a user