@sendly/mcp 2.3.0 → 2.4.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 +15 -6
- package/dist/index.js +309 -0
- 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 — 91 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
|
|
|
@@ -54,7 +54,7 @@ openclaw mcp set sendly '{"command":"npx","args":["-y","@sendly/mcp"],"env":{"SE
|
|
|
54
54
|
|
|
55
55
|
Then ask your agent: *"Send a test SMS to +15005550000 saying Hello from my agent"*
|
|
56
56
|
|
|
57
|
-
## All
|
|
57
|
+
## All 91 Tools
|
|
58
58
|
|
|
59
59
|
### Messaging (6)
|
|
60
60
|
|
|
@@ -90,7 +90,7 @@ Then ask your agent: *"Send a test SMS to +15005550000 saying Hello from my agen
|
|
|
90
90
|
| `mark_conversation_read` | Reset unread count to zero |
|
|
91
91
|
| `get_suggested_replies` | AI-generated replies in 3 tones |
|
|
92
92
|
|
|
93
|
-
### Contacts (
|
|
93
|
+
### Contacts (9)
|
|
94
94
|
|
|
95
95
|
| Tool | Description |
|
|
96
96
|
|------|-------------|
|
|
@@ -99,6 +99,9 @@ Then ask your agent: *"Send a test SMS to +15005550000 saying Hello from my agen
|
|
|
99
99
|
| `get_contact` | Get contact with list memberships |
|
|
100
100
|
| `update_contact` | Update name, email, or metadata |
|
|
101
101
|
| `delete_contact` | Delete (removes from all lists) |
|
|
102
|
+
| `mark_contact_valid` | Mark a contact's phone number as validated |
|
|
103
|
+
| `check_contact_numbers` | Bulk-check phone number validity |
|
|
104
|
+
| `bulk_mark_contacts_valid` | Bulk-mark contacts as validated |
|
|
102
105
|
| `import_contacts` | Bulk import up to 10,000 contacts |
|
|
103
106
|
|
|
104
107
|
### Contact Lists (7)
|
|
@@ -168,7 +171,7 @@ Then ask your agent: *"Send a test SMS to +15005550000 saying Hello from my agen
|
|
|
168
171
|
| `approve_draft` | Approve and send as real SMS |
|
|
169
172
|
| `reject_draft` | Reject with reason |
|
|
170
173
|
|
|
171
|
-
### Webhooks (
|
|
174
|
+
### Webhooks (12)
|
|
172
175
|
|
|
173
176
|
| Tool | Description |
|
|
174
177
|
|------|-------------|
|
|
@@ -181,6 +184,9 @@ Then ask your agent: *"Send a test SMS to +15005550000 saying Hello from my agen
|
|
|
181
184
|
| `list_webhook_deliveries` | Delivery history with statuses |
|
|
182
185
|
| `rotate_webhook_secret` | Rotate signing secret |
|
|
183
186
|
| `list_webhook_event_types` | List available event types |
|
|
187
|
+
| `reset_webhook_circuit` | Reset open circuit breaker on an endpoint |
|
|
188
|
+
| `redeliver_webhook` | Redeliver a failed webhook event |
|
|
189
|
+
| `backfill_webhook` | Backfill missed deliveries for an endpoint |
|
|
184
190
|
|
|
185
191
|
### OTP / Verify (7)
|
|
186
192
|
|
|
@@ -207,11 +213,14 @@ Then ask your agent: *"Send a test SMS to +15005550000 saying Hello from my agen
|
|
|
207
213
|
|------|-------------|
|
|
208
214
|
| `get_account` | Credit balance, verification status, rate limits |
|
|
209
215
|
|
|
210
|
-
### Enterprise (
|
|
216
|
+
### Enterprise (4)
|
|
211
217
|
|
|
212
218
|
| Tool | Description |
|
|
213
219
|
|------|-------------|
|
|
214
220
|
| `generate_business_page` | Generate hosted business page for verification *(enterprise only)* |
|
|
221
|
+
| `enterprise_workspace_get_verification` | Get current toll-free verification record for a workspace *(enterprise only)* |
|
|
222
|
+
| `enterprise_workspace_submit_verification` | Submit or resubmit toll-free verification (partial-update friendly) *(enterprise only)* |
|
|
223
|
+
| `enterprise_workspace_resubmit_verification` | Convenience alias of submit — use when retrying after rejection *(enterprise only)* |
|
|
215
224
|
|
|
216
225
|
## Authentication
|
|
217
226
|
|
|
@@ -241,7 +250,7 @@ With test keys, use magic numbers:
|
|
|
241
250
|
|
|
242
251
|
## Links
|
|
243
252
|
|
|
244
|
-
- [MCP Tools Reference](https://sendly.live/docs/ai/mcp-tools) — all
|
|
253
|
+
- [MCP Tools Reference](https://sendly.live/docs/ai/mcp-tools) — all 91 tools with schemas
|
|
245
254
|
- [Agent Skills](https://sendly.live/skills) — SKILL.md files for 8 platforms
|
|
246
255
|
- [API Reference](https://sendly.live/docs/api)
|
|
247
256
|
- [Sendly Dashboard](https://sendly.live/dashboard)
|
package/dist/index.js
CHANGED
|
@@ -1489,6 +1489,315 @@ function registerAllTools(server2, api2) {
|
|
|
1489
1489
|
}
|
|
1490
1490
|
}
|
|
1491
1491
|
);
|
|
1492
|
+
server2.tool(
|
|
1493
|
+
"enterprise_workspace_get_verification",
|
|
1494
|
+
"Get the current verification record for an enterprise workspace. Useful before submit/resubmit to see what's already on file (the server merges your submit payload with existing fields).",
|
|
1495
|
+
{
|
|
1496
|
+
workspaceId: z.string().describe("The enterprise workspace ID")
|
|
1497
|
+
},
|
|
1498
|
+
async ({ workspaceId }) => {
|
|
1499
|
+
try {
|
|
1500
|
+
return ok(
|
|
1501
|
+
await api2(
|
|
1502
|
+
"GET",
|
|
1503
|
+
`/enterprise/workspaces/${encodeURIComponent(workspaceId)}/verification`
|
|
1504
|
+
)
|
|
1505
|
+
);
|
|
1506
|
+
} catch (e) {
|
|
1507
|
+
return err(e);
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1510
|
+
);
|
|
1511
|
+
const verificationSubmitSchema = {
|
|
1512
|
+
workspaceId: z.string().describe("The enterprise workspace ID"),
|
|
1513
|
+
businessName: z.string().optional().describe("Legal business name"),
|
|
1514
|
+
doingBusinessAs: z.string().optional().describe("DBA / trade name, if different from legal name"),
|
|
1515
|
+
website: z.string().optional().describe("Business website URL (https://...)"),
|
|
1516
|
+
entityType: z.string().optional().describe(
|
|
1517
|
+
"Entity type (e.g., LLC, CORPORATION, SOLE_PROPRIETOR, NON_PROFIT, GOVERNMENT). For SOLE_PROPRIETOR, omit brn/brnType/brnCountry."
|
|
1518
|
+
),
|
|
1519
|
+
address: z.object({
|
|
1520
|
+
street: z.string().optional().describe("Street address"),
|
|
1521
|
+
city: z.string().optional().describe("City"),
|
|
1522
|
+
state: z.string().optional().describe("State or province (full name preferred, e.g., 'California')"),
|
|
1523
|
+
zip: z.string().optional().describe("ZIP or postal code"),
|
|
1524
|
+
country: z.string().optional().describe("ISO country code (e.g., 'US')")
|
|
1525
|
+
}).optional().describe("Business address (nested). Omit fields you don't want to change."),
|
|
1526
|
+
contact: z.object({
|
|
1527
|
+
firstName: z.string().optional().describe("Contact first name"),
|
|
1528
|
+
lastName: z.string().optional().describe("Contact last name"),
|
|
1529
|
+
email: z.string().optional().describe("Contact email"),
|
|
1530
|
+
phone: z.string().optional().describe("Contact phone in E.164 format")
|
|
1531
|
+
}).optional().describe("Authorized contact (nested). Omit fields you don't want to change."),
|
|
1532
|
+
brn: z.string().optional().describe("Business registration number (e.g., EIN). Omit for sole proprietors."),
|
|
1533
|
+
brnType: z.string().optional().describe("BRN type (e.g., EIN, DUNS, VAT). Omit for sole proprietors."),
|
|
1534
|
+
brnCountry: z.string().optional().describe("BRN issuing country ISO code. Omit for sole proprietors."),
|
|
1535
|
+
useCase: z.string().optional().describe("Use case (e.g., 'Insurance Services', '2FA', 'Appointment Reminders')"),
|
|
1536
|
+
useCaseSummary: z.string().optional().describe("Brief description of what the business sends and why"),
|
|
1537
|
+
sampleMessages: z.string().optional().describe("Sample messages the business will send (text, can be multi-line)"),
|
|
1538
|
+
optInWorkflow: z.string().optional().describe("Description of how recipients opt in (web form, paper form, verbal, etc.)"),
|
|
1539
|
+
optInImageUrls: z.array(z.string()).optional().describe("Array of URLs to opt-in proof images/screenshots"),
|
|
1540
|
+
monthlyVolume: z.number().optional().describe("Expected monthly message volume"),
|
|
1541
|
+
additionalInformation: z.string().optional().describe("Additional context for the carrier reviewer"),
|
|
1542
|
+
ageGatedContent: z.boolean().optional().describe("True if content is age-gated (alcohol, gambling, etc.)"),
|
|
1543
|
+
isvReseller: z.string().optional().describe("ISV / reseller name, if applicable"),
|
|
1544
|
+
privacyUrl: z.string().optional().describe("Privacy policy URL (auto-preserved if hosted on Sendly)"),
|
|
1545
|
+
termsUrl: z.string().optional().describe("Terms of service URL (auto-preserved if hosted on Sendly)")
|
|
1546
|
+
};
|
|
1547
|
+
const submitVerificationHandler = async (params) => {
|
|
1548
|
+
try {
|
|
1549
|
+
const { workspaceId, ...rest } = params;
|
|
1550
|
+
const body = {};
|
|
1551
|
+
for (const [k, v] of Object.entries(rest)) {
|
|
1552
|
+
if (v !== void 0) body[k] = v;
|
|
1553
|
+
}
|
|
1554
|
+
return ok(
|
|
1555
|
+
await api2(
|
|
1556
|
+
"POST",
|
|
1557
|
+
`/enterprise/workspaces/${encodeURIComponent(workspaceId)}/verification/submit`,
|
|
1558
|
+
body
|
|
1559
|
+
)
|
|
1560
|
+
);
|
|
1561
|
+
} catch (e) {
|
|
1562
|
+
return err(e);
|
|
1563
|
+
}
|
|
1564
|
+
};
|
|
1565
|
+
server2.tool(
|
|
1566
|
+
"enterprise_workspace_submit_verification",
|
|
1567
|
+
"Submit or resubmit a toll-free verification for an enterprise workspace. Partial-update friendly: omit fields you don't want to change \u2014 they'll be filled from the existing record. Hosted page URLs (/biz/, /opt-in/, /legal/) generated during provision are auto-preserved. For sole proprietors, leave brn/brnType/brnCountry undefined.",
|
|
1568
|
+
verificationSubmitSchema,
|
|
1569
|
+
submitVerificationHandler
|
|
1570
|
+
);
|
|
1571
|
+
server2.tool(
|
|
1572
|
+
"enterprise_workspace_resubmit_verification",
|
|
1573
|
+
"Convenience alias for submit_verification \u2014 identical behavior. Use when retrying after a rejection.",
|
|
1574
|
+
verificationSubmitSchema,
|
|
1575
|
+
submitVerificationHandler
|
|
1576
|
+
);
|
|
1577
|
+
const upgradeEntitySchema = {
|
|
1578
|
+
workspaceId: z.string().describe(
|
|
1579
|
+
"The Sendly workspace ID being upgraded. Found in the dashboard URL or the `organizationId` field of any object."
|
|
1580
|
+
)
|
|
1581
|
+
};
|
|
1582
|
+
const upgradeStartSchema = {
|
|
1583
|
+
workspaceId: z.string().describe("The Sendly workspace ID being upgraded."),
|
|
1584
|
+
businessName: z.string().describe(
|
|
1585
|
+
"Legal name of the new entity, exactly as filed with the IRS / state (e.g. 'Acme Holdings LLC')."
|
|
1586
|
+
),
|
|
1587
|
+
brn: z.string().describe(
|
|
1588
|
+
"Business registration number for the new entity. For US LLCs/Corps this is the EIN (XX-XXXXXXX)."
|
|
1589
|
+
),
|
|
1590
|
+
brnType: z.enum(["EIN", "SSN", "DUNS", "CRA", "VAT", "LEI", "OTHER"]).describe("Type of business registration number."),
|
|
1591
|
+
brnCountry: z.string().describe(
|
|
1592
|
+
"ISO 3166-1 alpha-2 country code for the registration (e.g. 'US', 'CA')."
|
|
1593
|
+
),
|
|
1594
|
+
entityType: z.enum([
|
|
1595
|
+
"SOLE_PROPRIETOR",
|
|
1596
|
+
"PRIVATE_PROFIT",
|
|
1597
|
+
"PUBLIC_PROFIT",
|
|
1598
|
+
"NON_PROFIT",
|
|
1599
|
+
"GOVERNMENT"
|
|
1600
|
+
]).describe(
|
|
1601
|
+
"Legal form of the entity. Use PRIVATE_PROFIT for LLCs and standard corporations."
|
|
1602
|
+
),
|
|
1603
|
+
doingBusinessAs: z.string().optional(),
|
|
1604
|
+
website: z.string().optional(),
|
|
1605
|
+
address1: z.string().optional(),
|
|
1606
|
+
address2: z.string().optional(),
|
|
1607
|
+
city: z.string().optional(),
|
|
1608
|
+
state: z.string().optional().describe("Full state/province name, not the 2-letter code."),
|
|
1609
|
+
zip: z.string().optional(),
|
|
1610
|
+
addressCountry: z.string().optional(),
|
|
1611
|
+
contactFirstName: z.string().optional(),
|
|
1612
|
+
contactLastName: z.string().optional(),
|
|
1613
|
+
contactEmail: z.string().optional(),
|
|
1614
|
+
contactPhone: z.string().optional().describe("E.164 format with country code, e.g. '+14155551234'."),
|
|
1615
|
+
monthlyVolume: z.string().optional(),
|
|
1616
|
+
useCase: z.string().optional(),
|
|
1617
|
+
useCaseSummary: z.string().optional(),
|
|
1618
|
+
sampleMessages: z.string().optional(),
|
|
1619
|
+
optInWorkflow: z.string().optional(),
|
|
1620
|
+
privacyUrl: z.string().optional(),
|
|
1621
|
+
termsUrl: z.string().optional(),
|
|
1622
|
+
additionalInformation: z.string().optional(),
|
|
1623
|
+
ageGatedContent: z.boolean().optional(),
|
|
1624
|
+
einDocBase64: z.string().optional().describe(
|
|
1625
|
+
"Optional IRS letter (CP-575 or 147C) as a base64-encoded PDF, \u22645MB. Strongly recommended for entities formed within the last 6 months \u2014 the carrier may otherwise reject because the new EIN isn't yet visible in public registries."
|
|
1626
|
+
),
|
|
1627
|
+
einDocFilename: z.string().optional().describe("Optional filename for the EIN doc (defaults to 'ein-doc.pdf').")
|
|
1628
|
+
};
|
|
1629
|
+
const buildUpgradeForm = (input) => {
|
|
1630
|
+
const form = new FormData();
|
|
1631
|
+
for (const [k, v] of Object.entries(input)) {
|
|
1632
|
+
if (k === "workspaceId" || k === "einDocBase64" || k === "einDocFilename")
|
|
1633
|
+
continue;
|
|
1634
|
+
if (v === void 0 || v === null) continue;
|
|
1635
|
+
form.append(k, typeof v === "boolean" ? String(v) : v);
|
|
1636
|
+
}
|
|
1637
|
+
if (input.einDocBase64 && typeof input.einDocBase64 === "string") {
|
|
1638
|
+
const buf = Buffer.from(input.einDocBase64, "base64");
|
|
1639
|
+
const blob = new Blob([buf], { type: "application/pdf" });
|
|
1640
|
+
form.append(
|
|
1641
|
+
"einDoc",
|
|
1642
|
+
blob,
|
|
1643
|
+
input.einDocFilename || "ein-doc.pdf"
|
|
1644
|
+
);
|
|
1645
|
+
}
|
|
1646
|
+
return form;
|
|
1647
|
+
};
|
|
1648
|
+
server2.tool(
|
|
1649
|
+
"preflight_business_upgrade",
|
|
1650
|
+
"Validate a proposed business entity upgrade before submitting. Returns issues + auto-fix suggestions (e.g. 'sole-prop + EIN mismatch \u2014 change entity to PRIVATE_PROFIT'). Use this to dry-run new entity details before calling start_business_upgrade. Read-only; no DB or carrier writes.",
|
|
1651
|
+
{
|
|
1652
|
+
businessName: z.string(),
|
|
1653
|
+
brn: z.string(),
|
|
1654
|
+
brnType: z.enum(["EIN", "SSN", "DUNS", "CRA", "VAT", "LEI", "OTHER"]),
|
|
1655
|
+
brnCountry: z.string(),
|
|
1656
|
+
entityType: z.enum([
|
|
1657
|
+
"SOLE_PROPRIETOR",
|
|
1658
|
+
"PRIVATE_PROFIT",
|
|
1659
|
+
"PUBLIC_PROFIT",
|
|
1660
|
+
"NON_PROFIT",
|
|
1661
|
+
"GOVERNMENT"
|
|
1662
|
+
]),
|
|
1663
|
+
doingBusinessAs: z.string().optional(),
|
|
1664
|
+
website: z.string().optional(),
|
|
1665
|
+
address1: z.string().optional(),
|
|
1666
|
+
city: z.string().optional(),
|
|
1667
|
+
state: z.string().optional(),
|
|
1668
|
+
zip: z.string().optional(),
|
|
1669
|
+
addressCountry: z.string().optional(),
|
|
1670
|
+
contactEmail: z.string().optional(),
|
|
1671
|
+
contactPhone: z.string().optional(),
|
|
1672
|
+
monthlyVolume: z.string().optional(),
|
|
1673
|
+
useCase: z.string().optional(),
|
|
1674
|
+
sampleMessages: z.string().optional(),
|
|
1675
|
+
optInWorkflow: z.string().optional()
|
|
1676
|
+
},
|
|
1677
|
+
async (input) => {
|
|
1678
|
+
try {
|
|
1679
|
+
return ok(await api2("POST", "/verification/preflight", input));
|
|
1680
|
+
} catch (e) {
|
|
1681
|
+
return err(e);
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1684
|
+
);
|
|
1685
|
+
server2.tool(
|
|
1686
|
+
"get_business_upgrade_best_prefill",
|
|
1687
|
+
"Read 'best-of' values for the upgrade form across all of the caller's verified workspaces. Returns most-recent non-empty values per messaging field (useCase, sampleMessages, optInWorkflow, etc.). Useful when populating a fresh upgrade form for a workspace whose current record is incomplete.",
|
|
1688
|
+
{},
|
|
1689
|
+
async () => {
|
|
1690
|
+
try {
|
|
1691
|
+
return ok(await api2("GET", "/verification/best-prefill"));
|
|
1692
|
+
} catch (e) {
|
|
1693
|
+
return err(e);
|
|
1694
|
+
}
|
|
1695
|
+
}
|
|
1696
|
+
);
|
|
1697
|
+
server2.tool(
|
|
1698
|
+
"start_business_upgrade",
|
|
1699
|
+
"Start a business entity upgrade for the given workspace. Auto-provisions a new toll-free number + messaging profile under the new entity, submits to the carrier for review, and stores the EIN document (if provided) securely until approval. The current toll-free number keeps sending throughout the 1-2 week review window; on approval, the new number takes over atomically. Use preflight_business_upgrade first to surface any blockers.",
|
|
1700
|
+
upgradeStartSchema,
|
|
1701
|
+
async (input) => {
|
|
1702
|
+
try {
|
|
1703
|
+
const { workspaceId } = input;
|
|
1704
|
+
const form = buildUpgradeForm(input);
|
|
1705
|
+
return ok(
|
|
1706
|
+
await api2(
|
|
1707
|
+
"POST",
|
|
1708
|
+
`/workspaces/${encodeURIComponent(workspaceId)}/upgrade`,
|
|
1709
|
+
form
|
|
1710
|
+
)
|
|
1711
|
+
);
|
|
1712
|
+
} catch (e) {
|
|
1713
|
+
return err(e);
|
|
1714
|
+
}
|
|
1715
|
+
}
|
|
1716
|
+
);
|
|
1717
|
+
server2.tool(
|
|
1718
|
+
"get_business_upgrade_status",
|
|
1719
|
+
"Check the status of a pending business entity upgrade for a workspace. Returns the pending row (with status, target toll-free number, rejection reason if any) or null if no upgrade is in flight. Statuses: pending, waiting_for_telnyx, waiting_for_customer, rejected, verified.",
|
|
1720
|
+
upgradeEntitySchema,
|
|
1721
|
+
async ({ workspaceId }) => {
|
|
1722
|
+
try {
|
|
1723
|
+
return ok(
|
|
1724
|
+
await api2(
|
|
1725
|
+
"GET",
|
|
1726
|
+
`/workspaces/${encodeURIComponent(workspaceId)}/upgrade/status`
|
|
1727
|
+
)
|
|
1728
|
+
);
|
|
1729
|
+
} catch (e) {
|
|
1730
|
+
return err(e);
|
|
1731
|
+
}
|
|
1732
|
+
}
|
|
1733
|
+
);
|
|
1734
|
+
server2.tool(
|
|
1735
|
+
"cancel_business_upgrade",
|
|
1736
|
+
"Cancel a pending business entity upgrade. Releases the reserved toll-free number, deletes the new messaging profile, removes the stored EIN document, and clears the pending record. The current toll-free number is unaffected. Idempotent \u2014 returns success even if there was nothing to cancel.",
|
|
1737
|
+
upgradeEntitySchema,
|
|
1738
|
+
async ({ workspaceId }) => {
|
|
1739
|
+
try {
|
|
1740
|
+
return ok(
|
|
1741
|
+
await api2(
|
|
1742
|
+
"POST",
|
|
1743
|
+
`/workspaces/${encodeURIComponent(workspaceId)}/upgrade/cancel`
|
|
1744
|
+
)
|
|
1745
|
+
);
|
|
1746
|
+
} catch (e) {
|
|
1747
|
+
return err(e);
|
|
1748
|
+
}
|
|
1749
|
+
}
|
|
1750
|
+
);
|
|
1751
|
+
server2.tool(
|
|
1752
|
+
"resubmit_business_upgrade",
|
|
1753
|
+
"Resubmit a previously rejected (or waiting-for-customer) business entity upgrade with corrected fields and optionally a new EIN document. Same field shape as start_business_upgrade; fields you omit keep the previously-submitted values.",
|
|
1754
|
+
upgradeStartSchema,
|
|
1755
|
+
async (input) => {
|
|
1756
|
+
try {
|
|
1757
|
+
const { workspaceId } = input;
|
|
1758
|
+
const form = buildUpgradeForm(input);
|
|
1759
|
+
return ok(
|
|
1760
|
+
await api2(
|
|
1761
|
+
"POST",
|
|
1762
|
+
`/workspaces/${encodeURIComponent(workspaceId)}/upgrade/resubmit`,
|
|
1763
|
+
form
|
|
1764
|
+
)
|
|
1765
|
+
);
|
|
1766
|
+
} catch (e) {
|
|
1767
|
+
return err(e);
|
|
1768
|
+
}
|
|
1769
|
+
}
|
|
1770
|
+
);
|
|
1771
|
+
server2.tool(
|
|
1772
|
+
"set_business_upgrade_old_number_disposition",
|
|
1773
|
+
"After a successful business upgrade, choose what happens to the old (now-superseded) toll-free number. 'moved' keeps it active under another workspace owned by the same user (requires targetWorkspaceId); 'released' returns it to the carrier pool. Idempotent.",
|
|
1774
|
+
{
|
|
1775
|
+
workspaceId: z.string(),
|
|
1776
|
+
disposition: z.enum(["moved", "released"]).describe(
|
|
1777
|
+
"'moved' = keep old number active on another workspace; 'released' = return to carrier pool."
|
|
1778
|
+
),
|
|
1779
|
+
targetWorkspaceId: z.string().optional().describe(
|
|
1780
|
+
"Required when disposition='moved'. Workspace ID to attach the old number to."
|
|
1781
|
+
)
|
|
1782
|
+
},
|
|
1783
|
+
async ({
|
|
1784
|
+
workspaceId,
|
|
1785
|
+
disposition,
|
|
1786
|
+
targetWorkspaceId
|
|
1787
|
+
}) => {
|
|
1788
|
+
try {
|
|
1789
|
+
return ok(
|
|
1790
|
+
await api2(
|
|
1791
|
+
"POST",
|
|
1792
|
+
`/workspaces/${encodeURIComponent(workspaceId)}/upgrade/disposition`,
|
|
1793
|
+
{ disposition, targetOrgId: targetWorkspaceId }
|
|
1794
|
+
)
|
|
1795
|
+
);
|
|
1796
|
+
} catch (e) {
|
|
1797
|
+
return err(e);
|
|
1798
|
+
}
|
|
1799
|
+
}
|
|
1800
|
+
);
|
|
1492
1801
|
}
|
|
1493
1802
|
|
|
1494
1803
|
// src/index.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sendly/mcp",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.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",
|