mcp-scraper 0.75.0 → 0.76.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/CHANGELOG.md CHANGED
@@ -4,6 +4,26 @@ All notable changes to MCP Scraper are documented here. The format is based on [
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.76.0] - 2026-08-28
8
+
9
+ ### Added
10
+
11
+ - Added a stable `mcp-scraper-core` executable that gives Thorbit exactly 34 direct public-web scraping and analysis tools while keeping integrations, connected-account actions, Scheduler, Memory, browser-agent, analytics, publishing, Commons, lead-list, Local Sourcebook, and generic workflows unregistered and uncallable.
12
+
13
+ ### Changed
14
+
15
+ - Shared the canonical schemas and handlers between the full and restricted stdio entrypoints, with fail-closed startup when a required restricted tool is missing or malformed; the normal `mcp-scraper` executable remains full-surface.
16
+
17
+ ### Fixed
18
+
19
+ - Made Commons ledger reads deterministic when multiple writes share the same timestamp, preventing release verification from observing an arbitrary operation order.
20
+
21
+ ## [0.75.1] - 2026-08-28
22
+
23
+ ### Fixed
24
+
25
+ - Parsed quoted Vercel environment files before analytics migrations, so the documented production migration command resolves the real PostgreSQL host without a custom wrapper while preserving process-level overrides.
26
+
7
27
  ## [0.75.0] - 2026-08-28
8
28
 
9
29
  ### Added
@@ -1392,7 +1412,9 @@ All notable changes to MCP Scraper are documented here. The format is based on [
1392
1412
  - Write actions remain unavailable until the account owner explicitly enables them.
1393
1413
  - Provider-specific connection data is normalized into one agent-facing contract.
1394
1414
 
1395
- [Unreleased]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.75.0...HEAD
1415
+ [Unreleased]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.76.0...HEAD
1416
+ [0.76.0]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.75.1...v0.76.0
1417
+ [0.75.1]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.75.0...v0.75.1
1396
1418
  [0.75.0]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.74.0...v0.75.0
1397
1419
  [0.74.0]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.73.8...v0.74.0
1398
1420
  [0.73.8]: https://github.com/VilovietaSEO/mcp-scraper/compare/v0.73.7...v0.73.8
package/README.md CHANGED
@@ -23,6 +23,7 @@ Use the MCPB Desktop Extension for the branded Claude Desktop install, or use th
23
23
  MCP Scraper ships one stdio entrypoint plus human-facing helper CLIs:
24
24
 
25
25
  - `mcp-scraper` — the single MCP server with every tool: live web intelligence (SERP, PAA, site extraction, YouTube, Facebook ads and organic video transcripts, Maps, directory, rank tracker blueprint, credits) plus agent-controlled direct/no-proxy hosted browser sessions (screenshots, clicks, typing, scrolling, watch URLs, replay links, MP4 replay download, and saved profile/login setup for authenticated AI visibility workflows). It is context-aware: in a human terminal it prints the branded ASCII install card; in an MCP client it runs as a protocol-clean stdio server. This is the entrypoint used by the MCPB Desktop Extension.
26
+ - `mcp-scraper-core` — a restricted stdio entrypoint for Thorbit that registers exactly 34 direct public-web scraping and analysis tools. It excludes MCP Scraper integrations and connected-account actions, Scheduler, Memory, browser-agent, analytics, publishing, Commons, lead-list, Local Sourcebook, and generic workflow surfaces. The normal `mcp-scraper` entrypoint remains full-surface.
26
27
  - `mcp-scraper-install` — explicit alias for the human-facing terminal installer card with the branded ASCII intro and copyable install commands.
27
28
  - `mcp-scraper-cli` — a human-facing CLI for setup checks, AI-agent config generation, workflow prompts, SEO workflow runs, and HTML reports. This command is safe to print because it is not an MCP stdio server.
28
29
 
@@ -173,7 +174,7 @@ Build the branded one-click bundle:
173
174
  npm run build:mcpb
174
175
  ```
175
176
 
176
- The generated bundle is written to `build/mcpb/mcp-scraper-<version>.mcpb` and copied to `public/downloads/` for the hosted download. The current public bundle is `https://mcpscraper.dev/downloads/mcp-scraper.mcpb` (`0.75.0`, SHA-256 `e1987385ca67a469f9fb73959b123ac8d925bee1f88c8d94252e9239d1e842f9`). Install it by opening or dragging it into Claude Desktop. Claude displays the `MCP Scraper` install card, icon, API-key configuration field, and manually curated current-release message from the bundle manifest.
177
+ The generated bundle is written to `build/mcpb/mcp-scraper-<version>.mcpb` and copied to `public/downloads/` for the hosted download. The current public bundle is `https://mcpscraper.dev/downloads/mcp-scraper.mcpb` (`0.76.0`, SHA-256 `70bc92f742fa937986ad71688a1f8530d55d4d9a32a6a32d757371c114d9a7bf`). Install it by opening or dragging it into Claude Desktop. Claude displays the `MCP Scraper` install card, icon, API-key configuration field, and manually curated current-release message from the bundle manifest.
177
178
 
178
179
  The MCPB install exposes every tool — web-intelligence plus all `browser_*` tools — through the one `mcp-scraper` server.
179
180
 
@@ -17,8 +17,8 @@ loadDotEnv();
17
17
  async function main() {
18
18
  const [{ serve }, { app }, { startWorker }, { migrate }] = await Promise.all([
19
19
  import("@hono/node-server"),
20
- import("../server-KNCC6FXQ.js"),
21
- import("../worker-7ASMH3MT.js"),
20
+ import("../server-IAGYCPN6.js"),
21
+ import("../worker-DR6R7J46.js"),
22
22
  import("../db-566MOHHD.js")
23
23
  ]);
24
24
  const PORT = parseInt(process.env.PORT ?? "3001");
@@ -13,7 +13,7 @@ import "../chunk-VXLU74YZ.js";
13
13
  import "../chunk-GGZEC22A.js";
14
14
  import {
15
15
  PACKAGE_VERSION
16
- } from "../chunk-RDPWFAR3.js";
16
+ } from "../chunk-JNFOBQVH.js";
17
17
 
18
18
  // src/cli/human-cli.ts
19
19
  import { Command } from "commander";
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ runMcpScraperStdio
4
+ } from "../chunk-SDX6TRJ6.js";
5
+ import "../chunk-BOGRXBH2.js";
6
+ import "../chunk-PGJQDMC2.js";
7
+ import "../chunk-DNM65UCK.js";
8
+ import "../chunk-T3MZISOF.js";
9
+ import "../chunk-7RQULQF3.js";
10
+ import "../chunk-6W4ADSWE.js";
11
+ import "../chunk-OM7HVEJ3.js";
12
+ import "../chunk-CXY5WV45.js";
13
+ import "../chunk-XSYEDC25.js";
14
+ import "../chunk-VXLU74YZ.js";
15
+ import "../chunk-GGZEC22A.js";
16
+ import "../chunk-JNFOBQVH.js";
17
+ import "../chunk-WEFPBAAG.js";
18
+
19
+ // src/mcp/thorbit-restricted-tool-surface.ts
20
+ var THORBIT_RESTRICTED_TOOL_NAMES = [
21
+ "harvest_paa",
22
+ "search_serp",
23
+ "extract_url",
24
+ "diff_page",
25
+ "map_site_urls",
26
+ "map_wayback_snapshots",
27
+ "extract_site",
28
+ "analyze_site_similarity",
29
+ "audit_site",
30
+ "check_site_export",
31
+ "site_export_read",
32
+ "site_export_image",
33
+ "archive_read",
34
+ "youtube_harvest",
35
+ "youtube_transcribe",
36
+ "facebook_page_intel",
37
+ "facebook_ad_search",
38
+ "reddit_thread",
39
+ "reddit_trending",
40
+ "video_frame_analysis",
41
+ "video_frame_analysis_status",
42
+ "facebook_ad_transcribe",
43
+ "google_ads_search",
44
+ "google_ads_page_intel",
45
+ "google_ads_transcribe",
46
+ "facebook_video_transcribe",
47
+ "instagram_profile_content",
48
+ "instagram_media_download",
49
+ "maps_place_intel",
50
+ "maps_search",
51
+ "trustpilot_reviews",
52
+ "g2_reviews",
53
+ "capture_serp_snapshot",
54
+ "capture_serp_page_snapshots"
55
+ ];
56
+
57
+ // bin/mcp-scraper-core.ts
58
+ runMcpScraperStdio({
59
+ toolsets: /* @__PURE__ */ new Set(["paa", "serp"]),
60
+ allowedToolNames: THORBIT_RESTRICTED_TOOL_NAMES
61
+ });
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  renderInstallTerminal
4
- } from "../chunk-45AZ5CR2.js";
4
+ } from "../chunk-XSYEDC25.js";
5
5
  import {
6
6
  PACKAGE_VERSION
7
- } from "../chunk-RDPWFAR3.js";
7
+ } from "../chunk-JNFOBQVH.js";
8
8
 
9
9
  // bin/mcp-scraper-install.ts
10
10
  var noColor = process.argv.includes("--no-color") || process.env.NO_COLOR !== void 0 || process.env.FORCE_COLOR === "0" || !process.stdout.isTTY;
@@ -1,173 +1,20 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- HttpMcpToolExecutor,
4
- MEMORY_TOOL_REGISTRY,
5
- SERVER_INSTRUCTIONS,
6
- ScheduledResultsMcpExecutor,
7
- hashOwnerId,
8
- installInputFieldDescriptions,
9
- permitsLocalNetworkAccess,
10
- registerBrowserAgentMcpTools,
11
- registerMemoryMcpTools,
12
- registerPaaExtractorMcpTools,
13
- registerScheduledResultsMcpTools,
14
- registerSerpIntelligenceCaptureTools,
15
- resolveDeploymentProfile
16
- } from "../chunk-DT7UD2ER.js";
3
+ runMcpScraperStdio
4
+ } from "../chunk-SDX6TRJ6.js";
5
+ import "../chunk-BOGRXBH2.js";
17
6
  import "../chunk-PGJQDMC2.js";
7
+ import "../chunk-DNM65UCK.js";
18
8
  import "../chunk-T3MZISOF.js";
19
9
  import "../chunk-7RQULQF3.js";
10
+ import "../chunk-6W4ADSWE.js";
20
11
  import "../chunk-OM7HVEJ3.js";
21
12
  import "../chunk-CXY5WV45.js";
22
- import {
23
- renderInstallTerminal
24
- } from "../chunk-45AZ5CR2.js";
13
+ import "../chunk-XSYEDC25.js";
25
14
  import "../chunk-VXLU74YZ.js";
26
15
  import "../chunk-GGZEC22A.js";
27
- import {
28
- PACKAGE_VERSION
29
- } from "../chunk-RDPWFAR3.js";
30
- import "../chunk-DNM65UCK.js";
31
- import "../chunk-6W4ADSWE.js";
16
+ import "../chunk-JNFOBQVH.js";
32
17
  import "../chunk-WEFPBAAG.js";
33
18
 
34
19
  // bin/mcp-stdio-server.ts
35
- import { readFileSync } from "fs";
36
- import { homedir } from "os";
37
- import { join } from "path";
38
- import { serveStdio } from "@modelcontextprotocol/server/stdio";
39
- import { McpServer } from "@modelcontextprotocol/server";
40
-
41
- // src/mcp/hosted-memory-mcp-tool-executor.ts
42
- var publicToolNameByUpstreamName = new Map(
43
- MEMORY_TOOL_REGISTRY.map((schema) => [schema.upstreamName, schema.id])
44
- );
45
- function parseJsonRpcEnvelope(text) {
46
- const payloads = text.split("\n").filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trim()).filter(Boolean);
47
- if (!payloads.length) return JSON.parse(text);
48
- for (const payload of payloads) {
49
- const parsed = JSON.parse(payload);
50
- if (parsed.result || parsed.error) return parsed;
51
- }
52
- throw new Error("hosted MCP returned no JSON-RPC result");
53
- }
54
- function errorResult(message) {
55
- return {
56
- content: [{ type: "text", text: JSON.stringify({ ok: false, error: message }) }],
57
- isError: true
58
- };
59
- }
60
- var HostedMemoryMcpToolExecutor = class {
61
- baseUrl;
62
- apiKey;
63
- constructor(baseUrl2, apiKey2) {
64
- this.baseUrl = baseUrl2.replace(/\/$/, "");
65
- this.apiKey = apiKey2;
66
- }
67
- async callMemoryTool(upstreamName, args) {
68
- const publicToolName = publicToolNameByUpstreamName.get(upstreamName);
69
- if (!publicToolName) return errorResult(`unknown memory tool: ${upstreamName}`);
70
- try {
71
- const res = await fetch(`${this.baseUrl}/mcp`, {
72
- method: "POST",
73
- headers: {
74
- "content-type": "application/json",
75
- accept: "application/json, text/event-stream",
76
- "x-api-key": this.apiKey
77
- },
78
- body: JSON.stringify({
79
- jsonrpc: "2.0",
80
- id: `memory:${publicToolName}`,
81
- method: "tools/call",
82
- params: { name: publicToolName, arguments: args }
83
- })
84
- });
85
- const text = await res.text();
86
- if (!res.ok) return errorResult(`hosted memory ${publicToolName} failed (HTTP ${res.status})`);
87
- const envelope = parseJsonRpcEnvelope(text);
88
- if (envelope.error) {
89
- return errorResult(envelope.error.message ?? `hosted memory ${publicToolName} failed`);
90
- }
91
- return envelope.result ?? errorResult(`hosted memory ${publicToolName} returned no result`);
92
- } catch (err) {
93
- return errorResult(err instanceof Error ? err.message : `hosted memory ${publicToolName} call failed`);
94
- }
95
- }
96
- };
97
-
98
- // bin/mcp-stdio-server.ts
99
- var forceStdio = process.argv.includes("--stdio") || process.env.MCP_SCRAPER_FORCE_STDIO === "1";
100
- var interactiveTerminal = Boolean(process.stdin.isTTY && process.stdout.isTTY);
101
- var wantsHelp = process.argv.includes("--help") || process.argv.includes("-h");
102
- if (!forceStdio && (interactiveTerminal || wantsHelp)) {
103
- const noColor = process.argv.includes("--no-color") || process.env.NO_COLOR !== void 0 || process.env.FORCE_COLOR === "0" || !process.stdout.isTTY;
104
- process.stdout.write(renderInstallTerminal({
105
- version: PACKAGE_VERSION,
106
- color: !noColor,
107
- apiKeyConfigured: Boolean(process.env.MCP_SCRAPER_API_KEY?.trim())
108
- }));
109
- process.exit(0);
110
- }
111
- function readApiKeyFile() {
112
- const explicitPath = process.env.MCP_SCRAPER_KEY_PATH?.trim();
113
- const paths = [explicitPath, join(homedir(), ".mcp-scraper-key")].filter(Boolean);
114
- for (const path of paths) {
115
- try {
116
- const value = readFileSync(path, "utf8").trim();
117
- if (value) return value;
118
- } catch {
119
- }
120
- }
121
- return void 0;
122
- }
123
- var apiKey = (process.env.MCP_SCRAPER_API_KEY ?? process.env.MCP_SCRAPER_KEY ?? process.env.MCP_API_KEY ?? readApiKeyFile())?.trim();
124
- if (!apiKey) {
125
- process.stderr.write("MCP_SCRAPER_API_KEY env var or ~/.mcp-scraper-key is required\n");
126
- process.exit(1);
127
- }
128
- var requiredApiKey = apiKey;
129
- var baseUrl = process.env.MCP_SCRAPER_BASE_URL?.trim() || process.env.MCP_BASE_URL?.trim() || "https://mcpscraper.dev";
130
- var deploymentProfile = resolveDeploymentProfile();
131
- var localNetworkAccess = permitsLocalNetworkAccess({
132
- deploymentProfile,
133
- transportProfile: "stdio",
134
- baseUrl,
135
- explicitlyEnabled: process.env.MCP_SCRAPER_ALLOW_PRIVATE_NETWORK === "1"
136
- });
137
- var consoleBaseUrl = process.env.BROWSER_AGENT_CONSOLE_URL?.trim() || baseUrl;
138
- function buildStdioServer() {
139
- const server = new McpServer({ name: "mcp-scraper", version: PACKAGE_VERSION }, {
140
- instructions: SERVER_INSTRUCTIONS,
141
- cacheHints: {
142
- "server/discover": { ttlMs: 3e5, cacheScope: "private" },
143
- "tools/list": { ttlMs: 3e5, cacheScope: "private" },
144
- "resources/list": { ttlMs: 3e5, cacheScope: "private" },
145
- "resources/templates/list": { ttlMs: 3e5, cacheScope: "private" },
146
- "resources/read": { ttlMs: 6e4, cacheScope: "private" }
147
- }
148
- });
149
- installInputFieldDescriptions(server);
150
- const httpExecutor = new HttpMcpToolExecutor(baseUrl, requiredApiKey, { localNetworkAccess });
151
- registerPaaExtractorMcpTools(server, httpExecutor, {
152
- ownerId: hashOwnerId(requiredApiKey),
153
- deploymentProfile,
154
- transportProfile: "stdio",
155
- baseUrl,
156
- localNetworkAccess,
157
- taskHandleSecret: requiredApiKey
158
- });
159
- registerSerpIntelligenceCaptureTools(server, httpExecutor, {
160
- exposeDevelopmentDiagnostics: deploymentProfile === "development" || deploymentProfile === "test"
161
- });
162
- registerBrowserAgentMcpTools(server, { baseUrl, apiKey: requiredApiKey, consoleBaseUrl });
163
- registerScheduledResultsMcpTools(server, new ScheduledResultsMcpExecutor(baseUrl, requiredApiKey));
164
- registerMemoryMcpTools(server, new HostedMemoryMcpToolExecutor(baseUrl, requiredApiKey));
165
- return server;
166
- }
167
- serveStdio(() => buildStdioServer(), {
168
- legacy: "serve",
169
- onerror(error) {
170
- process.stderr.write(`${error.message}
171
- `);
172
- }
173
- });
20
+ runMcpScraperStdio();