supersendtx-mcp 0.4.1 → 0.5.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 (2) hide show
  1. package/dist/index.js +79 -18
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -133,16 +133,21 @@ async function callMcpTool(client, name, args) {
133
133
  const from = optString(args, "from");
134
134
  const to = optString(args, "to");
135
135
  const subject = optString(args, "subject");
136
+ const templateId = optString(args, "template_id") || optString(args, "template_alias");
136
137
  if (!from) return textResult("Missing required argument: from", true);
137
138
  if (!to) return textResult("Missing required argument: to", true);
138
- if (!subject) return textResult("Missing required argument: subject", true);
139
+ if (!templateId && !subject) {
140
+ return textResult("Provide subject, or template_id / template_alias", true);
141
+ }
142
+ const variables = args.variables && typeof args.variables === "object" && !Array.isArray(args.variables) ? args.variables : void 0;
139
143
  const result = await client.emails.send({
140
144
  from,
141
145
  to,
142
- subject,
146
+ ...subject ? { subject } : {},
143
147
  html: optString(args, "html"),
144
148
  text: optString(args, "text"),
145
- reply_to: optString(args, "reply_to")
149
+ reply_to: optString(args, "reply_to"),
150
+ ...templateId ? { template: { id: templateId, ...variables ? { variables } : {} } } : {}
146
151
  });
147
152
  return textResult(result);
148
153
  }
@@ -164,9 +169,9 @@ async function callMcpTool(client, name, args) {
164
169
  return textResult("Missing required argument: domain", true);
165
170
  }
166
171
  const providerRaw = typeof args.provider === "string" ? args.provider.trim().toLowerCase() : "";
167
- if (providerRaw !== "cloudflare" && providerRaw !== "godaddy") {
172
+ if (providerRaw !== "cloudflare" && providerRaw !== "godaddy" && providerRaw !== "vercel") {
168
173
  return textResult(
169
- 'Missing or invalid provider. Use provider "cloudflare" or "godaddy".',
174
+ 'Missing or invalid provider. Use provider "cloudflare", "godaddy", or "vercel".',
170
175
  true
171
176
  );
172
177
  }
@@ -266,6 +271,28 @@ async function callMcpTool(client, name, args) {
266
271
  if (!idOrAlias) return textResult("Missing required argument: id or alias", true);
267
272
  return textResult(await client.templates.get(idOrAlias));
268
273
  }
274
+ case "create_template": {
275
+ const name2 = optString(args, "name");
276
+ const subjectArg = optString(args, "subject");
277
+ if (!name2) return textResult("Missing required argument: name", true);
278
+ if (!subjectArg) return textResult("Missing required argument: subject", true);
279
+ const format = optString(args, "format");
280
+ return textResult(
281
+ await client.templates.create({
282
+ name: name2,
283
+ subject: subjectArg,
284
+ ...format === "blocks" || format === "html" ? { format } : {},
285
+ html: optString(args, "html"),
286
+ text: optString(args, "text"),
287
+ alias: optString(args, "alias")
288
+ })
289
+ );
290
+ }
291
+ case "publish_template": {
292
+ const idOrAlias = optString(args, "id") ?? optString(args, "alias");
293
+ if (!idOrAlias) return textResult("Missing required argument: id or alias", true);
294
+ return textResult(await client.templates.publish(idOrAlias));
295
+ }
269
296
  case "send_test_webhook_event": {
270
297
  const event = optString(args, "event");
271
298
  if (!event || !EMAIL_WEBHOOK_EVENTS.has(event)) {
@@ -302,18 +329,25 @@ var paginationProps = {
302
329
  var MCP_TOOLS = [
303
330
  {
304
331
  name: "send_email",
305
- description: "Send a transactional email via SuperSend TX. Sandbox sends must use the shared sandbox from address and only deliver to the account email until a domain is verified.",
332
+ description: "Send a transactional email via SuperSend TX. Provide subject + html/text, or a published template_id / template_alias with optional variables.",
306
333
  inputSchema: {
307
334
  type: "object",
308
335
  properties: {
309
336
  from: { type: "string", description: "Sender address (must match a verified domain or sandbox sender)" },
310
337
  to: { type: "string", description: "Recipient email address" },
311
- subject: { type: "string" },
338
+ subject: { type: "string", description: "Optional when using a published template" },
312
339
  html: { type: "string" },
313
340
  text: { type: "string" },
314
- reply_to: { type: "string" }
341
+ reply_to: { type: "string" },
342
+ template_id: { type: "string", description: "Published template UUID" },
343
+ template_alias: { type: "string", description: "Published template alias" },
344
+ variables: {
345
+ type: "object",
346
+ description: "Template variables when using template_id or template_alias",
347
+ additionalProperties: true
348
+ }
315
349
  },
316
- required: ["from", "to", "subject"]
350
+ required: ["from", "to"]
317
351
  }
318
352
  },
319
353
  {
@@ -357,12 +391,12 @@ var MCP_TOOLS = [
357
391
  },
358
392
  {
359
393
  name: "apply_domain_dns",
360
- description: "Apply SuperSend TX DNS records for a domain. Cloudflare can use a token stored in the dashboard; GoDaddy accepts one-time credentials on the request.",
394
+ description: "Apply SuperSend TX DNS records for a domain. Cloudflare and GoDaddy can use credentials stored in the dashboard; GoDaddy also accepts one-time credentials on the request.",
361
395
  inputSchema: {
362
396
  type: "object",
363
397
  properties: {
364
398
  domain: { type: "string" },
365
- provider: { type: "string", enum: ["cloudflare", "godaddy"] },
399
+ provider: { type: "string", enum: ["cloudflare", "godaddy", "vercel"] },
366
400
  credentials: {
367
401
  type: "object",
368
402
  description: "Optional inline registrar credentials (GoDaddy api key/secret)"
@@ -473,6 +507,33 @@ var MCP_TOOLS = [
473
507
  }
474
508
  }
475
509
  },
510
+ {
511
+ name: "create_template",
512
+ description: "Create a draft email template (html or blocks format).",
513
+ inputSchema: {
514
+ type: "object",
515
+ properties: {
516
+ name: { type: "string" },
517
+ subject: { type: "string" },
518
+ format: { type: "string", enum: ["html", "blocks"] },
519
+ html: { type: "string" },
520
+ text: { type: "string" },
521
+ alias: { type: "string" }
522
+ },
523
+ required: ["name", "subject"]
524
+ }
525
+ },
526
+ {
527
+ name: "publish_template",
528
+ description: "Publish a template, snapshotting an immutable version for sends.",
529
+ inputSchema: {
530
+ type: "object",
531
+ properties: {
532
+ id: { type: "string" },
533
+ alias: { type: "string" }
534
+ }
535
+ }
536
+ },
476
537
  {
477
538
  name: "send_test_webhook_event",
478
539
  description: "Simulate a webhook event (POST /emails/test) for CI or local webhook testing. Optionally deliver to subscribed endpoints.",
@@ -561,14 +622,14 @@ function buildWwwAuthenticateChallenge(origin) {
561
622
  }
562
623
 
563
624
  // src/oauth-resolve.ts
564
- async function resolveOAuthAccessToken(accessToken, baseUrl) {
565
- const apiBase = (baseUrl || process.env.SUPERSENDTX_API_URL || "https://api.supersendtx.com").replace(
566
- /\/$/,
567
- ""
568
- );
625
+ function getOAuthResolveUrl() {
626
+ const appBase = (process.env.SUPERSENDTX_APP_URL?.trim() || process.env.SUPERSENDTX_OAUTH_ISSUER?.trim() || "https://app.supersendtx.com").replace(/\/$/, "");
627
+ return `${appBase}/api/mcp/oauth/resolve`;
628
+ }
629
+ async function resolveOAuthAccessToken(accessToken) {
569
630
  const resolveSecret = process.env.SUPERSENDTX_MCP_RESOLVE_SECRET?.trim() || process.env.SUPERSENDTX_CREDENTIALS_ENCRYPTION_KEY?.trim() || (process.env.NODE_ENV === "production" ? "" : "supersendtx-dev-mcp-resolve");
570
631
  if (!resolveSecret) return null;
571
- const response = await fetch(`${apiBase}/mcp/oauth/resolve`, {
632
+ const response = await fetch(getOAuthResolveUrl(), {
572
633
  method: "POST",
573
634
  headers: {
574
635
  authorization: `Bearer ${accessToken}`,
@@ -607,7 +668,7 @@ async function resolveApiKeyFromAuthorization(authorization, baseUrl) {
607
668
  const bearer = parseBearerToken(authorization);
608
669
  if (!bearer) return null;
609
670
  if (isSuperSendTxApiKey(bearer)) return bearer;
610
- return resolveOAuthAccessToken(bearer, baseUrl);
671
+ return resolveOAuthAccessToken(bearer);
611
672
  }
612
673
  async function handleHttpRequest(req, res, options = {}) {
613
674
  const origin = getRequestOrigin(req);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "supersendtx-mcp",
3
- "version": "0.4.1",
3
+ "version": "0.5.1",
4
4
  "description": "SuperSend TX MCP server — stdio or local HTTP (--http) for Cursor and Claude",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -40,7 +40,7 @@
40
40
  },
41
41
  "dependencies": {
42
42
  "@modelcontextprotocol/sdk": "^1.30.0",
43
- "supersendtx": "0.8.2"
43
+ "supersendtx": "0.11.0"
44
44
  },
45
45
  "devDependencies": {
46
46
  "tsup": "^8.5.0",