omni-notify-mcp 1.3.5 → 1.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ui/server.js +58 -17
- package/package.json +1 -1
- package/ui/public/app.js +4 -5
- package/ui/public/index.html +4 -4
package/dist/ui/server.js
CHANGED
|
@@ -28,7 +28,7 @@ function defaultConfig() {
|
|
|
28
28
|
whatsapp: { enabled: false, instanceId: "", apiToken: "", phone: "" },
|
|
29
29
|
sms: { enabled: false, accountSid: "", authToken: "", from: "", to: "" },
|
|
30
30
|
email: { enabled: false, to: "" },
|
|
31
|
-
ntfy: { enabled: false, topic: "" },
|
|
31
|
+
ntfy: { enabled: false, topic: "", serverUrl: "" },
|
|
32
32
|
discord: { enabled: false, webhookUrl: "", username: "Claude Notify" },
|
|
33
33
|
slack: { enabled: false, webhookUrl: "" },
|
|
34
34
|
teams: { enabled: false, webhookUrl: "" },
|
|
@@ -165,9 +165,8 @@ function ntfyFanout(topic, message, title, priority, tags) {
|
|
|
165
165
|
}
|
|
166
166
|
}
|
|
167
167
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
const { topic } = req.params;
|
|
168
|
+
function handleNtfySse(req, res) {
|
|
169
|
+
const topic = req.params.topic;
|
|
171
170
|
res.setHeader("Content-Type", "text/event-stream");
|
|
172
171
|
res.setHeader("Cache-Control", "no-cache");
|
|
173
172
|
res.setHeader("Connection", "keep-alive");
|
|
@@ -184,14 +183,10 @@ app.get("/ntfy/:topic/sse", (req, res) => {
|
|
|
184
183
|
catch {
|
|
185
184
|
clearInterval(keepalive);
|
|
186
185
|
} }, 30_000);
|
|
187
|
-
req.on("close", () => {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
});
|
|
192
|
-
// Also support ntfy's JSON stream endpoint
|
|
193
|
-
app.get("/ntfy/:topic/json", (req, res) => {
|
|
194
|
-
const { topic } = req.params;
|
|
186
|
+
req.on("close", () => { clearInterval(keepalive); ntfySubscribers.get(topic)?.delete(sub); });
|
|
187
|
+
}
|
|
188
|
+
function handleNtfyJson(req, res) {
|
|
189
|
+
const topic = req.params.topic;
|
|
195
190
|
res.setHeader("Content-Type", "application/x-ndjson");
|
|
196
191
|
res.setHeader("Cache-Control", "no-cache");
|
|
197
192
|
res.setHeader("Connection", "keep-alive");
|
|
@@ -208,12 +203,58 @@ app.get("/ntfy/:topic/json", (req, res) => {
|
|
|
208
203
|
clearInterval(keepalive);
|
|
209
204
|
}
|
|
210
205
|
}, 30_000);
|
|
211
|
-
req.on("close", () => {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
206
|
+
req.on("close", () => { clearInterval(keepalive); ntfySubscribers.get(topic)?.delete(sub); });
|
|
207
|
+
}
|
|
208
|
+
// ntfy app hits /:topic/sse or /:topic/json (no /ntfy/ prefix)
|
|
209
|
+
app.get("/:topic/sse", (req, res) => {
|
|
210
|
+
if (["api", "auth", "mcp", "assets", "ntfy"].includes(req.params.topic)) {
|
|
211
|
+
res.status(404).end();
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
handleNtfySse(req, res);
|
|
215
215
|
});
|
|
216
|
-
|
|
216
|
+
app.get("/:topic/json", (req, res) => {
|
|
217
|
+
if (["api", "auth", "mcp", "assets", "ntfy"].includes(req.params.topic)) {
|
|
218
|
+
res.status(404).end();
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
handleNtfyJson(req, res);
|
|
222
|
+
});
|
|
223
|
+
// Also with /ntfy/ prefix for internal use
|
|
224
|
+
app.get("/ntfy/:topic/sse", (req, res) => handleNtfySse(req, res));
|
|
225
|
+
app.get("/ntfy/:topic/json", (req, res) => handleNtfyJson(req, res));
|
|
226
|
+
// Publish endpoint — ntfy protocol POST (with and without /ntfy/ prefix)
|
|
227
|
+
app.put("/:topic", express.text({ type: "*/*" }), (req, res, next) => {
|
|
228
|
+
if (["api", "auth", "mcp", "assets", "ntfy"].includes(req.params.topic)) {
|
|
229
|
+
next();
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
handleNtfyPublish(req, res);
|
|
233
|
+
});
|
|
234
|
+
app.post("/:topic", express.text({ type: "*/*" }), (req, res, next) => {
|
|
235
|
+
if (["api", "auth", "mcp", "assets", "ntfy"].includes(req.params.topic)) {
|
|
236
|
+
next();
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
handleNtfyPublish(req, res);
|
|
240
|
+
});
|
|
241
|
+
app.get("/:topic/subscribers", (req, res) => {
|
|
242
|
+
if (["api", "auth", "mcp", "assets", "ntfy"].includes(req.params.topic)) {
|
|
243
|
+
res.status(404).end();
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
const count = ntfySubscribers.get(req.params.topic)?.size ?? 0;
|
|
247
|
+
res.json({ topic: req.params.topic, subscribers: count });
|
|
248
|
+
});
|
|
249
|
+
function handleNtfyPublish(req, res) {
|
|
250
|
+
const topic = req.params.topic;
|
|
251
|
+
const message = typeof req.body === "string" ? req.body : "";
|
|
252
|
+
const title = decodeURIComponent((req.headers["title"] || req.headers["x-title"] || "Claude Notify"));
|
|
253
|
+
const priority = parseInt((req.headers["priority"] || req.headers["x-priority"] || "3")) || 3;
|
|
254
|
+
const tags = (req.headers["tags"] || req.headers["x-tags"] || "");
|
|
255
|
+
ntfyFanout(topic, message, title, priority, tags);
|
|
256
|
+
res.json({ id: String(Date.now()), time: Math.floor(Date.now() / 1000), event: "message", topic, title, message, priority });
|
|
257
|
+
}
|
|
217
258
|
app.put("/ntfy/:topic", express.text({ type: "*/*" }), (req, res) => {
|
|
218
259
|
const { topic } = req.params;
|
|
219
260
|
const message = typeof req.body === "string" ? req.body : "";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "omni-notify-mcp",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.7",
|
|
4
4
|
"description": "An MCP server that lets AI agents (Claude, Cursor, etc.) reach you on any channel — desktop, Telegram, SMS, email — with two-way ask/reply, real-time inbox push, Do Not Disturb, idle gating, multi-session routing, and a one-page web UI for setup. Zero config code; configure once, agents call notify/ask.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
package/ui/public/app.js
CHANGED
|
@@ -82,9 +82,8 @@ function populateForm() {
|
|
|
82
82
|
const ntfy = config.ntfy ?? {};
|
|
83
83
|
$("ntfy-enabled").checked = !!ntfy.enabled;
|
|
84
84
|
$("ntfy-topic").value = ntfy.topic ?? "";
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
if (urlEl) urlEl.textContent = ntfyUrl;
|
|
85
|
+
const defaultUrl = `${location.protocol}//${location.hostname}:${location.port || (location.protocol === 'https:' ? 443 : 80)}`;
|
|
86
|
+
$("ntfy-server-url").value = ntfy.serverUrl || defaultUrl;
|
|
88
87
|
|
|
89
88
|
// Discord
|
|
90
89
|
const dc = config.discord ?? {};
|
|
@@ -360,12 +359,12 @@ async function saveSms() {
|
|
|
360
359
|
}
|
|
361
360
|
|
|
362
361
|
async function saveNtfy() {
|
|
363
|
-
await patch({ ntfy: { enabled: $("ntfy-enabled").checked, topic: $("ntfy-topic").value.trim() } });
|
|
362
|
+
await patch({ ntfy: { enabled: $("ntfy-enabled").checked, topic: $("ntfy-topic").value.trim(), serverUrl: $("ntfy-server-url").value.trim() } });
|
|
364
363
|
clearDirty("ntfy");
|
|
365
364
|
}
|
|
366
365
|
|
|
367
366
|
function copyNtfyUrl() {
|
|
368
|
-
const url =
|
|
367
|
+
const url = $("ntfy-server-url").value.trim();
|
|
369
368
|
navigator.clipboard.writeText(url).then(() => toast("Server URL copied!", "ok")).catch(() => toast("Copy failed", "error"));
|
|
370
369
|
}
|
|
371
370
|
async function saveDiscord() {
|
package/ui/public/index.html
CHANGED
|
@@ -235,12 +235,12 @@
|
|
|
235
235
|
</ol>
|
|
236
236
|
</details>
|
|
237
237
|
<div class="fg">
|
|
238
|
-
<label>
|
|
239
|
-
<div style="display:flex;gap:6px
|
|
240
|
-
<
|
|
238
|
+
<label>Server URL (for ntfy app)</label>
|
|
239
|
+
<div style="display:flex;gap:6px">
|
|
240
|
+
<input type="text" id="ntfy-server-url" placeholder="http://73.223.191.86:3737" oninput="markDirty('ntfy')" style="flex:1;font-family:monospace;font-size:12px">
|
|
241
241
|
<button class="btn btn-sm btn-ghost" onclick="copyNtfyUrl()">Copy</button>
|
|
242
242
|
</div>
|
|
243
|
-
<span class="hint">
|
|
243
|
+
<span class="hint">Paste into the ntfy app under "Use another server". Use your public IP if accessing remotely.</span>
|
|
244
244
|
</div>
|
|
245
245
|
<div class="fg"><label>Topic</label><input type="text" id="ntfy-topic" placeholder="Claude_Alerts" oninput="markDirty('ntfy')"></div>
|
|
246
246
|
</div>
|