scrapercity 1.0.15 → 1.0.16

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/AGENT_DOCS.txt CHANGED
@@ -214,9 +214,15 @@ GET /api/v1/database/leads?title=CTO&country=United States&hasEmail=true&page=1&
214
214
  503: the search took too long to run. Narrow it (fewer titles or keywords, add a location
215
215
  or company size) and retry.
216
216
 
217
- GET /api/v1/database/local-businesses?...
217
+ GET /api/v1/database/local-businesses?category=Dentist&country=US&hasContact=true&limit=100
218
+ Local businesses ($149/mo plan and up, 100k new businesses/day), same pattern as above.
219
+ Filters: category (repeat for several), country (two-letter code), state, city, postalCode,
220
+ query (business name and description), minRating, maxRating, minReviews, maxReviews,
221
+ hasEmail, hasPhone, hasWebsite, hasContact (only businesses with a named contact person).
222
+ Optional: excludeDelivered=true, after=<id> (as above).
223
+
218
224
  GET /api/v1/database/ecommerce?...
219
- Same pattern (including excludeDelivered and after), different datasets.
225
+ Same pattern (including excludeDelivered and after), different dataset.
220
226
 
221
227
  ────────────────────────────────────────
222
228
  ERROR CODES
package/SKILL.md CHANGED
@@ -79,7 +79,7 @@ Apollo scrapes take **up to 4 days** to deliver. Do NOT poll in a loop.
79
79
  | GET | `/api/v1/scrape/logs/{runId}` | Run logs |
80
80
  | GET | `/api/v1/apollo-status` | Apollo service health: `{status: "url-based" or "legacy", message, timestamp}` |
81
81
  | GET | `/api/v1/database/leads?title=CTO&country=United%20States&hasEmail=true&limit=100` | Lead DB ($149/mo plan and up, 100k new leads/day). Optional: `excludeDelivered=true` (only leads you don't have yet), `after=0` then `pagination.next_after` (cursor paging). Company filters: `keywords`, `revenueMin`/`revenueMax`, `companyCountry`/`companyState`/`companyCity`. Exclusions: `notTitle`, `notKeywords`, `notIndustry`. `url=<people-search URL>` searches with that URL's filters. POST with a JSON body takes the same parameters (use it for a long `url`) |
82
- | GET | `/api/v1/database/local-businesses?...` | Local biz DB ($149/mo plan and up). Same optional `excludeDelivered` / `after` |
82
+ | GET | `/api/v1/database/local-businesses?category=Dentist&country=US&hasContact=true&limit=100` | Local biz DB ($149/mo plan and up, 100k new businesses/day). Filters: `category`, `country`, `state`, `city`, `postalCode`, `query`, `minRating`/`maxRating`, `minReviews`/`maxReviews`, `hasEmail`, `hasPhone`, `hasWebsite`, `hasContact` (only businesses with a named contact person). Same optional `excludeDelivered` / `after` |
83
83
  | GET | `/api/v1/database/ecommerce?...` | Ecommerce DB ($149/mo plan and up). Same optional `excludeDelivered` / `after` |
84
84
 
85
85
  ## Status Values
package/bin/cli.mjs CHANGED
@@ -402,6 +402,33 @@ async function main() {
402
402
  break
403
403
  }
404
404
 
405
+ // ── Database: Local businesses ($149/mo plan and up) ──
406
+ case 'db-local': {
407
+ const params = {}
408
+ const keyFor = { '--category': 'category', '--country': 'country', '--state': 'state', '--city': 'city',
409
+ '--postal-code': 'postalCode', '--query': 'query', '--min-rating': 'minRating', '--max-rating': 'maxRating',
410
+ '--min-reviews': 'minReviews', '--max-reviews': 'maxReviews', '--page': 'page', '--limit': 'limit',
411
+ '--after': 'after' }
412
+ // List filters take commas: --category "Dentist,Orthodontist" sends both.
413
+ const lists = new Set(['--category', '--country'])
414
+ for (const f of Object.keys(keyFor)) {
415
+ const v = flag(f)
416
+ if (v === undefined) continue
417
+ params[keyFor[f]] = lists.has(f) ? String(v).split(',').map(s => s.trim()).filter(Boolean) : v
418
+ }
419
+ if (flagBool('--has-email')) params.hasEmail = 'true'
420
+ if (flagBool('--has-phone')) params.hasPhone = 'true'
421
+ if (flagBool('--has-website')) params.hasWebsite = 'true'
422
+ if (flagBool('--has-contact')) params.hasContact = 'true'
423
+ if (flagBool('--exclude-delivered')) params.excludeDelivered = 'true'
424
+ const r = await sc.dbLocalBusinesses(params)
425
+ console.log(`${r.pagination?.total || '?'} total businesses, page ${r.pagination?.page || 1} of ${r.pagination?.totalPages || '?'}`)
426
+ if (r.pagination?.next_after) console.log(`Next page: --after ${r.pagination.next_after}`)
427
+ console.log(json(r.data?.slice(0, 3) || r))
428
+ if (r.data?.length > 3) console.log(`... and ${r.data.length - 3} more`)
429
+ break
430
+ }
431
+
405
432
  // ── Poll (convenience) ────────────────────────────────
406
433
  case 'poll': {
407
434
  if (!args[0]) die('Usage: scrapercity poll <runId> [--interval 15]')
@@ -461,6 +488,12 @@ ScraperCity CLI - B2B lead generation from your terminal
461
488
  --url "<people-search URL>" Search with that URL's filters
462
489
  --exclude-delivered Only leads you don't already have
463
490
  --after <id> Cursor paging (start with 0, then use the printed next id)
491
+ scrapercity db-local [filters] Query local business database
492
+ --category --country --state --city --postal-code --query
493
+ --min-rating --max-rating --min-reviews --max-reviews
494
+ --has-email --has-phone --has-website --has-contact (only businesses with a named contact person)
495
+ --exclude-delivered Only businesses you don't already have
496
+ --after <id> Cursor paging (start with 0, then use the printed next id)
464
497
 
465
498
  Env: SCRAPERCITY_API_KEY=... or scrapercity login
466
499
  Docs: https://scrapercity.com/agents
package/bin/mcp.mjs CHANGED
@@ -81,6 +81,30 @@ const UTILITY_TOOLS = [
81
81
  excludeDelivered: { type: 'boolean', description: 'Skip leads this account already has (from the API or unlocked in the dashboard). With this on, keep page at 1 or use after.' },
82
82
  after: { type: 'string', description: 'Cursor paging: return leads after this lead id. Use "0" to start, then the pagination.next_after from each response.' }
83
83
  } }
84
+ },
85
+ {
86
+ name: 'query_local_business_database',
87
+ description: 'Query the local business database directly. Returns businesses with phone numbers, emails, websites, addresses and ratings, many with a named contact person. Up to 100 per request. Included with the $149/mo plan (100,000 new businesses a day; businesses you already have do not count again). Set hasContact=true for only businesses with a named contact person. For a daily pull of only new businesses set excludeDelivered=true. For big pulls page with after: send after="0" first, then the pagination.next_after from each response until it is null.',
88
+ inputSchema: { type: 'object', properties: {
89
+ category: { type: 'array', items: { type: 'string' }, description: 'Business categories, e.g. ["Dentist"]. A word also finds categories that contain it ("restaurant" finds "Mexican restaurant")' },
90
+ country: { type: 'array', items: { type: 'string' }, description: 'Two-letter country codes, e.g. ["US"]' },
91
+ state: { type: 'string', description: 'State or region, comma separated for several (US abbreviations work, e.g. "TX")' },
92
+ city: { type: 'string', description: 'City (partial match)' },
93
+ postalCode: { type: 'string', description: 'Postal or zip code' },
94
+ query: { type: 'string', description: 'Search business names and descriptions' },
95
+ minRating: { type: 'number', description: 'Minimum Google rating (1-5)' },
96
+ maxRating: { type: 'number', description: 'Maximum Google rating (1-5)' },
97
+ minReviews: { type: 'number', description: 'Minimum number of reviews' },
98
+ maxReviews: { type: 'number', description: 'Maximum number of reviews' },
99
+ hasEmail: { type: 'boolean', description: 'Only businesses with an email address' },
100
+ hasPhone: { type: 'boolean', description: 'Only businesses with a phone number' },
101
+ hasWebsite: { type: 'boolean', description: 'Only businesses with a website' },
102
+ hasContact: { type: 'boolean', description: 'Only businesses with a named contact person' },
103
+ page: { type: 'number', description: 'Page number (default 1)', default: 1 },
104
+ limit: { type: 'number', description: 'Results per page (max 100)', default: 50 },
105
+ excludeDelivered: { type: 'boolean', description: 'Skip businesses this account already has (from the API or unlocked in the dashboard). With this on, keep page at 1 or use after.' },
106
+ after: { type: 'string', description: 'Cursor paging: return businesses after this id. Use "0" to start, then the pagination.next_after from each response.' }
107
+ } }
84
108
  }
85
109
  ]
86
110
 
@@ -116,6 +140,16 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
116
140
  result = await sc.dbLeads(params)
117
141
  break
118
142
  }
143
+ case 'query_local_business_database': {
144
+ const params = { ...args }
145
+ for (const k of ['hasEmail', 'hasPhone', 'hasWebsite', 'hasContact', 'excludeDelivered']) {
146
+ if (params[k]) params[k] = 'true'
147
+ else delete params[k]
148
+ }
149
+ if (params.after !== undefined && params.after !== null) params.after = String(params.after)
150
+ result = await sc.dbLocalBusinesses(params)
151
+ break
152
+ }
119
153
  default:
120
154
  return { content: [{ type: 'text', text: `Unknown tool: ${name}` }], isError: true }
121
155
  }
@@ -1,6 +1,6 @@
1
1
  // AUTO-GENERATED by scripts/generate.mjs — DO NOT EDIT BY HAND.
2
2
  // Source of truth: scraperConfigs.ts (+ src/config/scrapers.ts). Regenerate: npm run generate
3
- // Generated: 2026-10-02T14:29:37.617Z
3
+ // Generated: 2026-10-08T22:24:15.688Z
4
4
  export const TOOLS = [
5
5
  {
6
6
  "name": "scrape_apollo",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scrapercity",
3
- "version": "1.0.15",
3
+ "version": "1.0.16",
4
4
  "description": "ScraperCity CLI & MCP Server - B2B lead generation for AI agents",
5
5
  "type": "module",
6
6
  "bin": {