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.
Files changed (2) hide show
  1. package/index.js +32 -27
  2. 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().email().describe("Recipient email address"),
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().email().optional().describe("Sender email address (optional, uses default if not provided)"),
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
- `Sent: ${sent} emails\n` +
274
- `Open Rate: ${openRate}% (${uniqueOpens}/${tracked} tracked emails)\n` +
275
- `Click Rate: ${clickRate}% (${uniqueLinksClicked}/${totalTrackedLinks} tracked links)\n\n` +
276
- `${fromDate || toDate ? `Period: ${fromDate || 'start'} to ${toDate || 'now'}\n` : ''}` +
277
- `${tag ? `Tag: ${tag}\n` : ''}`
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "postmark-mcp",
3
- "version": "1.0.9",
3
+ "version": "1.0.11",
4
4
  "description": "Universal Postmark MCP server using official SDK",
5
5
  "main": "index.js",
6
6
  "bin": {