@sellable/mcp 0.1.882 → 0.1.886-wip.phase192.20260817.4

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 CHANGED
@@ -528,6 +528,23 @@ compatibility and as the tested foundation-memory engine.
528
528
 
529
529
  ## Available Tools
530
530
 
531
+ ### Table Tools (Free)
532
+
533
+ - `list_tables` - List all authorized WorkflowTables, including Lead Lists,
534
+ standalone tables, and campaign-backed tables.
535
+ - `create_table` - Create one reviewed empty standalone table without creating
536
+ a CampaignOffer, sender, sequence, or lead-list surrogate. Optional registered
537
+ initial columns can include the existing inbound webhook.
538
+ - `create_workflow_table` / `create_on_demand_table` - Existing
539
+ campaign-backed creation paths; do not use them for standalone table intent.
540
+
541
+ Lead Lists are existing WorkflowTables with `config.type=lead_list` and remain
542
+ available on the Tables (`/leads`) product surface and through their existing
543
+ lead-list creation flows. A full webhook URL returned by `create_table` is a
544
+ creator-only secret: keep it only in the authorized private creator result or
545
+ an ephemeral delivery target, never in logs, audit receipts, screenshots,
546
+ exports, shared evidence, table lists, or durable notes.
547
+
531
548
  ### Workspace Tools (Free)
532
549
 
533
550
  - `list_workspaces` - List accessible workspaces
@@ -3,14 +3,14 @@
3
3
  * manifests. Keep this free of tool implementation imports so Next can bundle
4
4
  * it; registry parity is enforced in sellable-agent-tool-policy.test.ts.
5
5
  */
6
- export declare const SELLABLE_MCP_TOOL_NAMES: readonly ["add_column", "add_on_demand_leads", "add_rubric_item", "add_teammate", "add_to_comment_campaign", "add_to_connection_campaign", "add_to_inmail_campaign", "archive_campaign", "attach_recommended_sequence", "attach_sequence", "bootstrap_create_campaign", "bootstrap_engage", "bootstrap_engage_multi", "bootstrap_find_leads", "bulk_enrich_with_prospeo", "calculate_linkedin_hook_preview", "cancel_campaign_message_preparation", "cancel_find_leads", "cancel_lead_import", "capture_post_idea", "check_inbox_reply_eligibility", "check_rubric", "commit_blueprint", "complete_sender_research", "confirm_harvest_job_companies", "confirm_lead_list", "confirm_prospeo_company_accounts", "copy_sender_config", "create_campaign", "create_on_demand_campaign", "create_on_demand_table", "create_workflow_table", "create_workspace", "decide_agent_endpoint_proposal", "delete_column", "delete_rubric_item", "draft_rubrics", "duplicate_campaign", "enrich_with_prospeo", "export_table_csv", "export_workspace_csv", "fetch_company", "fetch_company_posts", "fetch_linkedin_posts", "fetch_linkedin_profile", "fetch_post_engagers", "fill_campaign_horizon", "get_active_workspace", "get_agent_endpoint_run", "get_agent_soul", "get_auth_status", "get_campaign", "get_campaign_context", "get_campaign_framework", "get_campaign_message_preparation_status", "get_campaign_messages_preview", "get_campaign_navigation_state", "get_campaign_refill_state", "get_campaign_table_schema", "get_campaign_waterfall", "get_campaigns", "get_column_schema", "get_company_info", "get_engage_memory", "get_engage_state", "get_engaged_posts", "get_find_leads_run", "get_inbox_thread", "get_integration_connection_status", "get_linkedin_profile", "get_or_create_direct_campaign_table", "get_post_draft", "get_post_find_leads_scout_registry", "get_post_idea", "get_prospeo_credits", "get_provider_prompt", "get_published_post", "get_refill_target_plan", "get_rows", "get_rows_minimal", "get_runtime_identity", "get_scheduler_fill_capacity", "get_sender", "get_sender_routing", "get_source_scout_registry", "get_subskill_asset", "get_subskill_prompt", "get_table_rows", "get_user_posts", "get_workspace", "import_leads", "init_on_demand_sequence", "integrations_call_tool", "integrations_describe_tool", "integrations_list_tools", "list_agent_endpoint_runs", "list_agent_endpoints", "list_column_types", "list_dnc_entries", "list_post_draft_iterations", "list_post_drafts", "list_post_ideas", "list_published_posts", "list_senders", "list_subskill_prompts", "list_tables", "list_workspaces", "load_csv_dnc_entries", "load_csv_domains", "load_csv_linkedin_leads", "lookup_sales_nav_filter", "mark_post_published", "migrate_flat_configs", "opportunity_sequence_enroll", "opportunity_sequence_next_page", "opportunity_sequence_record", "pause_campaign", "pause_direct_campaign", "pause_on_demand_campaign", "preflight_find_leads_provider", "prepare_campaign_ab_test", "publish_agent_endpoint", "queue_campaign_cells", "queue_cells", "record_campaign_review_batch", "record_engage_proven_search", "refill_sends", "refill_v3_advance", "refill_v3_continue", "refill_v3_edit_selected_campaign", "refill_v3_fill_ready", "refill_v3_world_state", "refresh_paid_inmail_credits", "refresh_sender_engagement", "reissue_find_leads_watch_link", "render_linkedin_post_preview", "reorder_columns", "resolve_campaign_fill_route", "revise_message_template_and_rerun", "rotate_agent_endpoint_key", "run_scheduler_sweep", "save_domain_filters", "save_hook_research", "save_post_draft", "save_rubrics", "search_apollo", "search_available_integrations", "search_engagement_posts", "search_harvest_jobs", "search_inbox_threads", "search_prospeo", "search_prospeo_companies", "search_sales_nav", "search_signals", "search_subskill_prompts", "select_campaign_cells", "select_necessary_rubrics", "select_promising_posts", "send_inbox_draft", "send_inbox_manual_reply", "set_active_workspace", "set_campaign_waterfall_order", "set_company_info", "set_engage_state", "set_engage_style_guide", "set_headline_icp_criteria", "set_sender_calendar_link", "set_sender_routing", "setup_evergreen_campaigns", "start_campaign", "start_campaign_message_preparation", "start_cli_login", "start_direct_campaign", "start_integration_connection", "start_on_demand_campaign", "stop_agent_endpoint_run", "update_agent_soul", "update_campaign", "update_campaign_brief", "update_cell", "update_column", "update_find_leads_run", "update_inbox_draft", "update_post_draft", "update_published_post_metrics", "update_rubric_item", "upsert_engage_tracked_person", "upsert_rubric", "validate_campaign1_kickoff_handoff", "verify_table_row", "wait_for_campaign_processing", "wait_for_campaign_table_ready", "wait_for_cli_login", "wait_for_find_leads_run", "wait_for_lead_list_ready", "wait_for_rubric_results"];
6
+ export declare const SELLABLE_MCP_TOOL_NAMES: readonly ["add_column", "add_on_demand_leads", "add_rubric_item", "add_teammate", "add_to_comment_campaign", "add_to_connection_campaign", "add_to_inmail_campaign", "archive_campaign", "attach_recommended_sequence", "attach_sequence", "bootstrap_create_campaign", "bootstrap_engage", "bootstrap_engage_multi", "bootstrap_find_leads", "bulk_enrich_with_prospeo", "calculate_linkedin_hook_preview", "cancel_campaign_message_preparation", "cancel_find_leads", "cancel_lead_import", "capture_post_idea", "check_inbox_reply_eligibility", "check_rubric", "commit_blueprint", "complete_sender_research", "confirm_harvest_job_companies", "confirm_lead_list", "confirm_prospeo_company_accounts", "copy_sender_config", "create_campaign", "create_on_demand_campaign", "create_on_demand_table", "create_table", "create_workflow_table", "create_workspace", "decide_agent_endpoint_proposal", "delete_column", "delete_rubric_item", "draft_rubrics", "duplicate_campaign", "enrich_with_prospeo", "export_table_csv", "export_workspace_csv", "fetch_company", "fetch_company_posts", "fetch_linkedin_posts", "fetch_linkedin_profile", "fetch_post_engagers", "fill_campaign_horizon", "get_active_workspace", "get_agent_endpoint_run", "get_agent_soul", "get_auth_status", "get_campaign", "get_campaign_context", "get_campaign_framework", "get_campaign_message_preparation_status", "get_campaign_messages_preview", "get_campaign_navigation_state", "get_campaign_refill_state", "get_campaign_table_schema", "get_campaign_waterfall", "get_campaigns", "get_column_schema", "get_company_info", "get_engage_memory", "get_engage_state", "get_engaged_posts", "get_find_leads_run", "get_inbox_thread", "get_integration_connection_status", "get_linkedin_profile", "get_or_create_direct_campaign_table", "get_post_draft", "get_post_find_leads_scout_registry", "get_post_idea", "get_prospeo_credits", "get_provider_prompt", "get_published_post", "get_refill_target_plan", "get_rows", "get_rows_minimal", "get_runtime_identity", "get_scheduler_fill_capacity", "get_sender", "get_sender_routing", "get_source_scout_registry", "get_subskill_asset", "get_subskill_prompt", "get_table_rows", "get_user_posts", "get_workspace", "import_leads", "init_on_demand_sequence", "integrations_call_tool", "integrations_describe_tool", "integrations_list_tools", "list_agent_endpoint_runs", "list_agent_endpoints", "list_column_types", "list_dnc_entries", "list_post_draft_iterations", "list_post_drafts", "list_post_ideas", "list_published_posts", "list_senders", "list_subskill_prompts", "list_tables", "list_workspaces", "load_csv_dnc_entries", "load_csv_domains", "load_csv_linkedin_leads", "lookup_sales_nav_filter", "mark_post_published", "migrate_flat_configs", "opportunity_sequence_enroll", "opportunity_sequence_next_page", "opportunity_sequence_record", "pause_campaign", "pause_direct_campaign", "pause_on_demand_campaign", "preflight_find_leads_provider", "prepare_campaign_ab_test", "publish_agent_endpoint", "queue_campaign_cells", "queue_cells", "record_campaign_review_batch", "record_engage_proven_search", "refill_sends", "refill_v3_advance", "refill_v3_continue", "refill_v3_edit_selected_campaign", "refill_v3_fill_ready", "refill_v3_world_state", "refresh_paid_inmail_credits", "refresh_sender_engagement", "reissue_find_leads_watch_link", "render_linkedin_post_preview", "reorder_columns", "resolve_campaign_fill_route", "revise_message_template_and_rerun", "rotate_agent_endpoint_key", "run_scheduler_sweep", "save_domain_filters", "save_hook_research", "save_post_draft", "save_rubrics", "search_apollo", "search_available_integrations", "search_engagement_posts", "search_harvest_jobs", "search_inbox_threads", "search_prospeo", "search_prospeo_companies", "search_sales_nav", "search_signals", "search_subskill_prompts", "select_campaign_cells", "select_necessary_rubrics", "select_promising_posts", "send_inbox_draft", "send_inbox_manual_reply", "set_active_workspace", "set_campaign_waterfall_order", "set_company_info", "set_engage_state", "set_engage_style_guide", "set_headline_icp_criteria", "set_sender_calendar_link", "set_sender_routing", "setup_evergreen_campaigns", "start_campaign", "start_campaign_message_preparation", "start_cli_login", "start_direct_campaign", "start_integration_connection", "start_on_demand_campaign", "stop_agent_endpoint_run", "update_agent_soul", "update_campaign", "update_campaign_brief", "update_cell", "update_column", "update_find_leads_run", "update_inbox_draft", "update_post_draft", "update_published_post_metrics", "update_rubric_item", "upsert_engage_tracked_person", "upsert_rubric", "validate_campaign1_kickoff_handoff", "verify_table_row", "wait_for_campaign_processing", "wait_for_campaign_table_ready", "wait_for_cli_login", "wait_for_find_leads_run", "wait_for_lead_list_ready", "wait_for_rubric_results"];
7
7
  /**
8
8
  * Explicit mutation classification lives beside (but outside) the flat tool
9
9
  * registry. Neither this list nor `isMutatingTool` is an input to
10
10
  * `compileAgentToolPolicy`, so editing it cannot move the fleet-pinned
11
11
  * `policyHash`.
12
12
  */
13
- export declare const MUTATING_TOOL_NAMES: readonly ["publish_agent_endpoint", "rotate_agent_endpoint_key", "decide_agent_endpoint_proposal", "stop_agent_endpoint_run", "pause_campaign", "archive_campaign", "update_campaign", "fill_campaign_horizon", "set_campaign_waterfall_order", "set_sender_routing", "send_inbox_draft", "send_inbox_manual_reply", "load_csv_dnc_entries", "update_cell", "queue_cells", "check_rubric", "queue_campaign_cells", "start_campaign_message_preparation", "opportunity_sequence_enroll", "opportunity_sequence_record", "refill_v3_fill_ready", "refill_v3_edit_selected_campaign", "refill_v3_advance", "refill_v3_continue"];
13
+ export declare const MUTATING_TOOL_NAMES: readonly ["create_table", "publish_agent_endpoint", "rotate_agent_endpoint_key", "decide_agent_endpoint_proposal", "stop_agent_endpoint_run", "pause_campaign", "archive_campaign", "update_campaign", "fill_campaign_horizon", "set_campaign_waterfall_order", "set_sender_routing", "send_inbox_draft", "send_inbox_manual_reply", "load_csv_dnc_entries", "update_cell", "queue_cells", "check_rubric", "queue_campaign_cells", "start_campaign_message_preparation", "opportunity_sequence_enroll", "opportunity_sequence_record", "refill_v3_fill_ready", "refill_v3_edit_selected_campaign", "refill_v3_advance", "refill_v3_continue"];
14
14
  export declare function isMutatingTool(name: string): boolean;
15
15
  export declare const CROSS_WORKSPACE_EXPLICIT_WORKSPACE_REQUIRED: {
16
16
  readonly code: "cross_workspace_explicit_workspace_required";
@@ -35,6 +35,7 @@ export const SELLABLE_MCP_TOOL_NAMES = [
35
35
  "create_campaign",
36
36
  "create_on_demand_campaign",
37
37
  "create_on_demand_table",
38
+ "create_table",
38
39
  "create_workflow_table",
39
40
  "create_workspace",
40
41
  "decide_agent_endpoint_proposal",
@@ -208,6 +209,10 @@ export const SELLABLE_MCP_TOOL_NAMES = [
208
209
  * `policyHash`.
209
210
  */
210
211
  export const MUTATING_TOOL_NAMES = [
212
+ // Standalone table creation is a reviewed workspace mutation. Keeping this
213
+ // explicit prevents the Agent-service registry fallback from treating it as
214
+ // an AUTO call.
215
+ "create_table",
211
216
  "publish_agent_endpoint",
212
217
  "rotate_agent_endpoint_key",
213
218
  "decide_agent_endpoint_proposal",
@@ -17,6 +17,15 @@ export const DEFAULT_AGENT_TOOL_CATALOGUE = [
17
17
  handler: "saveCompanyInfoMarkdown",
18
18
  workspaceBinding: "workspaceId",
19
19
  },
20
+ {
21
+ tool: "create_table",
22
+ version: "v1",
23
+ decision: "REQUESTER_CONFIRM",
24
+ method: "POST",
25
+ route: "/api/v3/mcp/tables",
26
+ handler: "createTable",
27
+ workspaceBinding: "workspaceId",
28
+ },
20
29
  ];
21
30
  export function compileAgentToolPolicy(entries = DEFAULT_AGENT_TOOL_CATALOGUE) {
22
31
  const compiledEntries = [...entries]
@@ -179,9 +188,35 @@ export function hashApprovalArguments(args) {
179
188
  return portableSha256(JSON.stringify(canonicalize(args)));
180
189
  }
181
190
  export function canonicalAgentToolArguments(tool, args) {
182
- if (tool !== "set_company_info" || !args || typeof args !== "object") {
191
+ if (!args || typeof args !== "object") {
183
192
  return args;
184
193
  }
194
+ if (tool === "create_table") {
195
+ const { approvalId: _approvalId, ...target } = args;
196
+ return {
197
+ ...target,
198
+ ...(typeof target.workspaceId === "string"
199
+ ? { workspaceId: target.workspaceId.trim() }
200
+ : {}),
201
+ ...(typeof target.name === "string" ? { name: target.name.trim() } : {}),
202
+ ...(target.description === undefined || target.description === null
203
+ ? {}
204
+ : typeof target.description === "string"
205
+ ? {
206
+ description: target.description.trim().length === 0
207
+ ? null
208
+ : target.description.trim(),
209
+ }
210
+ : { description: target.description }),
211
+ ...(typeof target.idempotencyKey === "string"
212
+ ? { idempotencyKey: target.idempotencyKey.trim() }
213
+ : {}),
214
+ ...(target.columns === undefined ? { columns: [] } : {}),
215
+ ...(target.inboundWebhook === undefined ? { inboundWebhook: false } : {}),
216
+ };
217
+ }
218
+ if (tool !== "set_company_info")
219
+ return args;
185
220
  const input = args;
186
221
  const markdown = typeof input.companyInfoMarkdown === "string"
187
222
  ? input.companyInfoMarkdown.trim()
package/dist/server.js CHANGED
@@ -3,9 +3,9 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
3
3
  import { CallToolRequestSchema, GetPromptRequestSchema, ListPromptsRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
4
4
  import { HttpAgentApprovalEffectPort } from "./agent-approval-effect-port.js";
5
5
  import { agentIntegrationRequestActor } from "./agent-integration-request-context.js";
6
+ import { agentOpportunitySequenceContext } from "./agent-opportunity-sequence-context.js";
6
7
  import { ensureAgentScope, getAgentScope, hasRecordedAgentScope, } from "./agent-scope.js";
7
8
  import { createMcpCredentialBoundary, resolveMcpCredentialIntent, } from "./agent-service-auth.js";
8
- import { agentOpportunitySequenceContext } from "./agent-opportunity-sequence-context.js";
9
9
  import { crossWorkspaceMutationRefusal } from "./agent-tool-names.js";
10
10
  import { compileAgentToolPolicy, createAgentMcpAuthorizationHandlers, } from "./agent-tool-policy.js";
11
11
  import { getApi } from "./api.js";
@@ -75,7 +75,7 @@ import { getSenderRoutingTool, setSenderRoutingTool, } from "./tools/sender-rout
75
75
  import { getSender, listSenders, refreshPaidInmailCredits, setSenderCalendarLink, } from "./tools/senders.js";
76
76
  import { attachRecommendedSequence, attachSequence, createWorkflowTable, } from "./tools/sequencer.js";
77
77
  import { setupEvergreenCampaigns } from "./tools/setup-evergreen-campaigns.js";
78
- import { exportTableCsv, listTables } from "./tools/tables.js";
78
+ import { createTable, exportTableCsv, listTables } from "./tools/tables.js";
79
79
  import { handleVerifyTableRow } from "./tools/verify-row.js";
80
80
  import { getCampaignWaterfall, setCampaignWaterfallOrder, } from "./tools/waterfalls.js";
81
81
  import { exportWorkspaceCsv } from "./tools/workspace-export.js";
@@ -668,6 +668,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
668
668
  case "list_tables":
669
669
  result = await listTables(args);
670
670
  break;
671
+ case "create_table":
672
+ result = await createTable(args, agentEffectId);
673
+ break;
671
674
  case "export_table_csv":
672
675
  result = await exportTableCsv(args);
673
676
  break;
@@ -13054,21 +13054,139 @@ export declare const allTools: ({
13054
13054
  inputSchema: {
13055
13055
  type: string;
13056
13056
  properties: {
13057
- limit: {
13057
+ workspaceId: {
13058
+ type: string;
13059
+ minLength: number;
13060
+ maxLength: number;
13061
+ description: string;
13062
+ };
13063
+ approvalId: {
13064
+ type: string;
13065
+ minLength: number;
13066
+ maxLength: number;
13067
+ description: string;
13068
+ };
13069
+ idempotencyKey: {
13070
+ type: string;
13071
+ minLength: number;
13072
+ maxLength: number;
13073
+ description: string;
13074
+ };
13075
+ name: {
13058
13076
  type: string;
13077
+ minLength: number;
13078
+ maxLength: number;
13079
+ description: string;
13080
+ };
13081
+ description: {
13082
+ type: string[];
13083
+ maxLength: number;
13059
13084
  description: string;
13060
13085
  };
13061
- hasSequence: {
13086
+ columns: {
13062
13087
  type: string;
13063
13088
  description: string;
13089
+ items: {
13090
+ type: string;
13091
+ properties: {
13092
+ id: {
13093
+ type: string;
13094
+ minLength: number;
13095
+ maxLength: number;
13096
+ };
13097
+ name: {
13098
+ type: string;
13099
+ minLength: number;
13100
+ maxLength: number;
13101
+ };
13102
+ columnType: {
13103
+ type: string;
13104
+ enum: string[];
13105
+ };
13106
+ config: {
13107
+ type: string;
13108
+ };
13109
+ inputMapping: {
13110
+ type: string;
13111
+ additionalProperties: {
13112
+ type: string;
13113
+ };
13114
+ };
13115
+ runCondition: {
13116
+ type: string;
13117
+ };
13118
+ position: {
13119
+ type: string;
13120
+ minimum: number;
13121
+ };
13122
+ runCells: {
13123
+ type: string;
13124
+ };
13125
+ dependsOn: {
13126
+ type: string;
13127
+ items: {
13128
+ type: string;
13129
+ };
13130
+ uniqueItems: boolean;
13131
+ };
13132
+ };
13133
+ required: string[];
13134
+ additionalProperties: boolean;
13135
+ };
13136
+ };
13137
+ inboundWebhook: {
13138
+ oneOf: ({
13139
+ type: string;
13140
+ properties?: undefined;
13141
+ additionalProperties?: undefined;
13142
+ } | {
13143
+ type: string;
13144
+ properties: {
13145
+ name: {
13146
+ type: string;
13147
+ minLength: number;
13148
+ maxLength: number;
13149
+ };
13150
+ config: {
13151
+ type: string;
13152
+ };
13153
+ rateLimit: {
13154
+ type: string;
13155
+ properties: {
13156
+ maxRequests: {
13157
+ type: string;
13158
+ minimum: number;
13159
+ };
13160
+ windowSeconds: {
13161
+ type: string;
13162
+ minimum: number;
13163
+ };
13164
+ };
13165
+ required: string[];
13166
+ additionalProperties: boolean;
13167
+ };
13168
+ };
13169
+ additionalProperties: boolean;
13170
+ })[];
13171
+ description: string;
13064
13172
  };
13173
+ limit?: undefined;
13174
+ hasSequence?: undefined;
13175
+ kind?: undefined;
13176
+ webhookEnabled?: undefined;
13065
13177
  tableId?: undefined;
13066
13178
  filters?: undefined;
13067
13179
  sort?: undefined;
13068
13180
  splitRows?: undefined;
13069
13181
  };
13070
- required: never[];
13071
- additionalProperties?: undefined;
13182
+ required: string[];
13183
+ additionalProperties: boolean;
13184
+ };
13185
+ annotations: {
13186
+ readOnlyHint: boolean;
13187
+ destructiveHint: boolean;
13188
+ idempotentHint: boolean;
13189
+ openWorldHint: boolean;
13072
13190
  };
13073
13191
  } | {
13074
13192
  name: string;
@@ -13096,10 +13214,20 @@ export declare const allTools: ({
13096
13214
  };
13097
13215
  limit?: undefined;
13098
13216
  hasSequence?: undefined;
13217
+ kind?: undefined;
13218
+ webhookEnabled?: undefined;
13219
+ workspaceId?: undefined;
13220
+ approvalId?: undefined;
13221
+ idempotencyKey?: undefined;
13222
+ name?: undefined;
13223
+ description?: undefined;
13224
+ columns?: undefined;
13225
+ inboundWebhook?: undefined;
13099
13226
  };
13100
13227
  required: string[];
13101
13228
  additionalProperties: boolean;
13102
13229
  };
13230
+ annotations?: undefined;
13103
13231
  } | {
13104
13232
  name: string;
13105
13233
  description: string;
@@ -1,6 +1,7 @@
1
1
  export interface WorkflowTableListItem {
2
2
  id: string;
3
3
  name: string;
4
+ description: string | null;
4
5
  workspaceId: string | null;
5
6
  status: string | null;
6
7
  campaignStatus: string | null;
@@ -9,15 +10,68 @@ export interface WorkflowTableListItem {
9
10
  campaignOfferId: string | null;
10
11
  campaignBacked: boolean;
11
12
  hasSequence: boolean;
13
+ webhookEnabled: boolean;
12
14
  columns: number;
13
15
  rows: number;
14
16
  createdAt: string;
15
17
  updatedAt: string;
16
18
  }
19
+ export type WorkflowTableListKind = "all" | "standalone" | "campaign_backed";
17
20
  export interface ListTablesInput {
18
21
  limit?: number;
19
22
  hasSequence?: boolean;
23
+ kind?: WorkflowTableListKind;
24
+ webhookEnabled?: boolean;
20
25
  }
26
+ export type CreateTableColumnInput = {
27
+ id?: string;
28
+ name: string;
29
+ columnType: "http_request" | "ai_column" | "inbound_webhook" | "formula" | "wait" | "score_icp_mcp" | "is_open_profile" | "check_paid_inmail_credits" | "check_connection" | "view_profile" | "send_invite" | "send_dm" | "send_inmail_open" | "send_inmail_closed" | "react_and_comment" | "text" | "checkbox";
30
+ config?: Record<string, unknown>;
31
+ inputMapping?: Record<string, string>;
32
+ runCondition?: string;
33
+ position?: number;
34
+ runCells?: boolean;
35
+ dependsOn?: string[];
36
+ };
37
+ export type CreateTableInput = {
38
+ workspaceId: string;
39
+ approvalId?: string;
40
+ idempotencyKey?: string;
41
+ name: string;
42
+ description?: string | null;
43
+ columns?: CreateTableColumnInput[];
44
+ inboundWebhook?: boolean | {
45
+ name?: string;
46
+ config?: Record<string, unknown>;
47
+ rateLimit?: {
48
+ maxRequests: number;
49
+ windowSeconds: number;
50
+ };
51
+ };
52
+ };
53
+ export type CreateTableResult = {
54
+ id: string;
55
+ name: string;
56
+ description: string | null;
57
+ workspaceId: string;
58
+ status: string;
59
+ campaignBacked: false;
60
+ columns: Array<{
61
+ id: string;
62
+ name: string;
63
+ columnType: string;
64
+ position: number;
65
+ dependsOnColumnIds: string[];
66
+ }>;
67
+ createdAt: string;
68
+ updatedAt: string;
69
+ webhook?: {
70
+ columnId: string;
71
+ url: string;
72
+ sensitive: true;
73
+ };
74
+ };
21
75
  export interface ExportTableCsvInput {
22
76
  tableId: string;
23
77
  filters?: unknown[];
@@ -38,13 +92,170 @@ export declare const tableToolDefinitions: ({
38
92
  type: string;
39
93
  description: string;
40
94
  };
95
+ kind: {
96
+ type: string;
97
+ enum: string[];
98
+ description: string;
99
+ };
100
+ webhookEnabled: {
101
+ type: string;
102
+ description: string;
103
+ };
104
+ workspaceId?: undefined;
105
+ approvalId?: undefined;
106
+ idempotencyKey?: undefined;
107
+ name?: undefined;
108
+ description?: undefined;
109
+ columns?: undefined;
110
+ inboundWebhook?: undefined;
41
111
  tableId?: undefined;
42
112
  filters?: undefined;
43
113
  sort?: undefined;
44
114
  splitRows?: undefined;
45
115
  };
46
116
  required: never[];
47
- additionalProperties?: undefined;
117
+ additionalProperties: boolean;
118
+ };
119
+ annotations?: undefined;
120
+ } | {
121
+ name: string;
122
+ description: string;
123
+ inputSchema: {
124
+ type: string;
125
+ properties: {
126
+ workspaceId: {
127
+ type: string;
128
+ minLength: number;
129
+ maxLength: number;
130
+ description: string;
131
+ };
132
+ approvalId: {
133
+ type: string;
134
+ minLength: number;
135
+ maxLength: number;
136
+ description: string;
137
+ };
138
+ idempotencyKey: {
139
+ type: string;
140
+ minLength: number;
141
+ maxLength: number;
142
+ description: string;
143
+ };
144
+ name: {
145
+ type: string;
146
+ minLength: number;
147
+ maxLength: number;
148
+ description: string;
149
+ };
150
+ description: {
151
+ type: string[];
152
+ maxLength: number;
153
+ description: string;
154
+ };
155
+ columns: {
156
+ type: string;
157
+ description: string;
158
+ items: {
159
+ type: string;
160
+ properties: {
161
+ id: {
162
+ type: string;
163
+ minLength: number;
164
+ maxLength: number;
165
+ };
166
+ name: {
167
+ type: string;
168
+ minLength: number;
169
+ maxLength: number;
170
+ };
171
+ columnType: {
172
+ type: string;
173
+ enum: string[];
174
+ };
175
+ config: {
176
+ type: string;
177
+ };
178
+ inputMapping: {
179
+ type: string;
180
+ additionalProperties: {
181
+ type: string;
182
+ };
183
+ };
184
+ runCondition: {
185
+ type: string;
186
+ };
187
+ position: {
188
+ type: string;
189
+ minimum: number;
190
+ };
191
+ runCells: {
192
+ type: string;
193
+ };
194
+ dependsOn: {
195
+ type: string;
196
+ items: {
197
+ type: string;
198
+ };
199
+ uniqueItems: boolean;
200
+ };
201
+ };
202
+ required: string[];
203
+ additionalProperties: boolean;
204
+ };
205
+ };
206
+ inboundWebhook: {
207
+ oneOf: ({
208
+ type: string;
209
+ properties?: undefined;
210
+ additionalProperties?: undefined;
211
+ } | {
212
+ type: string;
213
+ properties: {
214
+ name: {
215
+ type: string;
216
+ minLength: number;
217
+ maxLength: number;
218
+ };
219
+ config: {
220
+ type: string;
221
+ };
222
+ rateLimit: {
223
+ type: string;
224
+ properties: {
225
+ maxRequests: {
226
+ type: string;
227
+ minimum: number;
228
+ };
229
+ windowSeconds: {
230
+ type: string;
231
+ minimum: number;
232
+ };
233
+ };
234
+ required: string[];
235
+ additionalProperties: boolean;
236
+ };
237
+ };
238
+ additionalProperties: boolean;
239
+ })[];
240
+ description: string;
241
+ };
242
+ limit?: undefined;
243
+ hasSequence?: undefined;
244
+ kind?: undefined;
245
+ webhookEnabled?: undefined;
246
+ tableId?: undefined;
247
+ filters?: undefined;
248
+ sort?: undefined;
249
+ splitRows?: undefined;
250
+ };
251
+ required: string[];
252
+ additionalProperties: boolean;
253
+ };
254
+ annotations: {
255
+ readOnlyHint: boolean;
256
+ destructiveHint: boolean;
257
+ idempotentHint: boolean;
258
+ openWorldHint: boolean;
48
259
  };
49
260
  } | {
50
261
  name: string;
@@ -72,12 +283,23 @@ export declare const tableToolDefinitions: ({
72
283
  };
73
284
  limit?: undefined;
74
285
  hasSequence?: undefined;
286
+ kind?: undefined;
287
+ webhookEnabled?: undefined;
288
+ workspaceId?: undefined;
289
+ approvalId?: undefined;
290
+ idempotencyKey?: undefined;
291
+ name?: undefined;
292
+ description?: undefined;
293
+ columns?: undefined;
294
+ inboundWebhook?: undefined;
75
295
  };
76
296
  required: string[];
77
297
  additionalProperties: boolean;
78
298
  };
299
+ annotations?: undefined;
79
300
  })[];
80
301
  export declare function listTables(input: ListTablesInput): Promise<WorkflowTableListItem[]>;
302
+ export declare function createTable(input: CreateTableInput, agentEffectId?: string): Promise<CreateTableResult>;
81
303
  export declare function exportTableCsv(input: ExportTableCsvInput): Promise<{
82
304
  tableId: string;
83
305
  endpoint: string;
@@ -19,8 +19,135 @@ export const tableToolDefinitions = [
19
19
  type: "boolean",
20
20
  description: "Optional filter: true for sequence tables only, false for tables without sequences",
21
21
  },
22
+ kind: {
23
+ type: "string",
24
+ enum: ["all", "standalone", "campaign_backed"],
25
+ description: "Optional pre-pagination classification filter. standalone excludes campaign-backed tables; campaign_backed requires a CampaignOffer relation or legacy campaign identity.",
26
+ },
27
+ webhookEnabled: {
28
+ type: "boolean",
29
+ description: "Optional pre-pagination filter for tables with an inbound_webhook column.",
30
+ },
22
31
  },
23
32
  required: [],
33
+ additionalProperties: false,
34
+ },
35
+ },
36
+ {
37
+ name: "create_table",
38
+ description: "Create an empty standalone WorkflowTable in an explicitly named workspace, without creating a campaign, sender, sequence, or lead-list surrogate. Optionally add registered columns and one server-credentialed inbound webhook. The webhook URL is sensitive and is returned only in this authorized private creator result; never copy it into logs, evidence, screenshots, shared documents, or list output. Agent-service calls require requester confirmation; after approval, retry the exact same arguments with the returned approvalId. An idempotencyKey makes exact retries converge, but the key is optional, so the tool is truthfully not globally idempotent.",
39
+ inputSchema: {
40
+ type: "object",
41
+ properties: {
42
+ workspaceId: {
43
+ type: "string",
44
+ minLength: 1,
45
+ maxLength: 200,
46
+ description: "Exact workspace ID. Required even when an active workspace is configured.",
47
+ },
48
+ approvalId: {
49
+ type: "string",
50
+ minLength: 1,
51
+ maxLength: 160,
52
+ description: "The APPROVED approvalId returned by the first confirmation-required create_table attempt for these exact arguments. Transport-only; it is not persisted on the table.",
53
+ },
54
+ idempotencyKey: {
55
+ type: "string",
56
+ minLength: 1,
57
+ maxLength: 512,
58
+ description: "Optional caller-stable key. Exact replay returns the original table; reuse with different arguments is rejected.",
59
+ },
60
+ name: {
61
+ type: "string",
62
+ minLength: 1,
63
+ maxLength: 200,
64
+ description: "Standalone table name.",
65
+ },
66
+ description: {
67
+ type: ["string", "null"],
68
+ maxLength: 4000,
69
+ description: "Optional table description.",
70
+ },
71
+ columns: {
72
+ type: "array",
73
+ description: "Optional initial registered columns. Dependencies may reference an initial column by ID, name, or unambiguous type.",
74
+ items: {
75
+ type: "object",
76
+ properties: {
77
+ id: { type: "string", minLength: 1, maxLength: 200 },
78
+ name: { type: "string", minLength: 1, maxLength: 200 },
79
+ columnType: {
80
+ type: "string",
81
+ enum: [
82
+ "http_request",
83
+ "ai_column",
84
+ "inbound_webhook",
85
+ "formula",
86
+ "wait",
87
+ "score_icp_mcp",
88
+ "is_open_profile",
89
+ "check_paid_inmail_credits",
90
+ "check_connection",
91
+ "view_profile",
92
+ "send_invite",
93
+ "send_dm",
94
+ "send_inmail_open",
95
+ "send_inmail_closed",
96
+ "react_and_comment",
97
+ "text",
98
+ "checkbox",
99
+ ],
100
+ },
101
+ config: { type: "object" },
102
+ inputMapping: {
103
+ type: "object",
104
+ additionalProperties: { type: "string" },
105
+ },
106
+ runCondition: { type: "string" },
107
+ position: { type: "integer", minimum: 0 },
108
+ runCells: { type: "boolean" },
109
+ dependsOn: {
110
+ type: "array",
111
+ items: { type: "string" },
112
+ uniqueItems: true,
113
+ },
114
+ },
115
+ required: ["name", "columnType"],
116
+ additionalProperties: false,
117
+ },
118
+ },
119
+ inboundWebhook: {
120
+ oneOf: [
121
+ { type: "boolean" },
122
+ {
123
+ type: "object",
124
+ properties: {
125
+ name: { type: "string", minLength: 1, maxLength: 200 },
126
+ config: { type: "object" },
127
+ rateLimit: {
128
+ type: "object",
129
+ properties: {
130
+ maxRequests: { type: "integer", minimum: 1 },
131
+ windowSeconds: { type: "integer", minimum: 1 },
132
+ },
133
+ required: ["maxRequests", "windowSeconds"],
134
+ additionalProperties: false,
135
+ },
136
+ },
137
+ additionalProperties: false,
138
+ },
139
+ ],
140
+ description: "Optional existing inbound-webhook column shorthand. The server generates the credential; never supply a webhook token.",
141
+ },
142
+ },
143
+ required: ["workspaceId", "name"],
144
+ additionalProperties: false,
145
+ },
146
+ annotations: {
147
+ readOnlyHint: false,
148
+ destructiveHint: false,
149
+ idempotentHint: false,
150
+ openWorldHint: false,
24
151
  },
25
152
  },
26
153
  {
@@ -58,11 +185,32 @@ export async function listTables(input) {
58
185
  if (input.hasSequence !== undefined) {
59
186
  params.set("hasSequence", String(input.hasSequence));
60
187
  }
188
+ if (input.kind !== undefined) {
189
+ params.set("kind", input.kind);
190
+ }
191
+ if (input.webhookEnabled !== undefined) {
192
+ params.set("webhookEnabled", String(input.webhookEnabled));
193
+ }
61
194
  const queryString = params.toString();
62
195
  const path = `/api/v3/mcp/tables${queryString ? `?${queryString}` : ""}`;
63
196
  const result = await api.get(path);
64
197
  return result.tables;
65
198
  }
199
+ export async function createTable(input, agentEffectId) {
200
+ const workspaceId = input.workspaceId?.trim();
201
+ if (!workspaceId) {
202
+ throw new Error("workspaceId is required for create_table");
203
+ }
204
+ // approvalId is an MCP authorization transport. The backend receives only
205
+ // the exact mutation target that the approval/effect argument hash binds.
206
+ const { approvalId: _approvalId, ...target } = input;
207
+ const api = getApi();
208
+ const response = await api.post("/api/v3/mcp/tables", { ...target, workspaceId }, {
209
+ workspaceId,
210
+ ...(agentEffectId ? { agentEffectId } : {}),
211
+ });
212
+ return response.table;
213
+ }
66
214
  const csvEscape = (value) => {
67
215
  const text = value == null ? "" : String(value);
68
216
  if (/[",\n\r]/.test(text)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sellable/mcp",
3
- "version": "0.1.882",
3
+ "version": "0.1.886-wip.phase192.20260817.4",
4
4
  "type": "module",
5
5
  "description": "Sellable MCP server for Claude Code, Codex, and Hermes campaign workflows",
6
6
  "main": "dist/index.js",
@@ -28,6 +28,27 @@ directly for that narrow case, or use `sellable:update_column`,
28
28
  `sellable:delete_column`, and `sellable:reorder_columns` for explicit edits to
29
29
  an existing table.
30
30
 
31
+ ## Choose the table owner first
32
+
33
+ Use `sellable:create_table` when the user wants a new empty standalone table or
34
+ a campaign-independent table to configure with this workflow. It creates a
35
+ WorkflowTable directly and must not create a CampaignOffer, sender, sequence,
36
+ or lead-list surrogate. After its reviewed creation succeeds, use the returned
37
+ table id as the blueprint target.
38
+
39
+ Lead Lists are WorkflowTables with `config.type=lead_list`; they remain visible
40
+ on Tables (`/leads`) and must still be created through the existing lead-list
41
+ workflow. `sellable:create_workflow_table` and
42
+ `sellable:create_on_demand_table` remain campaign-backed creation paths. Do not
43
+ substitute either one when the user asked for an empty standalone table.
44
+
45
+ If standalone creation enables inbound webhook intake, treat the returned full
46
+ URL as a creator-only webhook URL: it may appear only in the authorized private
47
+ creator result/conversation and as an ephemeral request target. Never copy it
48
+ into logs, audit receipts, screenshots, exported/shared evidence, table lists,
49
+ or durable skill memory. Creating a standalone table must not post to Slack or
50
+ publish to LinkedIn.
51
+
31
52
  ## Reasoning checklist
32
53
 
33
54
  Before writing any blueprint JSON:
@@ -226,6 +247,8 @@ production behavior.
226
247
 
227
248
  ## Tool inventory
228
249
 
250
+ - `sellable:create_table`: create one reviewed empty standalone WorkflowTable,
251
+ optionally enabling the existing inbound-webhook runtime, without a campaign.
229
252
  - `sellable:commit_blueprint`: validate and atomically commit the full table
230
253
  blueprint in dependency order.
231
254
  - `sellable:add_column`: add one column to an already-committed table when the