@sendly/mcp
Advanced tools
+63
-1
@@ -443,2 +443,63 @@ #!/usr/bin/env node | ||
| server2.tool( | ||
| "mark_contact_valid", | ||
| "Clear the invalid flag on a contact so future campaigns include it again. Contacts get auto-flagged as invalid when a send fails with a terminal bad-number error (landline, invalid number) or when a carrier lookup reports they can't receive SMS. Use this when you disagree with the auto-flag.", | ||
| { | ||
| contactId: z.string().describe("The contact ID to clear the invalid flag on") | ||
| }, | ||
| async ({ contactId }) => { | ||
| try { | ||
| return ok(await api2("POST", `/contacts/${contactId}/mark-valid`)); | ||
| } catch (e) { | ||
| return err(e); | ||
| } | ||
| } | ||
| ); | ||
| server2.tool( | ||
| "check_contact_numbers", | ||
| "Trigger a background carrier lookup across contacts. Landlines and other non-SMS-capable numbers are auto-excluded from future campaigns. The lookup runs asynchronously (1-5 minutes). Results populate line_type, carrier_name, and invalid_reason fields on affected contacts. Idempotent: re-triggering while a lookup is running for the same scope is a no-op \u2014 response carries alreadyRunning: true in that case.", | ||
| { | ||
| listId: z.string().optional().describe("Scope the lookup to a single contact list"), | ||
| force: z.boolean().optional().describe("Re-check contacts even if already looked up (default: false)") | ||
| }, | ||
| async ({ listId, force }) => { | ||
| try { | ||
| return ok( | ||
| await api2("POST", "/contacts/lookup", { | ||
| listId: listId ?? null, | ||
| force: force ?? false | ||
| }) | ||
| ); | ||
| } catch (e) { | ||
| return err(e); | ||
| } | ||
| } | ||
| ); | ||
| server2.tool( | ||
| "bulk_mark_contacts_valid", | ||
| "Clear the invalid flag on many contacts at once (up to 10,000 per call). Pass either an explicit id array OR a listId \u2014 not both. Foreign ids silently no-op via the per-organization filter. Returns { cleared } \u2014 the number of contacts whose flag was actually cleared.", | ||
| { | ||
| ids: z.array(z.string()).max(1e4).optional().describe("Explicit contact ids to clear (max 10,000)"), | ||
| listId: z.string().optional().describe("Clear every flagged member of this list") | ||
| }, | ||
| async ({ ids, listId }) => { | ||
| if (!ids && !listId) { | ||
| return err("bulk_mark_contacts_valid requires either 'ids' or 'listId'"); | ||
| } | ||
| if (ids && listId) { | ||
| return err("bulk_mark_contacts_valid accepts 'ids' OR 'listId', not both"); | ||
| } | ||
| try { | ||
| return ok( | ||
| await api2( | ||
| "POST", | ||
| "/contacts/bulk-mark-valid", | ||
| ids ? { ids } : { listId } | ||
| ) | ||
| ); | ||
| } catch (e) { | ||
| return err(e); | ||
| } | ||
| } | ||
| ); | ||
| server2.tool( | ||
| "import_contacts", | ||
@@ -1400,3 +1461,4 @@ "Bulk import contacts from an array. Optionally add all imported contacts to a list. Returns created/updated/skipped counts.", | ||
| const headers = { | ||
| Authorization: `Bearer ${API_KEY}` | ||
| Authorization: `Bearer ${API_KEY}`, | ||
| "User-Agent": "@sendly/mcp/2.0.2" | ||
| }; | ||
@@ -1403,0 +1465,0 @@ if (body) headers["Content-Type"] = "application/json"; |
+1
-1
| { | ||
| "name": "@sendly/mcp", | ||
| "version": "2.0.1", | ||
| "version": "2.2.0", | ||
| "description": "Sendly MCP Server — Full SMS platform for AI agents. Messaging, contacts, campaigns, templates, webhooks, OTP verification, and more.", | ||
@@ -5,0 +5,0 @@ "type": "module", |
60409
4.61%1488
4.42%