scrapeloop-mcp 0.34.0 → 0.36.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 +14 -0
- package/src/mutation-policies.js +3 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "scrapeloop-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.36.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
|
@@ -657,6 +657,16 @@ const TOOLS = {
|
|
|
657
657
|
def: { description: 'Start or resume a complete native search after explicit approval of the exact reviewed plan, enabled checks and monthly/full-plan limits. This can spend credits. Requires the snapshot hash and updated timestamp from review_complete_scrape_plan, plus one stable operation UUID. A changed plan needs a fresh review. After uncertainty, read the plan and review; preserve the same operation and body. Never use this for sender Start or GHL writes.', inputSchema: obj({ plan_id: { ...S, format: 'uuid' }, operation_id: { ...S, format: 'uuid' }, snapshot_hash: { ...S, pattern: '^[0-9a-f]{64}$' }, expected_updated_at: { ...S, format: 'date-time' } }, ['plan_id', 'operation_id', 'snapshot_hash', 'expected_updated_at']) },
|
|
658
658
|
run: ({ plan_id, ...body }) => api('POST', `/plans/${enc(plan_id)}/launch`, body),
|
|
659
659
|
},
|
|
660
|
+
check_scrape_plan_stop: {
|
|
661
|
+
def: { description: 'Look at the stop a complete search plan is on. Use it when get_scrape_plan shows the block "A check is on hold". With dry_run true (the default) it only reads the saved records of the held Table check job. It says what it found, what would happen and how many check credits that could use, and it returns job_ids. To carry on, call it again with dry_run false and those same job_ids. It then acts only when the records prove that is safe: it ends the held job, gives unused held check credits back, runs free checks that never finished again, and runs paid checks that never started inside the plan limits. A paid check that got no answer is closed and never asked again. It sends no request to a checker itself. The answer has outcome safe, needs_person, wait or nothing, with a title, plain lines and a next line, all ready to show the person. Always show the dry run lines first and carry on only after the person says yes. If the held jobs changed since the dry run, nothing is changed and a fresh dry run comes back with changed true. A second call after it carried on finds nothing on hold. A held map search and a failed Table move are named and left to a person.', inputSchema: obj({ plan_id: { ...S, format: 'uuid' }, dry_run: B, job_ids: { ...ARR({ ...S, format: 'uuid' }), maxItems: 20 } }, ['plan_id']) },
|
|
662
|
+
run: (a) => {
|
|
663
|
+
const dryRun = a.dry_run !== false;
|
|
664
|
+
if (!dryRun && !Array.isArray(a.job_ids)) {
|
|
665
|
+
return { ok: false, status: 400, error: { detail: 'Run a dry run first, then pass its job_ids with dry_run false.' } };
|
|
666
|
+
}
|
|
667
|
+
return api('POST', `/plans/${enc(a.plan_id)}/check-stop`, dryRun ? { dry_run: true } : { dry_run: false, job_ids: a.job_ids });
|
|
668
|
+
},
|
|
669
|
+
},
|
|
660
670
|
pause_scrape_plan: {
|
|
661
671
|
def: { description: 'Pause new work from a scrape plan. A job already running may still finish. Inspect the plan and its jobs after pausing.', inputSchema: obj({ plan_id: { ...S, format: 'uuid' } }, ['plan_id']) },
|
|
662
672
|
run: (a) => api('POST', `/plans/${enc(a.plan_id)}/pause`),
|
|
@@ -1121,6 +1131,10 @@ const TOOLS = {
|
|
|
1121
1131
|
def: { description: 'Read dated verified ready stock, count shared businesses and emails once, and compare planning shares with estimated remaining-month demand. Includes linked goals, coverage and shared credit allowance. This is a read-only planning view, not a reservation or sender approval. Unknown proof remains unknown. The remaining-month estimate accounts for saved follow-ups and deducts the current sender queue before allocating local stock.', inputSchema: obj({}) },
|
|
1122
1132
|
run: () => api('GET', '/campaigns/supply'),
|
|
1123
1133
|
},
|
|
1134
|
+
get_campaign_supply_status: {
|
|
1135
|
+
def: { description: 'Read the one supply status for every campaign with a linked complete plan, or for one campaign_id. Each answer has exactly one state: Running by itself, Waiting, it carries on by itself (with what it waits for), or Stopped, needs you (with the one next action, and anything else that is wrong listed after it). It also gives leads in the campaign now, leads added in the last 24 hours, searches done of the total, lead and verify credits used of their limits, measured credits per lead, and where the limits run out. Read-only: stored values and small counts, no sender call and no credit use. A number that could not be read is null, never zero. Use this first when the user asks if a campaign is running, done or stuck right now, and say the summary to them as written. To see whether the setup itself fits together, use check_campaign_setup.', inputSchema: obj({ campaign_id: S }) },
|
|
1136
|
+
run: (a) => api('GET', a.campaign_id ? `/campaigns/${enc(a.campaign_id)}/supply-status` : '/campaigns/supply-status'),
|
|
1137
|
+
},
|
|
1124
1138
|
get_campaign_setup_options: {
|
|
1125
1139
|
def: { description: 'Read this workspace\'s channel choices and defaults for new campaign drafts. Explicit create choices win. Reading options changes nothing and starts no campaign.', inputSchema: obj({}) },
|
|
1126
1140
|
run: () => api('GET', '/campaigns/options'),
|
package/src/mutation-policies.js
CHANGED
|
@@ -48,6 +48,9 @@ export const MUTATION_POLICIES = Object.freeze({
|
|
|
48
48
|
preview_pipeline: read(),
|
|
49
49
|
preview_scrape_plan: read(),
|
|
50
50
|
create_scrape_plan: keyed('POST', ['list_scrape_plans'], ['name', 'target_list_id', 'kind']),
|
|
51
|
+
// A second run finds the job already closed and changes nothing, so a
|
|
52
|
+
// repeat after a lost reply is safe (tests/test_plan_stop_check.py).
|
|
53
|
+
check_scrape_plan_stop: idempotent('POST', ['get_scrape_plan', 'get_job'], ['plan_id', 'dry_run', 'job_ids']),
|
|
51
54
|
pause_scrape_plan: never('POST', ['get_scrape_plan'], ['plan_id']),
|
|
52
55
|
launch_complete_scrape_plan: reconcile('POST', ['get_scrape_plan', 'review_complete_scrape_plan'], ['plan_id', 'operation_id', 'snapshot_hash', 'expected_updated_at']),
|
|
53
56
|
start_scrape_plan: never('POST', ['get_scrape_plan'], ['plan_id']),
|