@sellable/mcp 0.1.277 → 0.1.278

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.
@@ -1,11 +1,6 @@
1
1
  export interface PrepareCampaignAbTestInput {
2
- sourceCampaignId?: string;
2
+ sourceCampaignId: string;
3
3
  sourceLeadListId?: string;
4
- campaignName?: string;
5
- campaignBrief?: string;
6
- offerPositioning?: Record<string, unknown>;
7
- clientProspectId?: string;
8
- senderLinkedinUrl?: string;
9
4
  variantName: string;
10
5
  variantBriefDelta: string;
11
6
  variantALabel?: string;
@@ -32,27 +27,6 @@ export declare const campaignAbTestToolDefinitions: {
32
27
  type: string;
33
28
  description: string;
34
29
  };
35
- campaignName: {
36
- type: string;
37
- description: string;
38
- };
39
- campaignBrief: {
40
- type: string;
41
- description: string;
42
- };
43
- offerPositioning: {
44
- type: string;
45
- additionalProperties: boolean;
46
- description: string;
47
- };
48
- clientProspectId: {
49
- type: string;
50
- description: string;
51
- };
52
- senderLinkedinUrl: {
53
- type: string;
54
- description: string;
55
- };
56
30
  variantName: {
57
31
  type: string;
58
32
  description: string;
@@ -2,38 +2,17 @@ import { getApi } from "../api.js";
2
2
  export const campaignAbTestToolDefinitions = [
3
3
  {
4
4
  name: "prepare_campaign_ab_test",
5
- description: "Prepare a campaign A/B test from an existing campaign, a clean source lead list, or just a campaign idea. If sourceCampaignId is omitted, pass campaignName and campaignBrief so the tool creates the A campaign first and duplicates it for B. sourceLeadListId is optional; when provided the tool also creates deterministic A/B split lead lists and imports those rows. The tool never launches either campaign.",
5
+ description: "Prepare a campaign A/B test from a full Campaign A created through the Sellable create-campaign workflow. The helper duplicates the source campaign through the product duplicate path so B preserves the approved brief, ICP filters, message setup, and campaign-table structure before applying the B delta. sourceLeadListId is optional and must only be supplied after asking whether to split Campaign A's clean selected lead list. The tool never launches either campaign.",
6
6
  inputSchema: {
7
7
  type: "object",
8
8
  properties: {
9
9
  sourceCampaignId: {
10
10
  type: "string",
11
- description: "Optional existing source campaign ID. If omitted, campaignName and campaignBrief are required.",
11
+ description: "Required Campaign A ID. Create Campaign A through the full Sellable create-campaign workflow before calling this helper.",
12
12
  },
13
13
  sourceLeadListId: {
14
14
  type: "string",
15
- description: "Optional clean source lead-list table ID. When supplied, rows are split into A/B lead lists and imported into the draft campaigns.",
16
- },
17
- campaignName: {
18
- type: "string",
19
- description: "Base campaign name generated from the user's idea when sourceCampaignId is omitted.",
20
- },
21
- campaignBrief: {
22
- type: "string",
23
- description: "Base campaign brief generated from the user's idea when sourceCampaignId is omitted.",
24
- },
25
- offerPositioning: {
26
- type: "object",
27
- additionalProperties: true,
28
- description: "Optional offer positioning JSON to store on the newly created A campaign.",
29
- },
30
- clientProspectId: {
31
- type: "string",
32
- description: "Optional client prospect ID to store on the newly created A campaign.",
33
- },
34
- senderLinkedinUrl: {
35
- type: "string",
36
- description: "Optional sender LinkedIn profile URL to preserve in A/B metadata.",
15
+ description: "Optional clean source lead-list table ID from Campaign A. Only pass this after the user approves splitting Campaign A's lead list; when supplied, rows are split into A/B lead lists and imported into review-copy campaigns.",
37
16
  },
38
17
  variantName: {
39
18
  type: "string",
@@ -74,7 +53,7 @@ export const campaignAbTestToolDefinitions = [
74
53
  description: "Optional stable key for retrying the same A/B preparation safely.",
75
54
  },
76
55
  },
77
- required: ["variantName", "variantBriefDelta"],
56
+ required: ["sourceCampaignId", "variantName", "variantBriefDelta"],
78
57
  additionalProperties: false,
79
58
  },
80
59
  },
@@ -1214,27 +1214,6 @@ export declare const allTools: ({
1214
1214
  type: string;
1215
1215
  description: string;
1216
1216
  };
1217
- campaignName: {
1218
- type: string;
1219
- description: string;
1220
- };
1221
- campaignBrief: {
1222
- type: string;
1223
- description: string;
1224
- };
1225
- offerPositioning: {
1226
- type: string;
1227
- additionalProperties: boolean;
1228
- description: string;
1229
- };
1230
- clientProspectId: {
1231
- type: string;
1232
- description: string;
1233
- };
1234
- senderLinkedinUrl: {
1235
- type: string;
1236
- description: string;
1237
- };
1238
1217
  variantName: {
1239
1218
  type: string;
1240
1219
  description: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sellable/mcp",
3
- "version": "0.1.277",
3
+ "version": "0.1.278",
4
4
  "type": "module",
5
5
  "description": "Sellable MCP server for Claude Code and Codex campaign workflows",
6
6
  "main": "dist/index.js",
@@ -1,14 +1,24 @@
1
1
  ---
2
2
  name: create-ab-test
3
- description: Create a Sellable campaign A/B test from a clean source lead list.
3
+ description: Create a Sellable campaign A/B test by duplicating a full Campaign A.
4
4
  visibility: public
5
5
  allowed-tools:
6
6
  - mcp__sellable__get_auth_status
7
+ - mcp__sellable__bootstrap_create_campaign
8
+ - mcp__sellable__get_subskill_prompt
9
+ - mcp__sellable__get_subskill_asset
7
10
  - mcp__sellable__get_active_workspace
11
+ - mcp__sellable__fetch_linkedin_profile
12
+ - mcp__sellable__complete_sender_research
13
+ - mcp__sellable__create_campaign
14
+ - mcp__sellable__update_campaign_brief
15
+ - mcp__sellable__update_campaign
16
+ - mcp__sellable__save_rubrics
8
17
  - mcp__sellable__get_campaign
9
18
  - mcp__sellable__get_campaign_context
10
19
  - mcp__sellable__get_campaign_navigation_state
11
20
  - mcp__sellable__get_campaign_messages_preview
21
+ - mcp__sellable__duplicate_campaign
12
22
  - mcp__sellable__prepare_campaign_ab_test
13
23
  - mcp__sellable__load_csv_linkedin_leads
14
24
  - mcp__sellable__wait_for_lead_list_ready
@@ -24,46 +34,65 @@ campaign-message approaches from the same source list.
24
34
 
25
35
  ## Opening Contract
26
36
 
27
- Start by identifying the campaign idea and the one variable being tested. A
28
- source campaign and clean source lead list are both optional: use an existing
29
- campaign when the user already has one, use a clean source lead list when leads
30
- are already available, or use only the idea by writing a campaign name and base
31
- brief for A. The tool creates A first, duplicates A into B, applies the B delta,
32
- and stops for review. The goal is two review-copy campaigns, not a launched
33
- campaign.
37
+ Start by identifying the campaign idea and the one variable being tested.
38
+ Campaign A must be a real, fully prepared Sellable campaign before this A/B
39
+ helper runs. If the user only supplied an idea, first run the normal
40
+ `$sellable:create-campaign` flow for Campaign A: research the sender/company,
41
+ create the campaign shell, build and approve the campaign brief, source or
42
+ attach leads when appropriate, save any approved ICP filters, and get the
43
+ message/template state into the campaign brief. Do not call
44
+ `prepare_campaign_ab_test` with only `campaignName`/`campaignBrief`.
45
+
46
+ Once Campaign A exists, the A/B step duplicates Campaign A through Sellable's
47
+ product duplicate path and applies only the B variant delta. This preserves the
48
+ approved brief, ICP filters, message setup, rubrics, and campaign-table
49
+ structure so the test differs only by the chosen variable and, if approved, the
50
+ split lead list.
34
51
 
35
52
  ## Required Flow
36
53
 
37
54
  1. Decide the source mode:
38
- - Existing campaign mode: confirm the source campaign ID or resolve it with
55
+ - Existing Campaign A: confirm the source campaign ID or resolve it with
39
56
  `get_campaign`.
40
- - Idea-first mode: write a proper campaign name and base campaign brief from
41
- the user's idea. If the user also has leads, confirm the clean source
42
- lead-list ID or use `load_csv_linkedin_leads` first.
57
+ - Idea-only request: run the full `$sellable:create-campaign` workflow first,
58
+ then use the created campaign ID as `sourceCampaignId`.
43
59
  2. Confirm the A/B variable in plain language. Keep variant B as the explicit
44
60
  change and leave variant A as the control unless the user names an A change.
45
- 3. If a source lead list is supplied, verify it is clean. A clean source list is
61
+ 3. Inspect Campaign A with `get_campaign` and `get_campaign_context`. Confirm
62
+ the brief exists and includes the approved messaging/template state when the
63
+ campaign has reached message review.
64
+ 4. If Campaign A has a clean `selectedLeadListId`, ask the user whether to split
65
+ Campaign A's lead list for this A/B test:
66
+ - Split the lead list: pass that clean list as `sourceLeadListId`.
67
+ - Do not split yet: omit `sourceLeadListId`; Campaign B is a duplicate for
68
+ review and no rows are imported.
69
+ Never silently split a list just because Campaign A has one.
70
+ 5. If a source lead list is supplied, verify it is clean. A clean source list is
46
71
  a lead-list or signal-lead-list table, not the generated campaign workflow
47
72
  table.
48
- 4. Call `prepare_campaign_ab_test` with `dryRun: true` first.
49
- 5. Review split counts, duplicate/skipped counts, campaign names, and variant
50
- brief deltas with the user.
51
- 6. Only after review, call `prepare_campaign_ab_test` without `dryRun` using the
73
+ 6. Call `prepare_campaign_ab_test` with `dryRun: true` first.
74
+ 7. Review split counts when applicable, campaign names, and variant brief deltas
75
+ with the user.
76
+ 8. Only after review, call `prepare_campaign_ab_test` without `dryRun` using the
52
77
  same `idempotencyKey` if one was returned or supplied.
53
- 7. Return the A and B campaign IDs, split lead-list IDs, counts, and the
54
- explicit note that both campaigns are `not_started`.
78
+ 9. Return Campaign A, duplicated Campaign B, split lead-list IDs when supplied,
79
+ counts, and the explicit note that both campaigns are `not_started`.
55
80
 
56
81
  ## Tool Inputs
57
82
 
58
83
  Use one of these shapes:
59
84
 
60
- - Existing campaign mode: pass `sourceCampaignId`, `variantName`,
61
- `variantBriefDelta`, and any optional split or A-variant fields.
62
- - Idea-first mode: omit `sourceCampaignId`, pass `campaignName`,
63
- `campaignBrief`, `variantName`, and `variantBriefDelta`. If a clean lead list
64
- is available, also pass `sourceLeadListId`; otherwise leave it out. The tool
65
- creates the A campaign, then duplicates A to create B and applies the B brief
66
- delta.
85
+ - No split: pass `sourceCampaignId`, `variantName`, `variantBriefDelta`, and
86
+ any optional A-variant fields. The helper treats the source campaign as A and
87
+ duplicates it for B.
88
+ - Approved split: pass `sourceCampaignId`, the approved clean
89
+ `sourceLeadListId`, `variantName`, `variantBriefDelta`, and any optional split
90
+ or A-variant fields. The helper creates deterministic A/B split lead lists and
91
+ review-copy campaigns from Campaign A.
92
+
93
+ Do not pass `campaignName`, `campaignBrief`, `offerPositioning`,
94
+ `clientProspectId`, or `senderLinkedinUrl` to `prepare_campaign_ab_test`.
95
+ Those belong to the full create-campaign workflow that creates Campaign A.
67
96
 
68
97
  ## Anti-Patterns
69
98
 
@@ -82,18 +111,18 @@ If the source campaign has no clean source lead list, or the source list is
82
111
  polluted with workflow/output columns, ask for the original CSV or clean source
83
112
  list. Use `load_csv_linkedin_leads`; it strips Sellable workflow columns if a
84
113
  contaminated CSV is supplied, then creates a clean lead list. If no clean source
85
- is available, continue in idea-first mode without `sourceLeadListId`.
114
+ is available, omit `sourceLeadListId` and create only the B duplicate for review.
86
115
 
87
116
  ## Output Contract
88
117
 
89
118
  Report:
90
119
 
91
- - source campaign ID, or note that the A campaign was created as the source
92
- campaign when no source campaign was provided
120
+ - source Campaign A ID
93
121
  - source lead-list ID when supplied
94
122
  - split strategy and counts when a source lead list was supplied
95
123
  - duplicate/skipped lead counts when a source lead list was supplied
96
- - A review campaign ID and split lead-list ID when supplied
97
- - B review campaign ID and split lead-list ID when supplied
124
+ - Campaign A ID, or A review-copy campaign ID when a split was approved
125
+ - duplicated Campaign B ID
126
+ - split lead-list IDs when supplied
98
127
  - variant difference
99
128
  - `launchState: not_started` for both campaigns