mcpscraper-cli 0.1.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/README.md +97 -0
- package/dist/bin/cli.js +172 -0
- package/package.json +34 -0
package/README.md
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# mcpscraper-cli
|
|
2
|
+
|
|
3
|
+
Command-line interface for [mcpscraper.dev](https://mcpscraper.dev) and [memory.mcpscraper.dev](https://memory.mcpscraper.dev).
|
|
4
|
+
|
|
5
|
+
This is a **curated subset** of the full API — search, scrape, crawl, map, Maps search, and a couple of memory commands. It is not full API coverage. For every operation (40 scraper endpoints, 85 memory tools), use [`mcpscraper-sdk`](../scraper) and [`mcpscraper-memory-sdk`](../memory) directly.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install -g mcpscraper-cli
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Auth
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
export MCPSCRAPER_API_KEY=sk_live_your_key
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
or pass `--api-key <key>` on any command.
|
|
20
|
+
|
|
21
|
+
## Commands
|
|
22
|
+
|
|
23
|
+
### `mcpscraper search <query>`
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
$ mcpscraper search "best roofing companies denver"
|
|
27
|
+
1. TOP 10 BEST Roofing Companies in Denver, CO
|
|
28
|
+
https://www.yelp.com/search?find_desc=Roofing+Companies&find_loc=Denver%2C+CO
|
|
29
|
+
2. Recomendations for roofing company in Denver - ASAP
|
|
30
|
+
https://www.reddit.com/r/Denver/comments/1kh2gd3/...
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Options: `--location <location>`, `--json`.
|
|
34
|
+
|
|
35
|
+
### `mcpscraper scrape <url>`
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
$ mcpscraper scrape https://example.com --deposit-to-vault --vault research
|
|
39
|
+
Example Domain
|
|
40
|
+
This domain is for use in illustrative examples...
|
|
41
|
+
|
|
42
|
+
Vault deposit: saved to research
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Options: `--screenshot`, `--deposit-to-vault`, `--vault <name>`, `--json`.
|
|
46
|
+
|
|
47
|
+
### `mcpscraper crawl <url>`
|
|
48
|
+
|
|
49
|
+
Crawls and extracts every page of a site. Options: `--max-pages <n>` (default 100), `--json`.
|
|
50
|
+
|
|
51
|
+
### `mcpscraper map <url>`
|
|
52
|
+
|
|
53
|
+
Discovers all URLs on a site (no extraction). Options: `--json`.
|
|
54
|
+
|
|
55
|
+
### `mcpscraper maps-search <query> --location <location>`
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
$ mcpscraper maps-search "roofers" --location "Denver, CO"
|
|
59
|
+
1. Forest Roofs (4.9★)
|
|
60
|
+
701 Birch Street
|
|
61
|
+
2. Mike & Sons Roofing (4.8★)
|
|
62
|
+
...
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Options: `--json`.
|
|
66
|
+
|
|
67
|
+
### `mcpscraper memory search <query>`
|
|
68
|
+
|
|
69
|
+
Semantic search across your mcp-memory vaults, dispatched through your mcpscraper.dev API key (no separate memory key needed).
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
$ mcpscraper memory search "roofing warranty terms"
|
|
73
|
+
[0.83] note:competitor-research/roofing-warranties.md
|
|
74
|
+
Standard roofing warranty terms cover materials for 25-30 years...
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### `mcpscraper memory list-vaults`
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
$ mcpscraper memory list-vaults
|
|
81
|
+
Ideas (2 notes, owner)
|
|
82
|
+
Inspiration (2 notes, owner)
|
|
83
|
+
Knowledge (3 notes, owner)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Every command supports `--json`
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
$ mcpscraper map https://example.com --json
|
|
90
|
+
{
|
|
91
|
+
"urls": ["https://example.com/", "https://example.com/about"]
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## See also
|
|
96
|
+
|
|
97
|
+
[Repo README](../../README.md) (multi-language examples with real sample output) · [`mcpscraper-sdk`](../scraper) · [`mcpscraper-memory-sdk`](../memory) · Python: [`mcpscraper-sdk`](../scraper-python) · [`mcpscraper-memory-sdk`](../memory-python)
|
package/dist/bin/cli.js
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/cli.ts
|
|
4
|
+
import { Command } from "commander";
|
|
5
|
+
import { fileURLToPath } from "url";
|
|
6
|
+
import { ScraperClient, ScraperApiError } from "mcpscraper-sdk";
|
|
7
|
+
|
|
8
|
+
// src/version.ts
|
|
9
|
+
var CLI_VERSION = "0.1.0";
|
|
10
|
+
|
|
11
|
+
// src/cli.ts
|
|
12
|
+
function printResult(result, json, summarize) {
|
|
13
|
+
if (json) {
|
|
14
|
+
console.log(JSON.stringify(result, null, 2));
|
|
15
|
+
} else {
|
|
16
|
+
summarize(result);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
async function run(fn) {
|
|
20
|
+
try {
|
|
21
|
+
await fn();
|
|
22
|
+
} catch (err) {
|
|
23
|
+
if (err instanceof ScraperApiError) {
|
|
24
|
+
console.error(`Error${err.code ? ` [${err.code}]` : ""}: ${err.message}`);
|
|
25
|
+
} else {
|
|
26
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
27
|
+
}
|
|
28
|
+
process.exitCode = 1;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function createProgram(fetchImpl = globalThis.fetch) {
|
|
32
|
+
function resolveApiKey(cmd) {
|
|
33
|
+
const opts = cmd.optsWithGlobals();
|
|
34
|
+
const key = opts.apiKey ?? process.env.MCPSCRAPER_API_KEY;
|
|
35
|
+
if (!key) {
|
|
36
|
+
console.error("Missing API key. Pass --api-key <key> or set MCPSCRAPER_API_KEY.");
|
|
37
|
+
process.exit(1);
|
|
38
|
+
}
|
|
39
|
+
return key;
|
|
40
|
+
}
|
|
41
|
+
function client(cmd) {
|
|
42
|
+
return new ScraperClient({ apiKey: resolveApiKey(cmd), fetch: fetchImpl });
|
|
43
|
+
}
|
|
44
|
+
const program = new Command();
|
|
45
|
+
program.name("mcpscraper").description("CLI for mcpscraper.dev and memory.mcpscraper.dev \u2014 a curated subset of the full API, see mcpscraper-sdk for full coverage").version(CLI_VERSION).option("--api-key <key>", "mcpscraper.dev API key (or set MCPSCRAPER_API_KEY)");
|
|
46
|
+
program.command("search <query>").description("Run a Google SERP search").option("--location <location>", "geographic location to search from").option("--json", "print raw JSON").action(async (query, opts, cmd) => {
|
|
47
|
+
await run(async () => {
|
|
48
|
+
const result = await client(cmd).searchSerp({
|
|
49
|
+
query,
|
|
50
|
+
location: opts.location,
|
|
51
|
+
depth: 4,
|
|
52
|
+
maxQuestions: 30,
|
|
53
|
+
gl: "us",
|
|
54
|
+
hl: "en",
|
|
55
|
+
device: "desktop",
|
|
56
|
+
proxyMode: "none",
|
|
57
|
+
pages: 1,
|
|
58
|
+
debug: false
|
|
59
|
+
});
|
|
60
|
+
printResult(result, Boolean(opts.json), (r) => {
|
|
61
|
+
const organic = r.result?.organicResults ?? [];
|
|
62
|
+
for (const item of organic) {
|
|
63
|
+
console.log(`${item.position}. ${item.title}
|
|
64
|
+
${item.url}`);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
program.command("scrape <url>").description("Extract a single page (markdown, headings, optional screenshot/vault deposit)").option("--screenshot", "capture a full-page screenshot").option("--deposit-to-vault", "save the full page into your mcp-memory vault").option("--vault <name>", "vault name for --deposit-to-vault").option("--json", "print raw JSON").action(async (url, opts, cmd) => {
|
|
70
|
+
await run(async () => {
|
|
71
|
+
const result = await client(cmd).extractUrl({
|
|
72
|
+
url,
|
|
73
|
+
screenshot: Boolean(opts.screenshot),
|
|
74
|
+
screenshotDevice: "desktop",
|
|
75
|
+
extractBranding: false,
|
|
76
|
+
downloadMedia: false,
|
|
77
|
+
allowLocal: false,
|
|
78
|
+
depositToVault: Boolean(opts.depositToVault),
|
|
79
|
+
vaultName: opts.vault
|
|
80
|
+
});
|
|
81
|
+
printResult(result, Boolean(opts.json), (r) => {
|
|
82
|
+
const page = r;
|
|
83
|
+
console.log(page.title ?? "(untitled)");
|
|
84
|
+
console.log((page.bodyMarkdown ?? "").slice(0, 500));
|
|
85
|
+
if (page.memory) console.log(`
|
|
86
|
+
Vault deposit: ${page.memory.deposited ? `saved to ${page.memory.vault}` : "failed"}`);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
program.command("crawl <url>").description("Crawl and extract every page of a site").option("--max-pages <n>", "maximum pages to crawl", (v) => parseInt(v, 10)).option("--json", "print raw JSON").action(async (url, opts, cmd) => {
|
|
91
|
+
await run(async () => {
|
|
92
|
+
const result = await client(cmd).extractSite({
|
|
93
|
+
url,
|
|
94
|
+
maxPages: opts.maxPages ?? 100,
|
|
95
|
+
background: false,
|
|
96
|
+
rotateProxies: false,
|
|
97
|
+
rotateProxyEvery: 30,
|
|
98
|
+
browserFallback: false,
|
|
99
|
+
kernelFallback: false
|
|
100
|
+
});
|
|
101
|
+
printResult(result, Boolean(opts.json), (r) => {
|
|
102
|
+
const pages = r.pages ?? [];
|
|
103
|
+
console.log(`Crawled ${pages.length} page(s).`);
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
program.command("map <url>").description("Discover all URLs on a site").option("--json", "print raw JSON").action(async (url, opts, cmd) => {
|
|
108
|
+
await run(async () => {
|
|
109
|
+
const result = await client(cmd).mapSiteUrls({
|
|
110
|
+
url,
|
|
111
|
+
maxUrls: 500,
|
|
112
|
+
concurrency: 12,
|
|
113
|
+
browserFallback: false,
|
|
114
|
+
kernelFallback: false
|
|
115
|
+
});
|
|
116
|
+
printResult(result, Boolean(opts.json), (r) => {
|
|
117
|
+
const urls = r.urls ?? [];
|
|
118
|
+
for (const u of urls) console.log(u);
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
program.command("maps-search <query>").description("Search Google Maps for local businesses").requiredOption("--location <location>", 'e.g. "Denver, CO"').option("--json", "print raw JSON").action(async (query, opts, cmd) => {
|
|
123
|
+
await run(async () => {
|
|
124
|
+
const result = await client(cmd).maps.search({
|
|
125
|
+
query,
|
|
126
|
+
location: opts.location,
|
|
127
|
+
gl: "us",
|
|
128
|
+
hl: "en",
|
|
129
|
+
maxResults: 10,
|
|
130
|
+
proxyMode: "location",
|
|
131
|
+
debug: false
|
|
132
|
+
});
|
|
133
|
+
printResult(result, Boolean(opts.json), (r) => {
|
|
134
|
+
const results = r.results ?? [];
|
|
135
|
+
for (const item of results) {
|
|
136
|
+
console.log(`${item.position}. ${item.name}${item.rating ? ` (${item.rating}\u2605)` : ""}
|
|
137
|
+
${item.address ?? ""}`);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
const memory = program.command("memory").description("Memory tools, dispatched through your mcpscraper.dev API key (see mcpscraper-memory-sdk for the full 85-tool surface)");
|
|
143
|
+
memory.command("search <query>").description("Semantic search across your mcp-memory vaults").option("--json", "print raw JSON").action(async (query, opts, cmd) => {
|
|
144
|
+
await run(async () => {
|
|
145
|
+
const result = await client(cmd).memoryTools.memory.search({ query });
|
|
146
|
+
printResult(result, Boolean(opts.json), (r) => {
|
|
147
|
+
const results = r.results ?? [];
|
|
148
|
+
for (const item of results) {
|
|
149
|
+
console.log(`[${item.score.toFixed(2)}] ${item.source}
|
|
150
|
+
${item.text.slice(0, 160)}`);
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
memory.command("list-vaults").description("List your mcp-memory vaults").option("--json", "print raw JSON").action(async (opts, cmd) => {
|
|
156
|
+
await run(async () => {
|
|
157
|
+
const result = await client(cmd).memoryTools.vaults.listVaults({});
|
|
158
|
+
printResult(result, Boolean(opts.json), (r) => {
|
|
159
|
+
const vaults = r.vaults ?? [];
|
|
160
|
+
for (const v of vaults) console.log(`${v.vault} (${v.notes} notes, ${v.role})`);
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
return program;
|
|
165
|
+
}
|
|
166
|
+
var isMain = process.argv[1] === fileURLToPath(import.meta.url);
|
|
167
|
+
if (isMain) {
|
|
168
|
+
await createProgram().parseAsync(process.argv);
|
|
169
|
+
}
|
|
170
|
+
export {
|
|
171
|
+
createProgram
|
|
172
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "mcpscraper-cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Command-line interface for mcpscraper.dev and memory.mcpscraper.dev",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"mcpscraper": "dist/bin/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsup src/cli.ts --format esm --out-dir dist/bin",
|
|
16
|
+
"typecheck": "tsc --noEmit",
|
|
17
|
+
"test": "tsx --test test/*.test.ts"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"mcpscraper-sdk": "^0.3.0",
|
|
21
|
+
"commander": "^12.0.0"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@types/node": "^22.0.0"
|
|
25
|
+
},
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "git+https://github.com/VilovietaSEO/mcpscraper-sdk.git",
|
|
29
|
+
"directory": "packages/cli"
|
|
30
|
+
},
|
|
31
|
+
"publishConfig": {
|
|
32
|
+
"access": "public"
|
|
33
|
+
}
|
|
34
|
+
}
|