scrapeloop-mcp 0.31.2 → 0.33.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/package.json +1 -1
- package/src/index.js +10 -8
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "scrapeloop-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.33.0",
|
|
4
4
|
"description": "Scrapeloop MCP server - set up and run Scrapeloop end-to-end (integrations, scraping, lead database, verification, cleaners, enrichment, strategies, Instantly campaigns) from any MCP client (Claude Desktop, Cursor, ChatGPT, …).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
package/src/index.js
CHANGED
|
@@ -46,6 +46,8 @@ const NATIVE_TABLE_TOOLS = Object.freeze([
|
|
|
46
46
|
'verify_phone',
|
|
47
47
|
'email_finder',
|
|
48
48
|
'business_email_finder',
|
|
49
|
+
'linkedin_finder',
|
|
50
|
+
'linkedin_activity',
|
|
49
51
|
]);
|
|
50
52
|
const TRACE_HEADER = 'X-Scrapeloop-Trace-Id';
|
|
51
53
|
const SAFE_TRACE_ID = /^[A-Za-z0-9_-]{8,80}$/;
|
|
@@ -372,7 +374,7 @@ const PLAN_FIELDS = {
|
|
|
372
374
|
chunk_interval_minutes: { type: 'integer', minimum: 0 },
|
|
373
375
|
chunk_order: { ...S, enum: ['sequential', 'largest_first', 'balanced'] },
|
|
374
376
|
rescrape_covered: B, min_age_days: { type: 'integer', minimum: 1 },
|
|
375
|
-
rescrape_after_days: { type: 'integer', minimum: 1 },
|
|
377
|
+
rescrape_after_days: { type: ['integer', 'null'], minimum: 1, maximum: 3650 },
|
|
376
378
|
};
|
|
377
379
|
const PLAN_REQUIRED = ['name', 'kind', 'country', 'granularity', 'locations', 'categories', 'run_mode'];
|
|
378
380
|
|
|
@@ -551,7 +553,7 @@ const TOOLS = {
|
|
|
551
553
|
},
|
|
552
554
|
create_scrape_plan: {
|
|
553
555
|
def: {
|
|
554
|
-
description: 'Save a scrape plan into an existing writable Table. Native coverage_mode complete requires start_mode draft, a stable scope_operation_id and no monthly raw-row caps
|
|
556
|
+
description: 'Save a scrape plan into an existing writable Table. Native coverage_mode complete requires start_mode draft, a stable scope_operation_id and no monthly raw-row caps. Optional rescrape_after_days waits until the full pass finishes, then waits the saved delay; old journals and monthly credit limits are preserved. It saves the whole scope in restartable batches and requires saved shared budgets and the exact complete-plan launch review before Start. Set start_mode to draft to save without starting searches or spending. The default active mode starts approved work and can spend credits or vendor money. Preview the exact choices first and stay within the approved limit and time period. Pass explicit territory values and matching billing limits. Reuse the same idempotency_key after a lost reply, inspect list_scrape_plans and never create a second plan to escape an uncertain result. Over-time limits reset monthly; a total one-time approval does not authorize recurring spend.',
|
|
555
557
|
inputSchema: obj({ ...PLAN_FIELDS, scope_operation_id: { ...S, format: 'uuid' }, target_list_id: { ...S, format: 'uuid' }, start_mode: { ...S, enum: ['active', 'draft'] } }, [...PLAN_REQUIRED, 'target_list_id']),
|
|
556
558
|
},
|
|
557
559
|
run: ({ idempotency_key: _key, ...body }) => api('POST', '/plans', body),
|
|
@@ -573,7 +575,7 @@ const TOOLS = {
|
|
|
573
575
|
run: (a) => api('GET', `/plans/${enc(a.plan_id)}/yield`),
|
|
574
576
|
},
|
|
575
577
|
set_scrape_plan_ready_goal: {
|
|
576
|
-
def: { description: 'Save a verified-email goal on a native Maps draft
|
|
578
|
+
def: { description: 'Save a verified-email goal on a native Maps draft with optional whole-scope repeat searches after the saved delay. Choose the ready Table and its email campaign, monthly goal/minimum, optional hard-maximum mode, unused-stock ceiling and evidence rules. Pass the reviewed expected_updated_at from get_scrape_plan. Counts require current input-bound verification, qualification, campaign fields and sender-history checks. This does not start scraping, verification or campaigns. Complete-search pacing must be available before Start.', inputSchema: obj({
|
|
577
579
|
plan_id: { ...S, format: 'uuid' }, expected_updated_at: { ...S, format: 'date-time' },
|
|
578
580
|
goal: obj({ kind: { ...S, enum: ['verified_email'] }, ready_list_id: { ...S, format: 'uuid' },
|
|
579
581
|
campaign_id: { ...S, format: 'uuid' }, monthly_goal: { type: 'integer', minimum: 1, maximum: 1000000 },
|
|
@@ -607,7 +609,7 @@ const TOOLS = {
|
|
|
607
609
|
run: ({ plan_id, ...body }) => api('PUT', `/plans/${enc(plan_id)}/budget`, body),
|
|
608
610
|
},
|
|
609
611
|
review_complete_scrape_plan: {
|
|
610
|
-
def: { description: 'Read the exact complete-search scope, ready-output goal, Table rules, shared limits and current launch blockers. Free read. This does not start source work, checks or campaigns.', inputSchema: obj({ plan_id: { ...S, format: 'uuid' } }, ['plan_id']) },
|
|
612
|
+
def: { description: 'Read the exact complete-search scope, ready-output goal, Table rules, shared limits, repeat delay and current launch blockers. Free read. This does not start source work, checks or campaigns.', inputSchema: obj({ plan_id: { ...S, format: 'uuid' } }, ['plan_id']) },
|
|
611
613
|
run: (a) => api('GET', `/plans/${enc(a.plan_id)}/launch-review`),
|
|
612
614
|
},
|
|
613
615
|
launch_complete_scrape_plan: {
|
|
@@ -1117,7 +1119,7 @@ const TOOLS = {
|
|
|
1117
1119
|
sender_options: { ...O, description: "GoHighLevel SMS choices: workflow_id, tags, require_verified_mobile, voip_counts_as_mobile, missing_fields (ask, create, never)." },
|
|
1118
1120
|
icon: { type: ["string", "null"], description: "One or two emoji, or null to clear." },
|
|
1119
1121
|
source_list_id: S,
|
|
1120
|
-
eligibility_rule: { type: ["object", "null"], additionalProperties: false, required: ["source_list_id", "filter"], properties: { source_list_id: S, filter: O }, description: "Optional Current qualification: an open static evidence Table and nonempty current lead/column conditions.
|
|
1122
|
+
eligibility_rule: { type: ["object", "null"], additionalProperties: false, required: ["source_list_id", "filter"], properties: { source_list_id: S, filter: O, excluded_campaign_ids: { type: 'array', items: S, maxItems: 20 } }, description: "Optional Current qualification: an open static evidence Table and nonempty current lead/column conditions. Optionally list other campaign IDs whose existing business place IDs must be held, even when the email differs. Null turns this check off." },
|
|
1121
1123
|
segment_id: S,
|
|
1122
1124
|
sender_credential_id: S,
|
|
1123
1125
|
external_list_id: S,
|
|
@@ -1160,7 +1162,7 @@ const TOOLS = {
|
|
|
1160
1162
|
run: (a) => api('GET', `/campaigns/${enc(a.campaign_id)}/qualification`),
|
|
1161
1163
|
},
|
|
1162
1164
|
update_campaign: {
|
|
1163
|
-
def: { description: 'Patch a campaign (feed_mode, target_active_count, cooldown_days, external_list_id, …). Switching feed_mode on for an already active campaign runs the same check as campaign_readiness_check: any fail answers 422 with the report under detail.readiness.', inputSchema: obj({ campaign_id: S, patch: { ...O, description: "Campaign settings to change. eligibility_rule uses {source_list_id, filter} for Current qualification, or null to turn it off. qualification: {} disables the Belgium website language gate; {rule: be_dutch, evidence_column_id: UUID, max_age_days: 90} enables it. Read back after saving. These settings do not start checks or remove sender leads.", properties: { eligibility_rule: { type: ["object", "null"], additionalProperties: false, required: ["source_list_id", "filter"], properties: { source_list_id: S, filter: O } }, qualification: { ...O, description: "Belgium website language rule, or {} to disable." }, sender_options: { ...O, description: "GoHighLevel SMS settings. Only supplied keys change." }, icon: { type: ["string", "null"], description: "One or two emoji, or null to clear." } }, additionalProperties: true } }, ['campaign_id', 'patch']) },
|
|
1165
|
+
def: { description: 'Patch a campaign (feed_mode, target_active_count, cooldown_days, external_list_id, …). Switching feed_mode on for an already active campaign runs the same check as campaign_readiness_check: any fail answers 422 with the report under detail.readiness.', inputSchema: obj({ campaign_id: S, patch: { ...O, description: "Campaign settings to change. eligibility_rule uses {source_list_id, filter, optional excluded_campaign_ids} for Current qualification, or null to turn it off. The optional campaign IDs hold businesses already in those campaigns by Google place ID. qualification: {} disables the Belgium website language gate; {rule: be_dutch, evidence_column_id: UUID, max_age_days: 90} enables it. Read back after saving. These settings do not start checks or remove sender leads.", properties: { eligibility_rule: { type: ["object", "null"], additionalProperties: false, required: ["source_list_id", "filter"], properties: { source_list_id: S, filter: O, excluded_campaign_ids: { type: 'array', items: S, maxItems: 20 } } }, qualification: { ...O, description: "Belgium website language rule, or {} to disable." }, sender_options: { ...O, description: "GoHighLevel SMS settings. Only supplied keys change." }, icon: { type: ["string", "null"], description: "One or two emoji, or null to clear." } }, additionalProperties: true } }, ['campaign_id', 'patch']) },
|
|
1164
1166
|
run: (a) => api('PATCH', `/campaigns/${enc(a.campaign_id)}`, a.patch || {}),
|
|
1165
1167
|
},
|
|
1166
1168
|
duplicate_campaign: {
|
|
@@ -1683,7 +1685,7 @@ const TOOLS = {
|
|
|
1683
1685
|
create_table_native_column: {
|
|
1684
1686
|
def: {
|
|
1685
1687
|
description:
|
|
1686
|
-
`Attach one native Scrapeloop tool as a real Smart Table column: ${NATIVE_TABLE_TOOLS.join(', ')}. These are
|
|
1688
|
+
`Attach one native Scrapeloop tool as a real Smart Table column: ${NATIVE_TABLE_TOOLS.join(', ')}. These are Scrapeloop's first-party tools, several of which superseded legacy presets, so they are addressed by tool key here rather than by preset slug through create_table_preset_column (which refuses a superseded slug for a new column). Each bills MANAGED VERIFICATION CREDITS per row, never dollars and never the customer's own vendor keys: verify_email reserves 1 credit per selected row, verify_phone reserves 5, each email finder reserves 3, linkedin_finder reserves 5, and linkedin_activity reserves 3. Settlement charges only fresh vendor checks and returns the unused reservation; missing inputs, cached rows, and skipped rows are free. linkedin_finder charges its 5 credits only for a row where it found the owner's LinkedIn profile; a row with no owner found is free. linkedin_activity reads each row's personal LinkedIn profile and newest post and labels it Active, Maybe or Weak (cell text), so LinkedIn invites go to people likely to answer; it charges 3 credits only for a profile it read, and rows with no personal profile, cached rows and profiles that no longer exist are free. Creating a column is always free. auto_run defaults false and queues nothing; when auto_run would backfill existing rows the API returns a 409 estimate whose cost.total_credits is the real charge, and you confirm it with confirm_auto_run plus confirmed_credits (CREDITS, not dollars - estimated_cost_usd is our vendor cost and is far smaller than what the workspace is billed). An auto_run that exceeds the workspace verify-credit balance returns 402 with {credit_kind, required, available} before anything is created. The Table master auto-run switch and workspace budget caps stay fail-closed. options are per tool and only the documented names are accepted - call get_table_native_tools for the current list. Owner email finder needs an owner first name plus the company website; point options.owner_name_column at an Owner name finder column to source the name, which auto_run requires. Business email finder is a SEPARATE column - create it with its own call and set options.owner_email_column to run it behind an owner finder. The Catch-all verifier is NOT creatable here: it needs a Verify email column that has already RUN and returned Catch All or Unknown, so use verify_catchall per address, or add the column from the Table's add-column menu.`,
|
|
1687
1689
|
inputSchema: obj(
|
|
1688
1690
|
{
|
|
1689
1691
|
table_id: S,
|
|
@@ -1700,7 +1702,7 @@ const TOOLS = {
|
|
|
1700
1702
|
options: {
|
|
1701
1703
|
...O,
|
|
1702
1704
|
description:
|
|
1703
|
-
'Tool-specific options. verify_phone: phone_col, default_region. email_finder: owner_name_column. business_email_finder: owner_email_column. An undocumented name is rejected, never ignored.',
|
|
1705
|
+
'Tool-specific options. verify_phone: phone_col, default_region. email_finder: owner_name_column. business_email_finder: owner_email_column. linkedin_finder: business_col. linkedin_activity: linkedin_col, business_col. An undocumented name is rejected, never ignored.',
|
|
1704
1706
|
},
|
|
1705
1707
|
operation_id: {
|
|
1706
1708
|
...S,
|