webdata-tools-mcp 0.2.0 → 0.10.1
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 +52 -7
- package/package.json +15 -4
- package/skills/innovation-analyst/SKILL.md +51 -0
- package/src/prompts.js +87 -0
- package/src/server.js +11 -0
- package/src/tools.js +277 -6
package/README.md
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
# webdata-tools-mcp
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/webdata-tools-mcp)
|
|
4
|
+
[](https://github.com/tacps126/webdata-tools-mcp/releases/latest)
|
|
4
5
|
[](https://github.com/tacps126/webdata-tools-mcp/actions/workflows/ci.yml)
|
|
5
6
|
[](LICENSE)
|
|
6
|
-
[
|
|
7
|
+
[](https://github.com/modelcontextprotocol/registry)
|
|
8
|
+
[](https://smithery.ai/servers/tacps126/webdata-tools-mcp)
|
|
7
9
|
[](https://glama.ai/mcp/servers/tacps126/webdata-tools-mcp)
|
|
8
10
|
|
|
9
|
-
An [MCP](https://modelcontextprotocol.io) server that gives AI agents
|
|
10
|
-
postings,
|
|
11
|
-
|
|
11
|
+
An [MCP](https://modelcontextprotocol.io) server that gives AI agents twenty-one web-data tools: job
|
|
12
|
+
postings (company career sites, remote jobs, startups on Wellfound, US tech jobs on Dice, Indeed,
|
|
13
|
+
Naukri), hiring signals, Google News, research papers and patents, field trends and idea validation, Trustpilot and app-store reviews, Reddit mentions and
|
|
14
|
+
buying-intent leads, website contacts, German and Austrian property listings, Shopify products and
|
|
15
|
+
store analysis, trade-show exhibitor lists and upcoming events. Two ready-made prompts turn the research
|
|
16
|
+
tools into an innovation analyst that works the same with any model.
|
|
12
17
|
|
|
13
18
|
Each tool runs a ready-made [Apify](https://apify.com/tacps126) Actor and returns clean JSON. You
|
|
14
19
|
pay Apify per result (about $1–3 per 1,000 results); there is no subscription and nothing is sent
|
|
@@ -20,14 +25,25 @@ anywhere except Apify.
|
|
|
20
25
|
|------|-----------------|----------------|-------|
|
|
21
26
|
| `search_google_news` | News articles with the publisher's real URL, date, related coverage | $2 / 1,000 articles | [google-news](https://apify.com/tacps126/google-news) |
|
|
22
27
|
| `find_hiring_companies` | Which companies are hiring for given roles (buying-intent signal) | 1¢ per company with a signal | [hiring-signals](https://apify.com/tacps126/hiring-signals) |
|
|
23
|
-
| `get_company_jobs` | All open jobs from career pages (Greenhouse, Lever, Ashby, Workday, …) | $1 / 1,000 jobs | [jobs-harvester](https://apify.com/tacps126/jobs-harvester) |
|
|
28
|
+
| `get_company_jobs` | All open jobs from career pages or company names (13 job-board systems: Greenhouse, Lever, Ashby, Workday, Rippling, …) | $1 / 1,000 jobs | [jobs-harvester](https://apify.com/tacps126/jobs-harvester) |
|
|
29
|
+
| `find_remote_jobs` | Remote jobs from company job boards plus the Remote OK, Jobicy, Working Nomads and Himalayas feeds | $2 / 1,000 jobs | [remote-jobs-scraper](https://apify.com/tacps126/remote-jobs-scraper) |
|
|
30
|
+
| `search_startup_jobs` | Startup jobs on Wellfound by role and city: salary and equity, startup size and pitch | $2 / 1,000 jobs | [wellfound-jobs-scraper](https://apify.com/tacps126/wellfound-jobs-scraper) |
|
|
31
|
+
| `search_tech_jobs` | US tech jobs on Dice: salary, employer type, Easy Apply, remote flag | $0.55 / 1,000 jobs | [dice-jobs-scraper](https://apify.com/tacps126/dice-jobs-scraper) |
|
|
24
32
|
| `search_indeed_jobs` | Indeed listings in 9 countries | $3 / 1,000 jobs | [indeed-jobs](https://apify.com/tacps126/indeed-jobs) |
|
|
33
|
+
| `search_naukri_jobs` | Naukri.com jobs (India): full description, salary in rupees, experience, rating | $1.50 / 1,000 jobs | [naukri-jobs-scraper](https://apify.com/tacps126/naukri-jobs-scraper) |
|
|
25
34
|
| `get_trustpilot_reviews` | Reviews, TrustScore and company profile | $0.50 / 1,000 reviews | [trustpilot-reviews](https://apify.com/tacps126/trustpilot-reviews) |
|
|
26
35
|
| `get_app_reviews` | App Store and Google Play reviews | $0.20 / 1,000 reviews | [app-reviews](https://apify.com/tacps126/app-reviews) |
|
|
27
|
-
| `search_reddit` | Reddit posts and comments by keyword or subreddit | $1 / 1,000 items | [reddit-monitor](https://apify.com/tacps126/reddit-monitor) |
|
|
36
|
+
| `search_reddit` | Reddit posts and comments by keyword or subreddit, tagged with buying intent | $1 / 1,000 items | [reddit-monitor](https://apify.com/tacps126/reddit-monitor) |
|
|
37
|
+
| `find_reddit_leads` | Reddit posts asking for a tool like yours, seeking a competitor alternative, comparing or complaining | $2 / 1,000 leads + $0.10 / 1,000 posts read | [reddit-lead-finder](https://apify.com/tacps126/reddit-lead-finder) |
|
|
38
|
+
| `search_research` | Papers, preprints and patents from OpenAlex, arXiv, PubMed and Europe PMC, merged; newest or most influential first, with field-normalized impact | $3 / 1,000 results | [research-radar](https://apify.com/tacps126/research-radar) |
|
|
39
|
+
| `analyze_field` | A technology field's opportunity score with reasons, growth and momentum, industry participation and top companies, leading countries, institutions and funders, rising topics; several fields ranked | $0.03 / field | [innovation-radar](https://apify.com/tacps126/innovation-radar) |
|
|
40
|
+
| `validate_idea` | How new or crowded an idea is, who is working on it, and the closest prior work | $0.03 / idea | [innovation-radar](https://apify.com/tacps126/innovation-radar) |
|
|
28
41
|
| `find_website_contacts` | Emails, phones, socials from websites | $2 / 1,000 sites with contacts | [contact-details](https://apify.com/tacps126/contact-details) |
|
|
29
|
-
| `search_german_property_listings` | Rent/buy listings in Germany (ImmoScout24) | $1 / 1,000 listings | [immobilienscout24-scraper](https://apify.com/tacps126/immobilienscout24-scraper) |
|
|
42
|
+
| `search_german_property_listings` | Rent/buy listings in Germany and Austria (ImmoScout24) | $1 / 1,000 listings | [immobilienscout24-scraper](https://apify.com/tacps126/immobilienscout24-scraper) |
|
|
30
43
|
| `get_shopify_products` | Prices, discounts, stock, variants from Shopify stores | $1 / 1,000 products | [shopify-products](https://apify.com/tacps126/shopify-products) |
|
|
44
|
+
| `analyze_shopify_stores` | Store location, currency, catalog size and snapshot, e-mails, phones, socials | $4 / 1,000 stores | [shopify-store-analyzer](https://apify.com/tacps126/shopify-store-analyzer) |
|
|
45
|
+
| `get_trade_show_exhibitors` | Trade-show exhibitors: booth, email, phone, website, address (91 shows or any supported exhibitor-list link; changes-only monitoring) | $2 / 1,000 exhibitors | [exhibition-scraper](https://apify.com/tacps126/exhibition-scraper) |
|
|
46
|
+
| `find_events` | Upcoming events from Luma, Eventbrite, Meetup: venue, organiser, hosts, tickets, attendees | $1 / 1,000 events | [events-scraper](https://apify.com/tacps126/events-scraper) |
|
|
31
47
|
|
|
32
48
|
Every tool also takes an optional `extra_input` object for any other field the Actor documents.
|
|
33
49
|
Every result comes back as text and as structured content (`tool`, `count`, `shown`, `truncated`,
|
|
@@ -35,12 +51,27 @@ Every result comes back as text and as structured content (`tool`, `count`, `sho
|
|
|
35
51
|
|
|
36
52
|
More about the tools: <https://tacps126.github.io/mcp.html>
|
|
37
53
|
|
|
54
|
+
## Prompts and agent skill
|
|
55
|
+
|
|
56
|
+
Two ready-made prompts turn the research tools into an analyst, whichever model you use (Claude, GPT, Gemini, a local model): the evidence, the reading guide and the answer shape are fixed, so results stay comparable.
|
|
57
|
+
|
|
58
|
+
| Prompt | What it does |
|
|
59
|
+
|--------|--------------|
|
|
60
|
+
| `field-opportunity-analysis` | Runs `analyze_field` on your fields, then writes ranked opportunities: what to build, for whom, why now, capital needed, who to talk to |
|
|
61
|
+
| `idea-validation` | Runs `validate_idea`, then assesses novelty, closest prior work, timing, who is already there, capital, risks and next steps |
|
|
62
|
+
|
|
63
|
+
For agents that load skills (Claude Code, Codex and others), copy [`skills/innovation-analyst`](skills/innovation-analyst/SKILL.md) into your skills folder.
|
|
64
|
+
|
|
38
65
|
## Setup
|
|
39
66
|
|
|
40
67
|
1. Create a free [Apify account](https://apify.com) and copy your API token from
|
|
41
68
|
**Console → Settings → API & Integrations**.
|
|
42
69
|
2. Add the server to your client. The token goes in `APIFY_TOKEN`.
|
|
43
70
|
|
|
71
|
+
**Claude Desktop, one click:** download `webdata-tools-mcp-<version>.mcpb` from the
|
|
72
|
+
[latest release](https://github.com/tacps126/webdata-tools-mcp/releases/latest) and open it. Claude
|
|
73
|
+
Desktop installs it and asks for your Apify token.
|
|
74
|
+
|
|
44
75
|
**Claude Desktop / Cursor / Windsurf** (`mcpServers` config):
|
|
45
76
|
|
|
46
77
|
```json
|
|
@@ -63,11 +94,18 @@ claude mcp add webdata -e APIFY_TOKEN=<your Apify token> -- npx -y webdata-tools
|
|
|
63
94
|
|
|
64
95
|
Requires Node.js 18 or newer.
|
|
65
96
|
|
|
97
|
+
Releases are tagged and published by CI from `main` (`.github/workflows/release.yml`).
|
|
98
|
+
|
|
66
99
|
## Try it
|
|
67
100
|
|
|
68
101
|
- "Which of these companies are hiring data engineers right now? https://boards.greenhouse.io/stripe, https://jobs.lever.co/spotify"
|
|
102
|
+
- "Find remote senior engineer jobs open to people in Canada posted this week."
|
|
103
|
+
- "Who on Reddit is looking for an alternative to HubSpot this month?"
|
|
104
|
+
- "Analyze these Shopify stores and give me their country, product count and contact e-mail: allbirds.com, gymshark.com"
|
|
69
105
|
- "Show the 1 and 2 star Trustpilot reviews of example.com from the last 30 days and group the complaints."
|
|
70
106
|
- "Find news from the last 7 days about open-source LLM licensing, with the real publisher links."
|
|
107
|
+
- "What should a seed-stage founder build in sodium-ion batteries? Compare it with solid-state." (field-opportunity-analysis prompt)
|
|
108
|
+
- "Find the most influential papers of the last three years on retrieval augmented generation."
|
|
71
109
|
- "Get contact emails for these 20 agency websites." (use only for lawful business outreach)
|
|
72
110
|
|
|
73
111
|
## Settings
|
|
@@ -118,6 +156,13 @@ a tool sends a field the Actor does not accept.
|
|
|
118
156
|
The Actors read publicly available pages. You are responsible for following each site's terms and
|
|
119
157
|
the law that applies to you (GDPR, CAN-SPAM) when you use the data, especially contact details.
|
|
120
158
|
|
|
159
|
+
## Listed on
|
|
160
|
+
|
|
161
|
+
<a href="https://glama.ai/mcp/servers/tacps126/webdata-tools-mcp"><img width="380" height="200" src="https://glama.ai/mcp/servers/tacps126/webdata-tools-mcp/badges/card.svg" alt="webdata-tools-mcp on Glama" /></a>
|
|
162
|
+
<a href="https://mcprush.com/to/webdata-tools-mcp?ref=badge"><img width="380" height="200" src="https://mcprush.com/badge/webdata-tools-mcp/card.svg" alt="Webdata Tools MCP server on MCPRush" /></a>
|
|
163
|
+
|
|
164
|
+
Also on [npm](https://www.npmjs.com/package/webdata-tools-mcp), the official [MCP Registry](https://github.com/modelcontextprotocol/registry) (`io.github.tacps126/webdata-tools-mcp`), and [Smithery](https://smithery.ai/servers/tacps126/webdata-tools-mcp).
|
|
165
|
+
|
|
121
166
|
## License
|
|
122
167
|
|
|
123
168
|
MIT
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "webdata-tools-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.1",
|
|
4
4
|
"mcpName": "io.github.tacps126/webdata-tools-mcp",
|
|
5
|
-
"description": "MCP server for AI agents: job postings, hiring signals, Google News, Trustpilot and app reviews, Reddit mentions, website contacts, German real estate and
|
|
5
|
+
"description": "MCP server for AI agents: job postings (career sites, remote, startups, US tech, Indeed, Naukri), hiring signals, Google News, research papers and patents, technology-field trends and idea validation (with analyst prompts), Trustpilot and app reviews, Reddit mentions and buying-intent leads, website contacts, German real estate, Shopify products and store analysis, trade-show exhibitors and upcoming events. Runs ready-made Apify Actors with your own Apify token.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
8
8
|
"webdata-tools-mcp": "src/index.js"
|
|
@@ -10,13 +10,16 @@
|
|
|
10
10
|
"main": "src/index.js",
|
|
11
11
|
"files": [
|
|
12
12
|
"src",
|
|
13
|
+
"skills",
|
|
13
14
|
"icon.png",
|
|
14
15
|
"README.md",
|
|
15
16
|
"LICENSE"
|
|
16
17
|
],
|
|
17
18
|
"scripts": {
|
|
18
19
|
"start": "node src/index.js",
|
|
19
|
-
"test": "node --test test/*.test.js"
|
|
20
|
+
"test": "node --test test/*.test.js",
|
|
21
|
+
"build:mcpb": "node scripts/build-mcpb.mjs",
|
|
22
|
+
"sync:inputs": "node scripts/sync-actor-inputs.mjs"
|
|
20
23
|
},
|
|
21
24
|
"keywords": [
|
|
22
25
|
"mcp",
|
|
@@ -28,7 +31,15 @@
|
|
|
28
31
|
"google-news",
|
|
29
32
|
"trustpilot",
|
|
30
33
|
"reviews",
|
|
31
|
-
"lead-generation"
|
|
34
|
+
"lead-generation",
|
|
35
|
+
"trade-shows",
|
|
36
|
+
"exhibitors",
|
|
37
|
+
"events",
|
|
38
|
+
"luma",
|
|
39
|
+
"eventbrite",
|
|
40
|
+
"research",
|
|
41
|
+
"patents",
|
|
42
|
+
"innovation"
|
|
32
43
|
],
|
|
33
44
|
"license": "MIT",
|
|
34
45
|
"engines": {
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: innovation-analyst
|
|
3
|
+
description: Analyse technology fields and validate product or research ideas from open research data (OpenAlex, Europe PMC patents) with the webdata-tools MCP server, then write evidence-backed opportunities — what to build, for whom, why now, capital needed, who to talk to. Use when someone asks what to build in a field, whether an idea is new or crowded, how fast a technology is growing, who leads it (companies, labs, countries), or to compare several technologies.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Innovation analyst
|
|
7
|
+
|
|
8
|
+
Turns the structured evidence from the `analyze_field`, `validate_idea` and `search_research` tools (webdata-tools MCP server, backed by the Innovation Radar and Research Radar Apify Actors) into an analysis. Works with any model: the evidence, the reading guide and the answer shape are fixed, so results stay comparable.
|
|
9
|
+
|
|
10
|
+
## Pick the tool
|
|
11
|
+
|
|
12
|
+
| Question | Call |
|
|
13
|
+
|---|---|
|
|
14
|
+
| "What should I build in X?", "Is X growing?", "Who leads X?", "Compare X, Y, Z" | `analyze_field` with all fields in one call (several come back ranked) |
|
|
15
|
+
| "Is my idea new?", "Who is already doing this?" | `validate_idea`; add `analyze_field` on the core technology for growth and industry signals |
|
|
16
|
+
| "What's the key recent work?", "Find papers on X" | `search_research` with `sort_by: "impact"` for influential work, `"newest"` for alerts |
|
|
17
|
+
|
|
18
|
+
Each field or idea costs about $0.03 on the user's Apify account. Don't call the same field twice in one conversation; reuse the record.
|
|
19
|
+
|
|
20
|
+
## How to read the evidence
|
|
21
|
+
|
|
22
|
+
- `scores.opportunity` (0–100) and `scores.why`: the overall ranking and the signals behind it.
|
|
23
|
+
- `scores.momentum` (0–100): output in the last two full years against the two before; 50 ≈ +40%.
|
|
24
|
+
- `scores.labToMarketGap` (0–100): high momentum with few company authors — research is ahead of products.
|
|
25
|
+
- `industry.recentShare`: share of recent works with a company author (under 5% academic, 5–15% engaging, over 15% active); `industry.trend`: companies moving in or out.
|
|
26
|
+
- `scores.geographicConcentration`: share of the top country among the leaders; high means supply-chain, policy and partner risk.
|
|
27
|
+
- `risingTopics`: sub-topics whose share grew most. `standoutRecentWorks`: the most cited recent papers.
|
|
28
|
+
- `topCompanies`, `keyResearchers`, `topInstitutions`, `topFunders`: partners, hires, licensors, competitors.
|
|
29
|
+
- `reviewShare`: many review papers means the field is consolidating.
|
|
30
|
+
- `relatedPatents[].likelyExpiredByTerm`: filed over 20 years ago — possibly free to use (not legal advice).
|
|
31
|
+
- `growth.stage` says when counts are small: percentages are noisy then; say so.
|
|
32
|
+
- Validation: `crowdedness` (open, early, active, crowded), `matchingWorks`, `worksLastTwoYears`, `closestWorks`, `whoIsWorkingOnIt`.
|
|
33
|
+
- `broaderSpace` / `position`: the biggest neighbouring space with one term left out. "Open niche in a crowded field" means the application is new but the base technology is busy: proof it works, and competition for talent and suppliers.
|
|
34
|
+
|
|
35
|
+
## Write the analysis
|
|
36
|
+
|
|
37
|
+
Capital buckets: **under $50k** (software or a service), **$50k–$1M** (hardware or regulated software), **over $1M** (deep tech, manufacturing, clinical).
|
|
38
|
+
|
|
39
|
+
**Field landscape** — sections:
|
|
40
|
+
1. Summary: two or three sentences; with several fields, the ranking and why.
|
|
41
|
+
2. Opportunities, three to five, best first: the idea, for whom, why now (name the signal), capital bucket with the reason, who to talk to (from the evidence).
|
|
42
|
+
3. Risks.
|
|
43
|
+
4. Evidence quality: strong, moderate or thin, and why.
|
|
44
|
+
|
|
45
|
+
**Idea validation** — sections: Novelty, Closest prior work, Timing, Who is already there, Capital (bucket and why), Risks, Next steps (three), Evidence quality.
|
|
46
|
+
|
|
47
|
+
Rules: cite the numbers you rely on; name real organisations only when they appear in the evidence; no generic advice ("do market research"); say when the evidence is thin. Research leads products by years — treat trends as early signals, not market size.
|
|
48
|
+
|
|
49
|
+
## Without the MCP server
|
|
50
|
+
|
|
51
|
+
The Innovation Radar Actor writes an `AI_BRIEF` record to its run's key-value store: this same rubric plus the run's evidence. Paste it into any assistant.
|
package/src/prompts.js
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// Ready-made analyst prompts: any model connected to this server gets the same
|
|
2
|
+
// rubric, so the analysis reads the same whichever AI writes it.
|
|
3
|
+
// Keep the text in step with apify_actors/actors/innovation-radar/src/rubric.rs
|
|
4
|
+
// (the Actor's own AI step and its AI_BRIEF record use the same rubric).
|
|
5
|
+
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
|
|
8
|
+
export const SIGNALS = `How to read the evidence:
|
|
9
|
+
- scores.opportunity (0-100) and scores.why: the overall ranking and the signals behind it.
|
|
10
|
+
- scores.momentum (0-100): research output in the last two full years against the two before; 50 = about +40%.
|
|
11
|
+
- scores.labToMarketGap (0-100): high momentum with few company authors — research is ahead of products.
|
|
12
|
+
- industry.recentShare: share of recent works with a company author (under 5% academic, 5-15% engaging, over 15% active); industry.trend says whether companies are moving in or out.
|
|
13
|
+
- scores.geographicConcentration: share of the top country among the leading countries; high means one country dominates (supply-chain, policy and partner risk).
|
|
14
|
+
- risingTopics: sub-topics whose share grew most; standoutRecentWorks: the most cited recent papers.
|
|
15
|
+
- topCompanies / keyResearchers / topInstitutions / topFunders: who to partner with, hire from, license from or compete against.
|
|
16
|
+
- reviewShare: a high share of review papers means the field is consolidating.
|
|
17
|
+
- broaderSpace / position (validation): the biggest neighbouring space with one term left out; "open niche in a crowded field" means the application is new but the technology around it is busy (competition for talent, suppliers and attention; also proof the base technology works).
|
|
18
|
+
- relatedPatents.likelyExpiredByTerm: filed more than 20 years ago — possibly free to use (not legal advice).
|
|
19
|
+
Small counts make percentages noisy — say so when growth.stage reports it.`;
|
|
20
|
+
|
|
21
|
+
export const LANDSCAPE = `You are a pragmatic technology and innovation analyst advising founders, R&D leaders and investors.
|
|
22
|
+
From the field evidence, find concrete product or business opportunities.
|
|
23
|
+
For each opportunity say what to build, for whom, why now (which signal shows the timing), what it would take
|
|
24
|
+
(capital bucket: under $50k software/service, $50k-$1M hardware or regulated software, over $1M deep tech, manufacturing or clinical),
|
|
25
|
+
and who in the evidence could be a partner, customer or competitor.
|
|
26
|
+
Be specific, cite the signals you rely on, and say when the evidence is thin. No generic advice.`;
|
|
27
|
+
|
|
28
|
+
export const VALIDATION = `You are a pragmatic technology and innovation analyst. Assess the idea against the evidence:
|
|
29
|
+
how new it is (crowdedness, closest prior work), whether the timing is right (growth), who is already working on it
|
|
30
|
+
(researchers, institutions, companies), what it would take to build (capital bucket: under $50k, $50k-$1M, over $1M),
|
|
31
|
+
the main risks, and the three most useful next steps. Be specific, cite the evidence, and say when it is thin.`;
|
|
32
|
+
|
|
33
|
+
const LANDSCAPE_SHAPE = `Answer in these sections:
|
|
34
|
+
1. Summary — two or three sentences; when several fields were analysed, the ranking and why.
|
|
35
|
+
2. Opportunities — three to five, best first. For each: the idea, for whom, why now, capital bucket with the reason, who to talk to.
|
|
36
|
+
3. Risks.
|
|
37
|
+
4. Evidence quality — strong, moderate or thin, and why.`;
|
|
38
|
+
|
|
39
|
+
const VALIDATION_SHAPE = `Answer in these sections: Novelty, Closest prior work, Timing, Who is already there,
|
|
40
|
+
Capital (bucket and why), Risks, Next steps (three), Evidence quality (strong, moderate or thin).`;
|
|
41
|
+
|
|
42
|
+
const list = (s) =>
|
|
43
|
+
String(s)
|
|
44
|
+
.split(/\n|;/)
|
|
45
|
+
.map((x) => x.trim())
|
|
46
|
+
.filter(Boolean);
|
|
47
|
+
|
|
48
|
+
export const PROMPTS = [
|
|
49
|
+
{
|
|
50
|
+
name: 'field-opportunity-analysis',
|
|
51
|
+
title: 'Find opportunities in a technology field',
|
|
52
|
+
description:
|
|
53
|
+
'Analyse one or more technology or research fields with analyze_field, then write ranked, evidence-backed product and business opportunities (why now, capital needed, who to talk to).',
|
|
54
|
+
args: {
|
|
55
|
+
fields: z.string().describe('Fields or technologies, one per line or separated by semicolons, e.g. "sodium-ion battery; solid state battery".'),
|
|
56
|
+
audience: z.string().optional().describe('Who the analysis is for, e.g. "a seed-stage founder", "a corporate R&D team". Default: founders, R&D leaders and investors.'),
|
|
57
|
+
},
|
|
58
|
+
text: ({ fields, audience }) => {
|
|
59
|
+
const names = list(fields);
|
|
60
|
+
return `Call the analyze_field tool with fields ${JSON.stringify(names)} (one call for all of them; ${names.length > 1 ? 'the records come back ranked by opportunity score' : 'one record'}).
|
|
61
|
+
Then use only its records as the evidence.${audience ? `\nThe analysis is for ${audience}.` : ''}
|
|
62
|
+
|
|
63
|
+
${LANDSCAPE}
|
|
64
|
+
|
|
65
|
+
${SIGNALS}
|
|
66
|
+
|
|
67
|
+
${LANDSCAPE_SHAPE}`;
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
name: 'idea-validation',
|
|
72
|
+
title: 'Validate a product or research idea',
|
|
73
|
+
description:
|
|
74
|
+
'Check an idea with validate_idea (how much research already covers it, who is working on it, closest prior work, related patents), then assess novelty, timing, capital, risks and next steps.',
|
|
75
|
+
args: {
|
|
76
|
+
idea: z.string().describe('The idea in a sentence or two, e.g. "a window that generates solar power with perovskite tandem cells".'),
|
|
77
|
+
},
|
|
78
|
+
text: ({ idea }) => `Call the validate_idea tool with ideas ${JSON.stringify([String(idea).trim()])}.
|
|
79
|
+
Then use only its record as the evidence. If the idea is broad, you may also call analyze_field on its core technology for growth and industry signals.
|
|
80
|
+
|
|
81
|
+
${VALIDATION}
|
|
82
|
+
|
|
83
|
+
${SIGNALS}
|
|
84
|
+
|
|
85
|
+
${VALIDATION_SHAPE}`,
|
|
86
|
+
},
|
|
87
|
+
];
|
package/src/server.js
CHANGED
|
@@ -4,6 +4,7 @@ import { readFileSync } from 'node:fs';
|
|
|
4
4
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
5
5
|
import { z } from 'zod';
|
|
6
6
|
import { ApifyError, runActorSync } from './apify.js';
|
|
7
|
+
import { PROMPTS } from './prompts.js';
|
|
7
8
|
import { extraInput, TOOLS } from './tools.js';
|
|
8
9
|
|
|
9
10
|
const { version: VERSION } = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
|
|
@@ -102,5 +103,15 @@ export function buildServer({ env = process.env, fetchImpl = fetch } = {}) {
|
|
|
102
103
|
},
|
|
103
104
|
);
|
|
104
105
|
}
|
|
106
|
+
for (const prompt of PROMPTS) {
|
|
107
|
+
server.registerPrompt(
|
|
108
|
+
prompt.name,
|
|
109
|
+
{ title: prompt.title, description: prompt.description, argsSchema: prompt.args },
|
|
110
|
+
(args) => ({
|
|
111
|
+
description: prompt.description,
|
|
112
|
+
messages: [{ role: 'user', content: { type: 'text', text: prompt.text(args) } }],
|
|
113
|
+
}),
|
|
114
|
+
);
|
|
115
|
+
}
|
|
105
116
|
return server;
|
|
106
117
|
}
|
package/src/tools.js
CHANGED
|
@@ -99,39 +99,116 @@ export const TOOLS = [
|
|
|
99
99
|
title: 'Get all open jobs from company career pages',
|
|
100
100
|
price: 'about $0.001 per job',
|
|
101
101
|
description:
|
|
102
|
-
'All open jobs from
|
|
102
|
+
'All open jobs from companies in one normalized format (title, company, location with country code, remote/hybrid, seniority, salary, skills, apply URL, posted date). Give career-page URLs (the company\'s own careers page or its job board) or just company names; 13 job-board systems are supported (Greenhouse, Lever, Ashby, Workday, SmartRecruiters, Workable, Rippling, BambooHR, Pinpoint, Breezy, Recruitee, Personio, Teamtailor) and found automatically.',
|
|
103
103
|
shape: {
|
|
104
|
-
career_page_urls:
|
|
104
|
+
career_page_urls: z.array(z.string()).optional().describe('Career page URLs, e.g. "https://www.figma.com/careers" or "https://jobs.lever.co/spotify".'),
|
|
105
|
+
company_names: z.array(z.string()).optional().describe('Company names, e.g. ["Datadog", "Ramp"]; each is looked up on every supported job-board system.'),
|
|
105
106
|
title_includes: z.array(z.string()).optional().describe('Keep jobs whose title contains any of these.'),
|
|
106
107
|
location_includes: z.array(z.string()).optional().describe('Keep jobs in these locations.'),
|
|
108
|
+
countries: z.array(z.string()).optional().describe('Keep jobs in these countries: ISO codes ("US", "DE") or names.'),
|
|
107
109
|
remote_only: z.boolean().optional().describe('Only remote jobs.'),
|
|
108
110
|
posted_within_days: z.number().int().min(1).max(365).optional().describe('Only jobs posted in the last N days.'),
|
|
109
111
|
max_items: maxItems(50),
|
|
110
112
|
},
|
|
113
|
+
check: (a) =>
|
|
114
|
+
(a.career_page_urls?.length || a.company_names?.length)
|
|
115
|
+
? null
|
|
116
|
+
: 'Provide at least one of: career_page_urls or company_names.',
|
|
111
117
|
map: (a) =>
|
|
112
118
|
clean({
|
|
113
119
|
careerPageUrls: a.career_page_urls,
|
|
120
|
+
companyNames: a.company_names,
|
|
114
121
|
titleIncludes: a.title_includes,
|
|
115
122
|
locationIncludes: a.location_includes,
|
|
123
|
+
countries: a.countries,
|
|
116
124
|
remoteOnly: a.remote_only,
|
|
117
125
|
postedWithinDays: a.posted_within_days,
|
|
118
126
|
maxItems: a.max_items,
|
|
119
127
|
}),
|
|
120
128
|
limit: (a) => a.max_items,
|
|
121
129
|
},
|
|
130
|
+
{
|
|
131
|
+
name: 'find_remote_jobs',
|
|
132
|
+
actor: 'tacps126/remote-jobs-scraper',
|
|
133
|
+
title: 'Find remote jobs from company career sites and remote-job feeds',
|
|
134
|
+
price: 'about $0.002 per job',
|
|
135
|
+
description:
|
|
136
|
+
'Remote jobs straight from employers: hundreds of company job boards plus the Remote OK, Jobicy, Working Nomads and Himalayas feeds, keeping only roles the posting marks as remote. Normalized title, company, country, seniority, salary and skills; each job links to its source.',
|
|
137
|
+
shape: {
|
|
138
|
+
title_includes: z.array(z.string()).optional().describe('Keep jobs whose title contains any of these, e.g. ["engineer"].'),
|
|
139
|
+
countries: z.array(z.string()).optional().describe('Keep jobs open to these countries: ISO codes ("US", "CA") or names.'),
|
|
140
|
+
posted_within_days: z.number().int().min(1).max(365).optional().describe('Only jobs posted in the last N days.'),
|
|
141
|
+
min_annual_salary: z.number().int().min(0).optional().describe('Minimum yearly pay in the posting\'s currency (jobs without pay are kept).'),
|
|
142
|
+
max_items: maxItems(50),
|
|
143
|
+
},
|
|
144
|
+
map: (a) =>
|
|
145
|
+
clean({
|
|
146
|
+
titleIncludes: a.title_includes,
|
|
147
|
+
countries: a.countries,
|
|
148
|
+
postedWithinDays: a.posted_within_days,
|
|
149
|
+
minAnnualSalary: a.min_annual_salary,
|
|
150
|
+
maxItems: a.max_items,
|
|
151
|
+
}),
|
|
152
|
+
limit: (a) => a.max_items,
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
name: 'search_startup_jobs',
|
|
156
|
+
actor: 'tacps126/wellfound-jobs-scraper',
|
|
157
|
+
title: 'Search startup jobs on Wellfound (AngelList Talent)',
|
|
158
|
+
price: 'about $0.002 per job',
|
|
159
|
+
description:
|
|
160
|
+
'Startup jobs from Wellfound by role and city, or remote: title, startup name, size and pitch, salary and equity range, years of experience, remote or on-site, apply link.',
|
|
161
|
+
shape: {
|
|
162
|
+
role: z.string().min(1).describe('The role, e.g. "software engineer", "product manager", "designer".'),
|
|
163
|
+
city: z.string().optional().describe('Optional city, e.g. "San Francisco", "New York", "London".'),
|
|
164
|
+
remote: z.boolean().default(false).describe('Only remote jobs (ignores city).'),
|
|
165
|
+
max_items: maxItems(50),
|
|
166
|
+
},
|
|
167
|
+
map: (a) =>
|
|
168
|
+
clean({
|
|
169
|
+
query: a.role,
|
|
170
|
+
location: a.remote ? undefined : a.city,
|
|
171
|
+
remote: a.remote || undefined,
|
|
172
|
+
maxItems: a.max_items,
|
|
173
|
+
}),
|
|
174
|
+
limit: (a) => a.max_items,
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
name: 'search_tech_jobs',
|
|
178
|
+
actor: 'tacps126/dice-jobs-scraper',
|
|
179
|
+
title: 'Search US tech jobs on Dice',
|
|
180
|
+
price: 'about $0.00055 per job',
|
|
181
|
+
description:
|
|
182
|
+
'US tech jobs from Dice by keyword and city: title, company, location, salary text, employer type (direct hire or recruiter), Easy Apply, remote / on-site / hybrid, posted and updated dates.',
|
|
183
|
+
shape: {
|
|
184
|
+
query: z.string().min(1).describe('What to search for, e.g. "data engineer", "java developer".'),
|
|
185
|
+
location: z.string().optional().describe('Optional US city or state, e.g. "Austin, TX".'),
|
|
186
|
+
remote: z.boolean().default(false).describe('Only remote jobs.'),
|
|
187
|
+
max_items: maxItems(50, 300),
|
|
188
|
+
},
|
|
189
|
+
map: (a) =>
|
|
190
|
+
clean({
|
|
191
|
+
query: a.query,
|
|
192
|
+
location: a.location,
|
|
193
|
+
remote: a.remote || undefined,
|
|
194
|
+
maxItems: a.max_items,
|
|
195
|
+
}),
|
|
196
|
+
limit: (a) => a.max_items,
|
|
197
|
+
},
|
|
122
198
|
{
|
|
123
199
|
name: 'search_indeed_jobs',
|
|
124
200
|
actor: 'tacps126/indeed-jobs',
|
|
125
201
|
title: 'Search Indeed jobs',
|
|
126
202
|
price: 'about $0.003 per job',
|
|
127
203
|
description:
|
|
128
|
-
'Search Indeed job listings by keyword and location in 9 countries (us, uk, ca, au, ie, de, fr, nl, sg): title, company, location, salary, job type, benefits, skills and
|
|
204
|
+
'Search Indeed job listings by keyword and location in 9 countries (us, uk, ca, au, ie, de, fr, nl, sg): title, company, location, salary, job type, benefits, skills, apply link and (with details) the full job description.',
|
|
129
205
|
shape: {
|
|
130
206
|
query: z.string().min(1).describe('Job title, skill or company, e.g. "react developer".'),
|
|
131
207
|
location: z.string().optional().describe('City, state, postcode or "Remote". Empty = whole country.'),
|
|
132
208
|
country: z.enum(['us', 'uk', 'ca', 'au', 'ie', 'de', 'fr', 'nl', 'sg']).default('us').describe('Indeed country site.'),
|
|
133
209
|
date_posted_days: z.enum(['1', '3', '7', '14']).optional().describe('Only jobs posted in the last N days.'),
|
|
134
210
|
job_type: z.enum(['fulltime', 'parttime', 'contract', 'temporary', 'internship']).optional().describe('Only this employment type.'),
|
|
211
|
+
include_details: z.boolean().default(true).describe("Add each job's full description. Off = search-card summary only."),
|
|
135
212
|
max_items: maxItems(30),
|
|
136
213
|
},
|
|
137
214
|
map: (a) =>
|
|
@@ -141,6 +218,31 @@ export const TOOLS = [
|
|
|
141
218
|
country: a.country,
|
|
142
219
|
datePosted: a.date_posted_days,
|
|
143
220
|
jobType: a.job_type,
|
|
221
|
+
includeDetails: a.include_details,
|
|
222
|
+
maxItems: a.max_items,
|
|
223
|
+
}),
|
|
224
|
+
limit: (a) => a.max_items,
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
name: 'search_naukri_jobs',
|
|
228
|
+
actor: 'tacps126/naukri-jobs-scraper',
|
|
229
|
+
title: 'Search Naukri.com jobs (India)',
|
|
230
|
+
price: 'about $0.0015 per job',
|
|
231
|
+
description:
|
|
232
|
+
"Jobs from Naukri.com, India's largest job board, by keyword and city: title, company, AmbitionBox rating, experience range in years, skills, and (with details) the full description, salary in rupees, industry, department and qualifications.",
|
|
233
|
+
shape: {
|
|
234
|
+
query: z.string().min(1).describe('Job title, skill or company, e.g. "python developer".'),
|
|
235
|
+
location: z.string().optional().describe('City in India, e.g. "Bangalore", "Pune", "Delhi NCR". Empty = all of India.'),
|
|
236
|
+
date_posted_days: z.enum(['1', '3', '7', '15', '30']).optional().describe('Only jobs posted in the last N days.'),
|
|
237
|
+
include_details: z.boolean().default(true).describe('Open each job for the full description, salary, industry and qualifications. Off = faster, search-card fields only.'),
|
|
238
|
+
max_items: maxItems(30, 500),
|
|
239
|
+
},
|
|
240
|
+
map: (a) =>
|
|
241
|
+
clean({
|
|
242
|
+
queries: [a.query],
|
|
243
|
+
locations: a.location ? [a.location] : undefined,
|
|
244
|
+
datePosted: a.date_posted_days,
|
|
245
|
+
includeDetails: a.include_details,
|
|
144
246
|
maxItems: a.max_items,
|
|
145
247
|
}),
|
|
146
248
|
limit: (a) => a.max_items,
|
|
@@ -224,6 +326,89 @@ export const TOOLS = [
|
|
|
224
326
|
}),
|
|
225
327
|
limit: (a) => a.max_items,
|
|
226
328
|
},
|
|
329
|
+
{
|
|
330
|
+
name: 'find_reddit_leads',
|
|
331
|
+
actor: 'tacps126/reddit-lead-finder',
|
|
332
|
+
title: 'Find buying-intent posts on Reddit',
|
|
333
|
+
price: 'about $0.002 per lead plus $0.0001 per post read',
|
|
334
|
+
description:
|
|
335
|
+
'Reddit posts and comments where people ask for a tool like yours, look for an alternative to a competitor, compare options or complain. Each lead is tagged with its intent (recommendation_request, alternative_seeking, comparison, pain_point) and the phrase that showed it.',
|
|
336
|
+
shape: {
|
|
337
|
+
categories: z.array(z.string()).optional().describe('What you sell, as buyers say it, e.g. ["CRM", "invoice software"].'),
|
|
338
|
+
competitors: z.array(z.string()).optional().describe('Products whose users you want, e.g. ["HubSpot"].'),
|
|
339
|
+
subreddits: z.array(z.string()).optional().describe('Only search these subreddits, e.g. ["smallbusiness", "SaaS"].'),
|
|
340
|
+
time: z.enum(['day', 'week', 'month', 'year']).default('month').describe('How far back to look.'),
|
|
341
|
+
max_items: maxItems(30, 300),
|
|
342
|
+
},
|
|
343
|
+
check: (a) =>
|
|
344
|
+
(a.categories?.length || a.competitors?.length)
|
|
345
|
+
? null
|
|
346
|
+
: 'Provide at least one of: categories or competitors.',
|
|
347
|
+
map: (a) =>
|
|
348
|
+
clean({
|
|
349
|
+
keywords: a.categories,
|
|
350
|
+
competitors: a.competitors,
|
|
351
|
+
subreddits: a.subreddits,
|
|
352
|
+
time: a.time,
|
|
353
|
+
maxItems: a.max_items,
|
|
354
|
+
maxPostsPerSource: 50,
|
|
355
|
+
}),
|
|
356
|
+
limit: (a) => a.max_items,
|
|
357
|
+
},
|
|
358
|
+
{
|
|
359
|
+
name: 'search_research',
|
|
360
|
+
actor: 'tacps126/research-radar',
|
|
361
|
+
title: 'Search papers, preprints and patents',
|
|
362
|
+
price: 'about $0.003 per result',
|
|
363
|
+
description:
|
|
364
|
+
'Papers, preprints and patents from OpenAlex, arXiv, PubMed and Europe PMC in one deduplicated list, newest first or most influential first: title, abstract, authors and affiliations, venue, DOI, PDF link, citations, citations per year, field-normalized impact (top 1% / 10%), open-access status, and for patents the number, applicants and IPC/CPC classes. Retracted papers are left out.',
|
|
365
|
+
shape: {
|
|
366
|
+
queries: strings('Topics, keywords or phrases, e.g. "solid state battery".'),
|
|
367
|
+
sources: z.array(z.enum(['openalex', 'arxiv', 'pubmed', 'europepmc', 'patents', 'crossref'])).optional().describe('Which sources to search. Default: openalex, arxiv, pubmed, europepmc, patents.'),
|
|
368
|
+
posted_within_days: z.number().int().min(1).max(3650).optional().describe('Only results published in the last N days.'),
|
|
369
|
+
open_access_only: z.boolean().default(false).describe('Only papers that are free to read.'),
|
|
370
|
+
sort_by: z.enum(['newest', 'citations', 'impact']).default('newest').describe('newest first, most cited, or highest field-normalized impact (influential work).'),
|
|
371
|
+
max_items: maxItems(30, 500),
|
|
372
|
+
},
|
|
373
|
+
map: (a) =>
|
|
374
|
+
clean({
|
|
375
|
+
queries: a.queries,
|
|
376
|
+
sources: a.sources,
|
|
377
|
+
postedWithinDays: a.posted_within_days,
|
|
378
|
+
openAccessOnly: a.open_access_only,
|
|
379
|
+
sortBy: a.sort_by,
|
|
380
|
+
maxItemsPerSource: Math.min(Math.max(a.max_items, 10), 100),
|
|
381
|
+
maxItems: a.max_items,
|
|
382
|
+
}),
|
|
383
|
+
limit: (a) => a.max_items,
|
|
384
|
+
},
|
|
385
|
+
{
|
|
386
|
+
name: 'analyze_field',
|
|
387
|
+
actor: 'tacps126/innovation-radar',
|
|
388
|
+
title: 'Analyse a technology or research field',
|
|
389
|
+
price: 'about $0.03 per field',
|
|
390
|
+
description:
|
|
391
|
+
'A landscape of a technology or research field from open research data: an opportunity score (0-100) with its reasons, momentum, lab-to-market gap and geographic concentration; works per year and growth stage; industry participation and the top companies; key researchers, institutions, countries and funders; rising sub-topics, standout recent work and related patents. Several fields come back ranked. For written opportunities, use the field-opportunity-analysis prompt.',
|
|
392
|
+
shape: {
|
|
393
|
+
fields: strings('Fields or technologies, e.g. "solid state battery", "CRISPR base editing".'),
|
|
394
|
+
years: z.number().int().min(2).max(40).default(10).describe('Years of history for the trend.'),
|
|
395
|
+
},
|
|
396
|
+
map: (a) => clean({ mode: 'landscape', fields: a.fields, years: a.years, topWorks: 10 }),
|
|
397
|
+
limit: (a) => a.fields.length,
|
|
398
|
+
},
|
|
399
|
+
{
|
|
400
|
+
name: 'validate_idea',
|
|
401
|
+
actor: 'tacps126/innovation-radar',
|
|
402
|
+
title: 'Check how new or crowded an idea is',
|
|
403
|
+
price: 'about $0.03 per idea',
|
|
404
|
+
description:
|
|
405
|
+
'How much research already covers a product or research idea: matching works, works in the last two years, crowdedness (open, early, active, crowded), growth, who is working on it (researchers, institutions, companies), the closest prior work and related patents. For a written assessment, use the idea-validation prompt.',
|
|
406
|
+
shape: {
|
|
407
|
+
ideas: strings('Ideas in plain words, e.g. "a window that generates solar power with perovskite tandem cells".'),
|
|
408
|
+
},
|
|
409
|
+
map: (a) => clean({ mode: 'validate', ideas: a.ideas, topWorks: 10 }),
|
|
410
|
+
limit: (a) => a.ideas.length,
|
|
411
|
+
},
|
|
227
412
|
{
|
|
228
413
|
name: 'find_website_contacts',
|
|
229
414
|
actor: 'tacps126/contact-details',
|
|
@@ -249,22 +434,28 @@ export const TOOLS = [
|
|
|
249
434
|
{
|
|
250
435
|
name: 'search_german_property_listings',
|
|
251
436
|
actor: 'tacps126/immobilienscout24-scraper',
|
|
252
|
-
title: 'Search German property listings (ImmoScout24)',
|
|
437
|
+
title: 'Search German and Austrian property listings (ImmoScout24)',
|
|
253
438
|
price: 'about $0.001 per listing',
|
|
254
439
|
description:
|
|
255
|
-
'Apartments and houses for rent or sale in Germany: price, rent, area, rooms, address with coordinates, energy class, features, agent, photos and dates.
|
|
440
|
+
'Apartments and houses for rent or sale in Germany or Austria: price, rent, area, rooms, address with coordinates, energy class, features, agent, photos and dates. Not Switzerland.',
|
|
256
441
|
shape: {
|
|
257
|
-
|
|
442
|
+
country: z.enum(['de', 'at']).default('de').describe('de = Germany (immobilienscout24.de), at = Austria (immobilienscout24.at).'),
|
|
443
|
+
locations: strings('Cities, districts or regions in plain words, e.g. ["Berlin","München Schwabing"]; in Austria a city or federal state, e.g. ["Wien","Tirol"].'),
|
|
258
444
|
offer_type: z.enum(['rent', 'buy']).default('rent').describe('Rent or buy listings.'),
|
|
259
445
|
property_type: z.enum(['apartment', 'house']).default('apartment').describe('Apartments or houses.'),
|
|
260
446
|
min_price: z.number().optional().describe('Minimum price in EUR (monthly rent or purchase price).'),
|
|
261
447
|
max_price: z.number().optional().describe('Maximum price in EUR (monthly rent or purchase price).'),
|
|
262
448
|
min_area: z.number().optional().describe('Minimum area in m2.'),
|
|
263
449
|
min_rooms: z.number().optional().describe('Minimum number of rooms.'),
|
|
450
|
+
changes_only: z
|
|
451
|
+
.boolean()
|
|
452
|
+
.default(false)
|
|
453
|
+
.describe('Only listings that are new, changed (old and new price, rent, size, rooms) or removed since the last call with the same search. For price tracking on a schedule.'),
|
|
264
454
|
max_items: maxItems(50),
|
|
265
455
|
},
|
|
266
456
|
map: (a) =>
|
|
267
457
|
clean({
|
|
458
|
+
country: a.country,
|
|
268
459
|
locations: a.locations,
|
|
269
460
|
offerType: a.offer_type,
|
|
270
461
|
propertyType: a.property_type,
|
|
@@ -272,6 +463,7 @@ export const TOOLS = [
|
|
|
272
463
|
maxPrice: a.max_price,
|
|
273
464
|
minArea: a.min_area,
|
|
274
465
|
minRooms: a.min_rooms,
|
|
466
|
+
changesOnly: a.changes_only || undefined,
|
|
275
467
|
maxItems: a.max_items,
|
|
276
468
|
}),
|
|
277
469
|
limit: (a) => a.max_items,
|
|
@@ -300,6 +492,85 @@ export const TOOLS = [
|
|
|
300
492
|
}),
|
|
301
493
|
limit: (a) => a.max_items,
|
|
302
494
|
},
|
|
495
|
+
{
|
|
496
|
+
name: 'analyze_shopify_stores',
|
|
497
|
+
actor: 'tacps126/shopify-store-analyzer',
|
|
498
|
+
title: 'Analyze Shopify stores (location, catalog, contacts)',
|
|
499
|
+
price: 'about $0.004 per store',
|
|
500
|
+
description:
|
|
501
|
+
'For each Shopify store: name, city and country, currency, product and collection counts, a catalog snapshot (price range and median, share on sale and in stock, top brands and product types, newest product) and its e-mails, phones and social profiles. Non-Shopify sites are skipped for free.',
|
|
502
|
+
shape: {
|
|
503
|
+
stores: strings('Store websites or domains, e.g. ["allbirds.com", "gymshark.com"].'),
|
|
504
|
+
include_contacts: z.boolean().default(true).describe('Also read the store\'s contact pages for e-mails, phones and socials.'),
|
|
505
|
+
countries: z.array(z.string()).optional().describe('Keep only stores based in these countries (ISO codes or names).'),
|
|
506
|
+
max_items: maxItems(20, 1000),
|
|
507
|
+
},
|
|
508
|
+
map: (a) =>
|
|
509
|
+
clean({
|
|
510
|
+
startUrls: a.stores,
|
|
511
|
+
includeContacts: a.include_contacts,
|
|
512
|
+
countries: a.countries,
|
|
513
|
+
maxItems: a.max_items,
|
|
514
|
+
}),
|
|
515
|
+
limit: (a) => a.max_items,
|
|
516
|
+
},
|
|
517
|
+
{
|
|
518
|
+
name: 'get_trade_show_exhibitors',
|
|
519
|
+
actor: 'tacps126/exhibition-scraper',
|
|
520
|
+
title: 'Get trade show exhibitor lists (booths and contacts)',
|
|
521
|
+
price: 'about $0.002 per exhibitor',
|
|
522
|
+
description:
|
|
523
|
+
"Exhibitor lists of trade shows as B2B leads: company, booth and hall, email, phone, website, address, socials and categories. 91 built-in shows (e.g. medica, sema-show, nab-show, fabtech, ish, automechanika, wtm-london, orgatec, eurotier, wine-paris, biofach) or any exhibitor-list link or show homepage on Messe Frankfurt, Messe Düsseldorf, Koelnmesse, NürnbergMesse, Newfront/ExpoPlatform, RX, Map Your Show, a2z / A2Z Connect, Swapcard or Corussoft; the link's own show and year are used. Contact coverage depends on what the organiser publishes.",
|
|
524
|
+
shape: {
|
|
525
|
+
shows: z.array(z.string().min(1)).optional().describe('Built-in show ids, e.g. ["medica","sema-show"]. The Actor README lists all ids.'),
|
|
526
|
+
urls: z.array(z.string().url()).optional().describe("Links to any show's exhibitor list or exhibitor search page (or its homepage)."),
|
|
527
|
+
include_contacts: z.boolean().default(true).describe('Open each exhibitor profile for email, phone, website, address and socials. Off = names and booths only (faster).'),
|
|
528
|
+
changes_only: z
|
|
529
|
+
.boolean()
|
|
530
|
+
.default(false)
|
|
531
|
+
.describe('Only exhibitors that are new, changed (old and new booth, email, phone, website, address) or removed since the last call with the same shows. Removed ones need the whole list, so it ignores max_items for that.'),
|
|
532
|
+
max_items: maxItems(50, 2000),
|
|
533
|
+
},
|
|
534
|
+
map: (a) =>
|
|
535
|
+
clean({
|
|
536
|
+
exhibitionList: a.shows,
|
|
537
|
+
startUrls: (a.urls ?? []).map((url) => ({ url })),
|
|
538
|
+
includeDetails: a.include_contacts,
|
|
539
|
+
changesOnly: a.changes_only || undefined,
|
|
540
|
+
maxResults: a.max_items,
|
|
541
|
+
}),
|
|
542
|
+
// max_items applies per show.
|
|
543
|
+
limit: (a) => a.max_items * Math.max(1, (a.shows?.length ?? 0) + (a.urls?.length ?? 0)),
|
|
544
|
+
},
|
|
545
|
+
{
|
|
546
|
+
name: 'find_events',
|
|
547
|
+
actor: 'tacps126/events-scraper',
|
|
548
|
+
title: 'Find upcoming events (Luma, Eventbrite, Meetup)',
|
|
549
|
+
price: 'about $0.001 per event',
|
|
550
|
+
description:
|
|
551
|
+
'Upcoming events by topic and city, or from Luma / Eventbrite / Meetup links (or any page with schema.org events): name, dates, venue with address and coordinates, organiser, hosts, ticket prices, free/sold-out and attendee count, in one format. Use for event prospecting, sponsorships and community research.',
|
|
552
|
+
shape: {
|
|
553
|
+
searches: z.array(z.string().min(1)).optional().describe('Topics or keywords, e.g. ["AI","startup"].'),
|
|
554
|
+
location: z.string().optional().describe('City in plain words (e.g. "London", "Bengaluru") or "online". Luma searches within a city.'),
|
|
555
|
+
urls: z.array(z.string().url()).optional().describe('Luma city/category/calendar/event links, Eventbrite searches or events, Meetup search or group links, or any events page.'),
|
|
556
|
+
sources: z.array(z.enum(['luma', 'eventbrite', 'meetup'])).optional().describe('Sites searched for `searches` (default all three). Meetup knows about 70 big cities by name; others as "City, CC" (e.g. "Lyon, FR").'),
|
|
557
|
+
include_details: z.boolean().default(true).describe('Open each event for organiser, tickets and full description. Off = faster.'),
|
|
558
|
+
max_items: maxItems(30, 500),
|
|
559
|
+
},
|
|
560
|
+
map: (a) =>
|
|
561
|
+
clean({
|
|
562
|
+
searches: a.searches,
|
|
563
|
+
location: a.location,
|
|
564
|
+
startUrls: (a.urls ?? []).map((url) => ({ url })),
|
|
565
|
+
sources: a.sources,
|
|
566
|
+
includeDetails: a.include_details,
|
|
567
|
+
maxItems: a.max_items,
|
|
568
|
+
}),
|
|
569
|
+
// max_items applies per link and per search on each site.
|
|
570
|
+
limit: (a) =>
|
|
571
|
+
a.max_items *
|
|
572
|
+
Math.max(1, (a.searches?.length ?? 0) * (a.sources?.length ?? 3) + (a.urls?.length ?? 0)),
|
|
573
|
+
},
|
|
303
574
|
];
|
|
304
575
|
|
|
305
576
|
export const ACTORS = [...new Set(TOOLS.map((t) => t.actor))];
|