notifycx-mcp 0.0.0-stage → 1.0.0
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/README.md +35 -2
- package/dist/index.d.ts +2 -0
- package/dist/index.js +144 -0
- package/package.json +46 -4
package/README.md
CHANGED
|
@@ -1,3 +1,36 @@
|
|
|
1
|
-
#
|
|
1
|
+
# notifycx-mcp
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Official [Model Context Protocol](https://modelcontextprotocol.io) server for [Notify](https://notify.cx).
|
|
4
|
+
|
|
5
|
+
Use this in Cursor, Claude Code, or other MCP hosts when a coding agent should call Notify tools directly. For app/CI code, prefer the [`notifycx`](https://www.npmjs.com/package/notifycx) SDK or plain `fetch`.
|
|
6
|
+
|
|
7
|
+
## Install (Cursor)
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
{
|
|
11
|
+
"mcpServers": {
|
|
12
|
+
"notify": {
|
|
13
|
+
"command": "npx",
|
|
14
|
+
"args": ["-y", "notifycx-mcp"],
|
|
15
|
+
"env": {
|
|
16
|
+
"NOTIFY_API_KEY": "nk_..."
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Get your API key from [Credentials](https://notify.cx/dashboard/credentials). Docs: [notify.cx/mcp](https://notify.cx/mcp).
|
|
24
|
+
|
|
25
|
+
## Tools
|
|
26
|
+
|
|
27
|
+
| Tool | When to use |
|
|
28
|
+
|------|-------------|
|
|
29
|
+
| `send_email` | Production transactional send (verified `from`) |
|
|
30
|
+
| `send_test_email` | Non-delivering API rehearsal |
|
|
31
|
+
| `list_domains` | Domain / SPF / DKIM status |
|
|
32
|
+
| `list_email_logs` | Recent delivery logs |
|
|
33
|
+
|
|
34
|
+
## Pricing
|
|
35
|
+
|
|
36
|
+
Free: 1,000 emails/mo. Pro: **$10 / 10,000**. Scale: $50 / 100,000.
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
|
+
import Notify, { NotifyError } from "notifycx";
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
function requireApiKey() {
|
|
9
|
+
const apiKey = process.env.NOTIFY_API_KEY;
|
|
10
|
+
if (!apiKey) {
|
|
11
|
+
throw new Error(
|
|
12
|
+
"Missing NOTIFY_API_KEY. Set it in your MCP server env (dashboard \u2192 Credentials)."
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
return apiKey;
|
|
16
|
+
}
|
|
17
|
+
function client() {
|
|
18
|
+
return new Notify({
|
|
19
|
+
apiKey: requireApiKey(),
|
|
20
|
+
baseUrl: process.env.NOTIFY_BASE_URL
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
function formatError(err) {
|
|
24
|
+
if (err instanceof NotifyError) {
|
|
25
|
+
return JSON.stringify(
|
|
26
|
+
{
|
|
27
|
+
error: err.message,
|
|
28
|
+
status: err.status,
|
|
29
|
+
body: err.body,
|
|
30
|
+
hint: err.status === 401 ? "Check NOTIFY_API_KEY in MCP config" : err.message.toLowerCase().includes("domain") || err.message.toLowerCase().includes("sandbox") ? "Verify a domain (SPF/DKIM) or use send_test_email until production is unlocked" : void 0
|
|
31
|
+
},
|
|
32
|
+
null,
|
|
33
|
+
2
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
if (err instanceof Error) return err.message;
|
|
37
|
+
return String(err);
|
|
38
|
+
}
|
|
39
|
+
var sendShape = {
|
|
40
|
+
to: z.string().email().describe("Recipient email address"),
|
|
41
|
+
from: z.string().min(1).describe(
|
|
42
|
+
"Sender address or Name <email@verified-domain.com>. Production custom from requires a verified domain."
|
|
43
|
+
),
|
|
44
|
+
subject: z.string().min(1).describe("Email subject line"),
|
|
45
|
+
html: z.string().min(1).optional().describe("HTML (or plain text) body. Prefer html; message/text also work."),
|
|
46
|
+
message: z.string().min(1).optional().describe("Alias for html/body content"),
|
|
47
|
+
text: z.string().min(1).optional().describe("Alias for html/body content")
|
|
48
|
+
};
|
|
49
|
+
var server = new McpServer({
|
|
50
|
+
name: "notifycx-mcp",
|
|
51
|
+
version: "1.0.0"
|
|
52
|
+
});
|
|
53
|
+
server.tool(
|
|
54
|
+
"send_email",
|
|
55
|
+
"Send transactional email via Notify (password reset, receipt, magic link, invoice, etc.) with a verified from domain. Use when the user wants production delivery. Prefer html for the body. For non-delivering API rehearsal before domain verification, use send_test_email instead.",
|
|
56
|
+
sendShape,
|
|
57
|
+
async (args) => {
|
|
58
|
+
try {
|
|
59
|
+
const result = await client().send(args);
|
|
60
|
+
return {
|
|
61
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
62
|
+
};
|
|
63
|
+
} catch (err) {
|
|
64
|
+
return {
|
|
65
|
+
content: [{ type: "text", text: formatError(err) }],
|
|
66
|
+
isError: true
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
);
|
|
71
|
+
server.tool(
|
|
72
|
+
"send_test_email",
|
|
73
|
+
"API rehearsal for Notify: same request shape as production send but does not deliver and does not count toward quota. Use before domain verification or when testing the HTTP contract. For real inbox delivery, use send_email after verifying SPF/DKIM.",
|
|
74
|
+
sendShape,
|
|
75
|
+
async (args) => {
|
|
76
|
+
try {
|
|
77
|
+
const result = await client().sendTest(args);
|
|
78
|
+
return {
|
|
79
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
80
|
+
};
|
|
81
|
+
} catch (err) {
|
|
82
|
+
return {
|
|
83
|
+
content: [{ type: "text", text: formatError(err) }],
|
|
84
|
+
isError: true
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
);
|
|
89
|
+
server.tool(
|
|
90
|
+
"list_domains",
|
|
91
|
+
"List Notify sending domains and verification status (SPF/DKIM). Use when wiring a production from address or debugging domain auth.",
|
|
92
|
+
{},
|
|
93
|
+
async () => {
|
|
94
|
+
try {
|
|
95
|
+
const result = await client().listDomains();
|
|
96
|
+
return {
|
|
97
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
98
|
+
};
|
|
99
|
+
} catch (err) {
|
|
100
|
+
return {
|
|
101
|
+
content: [{ type: "text", text: formatError(err) }],
|
|
102
|
+
isError: true
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
);
|
|
107
|
+
server.tool(
|
|
108
|
+
"list_email_logs",
|
|
109
|
+
"List recent Notify email delivery logs. Use after a send to check delivery, bounce, open, or click status.",
|
|
110
|
+
{
|
|
111
|
+
page: z.number().int().positive().optional().describe("Page number (default 1)"),
|
|
112
|
+
limit: z.number().int().min(1).max(100).optional().describe("Page size (default 20, max 100)"),
|
|
113
|
+
eventType: z.enum([
|
|
114
|
+
"Bounce",
|
|
115
|
+
"Click",
|
|
116
|
+
"Complaint",
|
|
117
|
+
"Delivery",
|
|
118
|
+
"DeliveryDelay",
|
|
119
|
+
"Open",
|
|
120
|
+
"Send"
|
|
121
|
+
]).optional().describe("Filter logs by analytics event type")
|
|
122
|
+
},
|
|
123
|
+
async (args) => {
|
|
124
|
+
try {
|
|
125
|
+
const result = await client().listLogs(args);
|
|
126
|
+
return {
|
|
127
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
128
|
+
};
|
|
129
|
+
} catch (err) {
|
|
130
|
+
return {
|
|
131
|
+
content: [{ type: "text", text: formatError(err) }],
|
|
132
|
+
isError: true
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
);
|
|
137
|
+
async function main() {
|
|
138
|
+
const transport = new StdioServerTransport();
|
|
139
|
+
await server.connect(transport);
|
|
140
|
+
}
|
|
141
|
+
main().catch((err) => {
|
|
142
|
+
console.error(err);
|
|
143
|
+
process.exit(1);
|
|
144
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,48 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "notifycx-mcp",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Official MCP server for Notify — transactional email tools for coding agents",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"notifycx-mcp": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "./dist/index.js",
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsup",
|
|
16
|
+
"start": "node dist/index.js",
|
|
17
|
+
"prepublishOnly": "npm run build"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"notify",
|
|
21
|
+
"mcp",
|
|
22
|
+
"model-context-protocol",
|
|
23
|
+
"transactional-email",
|
|
24
|
+
"cursor",
|
|
25
|
+
"claude"
|
|
26
|
+
],
|
|
27
|
+
"homepage": "https://notify.cx/mcp",
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "https://github.com/sunil-sandhu/notifycx.git",
|
|
31
|
+
"directory": "mcp"
|
|
32
|
+
},
|
|
33
|
+
"author": "notify.cx",
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=18"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
40
|
+
"notifycx": "^1.0.0",
|
|
41
|
+
"zod": "^3.24.2"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/node": "^22.8.1",
|
|
45
|
+
"tsup": "^8.0.1",
|
|
46
|
+
"typescript": "^5.6.3"
|
|
47
|
+
}
|
|
48
|
+
}
|