Skip to content

Commit 9b6bb35

Browse files
authored
Separate triggered and blast campaign tools (#30)
1 parent 102097d commit 9b6bb35

File tree

11 files changed

+42
-27
lines changed

11 files changed

+42
-27
lines changed

TOOLS.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
1-
# Available Iterable MCP Tools (104 tools)
1+
# Available Iterable MCP Tools (105 tools)
22

33
**Legend:**
44
- 🔒 = Requires enabling user PII access
55
- ✏️ = Requires enabling writes
66
- ✉️ = Requires enabling sends
77

88

9-
## Campaigns (13 tools)
9+
## Campaigns (14 tools)
1010
- **abort_campaign** ✏️: Abort a campaign that is currently running
1111
- **activate_triggered_campaign** ✏️✉️: Activate a triggered campaign (requires API triggered campaign activation enabled)
1212
- **archive_campaigns** ✏️: Archive one or more campaigns. Scheduled/recurring campaigns will be cancelled, running campaigns will be aborted.
1313
- **cancel_campaign** ✏️: Cancel a scheduled or recurring campaign
14-
- **create_campaign** ✏️✉️: Create a new blast or triggered campaign from an existing template. If listIds are provided, the campaign will be a blast campaign; it is created in Scheduled state and will be sent at the given sendAt time, which is required. If listIds are not provided, the campaign will be a triggered campaign in Ready state that must be activated before it can send.
14+
- **create_and_schedule_campaign** ✏️✉️: Create a new blast campaign from an existing template and schedule it for delivery. The campaign is created in Scheduled state and will be sent to the specified lists at the given sendAt time.
15+
- **create_triggered_campaign** ✏️: Create a new triggered campaign from an existing template. The campaign is created in Ready state and must be activated before it can send.
1516
- **deactivate_triggered_campaign** ✏️: Deactivate a triggered campaign (requires API triggered campaign deactivation enabled)
1617
- **get_campaign**: Get detailed information about a specific campaign
1718
- **get_campaign_metrics**: Get campaign performance metrics

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@
7575
},
7676
"dependencies": {
7777
"@alcyone-labs/zod-to-json-schema": "4.0.10",
78-
"@iterable/api": "0.6.1",
78+
"@iterable/api": "0.7.0",
7979
"@modelcontextprotocol/sdk": "1.18.1",
8080
"@primno/dpapi": "2.0.1",
8181
"@types/json-schema": "7.0.15",

pnpm-lock.yaml

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/tool-filter.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ export const NON_PII_TOOLS: Set<string> = new Set([
1313
"archive_campaigns",
1414
"bulk_delete_catalog_items",
1515
"cancel_campaign",
16-
"create_campaign",
16+
"create_and_schedule_campaign",
17+
"create_triggered_campaign",
1718
"create_catalog",
1819
"create_list",
1920
"create_snippet",
@@ -117,8 +118,8 @@ export const SEND_TOOLS: Set<string> = new Set([
117118
"send_campaign",
118119
"trigger_campaign",
119120
"schedule_campaign",
120-
// Creating a blast campaign schedules a send (sendAt is required when listIds is provided)
121-
"create_campaign",
121+
// Creating a blast campaign schedules a send
122+
"create_and_schedule_campaign",
122123
// Triggered campaigns can cause sends upon activation; block unless explicitly allowed
123124
"activate_triggered_campaign",
124125
// Journey triggers enqueue users which may send

src/tools/campaigns.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import {
88
ActivateTriggeredCampaignParamsSchema,
99
ArchiveCampaignsParamsSchema,
1010
CancelCampaignParamsSchema,
11-
CreateCampaignParamsSchema,
11+
CreateAndScheduleCampaignParamsSchema,
12+
CreateTriggeredCampaignParamsSchema,
1213
DeactivateTriggeredCampaignParamsSchema,
1314
GetCampaignMetricsParamsSchema,
1415
GetCampaignParamsSchema,
@@ -45,11 +46,18 @@ export function createCampaignTools(client: IterableClient): Tool[] {
4546
execute: (params) => client.getCampaignMetrics(params),
4647
}),
4748
createTool({
48-
name: "create_campaign",
49+
name: "create_and_schedule_campaign",
4950
description:
50-
"Create a new blast or triggered campaign from an existing template. If listIds are provided, the campaign will be a blast campaign; it is created in Scheduled state and will be sent at the given sendAt time, which is required. If listIds are not provided, the campaign will be a triggered campaign in Ready state that must be activated before it can send.",
51-
schema: CreateCampaignParamsSchema,
52-
execute: (params) => client.createCampaign(params),
51+
"Create a new blast campaign from an existing template and schedule it for delivery. The campaign is created in Scheduled state and will be sent to the specified lists at the given sendAt time.",
52+
schema: CreateAndScheduleCampaignParamsSchema,
53+
execute: (params) => client.createAndScheduleCampaign(params),
54+
}),
55+
createTool({
56+
name: "create_triggered_campaign",
57+
description:
58+
"Create a new triggered campaign from an existing template. The campaign is created in Ready state and must be activated before it can send.",
59+
schema: CreateTriggeredCampaignParamsSchema,
60+
execute: (params) => client.createTriggeredCampaign(params),
5361
}),
5462
createTool({
5563
name: "get_child_campaigns",

tests/unit/prompts.test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ describe("MCP Prompts", () => {
6161
expect(promptNames).toContain("get-user-by-user-id");
6262
expect(promptNames).toContain("get-campaigns");
6363
expect(promptNames).toContain("get-experiment-metrics");
64-
expect(promptNames).toContain("create-campaign"); // Now included since we pass all tools
64+
expect(promptNames).toContain("create-and-schedule-campaign");
65+
expect(promptNames).toContain("create-triggered-campaign");
6566
expect(promptNames).toContain("get-child-campaigns");
6667
});
6768

@@ -131,7 +132,7 @@ describe("MCP Prompts", () => {
131132
expect(promptNames).toContain("get-campaigns");
132133

133134
// Should NOT include write or send tools
134-
expect(promptNames).not.toContain("create-campaign");
135+
expect(promptNames).not.toContain("create-and-schedule-campaign");
135136
expect(promptNames).not.toContain("update-user");
136137
expect(promptNames).not.toContain("send-email");
137138
expect(promptNames).not.toContain("send-email-template-proof");

tests/unit/send-tools-registry.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ describe("SEND_TOOLS registry", () => {
2828
"send_campaign",
2929
"trigger_campaign",
3030
"schedule_campaign",
31-
"create_campaign",
31+
"create_and_schedule_campaign",
3232
"activate_triggered_campaign",
3333
"trigger_journey",
3434
"track_event",

tests/unit/tool-filter-defaults.test.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ describe("filterTools defaults", () => {
1010
} as any;
1111

1212
const writeTool: any = {
13-
name: "create_campaign", // NOT in READ_ONLY_TOOLS
13+
name: "create_and_schedule_campaign", // NOT in READ_ONLY_TOOLS
1414
description: "",
1515
inputSchema: { type: "object", properties: {} },
1616
handler: async () => ({}),
@@ -26,7 +26,9 @@ describe("filterTools defaults", () => {
2626
})
2727
);
2828
expect(out.map((t) => t.name)).toContain("get_campaigns");
29-
expect(out.map((t) => t.name)).not.toContain("create_campaign");
29+
expect(out.map((t) => t.name)).not.toContain(
30+
"create_and_schedule_campaign"
31+
);
3032
});
3133

3234
it("includes write tools when allowWrites=true", () => {
@@ -38,6 +40,6 @@ describe("filterTools defaults", () => {
3840
allowSends: true,
3941
})
4042
);
41-
expect(out.map((t) => t.name)).toContain("create_campaign");
43+
expect(out.map((t) => t.name)).toContain("create_and_schedule_campaign");
4244
});
4345
});

tests/unit/tool-filter-sends.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ describe("filterTools with allowSends", () => {
1616
mkTool("send_campaign"),
1717
mkTool("trigger_campaign"),
1818
mkTool("schedule_campaign"),
19-
mkTool("create_campaign"),
19+
mkTool("create_and_schedule_campaign"),
2020
mkTool("track_event"),
2121
mkTool("track_bulk_events"),
2222
mkTool("trigger_journey"),
@@ -47,7 +47,7 @@ describe("filterTools with allowSends", () => {
4747
expect(names.has("send_campaign")).toBe(false);
4848
expect(names.has("trigger_campaign")).toBe(false);
4949
expect(names.has("schedule_campaign")).toBe(false);
50-
expect(names.has("create_campaign")).toBe(false);
50+
expect(names.has("create_and_schedule_campaign")).toBe(false);
5151
expect(names.has("track_event")).toBe(false);
5252
expect(names.has("track_bulk_events")).toBe(false);
5353
expect(names.has("trigger_journey")).toBe(false);

tests/unit/tool-filter.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,8 @@ describe("Tool Filter", () => {
145145
const filteredNames = filteredTools.map((tool) => tool.name);
146146

147147
const writeTools = [
148-
"create_campaign",
148+
"create_and_schedule_campaign",
149+
"create_triggered_campaign",
149150
"update_user",
150151
"delete_user_by_email",
151152
"delete_user_by_user_id",

0 commit comments

Comments
 (0)