omni-notify-mcp 1.1.6 → 1.1.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/assets/screenshots/main-ui.png +0 -0
- package/dist/ui/server.js +45 -0
- package/package.json +1 -1
- package/ui/public/app.js +9 -6
- package/ui/public/index.html +3 -2
- package/ui/public/style.css +28 -6
|
Binary file
|
package/dist/ui/server.js
CHANGED
|
@@ -970,6 +970,51 @@ BEHAVIORAL RULES for every client that connects:
|
|
|
970
970
|
6. The 'get_idle_*' and 'get_dnd_status' tools are informational. You can
|
|
971
971
|
inspect them if you want to explain a delivery decision, but they are NOT
|
|
972
972
|
required pre-flights — the server gates server-side.
|
|
973
|
+
|
|
974
|
+
7. If your tool call fails with "MCP server not connected" / "transport
|
|
975
|
+
closed" / similar — the SERVER IS ALMOST CERTAINLY FINE. Other clients are
|
|
976
|
+
connected to the same server right now. Only YOUR client's transport
|
|
977
|
+
broke (commonly: stdio child process died, or HTTP client gave up after a
|
|
978
|
+
transient slow response at startup). DO NOT tell the user "notify is down"
|
|
979
|
+
without first probing the server directly.
|
|
980
|
+
|
|
981
|
+
Probe before declaring the server dead:
|
|
982
|
+
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:3737/mcp
|
|
983
|
+
- 406 (Not Acceptable) = server is healthy, doing MCP protocol
|
|
984
|
+
negotiation. Your client is the broken party. Use the bypass below.
|
|
985
|
+
- Connection refused / timeout = server is genuinely down. Tell the user.
|
|
986
|
+
|
|
987
|
+
HTTP-transport bypass when your MCP client is broken (works from any
|
|
988
|
+
shell that has curl). Three calls, stateful — the session id from step 1
|
|
989
|
+
must be passed in mcp-session-id on every subsequent call:
|
|
990
|
+
|
|
991
|
+
# 1) initialize and capture session id from response headers
|
|
992
|
+
SID=$(curl -s -i -X POST http://localhost:3737/mcp \
|
|
993
|
+
-H "Content-Type: application/json" \
|
|
994
|
+
-H "Accept: application/json, text/event-stream" \
|
|
995
|
+
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"curl-bridge","version":"1.0"}}}' \
|
|
996
|
+
| grep -i "^mcp-session-id:" | awk '{print $2}' | tr -d '\r')
|
|
997
|
+
|
|
998
|
+
# 2) ack initialized (no response body, fire-and-forget)
|
|
999
|
+
curl -s -X POST http://localhost:3737/mcp \
|
|
1000
|
+
-H "Content-Type: application/json" \
|
|
1001
|
+
-H "Accept: application/json, text/event-stream" \
|
|
1002
|
+
-H "mcp-session-id: $SID" \
|
|
1003
|
+
-d '{"jsonrpc":"2.0","method":"notifications/initialized"}' >/dev/null
|
|
1004
|
+
|
|
1005
|
+
# 3) call any tool — successful response includes "Sent via: <channel>"
|
|
1006
|
+
curl -s -X POST http://localhost:3737/mcp \
|
|
1007
|
+
-H "Content-Type: application/json" \
|
|
1008
|
+
-H "Accept: application/json, text/event-stream" \
|
|
1009
|
+
-H "mcp-session-id: $SID" \
|
|
1010
|
+
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"notify","arguments":{"message":"YOUR MESSAGE","priority":"normal"}}}'
|
|
1011
|
+
|
|
1012
|
+
Same pattern works for 'ask', 'poll', 'get_idle_seconds', etc. — change
|
|
1013
|
+
the "name" and "arguments" in step 3. Reuse the same $SID for all calls
|
|
1014
|
+
in one bypass session.
|
|
1015
|
+
|
|
1016
|
+
Bottom line: rule #1 still applies. If you owe the user a notify and your
|
|
1017
|
+
MCP client is broken, you owe them the bypass — not an excuse.
|
|
973
1018
|
`.trim();
|
|
974
1019
|
function createMcpServer(clientId, sessionTag) {
|
|
975
1020
|
const server = new McpServer({ name: "notify-mcp", version: "1.0.0" }, { instructions: MCP_INSTRUCTIONS });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "omni-notify-mcp",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.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
|
@@ -117,14 +117,16 @@ function updateBadges() {
|
|
|
117
117
|
email.connectedEmail ? "Connected" : email.clientId ? "Credentials saved" : "Not configured");
|
|
118
118
|
|
|
119
119
|
const tg = config.telegram ?? {};
|
|
120
|
+
const tgReady = tg.token && tg.chatId;
|
|
120
121
|
setBadge("telegram",
|
|
121
|
-
tg.enabled &&
|
|
122
|
-
tg.enabled &&
|
|
122
|
+
tg.enabled && tgReady ? "ok" : tgReady ? "warn" : tg.token ? "warn" : "idle",
|
|
123
|
+
tg.enabled && tgReady ? "Configured" : tgReady ? "Disabled" : tg.token ? "Incomplete" : "Not configured");
|
|
123
124
|
|
|
124
|
-
const sms = config.sms ?? {};
|
|
125
|
+
const sms = config.sms ?? {};
|
|
126
|
+
const smsReady = sms.accountSid && sms.authToken;
|
|
125
127
|
setBadge("sms",
|
|
126
|
-
sms.enabled &&
|
|
127
|
-
sms.enabled &&
|
|
128
|
+
sms.enabled && smsReady ? "ok" : smsReady ? "warn" : sms.accountSid ? "warn" : "idle",
|
|
129
|
+
sms.enabled && smsReady ? "Configured" : smsReady ? "Disabled" : sms.accountSid ? "Incomplete" : "Not configured");
|
|
128
130
|
|
|
129
131
|
// DND badge: "Active" (red), "Scheduled" (warn), or "Off" (idle)
|
|
130
132
|
const dnd = config.dnd ?? {};
|
|
@@ -187,7 +189,8 @@ async function loadVoices() {
|
|
|
187
189
|
for (const v of byLocale[locale].sort((a, b) => a.shortName.localeCompare(b.shortName))) {
|
|
188
190
|
const opt = document.createElement("option");
|
|
189
191
|
opt.value = v.shortName;
|
|
190
|
-
|
|
192
|
+
const name = v.shortName.replace(locale + "-", "").replace(/Neural$/, "").replace(/Multilingual$/, " (Multi)");
|
|
193
|
+
opt.textContent = `${name} · ${v.gender}`;
|
|
191
194
|
if (v.shortName === current) opt.selected = true;
|
|
192
195
|
og.appendChild(opt);
|
|
193
196
|
}
|
package/ui/public/index.html
CHANGED
|
@@ -63,8 +63,9 @@
|
|
|
63
63
|
<span class="toggle-lbl">Speak notification</span>
|
|
64
64
|
<button class="btn btn-sm btn-ghost" onclick="testTts()">Test voice</button>
|
|
65
65
|
</div>
|
|
66
|
-
<div id="tts-voice-row" class="
|
|
67
|
-
<
|
|
66
|
+
<div id="tts-voice-row" class="fg" style="margin-top:8px; display:none">
|
|
67
|
+
<label>Voice</label>
|
|
68
|
+
<select id="desktop-tts-voice" onchange="saveDesktop()"></select>
|
|
68
69
|
</div>
|
|
69
70
|
<span id="os-hint" class="os-tag hidden"></span>
|
|
70
71
|
</div>
|
package/ui/public/style.css
CHANGED
|
@@ -102,11 +102,11 @@ main {
|
|
|
102
102
|
flex: 1;
|
|
103
103
|
min-height: 0;
|
|
104
104
|
height: 100%;
|
|
105
|
-
overflow:
|
|
106
|
-
display:
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
align-content:
|
|
105
|
+
overflow: auto;
|
|
106
|
+
display: grid;
|
|
107
|
+
grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
|
|
108
|
+
grid-auto-rows: min-content;
|
|
109
|
+
align-content: start;
|
|
110
110
|
gap: 12px;
|
|
111
111
|
}
|
|
112
112
|
|
|
@@ -207,8 +207,9 @@ main {
|
|
|
207
207
|
/* ── Cards ───────────────────────────────────────────────────────────────── */
|
|
208
208
|
|
|
209
209
|
.card {
|
|
210
|
-
width:
|
|
210
|
+
width: auto;
|
|
211
211
|
max-width: 100%;
|
|
212
|
+
min-width: 0;
|
|
212
213
|
background: var(--surface);
|
|
213
214
|
border: 2px solid #4a4a5a;
|
|
214
215
|
border-radius: var(--r);
|
|
@@ -362,6 +363,27 @@ input[type="time"] {
|
|
|
362
363
|
box-shadow: inset 0 1px 0 rgba(255,255,255,0.08);
|
|
363
364
|
}
|
|
364
365
|
input::placeholder { color: #cdcdda; opacity: 1; }
|
|
366
|
+
|
|
367
|
+
select {
|
|
368
|
+
width: 100%;
|
|
369
|
+
max-width: 100%;
|
|
370
|
+
box-sizing: border-box;
|
|
371
|
+
padding: 8px 11px;
|
|
372
|
+
border: 2px solid #7a7a95;
|
|
373
|
+
border-radius: 7px;
|
|
374
|
+
font-size: 14px;
|
|
375
|
+
font-weight: 500;
|
|
376
|
+
color: #ffffff;
|
|
377
|
+
background: #55556a;
|
|
378
|
+
outline: none;
|
|
379
|
+
transition: border-color .15s, box-shadow .15s;
|
|
380
|
+
color-scheme: dark;
|
|
381
|
+
box-shadow: inset 0 1px 0 rgba(255,255,255,0.08);
|
|
382
|
+
cursor: pointer;
|
|
383
|
+
text-overflow: ellipsis;
|
|
384
|
+
}
|
|
385
|
+
select:hover { border-color: #9a9ab5; }
|
|
386
|
+
select:focus { border-color: var(--accent); box-shadow: 0 0 0 2px rgba(124,109,250,.15); }
|
|
365
387
|
input[type="text"]:hover,
|
|
366
388
|
input[type="email"]:hover,
|
|
367
389
|
input[type="tel"]:hover,
|