postmark-mcp 1.0.9 → 1.0.11
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/index.js +32 -27
- package/package.json +1 -1
package/index.js
CHANGED
@@ -50,10 +50,10 @@ async function initializeServices() {
|
|
50
50
|
|
51
51
|
// Initialize Postmark client
|
52
52
|
const client = new postmark.ServerClient(serverToken);
|
53
|
-
|
53
|
+
|
54
54
|
// Verify Postmark client by making a test API call
|
55
55
|
await client.getServer();
|
56
|
-
|
56
|
+
|
57
57
|
// Create MCP server
|
58
58
|
const mcpServer = new McpServer({
|
59
59
|
name: "postmark-mcp",
|
@@ -73,16 +73,16 @@ async function initializeServices() {
|
|
73
73
|
async function main() {
|
74
74
|
try {
|
75
75
|
const { postmarkClient, mcpServer: server } = await initializeServices();
|
76
|
-
|
76
|
+
|
77
77
|
// Register tools with validated client
|
78
78
|
registerTools(server, postmarkClient);
|
79
|
-
|
79
|
+
|
80
80
|
console.error('Connecting to MCP transport...');
|
81
81
|
const transport = new StdioServerTransport();
|
82
82
|
await server.connect(transport);
|
83
|
-
|
83
|
+
|
84
84
|
console.error('Postmark MCP server is running and ready!');
|
85
|
-
|
85
|
+
|
86
86
|
// Setup graceful shutdown
|
87
87
|
process.on('SIGTERM', () => handleShutdown(server));
|
88
88
|
process.on('SIGINT', () => handleShutdown(server));
|
@@ -122,19 +122,25 @@ function registerTools(server, postmarkClient) {
|
|
122
122
|
server.tool(
|
123
123
|
"sendEmail",
|
124
124
|
{
|
125
|
-
to: z.string().
|
125
|
+
to: z.string().describe("Recipient email address"),
|
126
126
|
subject: z.string().describe("Email subject"),
|
127
127
|
textBody: z.string().describe("Plain text body of the email"),
|
128
128
|
htmlBody: z.string().optional().describe("HTML body of the email (optional)"),
|
129
|
-
from: z.string().
|
130
|
-
tag: z.string().optional().describe("Optional tag for categorization")
|
129
|
+
from: z.string().optional().describe("Sender email address (optional, uses default if not provided)"),
|
130
|
+
tag: z.string().optional().describe("Optional tag for categorization"),
|
131
|
+
inReplyTo: z.string().optional().describe("Message ID this email is in reply to (optional)")
|
131
132
|
},
|
132
133
|
async ({ to, subject, textBody, htmlBody, from, tag }) => {
|
134
|
+
const headers = [
|
135
|
+
{ "Name": "In-Reply-To", "Value": inReplyTo },
|
136
|
+
{ "Name": "References", "Value": inReplyTo }
|
137
|
+
];
|
133
138
|
const emailData = {
|
134
139
|
From: from || defaultSender,
|
135
140
|
To: to,
|
136
141
|
Subject: subject,
|
137
142
|
TextBody: textBody,
|
143
|
+
Headers: inReplyTo ? headers : undefined,
|
138
144
|
MessageStream: defaultMessageStream,
|
139
145
|
TrackOpens: true,
|
140
146
|
TrackLinks: "HtmlAndText"
|
@@ -146,7 +152,7 @@ function registerTools(server, postmarkClient) {
|
|
146
152
|
console.error('Sending email...', { to, subject });
|
147
153
|
const result = await postmarkClient.sendEmail(emailData);
|
148
154
|
console.error('Email sent successfully:', result.MessageID);
|
149
|
-
|
155
|
+
|
150
156
|
return {
|
151
157
|
content: [{
|
152
158
|
type: "text",
|
@@ -192,10 +198,10 @@ function registerTools(server, postmarkClient) {
|
|
192
198
|
console.error('Sending template email...', { to, templateId: templateId || templateAlias });
|
193
199
|
const result = await postmarkClient.sendEmailWithTemplate(emailData);
|
194
200
|
console.error('Template email sent successfully:', result.MessageID);
|
195
|
-
|
201
|
+
|
196
202
|
return {
|
197
203
|
content: [{
|
198
|
-
type: "text",
|
204
|
+
type: "text",
|
199
205
|
text: `Template email sent successfully!\nMessageID: ${result.MessageID}\nTo: ${to}\nTemplate: ${templateId || templateAlias}`
|
200
206
|
}]
|
201
207
|
};
|
@@ -210,11 +216,11 @@ function registerTools(server, postmarkClient) {
|
|
210
216
|
console.error('Fetching templates...');
|
211
217
|
const result = await postmarkClient.getTemplates();
|
212
218
|
console.error(`Found ${result.Templates.length} templates`);
|
213
|
-
|
214
|
-
const templateList = result.Templates.map(t =>
|
219
|
+
|
220
|
+
const templateList = result.Templates.map(t =>
|
215
221
|
`• **${t.Name}**\n - ID: ${t.TemplateId}\n - Alias: ${t.Alias || 'none'}\n - Subject: ${t.Subject || 'none'}`
|
216
222
|
).join('\n\n');
|
217
|
-
|
223
|
+
|
218
224
|
return {
|
219
225
|
content: [{
|
220
226
|
type: "text",
|
@@ -231,18 +237,17 @@ function registerTools(server, postmarkClient) {
|
|
231
237
|
tag: z.string().optional().describe("Filter by tag (optional)"),
|
232
238
|
fromDate: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional().describe("Start date in YYYY-MM-DD format (optional)"),
|
233
239
|
toDate: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional().describe("End date in YYYY-MM-DD format (optional)"),
|
234
|
-
foo: z.string().optional().describe("Just a test parameter")
|
235
240
|
},
|
236
241
|
async ({ tag, fromDate, toDate }) => {
|
237
242
|
const query = [];
|
238
243
|
if (fromDate) query.push(`fromdate=${encodeURIComponent(fromDate)}`);
|
239
244
|
if (toDate) query.push(`todate=${encodeURIComponent(toDate)}`);
|
240
245
|
if (tag) query.push(`tag=${encodeURIComponent(tag)}`);
|
241
|
-
|
246
|
+
|
242
247
|
const url = `https://api.postmarkapp.com/stats/outbound${query.length ? '?' + query.join('&') : ''}`;
|
243
|
-
|
248
|
+
|
244
249
|
console.error('Fetching delivery stats...');
|
245
|
-
|
250
|
+
|
246
251
|
const response = await fetch(url, {
|
247
252
|
headers: {
|
248
253
|
"Accept": "application/json",
|
@@ -256,25 +261,25 @@ function registerTools(server, postmarkClient) {
|
|
256
261
|
|
257
262
|
const data = await response.json();
|
258
263
|
console.error('Stats retrieved successfully');
|
259
|
-
|
264
|
+
|
260
265
|
const sent = data.Sent || 0;
|
261
266
|
const tracked = data.Tracked || 0;
|
262
267
|
const uniqueOpens = data.UniqueOpens || 0;
|
263
268
|
const totalTrackedLinks = data.TotalTrackedLinksSent || 0;
|
264
269
|
const uniqueLinksClicked = data.UniqueLinksClicked || 0;
|
265
|
-
|
270
|
+
|
266
271
|
const openRate = tracked > 0 ? ((uniqueOpens / tracked) * 100).toFixed(1) : '0.0';
|
267
272
|
const clickRate = totalTrackedLinks > 0 ? ((uniqueLinksClicked / totalTrackedLinks) * 100).toFixed(1) : '0.0';
|
268
|
-
|
273
|
+
|
269
274
|
return {
|
270
275
|
content: [{
|
271
276
|
type: "text",
|
272
277
|
text: `Email Statistics Summary\n\n` +
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
+
`Sent: ${sent} emails\n` +
|
279
|
+
`Open Rate: ${openRate}% (${uniqueOpens}/${tracked} tracked emails)\n` +
|
280
|
+
`Click Rate: ${clickRate}% (${uniqueLinksClicked}/${totalTrackedLinks} tracked links)\n\n` +
|
281
|
+
`${fromDate || toDate ? `Period: ${fromDate || 'start'} to ${toDate || 'now'}\n` : ''}` +
|
282
|
+
`${tag ? `Tag: ${tag}\n` : ''}`
|
278
283
|
}]
|
279
284
|
};
|
280
285
|
}
|