arcticaurora commited on
Commit
2c266ba
·
verified ·
1 Parent(s): c91b4f8

Create notification.py

Browse files
Files changed (1) hide show
  1. tools/notification.py +87 -0
tools/notification.py ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from mcp.server.fastmcp import FastMCP
2
+ import requests
3
+ from typing import Optional, List, Union
4
+ import re
5
+
6
+ mcp = FastMCP("Notifications")
7
+
8
+ @mcp.tool()
9
+ def send_notification(
10
+ topic: str,
11
+ message: str,
12
+ title: Optional[str] = None,
13
+ priority: Optional[str] = None,
14
+ tags: Optional[Union[List[str], str]] = None,
15
+ click_url: Optional[str] = None,
16
+ attach_url: Optional[str] = None,
17
+ delay: Optional[str] = None
18
+ ) -> str:
19
+ """Send notification via ntfy.sh.
20
+
21
+ Args:
22
+ topic: Topic name (letters, numbers, dashes, underscores only)
23
+ message: Message body (supports markdown)
24
+ title: Optional title
25
+ priority: "min", "low", "default", "high", "urgent"
26
+ tags: Emoji shortcodes as list or comma-separated (e.g. "warning,fire" or ["bell","calendar"])
27
+ click_url: URL to open on click
28
+ attach_url: Image/file URL to attach
29
+ delay: Delay like "10s", "5m", "2h"
30
+
31
+ Returns:
32
+ Success or error message
33
+ """
34
+ # Validate topic name
35
+ if not re.match(r'^[a-zA-Z0-9_-]+$', topic):
36
+ return "❌ Invalid topic: use only letters, numbers, dashes, underscores"
37
+
38
+ url = f"https://ntfy.sh/{topic}"
39
+
40
+ headers = {"Content-Type": "text/plain; charset=utf-8"}
41
+
42
+ if title:
43
+ headers["Title"] = title
44
+
45
+ if priority:
46
+ if priority not in ["min", "low", "default", "high", "urgent"]:
47
+ return f"❌ Invalid priority: {priority}"
48
+ headers["Priority"] = priority
49
+
50
+ if tags:
51
+ # Handle both string and list inputs
52
+ if isinstance(tags, str):
53
+ tags = [t.strip() for t in tags.split(",")]
54
+ headers["Tags"] = ",".join(tags)
55
+
56
+ if click_url:
57
+ headers["Click"] = click_url
58
+
59
+ if attach_url:
60
+ headers["Attach"] = attach_url
61
+
62
+ if delay:
63
+ headers["Delay"] = delay
64
+
65
+ try:
66
+ response = requests.post(url, data=message.encode('utf-8'), headers=headers, timeout=10)
67
+ response.raise_for_status()
68
+
69
+ result = f"✅ Sent to '{topic}'"
70
+ if delay:
71
+ result += f" (delayed by {delay})"
72
+ return result
73
+
74
+ except requests.exceptions.HTTPError as e:
75
+ status = e.response.status_code
76
+ if status == 400:
77
+ return "❌ Bad request: check message format"
78
+ elif status == 429:
79
+ return "❌ Rate limited: too many requests"
80
+ elif status == 507:
81
+ return "❌ Storage full: message too large"
82
+ return f"❌ HTTP error: {status}"
83
+ except Exception as e:
84
+ return f"❌ Error: {str(e)}"
85
+
86
+ if __name__ == "__main__":
87
+ mcp.run()