@sendly/mcp 2.2.0 → 2.3.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 +2 -2
- package/dist/index.js +81 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @sendly/mcp
|
|
2
2
|
|
|
3
|
-
Full SMS platform for AI agents —
|
|
3
|
+
Full SMS platform for AI agents — 85 tools for messaging, contacts, campaigns, templates, webhooks, OTP verification, conversations, labels, drafts, and more via [Model Context Protocol](https://modelcontextprotocol.io).
|
|
4
4
|
|
|
5
5
|
## Quick Setup
|
|
6
6
|
|
|
@@ -241,7 +241,7 @@ With test keys, use magic numbers:
|
|
|
241
241
|
|
|
242
242
|
## Links
|
|
243
243
|
|
|
244
|
-
- [MCP Tools Reference](https://sendly.live/docs/ai/mcp-tools) — all
|
|
244
|
+
- [MCP Tools Reference](https://sendly.live/docs/ai/mcp-tools) — all 85 tools with schemas
|
|
245
245
|
- [Agent Skills](https://sendly.live/skills) — SKILL.md files for 8 platforms
|
|
246
246
|
- [API Reference](https://sendly.live/docs/api)
|
|
247
247
|
- [Sendly Dashboard](https://sendly.live/dashboard)
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
5
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
|
+
import { readFileSync } from "fs";
|
|
7
|
+
import { dirname, resolve } from "path";
|
|
8
|
+
import { fileURLToPath } from "url";
|
|
6
9
|
|
|
7
10
|
// src/tools.ts
|
|
8
11
|
import { z } from "zod";
|
|
@@ -1238,6 +1241,78 @@ function registerAllTools(server2, api2) {
|
|
|
1238
1241
|
}
|
|
1239
1242
|
}
|
|
1240
1243
|
);
|
|
1244
|
+
server2.tool(
|
|
1245
|
+
"reset_webhook_circuit",
|
|
1246
|
+
"Reset the circuit breaker for a webhook so deliveries resume immediately instead of waiting for the automatic 5-minute recovery.",
|
|
1247
|
+
{ webhookId: z.string().describe("The webhook ID") },
|
|
1248
|
+
async ({ webhookId }) => {
|
|
1249
|
+
try {
|
|
1250
|
+
return ok(await api2("POST", `/webhooks/${webhookId}/reset-circuit`));
|
|
1251
|
+
} catch (e) {
|
|
1252
|
+
return err(e);
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
);
|
|
1256
|
+
server2.tool(
|
|
1257
|
+
"redeliver_webhook",
|
|
1258
|
+
"Replay failed or cancelled webhook deliveries from the audit log for a time window. Use after a customer endpoint has recovered from an outage. Reset the circuit first if it is open. Each replay preserves the original event_id for dedup.",
|
|
1259
|
+
{
|
|
1260
|
+
webhookId: z.string().describe("The webhook ID"),
|
|
1261
|
+
since: z.string().optional().describe(
|
|
1262
|
+
"Earliest delivery time, ISO-8601. Defaults to 24h ago."
|
|
1263
|
+
),
|
|
1264
|
+
until: z.string().optional().describe("Latest delivery time, ISO-8601. Defaults to now."),
|
|
1265
|
+
eventTypes: z.array(z.string()).optional().describe("Filter by event type. Defaults to all."),
|
|
1266
|
+
statuses: z.array(z.string()).optional().describe(
|
|
1267
|
+
"Replay deliveries in any of these statuses. Defaults to ['failed', 'cancelled']."
|
|
1268
|
+
),
|
|
1269
|
+
limit: z.number().int().positive().max(1e4).optional().describe("Max deliveries to requeue. Defaults to 1000, max 10000.")
|
|
1270
|
+
},
|
|
1271
|
+
async ({ webhookId, since, until, eventTypes, statuses, limit }) => {
|
|
1272
|
+
try {
|
|
1273
|
+
const body = {};
|
|
1274
|
+
if (since !== void 0) body.since = since;
|
|
1275
|
+
if (until !== void 0) body.until = until;
|
|
1276
|
+
if (eventTypes !== void 0) body.event_types = eventTypes;
|
|
1277
|
+
if (statuses !== void 0) body.statuses = statuses;
|
|
1278
|
+
if (limit !== void 0) body.limit = limit;
|
|
1279
|
+
return ok(
|
|
1280
|
+
await api2("POST", `/webhooks/${webhookId}/redeliver`, body)
|
|
1281
|
+
);
|
|
1282
|
+
} catch (e) {
|
|
1283
|
+
return err(e);
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
);
|
|
1287
|
+
server2.tool(
|
|
1288
|
+
"backfill_webhook",
|
|
1289
|
+
"Synthesize webhook events from the underlying message log for events that have no audit row (the case redeliver_webhook cannot recover). Use this when a circuit-breaker outage left events with no delivery record. Synthesized events have fresh IDs \u2014 clients should dedupe by event.data.object.id (the message ID). Reset the circuit first if it is open.",
|
|
1290
|
+
{
|
|
1291
|
+
webhookId: z.string().describe("The webhook ID"),
|
|
1292
|
+
since: z.string().optional().describe(
|
|
1293
|
+
"Earliest message time, ISO-8601. Defaults to 24h ago."
|
|
1294
|
+
),
|
|
1295
|
+
until: z.string().optional().describe("Latest message time, ISO-8601. Defaults to now."),
|
|
1296
|
+
eventTypes: z.array(z.string()).optional().describe(
|
|
1297
|
+
"Filter by event type. Defaults to subscribed message events."
|
|
1298
|
+
),
|
|
1299
|
+
limit: z.number().int().positive().max(1e4).optional().describe("Max events to synthesize. Defaults to 1000, max 10000.")
|
|
1300
|
+
},
|
|
1301
|
+
async ({ webhookId, since, until, eventTypes, limit }) => {
|
|
1302
|
+
try {
|
|
1303
|
+
const body = {};
|
|
1304
|
+
if (since !== void 0) body.since = since;
|
|
1305
|
+
if (until !== void 0) body.until = until;
|
|
1306
|
+
if (eventTypes !== void 0) body.event_types = eventTypes;
|
|
1307
|
+
if (limit !== void 0) body.limit = limit;
|
|
1308
|
+
return ok(
|
|
1309
|
+
await api2("POST", `/webhooks/${webhookId}/backfill`, body)
|
|
1310
|
+
);
|
|
1311
|
+
} catch (e) {
|
|
1312
|
+
return err(e);
|
|
1313
|
+
}
|
|
1314
|
+
}
|
|
1315
|
+
);
|
|
1241
1316
|
server2.tool(
|
|
1242
1317
|
"send_otp",
|
|
1243
1318
|
"Send an OTP verification code via SMS. Use for phone verification, 2FA, or identity confirmation. In sandbox mode (test API key), the code is returned in the response.",
|
|
@@ -1417,7 +1492,11 @@ function registerAllTools(server2, api2) {
|
|
|
1417
1492
|
}
|
|
1418
1493
|
|
|
1419
1494
|
// src/index.ts
|
|
1420
|
-
var
|
|
1495
|
+
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
1496
|
+
var pkg = JSON.parse(
|
|
1497
|
+
readFileSync(resolve(__dirname, "../package.json"), "utf8")
|
|
1498
|
+
);
|
|
1499
|
+
var VERSION = pkg.version;
|
|
1421
1500
|
var API_KEY = process.env.SENDLY_API_KEY;
|
|
1422
1501
|
var BASE_URL = process.env.SENDLY_BASE_URL || "https://sendly.live";
|
|
1423
1502
|
if (!API_KEY) {
|
|
@@ -1458,7 +1537,7 @@ async function api(method, path, body, query) {
|
|
|
1458
1537
|
}
|
|
1459
1538
|
const headers = {
|
|
1460
1539
|
Authorization: `Bearer ${API_KEY}`,
|
|
1461
|
-
"User-Agent":
|
|
1540
|
+
"User-Agent": `@sendly/mcp/${VERSION}`
|
|
1462
1541
|
};
|
|
1463
1542
|
if (body) headers["Content-Type"] = "application/json";
|
|
1464
1543
|
const res = await fetch(url.toString(), {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sendly/mcp",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "Sendly MCP Server — Full SMS platform for AI agents. Messaging, contacts, campaigns, templates, webhooks, OTP verification, and more.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|