mcp-scraper 0.4.2 → 0.4.3

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.
@@ -7,7 +7,7 @@ import {
7
7
  registerMemoryMcpTools,
8
8
  registerPaaExtractorMcpTools,
9
9
  registerSerpIntelligenceCaptureTools
10
- } from "../chunk-GFY6XHZS.js";
10
+ } from "../chunk-BAMVP57P.js";
11
11
  import "../chunk-GWRIO6JT.js";
12
12
  import "../chunk-HPV4VOQX.js";
13
13
  import {
@@ -16,7 +16,7 @@ import {
16
16
  import "../chunk-XGIPATLV.js";
17
17
  import {
18
18
  PACKAGE_VERSION
19
- } from "../chunk-7HICT4GY.js";
19
+ } from "../chunk-SRMGSCC3.js";
20
20
  import "../chunk-M2S27J6Z.js";
21
21
 
22
22
  // bin/mcp-stdio-server.ts
@@ -17,7 +17,7 @@ import {
17
17
  } from "./chunk-XGIPATLV.js";
18
18
  import {
19
19
  PACKAGE_VERSION
20
- } from "./chunk-7HICT4GY.js";
20
+ } from "./chunk-SRMGSCC3.js";
21
21
  import {
22
22
  sanitizeVendorName
23
23
  } from "./chunk-M2S27J6Z.js";
@@ -2037,6 +2037,51 @@ ${rows}`,
2037
2037
  }
2038
2038
  };
2039
2039
  }
2040
+ function formatTrustpilotReviews(raw, input) {
2041
+ const parsed = parseData(raw);
2042
+ if ("error" in parsed) return { content: [{ type: "text", text: parsed.error }], isError: true };
2043
+ const d = parsed.data;
2044
+ const domain = d.domain ?? input.domain;
2045
+ const reviewUrl = d.reviewUrl;
2046
+ const extractedAt = d.extractedAt;
2047
+ const requestedMaxPages = d.requestedMaxPages ?? input.maxPages ?? 5;
2048
+ const pagesFetched = d.pagesFetched;
2049
+ const reviews = d.reviews ?? [];
2050
+ const durationMs = d.durationMs;
2051
+ const rows = reviews.map((r) => {
2052
+ const stars = r.rating != null ? "\u2605".repeat(r.rating) + "\u2606".repeat(r.ratingScale - r.rating) : "\u2014";
2053
+ const answer = r.body[0]?.answer ?? "";
2054
+ return `| ${cell(r.reviewer.name ?? "Anonymous")} | ${stars} | ${cell(r.title)} | ${cell(r.date ? r.date.slice(0, 10) : null)} | ${r.flags.origin ?? "\u2014"} | ${r.flags.companyReplied ? "yes" : "no"} | ${cell(truncate(answer, 100))} |`;
2055
+ }).join("\n");
2056
+ const full = [
2057
+ `# Trustpilot Reviews: ${domain}`,
2058
+ `**Collected:** ${reviews.length} review${reviews.length === 1 ? "" : "s"} across ${pagesFetched ?? 0}/${requestedMaxPages} page${requestedMaxPages === 1 ? "" : "s"}`,
2059
+ reviewUrl ? `**Source:** ${reviewUrl}` : null,
2060
+ `
2061
+ ## Reviews
2062
+ | Reviewer | Rating | Title | Date | Origin | Company Replied | Excerpt |
2063
+ |----------|--------|-------|------|--------|------------------|---------|
2064
+ ${rows}`,
2065
+ `
2066
+ ---
2067
+ \u{1F4A1} **Note:** sampling tool, default 5 pages (~100 reviews), max 50. For full-corpus export use Trustpilot's official Business API.`,
2068
+ durationMs != null ? `
2069
+ *Extracted in ${(durationMs / 1e3).toFixed(1)}s*` : null
2070
+ ].filter(Boolean).join("\n");
2071
+ return {
2072
+ ...oneBlock(full),
2073
+ structuredContent: {
2074
+ domain,
2075
+ reviewUrl: reviewUrl ?? null,
2076
+ extractedAt: extractedAt ?? null,
2077
+ requestedMaxPages,
2078
+ pagesFetched: pagesFetched ?? 0,
2079
+ reviewCount: reviews.length,
2080
+ reviews,
2081
+ durationMs: durationMs ?? 0
2082
+ }
2083
+ };
2084
+ }
2040
2085
  async function formatDirectoryWorkflow(raw, input, ctx) {
2041
2086
  const parsed = parseData(raw);
2042
2087
  if ("error" in parsed) return { content: [{ type: "text", text: parsed.error }], isError: true };
@@ -2788,6 +2833,34 @@ var MapsPlaceIntelInputSchema = {
2788
2833
  maxReviews: z.number().int().min(1).max(500).default(50).describe("Max review cards when includeReviews is true. Default 50, maximum 500."),
2789
2834
  includeServices: z.boolean().default(false).describe("Fetch the business's configured services list and areas-served list, when the profile has them. Adds one extra page visit; not present for every business.")
2790
2835
  };
2836
+ var TrustpilotReviewsInputSchema = {
2837
+ domain: z.string().min(1).describe(`The business's domain as it appears in its Trustpilot URL, e.g. "www.bhphotovideo.com" (include the www. if the site uses it \u2014 pass the domain as-is, do not guess).`),
2838
+ maxPages: z.number().int().min(1).max(50).default(5).describe("Review pages to fetch (~20 reviews per page). Default 5 (~100 reviews). Maximum 50 \u2014 large companies can have 1,000+ pages; this tool is for sampling, not full-corpus export.")
2839
+ };
2840
+ var ReviewCardSchema = z.object({
2841
+ source: z.enum(["trustpilot", "g2"]),
2842
+ sourceReviewId: z.string().nullable(),
2843
+ reviewUrl: z.string().nullable(),
2844
+ reviewer: z.object({
2845
+ name: z.string().nullable(),
2846
+ profileId: z.string().nullable(),
2847
+ title: z.string().nullable(),
2848
+ companySegment: z.string().nullable()
2849
+ }),
2850
+ rating: z.number().nullable(),
2851
+ ratingScale: z.number(),
2852
+ title: z.string().nullable(),
2853
+ date: z.string().nullable(),
2854
+ body: z.array(z.object({ question: z.string().nullable(), answer: z.string() })),
2855
+ truncated: z.boolean(),
2856
+ flags: z.object({
2857
+ origin: z.string().nullable(),
2858
+ incentivized: z.boolean().nullable(),
2859
+ validated: z.boolean().nullable(),
2860
+ currentUser: z.boolean().nullable(),
2861
+ companyReplied: z.boolean().nullable()
2862
+ })
2863
+ });
2791
2864
  var MapsSearchInputSchema = {
2792
2865
  query: z.string().min(1).describe('Business category, niche, or search term, e.g. "roofers". Do not include location here \u2014 use location instead.'),
2793
2866
  location: z.string().optional().describe('City, region, country, or service area, e.g. "Denver, CO".'),
@@ -3104,6 +3177,16 @@ var MapsPlaceIntelOutputSchema = {
3104
3177
  areasServed: z.array(z.string()),
3105
3178
  servicesStatus: z.string()
3106
3179
  };
3180
+ var TrustpilotReviewsOutputSchema = {
3181
+ domain: z.string(),
3182
+ reviewUrl: z.string(),
3183
+ extractedAt: z.string(),
3184
+ requestedMaxPages: z.number().int(),
3185
+ pagesFetched: z.number().int(),
3186
+ reviewCount: z.number().int(),
3187
+ reviews: z.array(ReviewCardSchema),
3188
+ durationMs: z.number()
3189
+ };
3107
3190
  var CreditsInfoOutputSchema = {
3108
3191
  balanceCredits: z.number().nullable(),
3109
3192
  matchedCost: z.object({
@@ -4163,6 +4246,13 @@ function registerPaaExtractorMcpTools(server, executor, options = {}) {
4163
4246
  outputSchema: recordOutputSchema("maps_search", MapsSearchOutputSchema),
4164
4247
  annotations: liveWebToolAnnotations("Google Maps Business Search")
4165
4248
  }, async (input) => formatMapsSearch(await executor.mapsSearch(input), input));
4249
+ server.registerTool("trustpilot_reviews", {
4250
+ title: "Trustpilot Review Harvest",
4251
+ description: "Extract customer reviews for a business from Trustpilot \u2014 reviewer, rating, title, body, date, invited/organic origin, company-reply flag. Sampling tool, not a full-corpus export: default 5 pages (~100 reviews), max 50 pages. For bulk/complete extraction across thousands of pages, use Trustpilot's official Business API instead.",
4252
+ inputSchema: TrustpilotReviewsInputSchema,
4253
+ outputSchema: recordOutputSchema("trustpilot_reviews", TrustpilotReviewsOutputSchema),
4254
+ annotations: liveWebToolAnnotations("Trustpilot Review Harvest")
4255
+ }, async (input) => formatTrustpilotReviews(await executor.trustpilotReviews(input), input));
4166
4256
  server.registerTool("directory_workflow", {
4167
4257
  title: "Directory Workflow: Markets + Maps",
4168
4258
  description: `Build directory/prospecting datasets: selects US city markets from Census population data, optionally joins configured ZIP groups, then runs Google Maps business searches per city in parallel. Use for "all cities over 100k population in a state" or market+Maps workflows. ${fileBehavior("Saves a CSV of results per city.", "Large results are stored as a retrievable artifact \u2014 you get an inline summary plus an artifactId for report_artifact_read.")}`,
@@ -4494,6 +4584,9 @@ var HttpMcpToolExecutor = class {
4494
4584
  mapsSearch(input) {
4495
4585
  return this.call("/maps/search", input);
4496
4586
  }
4587
+ trustpilotReviews(input) {
4588
+ return this.call("/trustpilot/reviews", input, this.httpTimeoutOverrideMs ?? 3e5);
4589
+ }
4497
4590
  directoryWorkflow(input) {
4498
4591
  const cityCount = typeof input.maxCities === "number" ? input.maxCities : 25;
4499
4592
  const concurrency = typeof input.concurrency === "number" && input.concurrency > 0 ? input.concurrency : 5;
@@ -8096,4 +8189,4 @@ export {
8096
8189
  registerMemoryMcpTools,
8097
8190
  MemoryMcpToolExecutor
8098
8191
  };
8099
- //# sourceMappingURL=chunk-GFY6XHZS.js.map
8192
+ //# sourceMappingURL=chunk-BAMVP57P.js.map