postmark-mcp 1.0.0 → 1.0.1

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 (3) hide show
  1. package/.env.example +4 -4
  2. package/index.js +28 -28
  3. package/package.json +8 -20
package/.env.example CHANGED
@@ -1,4 +1,4 @@
1
- # Postmark Configuration
2
- POSTMARK_SERVER_TOKEN=your-postmark-server-token-here
3
- DEFAULT_SENDER_EMAIL=your-sender-email@example.com
4
- DEFAULT_MESSAGE_STREAM=outbound
1
+ # Secure your tokens properly! We advise not putting your tokens directly in code if it will be hosted.
2
+ POSTMARK_SERVER_TOKEN=your-postmark-server-token
3
+ DEFAULT_SENDER_EMAIL=info@example.com
4
+ DEFAULT_MESSAGE_STREAM=outbound
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,11 +122,11 @@ function registerTools(server, postmarkClient) {
122
122
  server.tool(
123
123
  "sendEmail",
124
124
  {
125
- to: z.string().email().describe("Recipient email address"),
126
- subject: z.string().describe("Email subject"),
127
- textBody: z.string().describe("Plain text body of the email"),
125
+ to: z.string().optional().describe("Recipient email address"),
126
+ subject: z.string().optional().describe("Email subject"),
127
+ textBody: z.string().optional().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)"),
129
+ from: z.string().optional().describe("Sender email address (optional)"),
130
130
  tag: z.string().optional().describe("Optional tag for categorization")
131
131
  },
132
132
  async ({ to, subject, textBody, htmlBody, from, tag }) => {
@@ -146,7 +146,7 @@ function registerTools(server, postmarkClient) {
146
146
  console.error('Sending email...', { to, subject });
147
147
  const result = await postmarkClient.sendEmail(emailData);
148
148
  console.error('Email sent successfully:', result.MessageID);
149
-
149
+
150
150
  return {
151
151
  content: [{
152
152
  type: "text",
@@ -192,10 +192,10 @@ function registerTools(server, postmarkClient) {
192
192
  console.error('Sending template email...', { to, templateId: templateId || templateAlias });
193
193
  const result = await postmarkClient.sendEmailWithTemplate(emailData);
194
194
  console.error('Template email sent successfully:', result.MessageID);
195
-
195
+
196
196
  return {
197
197
  content: [{
198
- type: "text",
198
+ type: "text",
199
199
  text: `Template email sent successfully!\nMessageID: ${result.MessageID}\nTo: ${to}\nTemplate: ${templateId || templateAlias}`
200
200
  }]
201
201
  };
@@ -210,11 +210,11 @@ function registerTools(server, postmarkClient) {
210
210
  console.error('Fetching templates...');
211
211
  const result = await postmarkClient.getTemplates();
212
212
  console.error(`Found ${result.Templates.length} templates`);
213
-
214
- const templateList = result.Templates.map(t =>
213
+
214
+ const templateList = result.Templates.map(t =>
215
215
  `• **${t.Name}**\n - ID: ${t.TemplateId}\n - Alias: ${t.Alias || 'none'}\n - Subject: ${t.Subject || 'none'}`
216
216
  ).join('\n\n');
217
-
217
+
218
218
  return {
219
219
  content: [{
220
220
  type: "text",
@@ -237,11 +237,11 @@ function registerTools(server, postmarkClient) {
237
237
  if (fromDate) query.push(`fromdate=${encodeURIComponent(fromDate)}`);
238
238
  if (toDate) query.push(`todate=${encodeURIComponent(toDate)}`);
239
239
  if (tag) query.push(`tag=${encodeURIComponent(tag)}`);
240
-
240
+
241
241
  const url = `https://api.postmarkapp.com/stats/outbound${query.length ? '?' + query.join('&') : ''}`;
242
-
242
+
243
243
  console.error('Fetching delivery stats...');
244
-
244
+
245
245
  const response = await fetch(url, {
246
246
  headers: {
247
247
  "Accept": "application/json",
@@ -255,25 +255,25 @@ function registerTools(server, postmarkClient) {
255
255
 
256
256
  const data = await response.json();
257
257
  console.error('Stats retrieved successfully');
258
-
258
+
259
259
  const sent = data.Sent || 0;
260
260
  const tracked = data.Tracked || 0;
261
261
  const uniqueOpens = data.UniqueOpens || 0;
262
262
  const totalTrackedLinks = data.TotalTrackedLinksSent || 0;
263
263
  const uniqueLinksClicked = data.UniqueLinksClicked || 0;
264
-
264
+
265
265
  const openRate = tracked > 0 ? ((uniqueOpens / tracked) * 100).toFixed(1) : '0.0';
266
266
  const clickRate = totalTrackedLinks > 0 ? ((uniqueLinksClicked / totalTrackedLinks) * 100).toFixed(1) : '0.0';
267
-
267
+
268
268
  return {
269
269
  content: [{
270
270
  type: "text",
271
271
  text: `Email Statistics Summary\n\n` +
272
- `Sent: ${sent} emails\n` +
273
- `Open Rate: ${openRate}% (${uniqueOpens}/${tracked} tracked emails)\n` +
274
- `Click Rate: ${clickRate}% (${uniqueLinksClicked}/${totalTrackedLinks} tracked links)\n\n` +
275
- `${fromDate || toDate ? `Period: ${fromDate || 'start'} to ${toDate || 'now'}\n` : ''}` +
276
- `${tag ? `Tag: ${tag}\n` : ''}`
272
+ `Sent: ${sent} emails\n` +
273
+ `Open Rate: ${openRate}% (${uniqueOpens}/${tracked} tracked emails)\n` +
274
+ `Click Rate: ${clickRate}% (${uniqueLinksClicked}/${totalTrackedLinks} tracked links)\n\n` +
275
+ `${fromDate || toDate ? `Period: ${fromDate || 'start'} to ${toDate || 'now'}\n` : ''}` +
276
+ `${tag ? `Tag: ${tag}\n` : ''}`
277
277
  }]
278
278
  };
279
279
  }
@@ -284,4 +284,4 @@ function registerTools(server, postmarkClient) {
284
284
  main().catch((error) => {
285
285
  console.error('💥 Failed to start server:', error.message);
286
286
  process.exit(1);
287
- });
287
+ });
package/package.json CHANGED
@@ -1,31 +1,19 @@
1
1
  {
2
2
  "name": "postmark-mcp",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "Universal Postmark MCP server using official SDK",
5
5
  "main": "index.js",
6
6
  "type": "module",
7
- "bin": {
8
- "postmark-mcp": "./index.js"
9
- },
10
- "files": [
11
- "index.js",
12
- "README.md",
13
- "LICENSE",
14
- ".env.example"
15
- ],
16
7
  "scripts": {
17
8
  "start": "node index.js",
18
9
  "inspector": "npx @modelcontextprotocol/inspector index.js"
19
10
  },
20
- "repository": {
21
- "type": "git",
22
- "url": "git+https://github.com/ActiveCampaign/postmark-mcp.git"
23
- },
24
- "homepage": "https://github.com/ActiveCampaign/postmark-mcp#readme",
25
- "bugs": {
26
- "url": "https://github.com/ActiveCampaign/postmark-mcp/issues"
27
- },
28
- "keywords": ["postmark", "email", "mcp", "ai", "model-context-protocol"],
11
+ "keywords": [
12
+ "postmark",
13
+ "email",
14
+ "mcp",
15
+ "ai"
16
+ ],
29
17
  "author": "Jabal Torres",
30
18
  "license": "MIT",
31
19
  "dependencies": {
@@ -35,4 +23,4 @@
35
23
  "postmark": "^4.0.5",
36
24
  "zod": "^3.23.8"
37
25
  }
38
- }
26
+ }