@sellable/mcp 0.1.254 → 0.1.256

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/dist/api.d.ts CHANGED
@@ -10,8 +10,11 @@ export declare class SellableApiError extends Error {
10
10
  constructor(status: number, body: string, guidance?: string);
11
11
  }
12
12
  export declare class SellableApi {
13
+ private buildError;
14
+ private requestResponse;
13
15
  private request;
14
16
  get<T>(path: string): Promise<T>;
17
+ getText(path: string): Promise<string>;
15
18
  post<T>(path: string, body?: object): Promise<T>;
16
19
  put<T>(path: string, body?: object): Promise<T>;
17
20
  patch<T>(path: string, body?: object): Promise<T>;
package/dist/api.js CHANGED
@@ -14,7 +14,21 @@ export class SellableApiError extends Error {
14
14
  }
15
15
  }
16
16
  export class SellableApi {
17
- async request(method, path, body) {
17
+ buildError(status, errorText) {
18
+ const isAuthError = status === 401 || status === 403;
19
+ const missingWorkspace = status === 400 && errorText.includes("Workspace");
20
+ const guidance = isAuthError
21
+ ? "Sellable authentication failed.\n\n" +
22
+ `Update ${getConfigPath()} with a valid token from Sellable Settings -> Integrations, then retry.\n\n` +
23
+ "NOTE: If the token was just updated via the LLM (editing the config file), " +
24
+ "the change should take effect immediately. If it still fails, restart Claude Code to restart the MCP server."
25
+ : missingWorkspace
26
+ ? "No active workspace selected.\n\n" +
27
+ "Run list_workspaces then set_active_workspace to choose a workspace."
28
+ : undefined;
29
+ return new SellableApiError(status, errorText, guidance);
30
+ }
31
+ async requestResponse(method, path, body) {
18
32
  // Re-read config on every request so workspace switches take effect immediately
19
33
  const config = getConfig();
20
34
  const url = `${config.apiUrl}${path}`;
@@ -30,24 +44,21 @@ export class SellableApi {
30
44
  });
31
45
  if (!response.ok) {
32
46
  const errorText = await response.text();
33
- const isAuthError = response.status === 401 || response.status === 403;
34
- const missingWorkspace = response.status === 400 && errorText.includes("Workspace");
35
- const guidance = isAuthError
36
- ? "Sellable authentication failed.\n\n" +
37
- `Update ${getConfigPath()} with a valid token from Sellable Settings -> Integrations, then retry.\n\n` +
38
- "NOTE: If the token was just updated via the LLM (editing the config file), " +
39
- "the change should take effect immediately. If it still fails, restart Claude Code to restart the MCP server."
40
- : missingWorkspace
41
- ? "No active workspace selected.\n\n" +
42
- "Run list_workspaces then set_active_workspace to choose a workspace."
43
- : undefined;
44
- throw new SellableApiError(response.status, errorText, guidance);
47
+ throw this.buildError(response.status, errorText);
45
48
  }
49
+ return response;
50
+ }
51
+ async request(method, path, body) {
52
+ const response = await this.requestResponse(method, path, body);
46
53
  return response.json();
47
54
  }
48
55
  async get(path) {
49
56
  return this.request("GET", path);
50
57
  }
58
+ async getText(path) {
59
+ const response = await this.requestResponse("GET", path);
60
+ return response.text();
61
+ }
51
62
  async post(path, body) {
52
63
  return this.request("POST", path, body);
53
64
  }
package/dist/index-dev.js CHANGED
File without changes
package/dist/index.js CHANGED
File without changes
package/dist/server.js CHANGED
@@ -5,12 +5,12 @@ import { getSkillByName, listSkills } from "./skills.js";
5
5
  import { getAuthStatus } from "./tools/auth.js";
6
6
  import { handleAddColumn, handleCommitBlueprint, } from "./tools/blueprint-commit.js";
7
7
  import { bootstrapCreateCampaign } from "./tools/bootstrap.js";
8
- import { createCampaign, getCampaign, getCampaignMessagesPreview, getCampaigns, pauseCampaign, startCampaign, updateCampaign, updateCampaignBrief, } from "./tools/campaigns.js";
9
8
  import { getCampaignTableSchema, queueCampaignCells, reviseMessageTemplateAndRerun, selectCampaignCells, waitForCampaignProcessing, } from "./tools/campaign-processing.js";
9
+ import { createCampaign, duplicateCampaign, getCampaign, getCampaignMessagesPreview, getCampaigns, pauseCampaign, startCampaign, updateCampaign, updateCampaignBrief, } from "./tools/campaigns.js";
10
10
  import { queueCells, updateCell } from "./tools/cells.js";
11
11
  import { handleStartCliLogin, handleWaitForCliLogin, } from "./tools/cli-login.js";
12
+ import { capturePostIdeaTool, getPostDraftTool, getPostIdeaTool, getPublishedPostTool, listPostDraftIterationsTool, listPostDraftsTool, listPostIdeasTool, listPublishedPostsTool, markPostPublishedTool, saveHookResearchTool, savePostDraftTool, updatePostDraftTool, updatePublishedPostMetricsTool, } from "./tools/content-posts.js";
12
13
  import { getCampaignContext, hydrateCampaignContextFromCampaign, markCampaignContextDirty, } from "./tools/context.js";
13
- import { capturePostIdeaTool, getPublishedPostTool, getPostDraftTool, getPostIdeaTool, listPostDraftIterationsTool, listPostDraftsTool, listPostIdeasTool, listPublishedPostsTool, markPostPublishedTool, saveHookResearchTool, savePostDraftTool, updatePostDraftTool, updatePublishedPostMetricsTool, } from "./tools/content-posts.js";
14
14
  import { addToCommentCampaign, addToConnectionCampaign, addToInmailCampaign, getEngagedPosts, getOrCreateDirectCampaignTable, pauseDirectCampaign, startDirectCampaign, } from "./tools/direct-campaigns.js";
15
15
  import { bootstrapEngage, bootstrapEngageMulti, } from "./tools/engage-bootstrap.js";
16
16
  import { searchEngagementPosts } from "./tools/engage-discovery.js";
@@ -18,7 +18,7 @@ import { copySenderConfigTool, getEngageMemoryTool, migrateFlatConfigsTool, reco
18
18
  import { getEngageStateTool, setEngageStateTool, } from "./tools/engage-state.js";
19
19
  import { bulkEnrichWithProspeo, enrichWithProspeo, getProspeoCredits, } from "./tools/enrichment.js";
20
20
  import { getCampaignFramework } from "./tools/framework.js";
21
- import { cancelLeadImport, confirmProspeoCompanyAccounts, confirmLeadList, getProviderPrompt, importLeads, loadCsvDncEntriesTool, loadCsvDomains, loadCsvLinkedinLeads, lookupSalesNavFilter, saveDomainFilters, searchApollo, searchProspeoCompanies, searchProspeo, searchSalesNav, searchSignals, selectPromisingPosts, setHeadlineICPCriteria, } from "./tools/leads.js";
21
+ import { cancelLeadImport, confirmLeadList, confirmProspeoCompanyAccounts, getProviderPrompt, importLeads, loadCsvDncEntriesTool, loadCsvDomains, loadCsvLinkedinLeads, lookupSalesNavFilter, saveDomainFilters, searchApollo, searchProspeo, searchProspeoCompanies, searchSalesNav, searchSignals, selectPromisingPosts, setHeadlineICPCriteria, } from "./tools/leads.js";
22
22
  import { fetchCompany, fetchCompanyPosts, fetchLinkedInPosts, fetchLinkedInProfile, fetchPostEngagers, getLinkedInProfile, getUserPosts, } from "./tools/linkedin.js";
23
23
  import { getCampaignNavigationState } from "./tools/navigation.js";
24
24
  import { addOnDemandLeads, createOnDemandCampaign, createOnDemandTable, initOnDemandSequence, pauseOnDemandCampaign, startOnDemandCampaign, } from "./tools/one-off.js";
@@ -30,7 +30,7 @@ import { getRows, getTableRows, getTableRowsMinimal } from "./tools/rows.js";
30
30
  import { addRubricItem, checkRubric, deleteRubricItem, draftRubrics, saveRubrics, selectNecessaryRubrics, updateRubricItem, waitForRubricResults, } from "./tools/rubrics.js";
31
31
  import { getSender, listSenders } from "./tools/senders.js";
32
32
  import { attachRecommendedSequence, attachSequence, createWorkflowTable, } from "./tools/sequencer.js";
33
- import { listTables } from "./tools/tables.js";
33
+ import { exportTableCsv, listTables } from "./tools/tables.js";
34
34
  import { handleVerifyTableRow } from "./tools/verify-row.js";
35
35
  import { sanitizeWatchUrlsForMcpResult } from "./tools/watch-url-security.js";
36
36
  import { addTeammate, createWorkspace, getActiveWorkspace, listWorkspaces, setActiveWorkspace, } from "./tools/workspaces.js";
@@ -208,6 +208,12 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
208
208
  case "pause_campaign":
209
209
  result = await pauseCampaign(args?.campaignId);
210
210
  break;
211
+ case "duplicate_campaign":
212
+ result = await duplicateCampaign(args?.campaignId);
213
+ if (result?.campaignOfferId) {
214
+ markCampaignContextDirty(result.campaignOfferId, "duplicate_campaign");
215
+ }
216
+ break;
211
217
  case "update_campaign_brief":
212
218
  result = await updateCampaignBrief(args?.campaignId, args?.campaignBrief);
213
219
  if (args?.campaignId) {
@@ -277,6 +283,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
277
283
  case "list_tables":
278
284
  result = await listTables(args);
279
285
  break;
286
+ case "export_table_csv":
287
+ result = await exportTableCsv(args);
288
+ break;
280
289
  case "commit_blueprint":
281
290
  result = await handleCommitBlueprint(args);
282
291
  break;
@@ -150,6 +150,42 @@ export interface UpdateCampaignInput {
150
150
  rubric?: unknown[];
151
151
  }
152
152
  export declare const campaignToolDefinitions: ({
153
+ name: string;
154
+ description: string;
155
+ inputSchema: {
156
+ type: string;
157
+ properties: {
158
+ campaignId: {
159
+ type: string;
160
+ description: string;
161
+ };
162
+ limit?: undefined;
163
+ tableId?: undefined;
164
+ leadLimit?: undefined;
165
+ page?: undefined;
166
+ filters?: undefined;
167
+ name?: undefined;
168
+ clientProspectId?: undefined;
169
+ senderLinkedinUrl?: undefined;
170
+ offerPositioning?: undefined;
171
+ campaignBrief?: undefined;
172
+ messageGenerationMode?: undefined;
173
+ currentStep?: undefined;
174
+ watchNarration?: undefined;
175
+ leadSourceType?: undefined;
176
+ leadSourceProvider?: undefined;
177
+ selectedLeadListId?: undefined;
178
+ senderIds?: undefined;
179
+ interactionMode?: undefined;
180
+ enableICPFilters?: undefined;
181
+ useMessagingTemplate?: undefined;
182
+ rubric?: undefined;
183
+ flowVersion?: undefined;
184
+ };
185
+ required: string[];
186
+ additionalProperties: boolean;
187
+ };
188
+ } | {
153
189
  name: string;
154
190
  description: string;
155
191
  inputSchema: {
@@ -600,6 +636,11 @@ export declare function startCampaign(campaignId: string): Promise<{
600
636
  export declare function pauseCampaign(campaignId: string): Promise<{
601
637
  success: boolean;
602
638
  }>;
639
+ export declare function duplicateCampaign(campaignId: string): Promise<{
640
+ campaignOfferId: string;
641
+ campaignName: string;
642
+ workflowTableId: string | null;
643
+ }>;
603
644
  export declare function updateCampaignBrief(campaignId: string, campaignBrief: string): Promise<{
604
645
  success: boolean;
605
646
  campaignBrief: string;
@@ -49,8 +49,7 @@ function getCampaignBuilderWatchModeFromUrl(watchUrl) {
49
49
  export function getCampaignBuilderWatchModeDriverLabel(mode = getCampaignBuilderWatchModeParam()) {
50
50
  return mode === "codex" ? "Codex" : "Claude Code";
51
51
  }
52
- export function buildCampaignWatchHandoffMarkdown(watchUrl, mode = getCampaignBuilderWatchModeFromUrl(watchUrl) ??
53
- getCampaignBuilderWatchModeParam()) {
52
+ export function buildCampaignWatchHandoffMarkdown(watchUrl, mode = getCampaignBuilderWatchModeFromUrl(watchUrl) ?? getCampaignBuilderWatchModeParam()) {
54
53
  const driverLabel = getCampaignBuilderWatchModeDriverLabel(mode);
55
54
  const headline = `WATCH ${driverLabel.toUpperCase()} BUILD THE CAMPAIGN LIVE`;
56
55
  return [
@@ -85,6 +84,21 @@ function assertBriefHandoffWatchUrl(watchUrl, campaignId) {
85
84
  "with create_campaign({ campaignId }) or get_campaign before asking for approval.");
86
85
  }
87
86
  export const campaignToolDefinitions = [
87
+ {
88
+ name: "duplicate_campaign",
89
+ description: "Duplicate a campaign by calling Sellable's existing duplicate endpoint. Returns campaignOfferId, campaignName, and workflowTableId for the new copy.",
90
+ inputSchema: {
91
+ type: "object",
92
+ properties: {
93
+ campaignId: {
94
+ type: "string",
95
+ description: "Source campaign ID to duplicate.",
96
+ },
97
+ },
98
+ required: ["campaignId"],
99
+ additionalProperties: false,
100
+ },
101
+ },
88
102
  {
89
103
  name: "get_campaigns",
90
104
  description: "List campaigns for the authenticated user. Returns id, name, createdAt. Ordered by most recent first.",
@@ -845,7 +859,8 @@ export async function createCampaign(input) {
845
859
  name,
846
860
  clientProspectId,
847
861
  offerPositioning,
848
- ...(shouldPersistSourceStateOnCreate && input.leadSourceProvider !== undefined
862
+ ...(shouldPersistSourceStateOnCreate &&
863
+ input.leadSourceProvider !== undefined
849
864
  ? { leadSourceProvider: normalizedLeadSourceProvider }
850
865
  : {}),
851
866
  currentStep: effectiveCurrentStep,
@@ -950,6 +965,10 @@ export async function pauseCampaign(campaignId) {
950
965
  const api = getApi();
951
966
  return api.post(`/api/v3/campaigns/${campaignId}/pause`);
952
967
  }
968
+ export async function duplicateCampaign(campaignId) {
969
+ const api = getApi();
970
+ return api.post(`/api/v3/campaigns/${campaignId}/duplicate`);
971
+ }
953
972
  export async function updateCampaignBrief(campaignId, campaignBrief) {
954
973
  const api = getApi();
955
974
  return api.patch(`/api/v3/mcp/campaigns/${campaignId}`, { campaignBrief });