@imenam/simple-scraper 1.0.24 → 1.0.28

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 CHANGED
@@ -1,398 +1,444 @@
1
- # simple-scraper-mcp
2
-
3
- A Model Context Protocol (MCP) server for web scraping and JavaScript execution using a headless browser (Puppeteer). Includes an optional GUI for cookie management.
4
-
5
- ## Features
6
-
7
- - **`scrape_page`** — Navigate to a URL and return the full rendered HTML of the page
8
- - **`execute_js`** — Navigate to a URL and execute custom JavaScript in the page context
9
- - **`get_page_inputs`** — Extract all form inputs from a page as a structured JSON object
10
- - **`get_show_page`** — Parse a detail/show page and extract key-value blocks and tables as structured JSON
11
- - **Interactive sessions** — Keep a browser page alive across multiple tool calls to navigate, click, type, run JS, and screenshot the page in any desired state
12
- - **`screenshot`** — Capture a screenshot of any page or active session, with inline or file output
13
- - **Cookie support** — Load Netscape-format cookie files automatically before each request
14
- - **Optional GUI** — Cookie manager interface, available when integrated with the [MCP proxy](https://www.npmjs.com/package/@imenam/mcp-http-gateway)
15
-
16
- ## Requirements
17
-
18
- - Node.js >= 18
19
- - Puppeteer will automatically download a compatible Chromium browser (~300 MB) on first install
20
-
21
- ## Installation
22
-
23
- ```bash
24
- npx @imenam/simple-scraper
25
- ```
26
-
27
- Or install globally:
28
-
29
- ```bash
30
- npm install -g @imenam/simple-scraper
31
- simple-scraper
32
- ```
33
-
34
- ## MCP Configuration
35
-
36
- ### Quick setup
37
-
38
- From the repo you want to scrape from, generate a ready-to-fill `.mcp.json` in the current directory:
39
-
40
- ```bash
41
- npx @imenam/simple-scraper --claude-setup-mcp
42
- ```
43
-
44
- It creates the `simple-scraper-mcp` entry with the proxy variables pre-filled from the current
45
- folder name (`PROXY_URL`, `APP_GROUP`, `PROXY_APP_NAME`, `PROXY_APP_PATH`) plus a 1920x1080
46
- viewport, and prints the remaining optional variables. An empty variable is simply inactive
47
- (no `PROXY_URL` = no GUI), so the generated config runs as-is. An existing `.mcp.json` is merged,
48
- other servers are preserved, and an existing `simple-scraper-mcp` entry is only replaced when
49
- `--force` is passed.
50
-
51
- ## Environment Variables
52
-
53
- | Variable | Required | Default | Description |
54
- |----------|----------|---------|-------------|
55
- | `PUPPETEER_HEADLESS` | No | `true` | Run Chromium in headless mode. Set to `false` to display the browser window. |
56
- | `PUPPETEER_TIMEOUT` | No | `30000` | Default timeout in milliseconds for page navigation and waits. |
57
- | `PUPPETEER_VIEWPORT_WIDTH` | No | `1280` | Viewport width in CSS pixels, applied to every page. Affects responsive layouts and lazy-loading, not just screenshots. |
58
- | `PUPPETEER_VIEWPORT_HEIGHT` | No | `800` | Viewport height in CSS pixels, applied to every page. |
59
- | `PUPPETEER_DEVICE_SCALE_FACTOR` | No | `1` | Physical pixels per CSS pixel. Set to `2` for retina-density screenshots (same framing, twice the detail, ~4× the file size). |
60
- | `COOKIES_DIR` | No | - | Absolute path to a folder containing Netscape-format `.txt` cookie files. The folder is created automatically if it does not exist. All files are loaded and merged automatically before each request. |
61
- | `MCP_LOG_DIR` | No | `.mcp-gui/logs` | Absolute path to the directory where log files are written. |
62
- | `PROXY_URL` | No | - | Base URL of the [MCP HTTP Gateway](https://www.npmjs.com/package/@imenam/mcp-http-gateway). Required to enable the GUI. |
63
- | `PROXY_APP_PATH` | No | `/simple-scraper-mcp` | URL path under which the GUI is registered on the proxy. |
64
- | `PROXY_APP_NAME` | No | `Simple Scraper MCP` | Display name shown in the proxy's app list. |
65
- | `APP_GROUP` | No | - | Groups the app under a collapsible section (folded by default) in the proxy dashboard. Apps sharing the same value appear together; if unset, the app lands in the default "ungrouped" section. |
66
- | `SCRAPER_MAX_SESSIONS` | No | `5` | Maximum number of concurrent interactive sessions. |
67
- | `SCRAPER_SESSION_TTL_MS` | No | `600000` | Inactivity TTL for sessions in milliseconds (default: 10 minutes). Sessions unused beyond this duration are closed automatically. |
68
-
69
- ## Configuration
70
-
71
- Copy `.env.example` to `.env` and configure the variables:
72
-
73
- ```env
74
- # Puppeteer options (optional)
75
- PUPPETEER_HEADLESS=true
76
- PUPPETEER_TIMEOUT=30000
77
- PUPPETEER_VIEWPORT_WIDTH=1280
78
- PUPPETEER_VIEWPORT_HEIGHT=800
79
- PUPPETEER_DEVICE_SCALE_FACTOR=1
80
-
81
- # Optional: path to a folder containing Netscape-format cookie files (.txt)
82
- # All files in this folder will be loaded automatically before each request.
83
- # COOKIES_DIR=/path/to/cookies
84
-
85
- # GUI (optional) — required to enable the cookie manager interface
86
- # PROXY_URL=http://localhost:3000
87
- # PROXY_APP_PATH=/simple-scraper-mcp
88
- # PROXY_APP_NAME=Simple Scraper MCP
89
- # Optional: groups this app under a collapsible section of the proxy dashboard
90
- # APP_GROUP=Scraping
91
- ```
92
-
93
- ### The process environment wins over `.env`
94
-
95
- Any variable already set in the environment of the process that starts this MCP
96
- (a shell `export`, a `claude_desktop_config.json` `env` block, or a supervisor
97
- such as `@imenam/mcp-gateway-manager`) **takes precedence over the same key in
98
- this repository's `.env`**. This is dotenv's default behaviour, and the usual
99
- Unix convention: the caller wins.
100
-
101
- The `.env` is still reloaded on the fly — the GUI writes to it and the change is
102
- picked up without restarting the server — but that reload can no longer clobber
103
- what the caller injected. Concretely, an `APP_GROUP=Scraping` line in this
104
- `.env` no longer overrides an `APP_GROUP` passed in by a supervisor; it only
105
- applies when nobody passed one.
106
-
107
- To change a variable that the caller provides, change it where the caller sets
108
- it; editing `.env` will have no effect on that key.
109
-
110
- ## Usage with Claude Desktop
111
-
112
- Add the following to your `claude_desktop_config.json`. Full example with all available options:
113
-
114
- ```json
115
- {
116
- "mcpServers": {
117
- "simple-scraper": {
118
- "command": "npx",
119
- "args": ["@imenam/simple-scraper"],
120
- "env": {
121
- "PUPPETEER_HEADLESS": "true",
122
- "PUPPETEER_TIMEOUT": "30000",
123
- "COOKIES_DIR": "/path/to/your/cookies",
124
- "MCP_LOG_DIR": "/path/to/your/logs",
125
- "PROXY_URL": "http://localhost:4500",
126
- "PROXY_APP_PATH": "/simple-scraper",
127
- "PROXY_APP_NAME": "Simple Scraper"
128
- }
129
- }
130
- }
131
- }
132
- ```
133
-
134
- To load cookies automatically, add `COOKIES_DIR` pointing to a folder containing `.txt` files in [Netscape cookie format](http://www.cookiecentral.com/faq/#3.5):
135
-
136
- ```json
137
- {
138
- "mcpServers": {
139
- "simple-scraper": {
140
- "command": "npx",
141
- "args": ["@imenam/simple-scraper"],
142
- "env": {
143
- "PUPPETEER_HEADLESS": "true",
144
- "COOKIES_DIR": "/path/to/your/cookies"
145
- }
146
- }
147
- }
148
- }
149
- ```
150
-
151
- ## Usage with Cursor
152
-
153
- In Cursor, MCP servers are configured in `.cursor/mcp.json`. You can pass environment variables directly in the config. Full example with all available options:
154
-
155
- ```json
156
- {
157
- "mcpServers": {
158
- "simple-scraper": {
159
- "command": "npx",
160
- "args": ["-y", "@imenam/simple-scraper"],
161
- "env": {
162
- "PUPPETEER_HEADLESS": "true",
163
- "PUPPETEER_TIMEOUT": "30000",
164
- "COOKIES_DIR": "/path/to/your/cookies",
165
- "MCP_LOG_DIR": "/path/to/your/logs",
166
- "PROXY_URL": "http://localhost:4500",
167
- "PROXY_APP_PATH": "/simple-scraper",
168
- "PROXY_APP_NAME": "Simple Scraper"
169
- }
170
- }
171
- }
172
- }
173
- ```
174
-
175
- > **Note:** The `-y` flag in `args` avoids the interactive confirmation prompt when using `npx`.
176
-
177
- ## MCP Tools
178
-
179
- ### `scrape_page`
180
-
181
- Navigate to a URL and return the full rendered HTML.
182
-
183
- | Parameter | Type | Required | Description |
184
- |-----------|------|----------|-------------|
185
- | `url` | string | ✅ | URL of the page to scrape |
186
- | `wait_for` | string | | CSS selector to wait for before capturing HTML |
187
- | `timeout` | number | | Timeout in ms (default: 30000) |
188
-
189
- ### `execute_js`
190
-
191
- Navigate to a URL and execute custom JavaScript in the page context.
192
-
193
- The `script` parameter is executed as the body of a JavaScript function in the browser page context, equivalent to:
194
-
195
- ```js
196
- new Function(script)();
197
- ```
198
-
199
- To return data from the tool, the script must use an explicit `return`. A bare expression such as `document.title` will evaluate but the tool will receive `undefined`.
200
-
201
- Example:
202
-
203
- ```js
204
- return {
205
- title: document.title,
206
- url: window.location.href,
207
- text: document.body.innerText.slice(0, 500)
208
- };
209
- ```
210
-
211
- For asynchronous work, return a promise, for example with an async IIFE:
212
-
213
- ```js
214
- return (async () => {
215
- const response = await fetch('/api/data');
216
- return await response.json();
217
- })();
218
- ```
219
-
220
- Returned objects and arrays are serialized as formatted JSON. Primitive values are returned as text.
221
-
222
- | Parameter | Type | Required | Description |
223
- |-----------|------|----------|-------------|
224
- | `url` | string | ✅ | URL of the page |
225
- | `script` | string | ✅ | JavaScript function body to execute in the page context. Use `return` to send a result back to the tool. |
226
- | `wait_for` | string | | CSS selector to wait for before executing |
227
- | `timeout` | number | | Timeout in ms (default: 30000) |
228
-
229
- ### `get_page_inputs`
230
-
231
- Extract all form inputs from a page as a structured JSON object.
232
-
233
- | Parameter | Type | Required | Description |
234
- |-----------|------|----------|-------------|
235
- | `url` | string | ✅ | URL of the page |
236
- | `selector` | string | | CSS selector to scope the search (e.g. `#my-form`) |
237
- | `wait_for` | string | | CSS selector to wait for before extracting |
238
- | `show_hidden` | boolean | | Include `input[type=hidden]` fields (default: false) |
239
- | `timeout` | number | | Timeout in ms (default: 30000) |
240
-
241
- ### `get_show_page`
242
-
243
- Parse a detail page and extract key-value blocks and tables as structured JSON.
244
-
245
- | Parameter | Type | Required | Description |
246
- |-----------|------|----------|-------------|
247
- | `url` | string | ✅ | URL of the page |
248
- | `keys_map` | object | | Map of HTML label → JS key for field name translation |
249
- | `box_selector` | string | | CSS selector for section containers (default: `.box.box-primary`) |
250
- | `tables_max_items` | number | | Max rows per table (default: 2) |
251
- | `wait_for` | string | | CSS selector to wait for before extraction |
252
- | `timeout` | number | | Timeout in ms (default: 30000) |
253
-
254
- ---
255
-
256
- ## Interactive Sessions
257
-
258
- Interactive sessions let you keep a browser page alive across multiple tool calls, so you can bring the page into the exact state you need before extracting data or taking a screenshot.
259
-
260
- ### Typical workflow
261
-
262
- ```
263
- open_session → session_click / session_type / session_evaluate → screenshot / session_html → close_session
264
- ```
265
-
266
- ### `open_session`
267
-
268
- Open a persistent browser session. Returns a `session_id` to use with all `session_*` tools and `screenshot`.
269
-
270
- | Parameter | Type | Required | Description |
271
- |-----------|------|----------|-------------|
272
- | `url` | string | ✅ | URL to navigate to |
273
- | `wait_for` | string | | CSS selector to wait for before the session is considered ready |
274
- | `timeout` | number | | Timeout in ms (default: 30000) |
275
- | `viewport` | object | | Viewport override for this session, applied before navigation: `{ width, height, device_scale_factor }`. Omitted fields fall back to the server defaults. |
276
-
277
- ### `close_session`
278
-
279
- Close a session and free its resources. Always call this when you are done.
280
-
281
- | Parameter | Type | Required | Description |
282
- |-----------|------|----------|-------------|
283
- | `session_id` | string | ✅ | Session ID returned by `open_session` |
284
-
285
- ### `list_sessions`
286
-
287
- List all currently active sessions with their IDs and timestamps. No parameters.
288
-
289
- ### `session_goto`
290
-
291
- Navigate the session to a new URL without closing it.
292
-
293
- | Parameter | Type | Required | Description |
294
- |-----------|------|----------|-------------|
295
- | `session_id` | string | ✅ | Session ID |
296
- | `url` | string | ✅ | URL to navigate to |
297
- | `wait_for` | string | | CSS selector to wait for after navigation |
298
- | `timeout` | number | | Timeout in ms (default: 30000) |
299
-
300
- ### `session_click`
301
-
302
- Click an element in the session page.
303
-
304
- | Parameter | Type | Required | Description |
305
- |-----------|------|----------|-------------|
306
- | `session_id` | string | ✅ | Session ID |
307
- | `selector` | string | ✅ | CSS selector of the element to click |
308
- | `timeout` | number | | Timeout in ms to wait for the element (default: 30000) |
309
-
310
- ### `session_type`
311
-
312
- Type text into an input element in the session page.
313
-
314
- | Parameter | Type | Required | Description |
315
- |-----------|------|----------|-------------|
316
- | `session_id` | string | ✅ | Session ID |
317
- | `selector` | string | ✅ | CSS selector of the input element |
318
- | `text` | string | ✅ | Text to type |
319
- | `clear` | boolean | | Clear the field before typing (default: false) |
320
- | `timeout` | number | | Timeout in ms to wait for the element (default: 30000) |
321
-
322
- ### `session_wait_for`
323
-
324
- Wait for a CSS selector to appear in the session page.
325
-
326
- | Parameter | Type | Required | Description |
327
- |-----------|------|----------|-------------|
328
- | `session_id` | string | ✅ | Session ID |
329
- | `selector` | string | ✅ | CSS selector to wait for |
330
- | `timeout` | number | | Timeout in ms (default: 30000) |
331
-
332
- ### `session_evaluate`
333
-
334
- Execute JavaScript in the context of the session page. Same conventions as `execute_js`.
335
-
336
- | Parameter | Type | Required | Description |
337
- |-----------|------|----------|-------------|
338
- | `session_id` | string | ✅ | Session ID |
339
- | `script` | string | ✅ | JavaScript function body. Use `return` to get a result back. |
340
- | `wait_for` | string | | CSS selector to wait for before executing |
341
- | `timeout` | number | | Timeout in ms (default: 30000) |
342
-
343
- ### `session_html`
344
-
345
- Return the current full rendered HTML of the session page.
346
-
347
- | Parameter | Type | Required | Description |
348
- |-----------|------|----------|-------------|
349
- | `session_id` | string | ✅ | Session ID |
350
-
351
- ### `screenshot`
352
-
353
- Capture a screenshot of a page. Use `session_id` to capture an active session in its current state, or `url` for a one-shot capture.
354
-
355
- The capture area is resolved by precedence: `selector` → `clip` → `full_page` → the visible viewport.
356
-
357
- | Parameter | Type | Required | Description |
358
- |-----------|------|----------|-------------|
359
- | `session_id` | string | | Session ID. If provided, `url` is ignored and the current page state is captured. |
360
- | `url` | string | | URL for a one-shot screenshot. Required if `session_id` is not provided. |
361
- | `wait_for` | string | | CSS selector to wait for (one-shot mode only) |
362
- | `timeout` | number | | Timeout in ms (default: 30000) |
363
- | `selector` | string | | CSS selector of a specific element to capture |
364
- | `clip` | object | | Arbitrary pixel region `{ x, y, width, height }` in CSS pixels, measured from the top-left of the page. May extend below the visible viewport. Ignored when `selector` is set; cannot be combined with `full_page`. |
365
- | `viewport` | object | | Viewport override for this capture: `{ width, height, device_scale_factor }`. For a session, the previous viewport is restored afterwards. |
366
- | `full_page` | boolean | | Capture the full scrollable page height (default: false, ignored when `selector` or `clip` is provided) |
367
- | `format` | `png` \| `jpeg` | | Image format (default: `png`) |
368
- | `output` | `inline` \| `file` \| `both` | ✅ | `inline` embeds the image in the response, `file` writes it on the agent machine, `both` does both |
369
- | `destination_path` | string | ⚠️ | **Absolute directory** on the agent machine where the image is written. Created if missing. Required when `output` is `file` or `both` |
370
- | `filename` | string | ⚠️ | Name the image gets there, e.g. `home.png`. No path separators. Required when `output` is `file` or `both` |
371
- | `destination_overwrite` | boolean | | Replace the destination file if it exists (default: `false`) |
372
- | `destination_relay` | boolean | | Filled in by the mcp-http-gateway relay, never by the agent |
373
-
374
- > **Where the file lands.** There is no default destination: one would resolve on *this
375
- > server's* disk, which is not necessarily the agent's — a file nobody finds rather than an
376
- > error. In stdio the server writes it itself; behind
377
- > [`@imenam/mcp-http-gateway`](https://www.npmjs.com/package/@imenam/mcp-http-gateway) it
378
- > returns the bytes and the relay, which runs on the agent machine, writes them at
379
- > `destination_path`. That path requires `GATEWAY_INLINE_WRITE_ROOTS` in the relay's `env`
380
- > block. The image never passes through the conversation unless `output` includes `inline`.
381
-
382
- ---
383
-
384
- ## Cookie Files
385
-
386
- Cookies are loaded from `.txt` files in [Netscape format](http://www.cookiecentral.com/faq/#3.5). Place them in the folder specified by `COOKIES_DIR`. All files in the folder are loaded and merged automatically before each request. If the folder does not exist yet, it is created automatically (including any missing parent directories), so a fresh `COOKIES_DIR` no longer raises an error.
387
-
388
- ## GUI (Optional)
389
-
390
- When `PROXY_URL` is set, a cookie manager web interface is registered with the MCP proxy. It allows you to list, upload, and delete cookie files through a browser UI.
391
-
392
- ### Network exposure
393
-
394
- The GUI listens on `127.0.0.1` only: other machines reach it through the proxy or the gateway manager. A request guard from [`@imenam/mcp-gui-interface`](https://www.npmjs.com/package/@imenam/mcp-gui-interface) answers `403` to any request whose `Host` header is not `localhost`, `127.0.0.1` or `::1` (DNS rebinding protection), and to modifying requests (`POST`, `DELETE`…) sent from another site (foreign `Sec-Fetch-Site` or `Origin`).
395
-
396
- ## License
397
-
398
- ISC
1
+ # simple-scraper-mcp
2
+
3
+ A Model Context Protocol (MCP) server for web scraping and JavaScript execution using a headless browser (Puppeteer). Logged-in sites keep their session: cookies are saved per site, renewed automatically, kept alive on a schedule, and restored through an assisted login when the site ends the session. An optional GUI manages sites and shows live sessions.
4
+
5
+ ## Features
6
+
7
+ - **`scrape_page`** — Navigate to a URL and return the full rendered HTML of the page
8
+ - **`execute_js`** — Navigate to a URL and execute custom JavaScript in the page context
9
+ - **`get_page_inputs`** — Extract all form inputs from a page as a structured JSON object
10
+ - **`get_show_page`** — Parse a detail/show page and extract key-value blocks and tables as structured JSON
11
+ - **Interactive sessions** — Keep a browser page alive across multiple tool calls to navigate, click, type, run JS, and screenshot the page in any desired state
12
+ - **`screenshot`** — Capture a screenshot of any page or active session, with inline or file output
13
+ - **Sites** — Per-site cookies loaded into the browser, written back as the site renews them, kept alive on a schedule; assisted login in a visible window when a session is lost (see [Sites](#sites-connected-accounts))
14
+ - **Optional GUI** — Sites, live sessions and activity, available when integrated with the [MCP proxy](https://www.npmjs.com/package/@imenam/mcp-http-gateway)
15
+
16
+ ## Requirements
17
+
18
+ - Node.js >= 18
19
+ - Puppeteer will automatically download a compatible Chromium browser (~300 MB) on first install
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ npx @imenam/simple-scraper
25
+ ```
26
+
27
+ Or install globally:
28
+
29
+ ```bash
30
+ npm install -g @imenam/simple-scraper
31
+ simple-scraper
32
+ ```
33
+
34
+ ## MCP Configuration
35
+
36
+ ### Quick setup
37
+
38
+ From the repo you want to scrape from, generate a ready-to-fill `.mcp.json` in the current directory:
39
+
40
+ ```bash
41
+ npx @imenam/simple-scraper --claude-setup-mcp
42
+ ```
43
+
44
+ It creates the `simple-scraper-mcp` entry with the proxy variables pre-filled from the current
45
+ folder name (`PROXY_URL`, `APP_GROUP`, `PROXY_APP_NAME`, `PROXY_APP_PATH`) plus a 1920x1080
46
+ viewport, and prints the remaining optional variables. An empty variable is simply inactive
47
+ (no `PROXY_URL` = no GUI), so the generated config runs as-is. An existing `.mcp.json` is merged,
48
+ other servers are preserved, and an existing `simple-scraper-mcp` entry is only replaced when
49
+ `--force` is passed.
50
+
51
+ ## Environment Variables
52
+
53
+ | Variable | Required | Default | Description |
54
+ |----------|----------|---------|-------------|
55
+ | `PUPPETEER_HEADLESS` | No | `true` | Run Chromium in headless mode. Set to `false` to display the browser window. |
56
+ | `PUPPETEER_TIMEOUT` | No | `30000` | Default timeout in milliseconds for page navigation and waits. |
57
+ | `PUPPETEER_VIEWPORT_WIDTH` | No | `1280` | Viewport width in CSS pixels, applied to every page. Affects responsive layouts and lazy-loading, not just screenshots. |
58
+ | `PUPPETEER_VIEWPORT_HEIGHT` | No | `800` | Viewport height in CSS pixels, applied to every page. |
59
+ | `PUPPETEER_DEVICE_SCALE_FACTOR` | No | `1` | Physical pixels per CSS pixel. Set to `2` for retina-density screenshots (same framing, twice the detail, ~4× the file size). |
60
+ | `SCRAPER_DATA_DIR` | No | - | Absolute path to the folder where sites are stored (settings, cookies, activity). Created if missing. Without it, sites are disabled. See [Sites](#sites-connected-accounts). |
61
+ | `COOKIES_DIR` | No | - | Other name for `SCRAPER_DATA_DIR`, so existing configurations keep working. If both are set, they must point to the same folder, otherwise the server refuses to start. |
62
+ | `MCP_LOG_DIR` | No | `.mcp-gui/logs` | Absolute path to the directory where log files are written. |
63
+ | `PROXY_URL` | No | - | Base URL of the [MCP HTTP Gateway](https://www.npmjs.com/package/@imenam/mcp-http-gateway). Required to enable the GUI. |
64
+ | `PROXY_APP_PATH` | No | `/simple-scraper-mcp` | URL path under which the GUI is registered on the proxy. |
65
+ | `PROXY_APP_NAME` | No | `Simple Scraper MCP` | Display name shown in the proxy's app list. |
66
+ | `APP_GROUP` | No | - | Groups the app under a collapsible section (folded by default) in the proxy dashboard. Apps sharing the same value appear together; if unset, the app lands in the default "ungrouped" section. |
67
+ | `SCRAPER_MAX_SESSIONS` | No | `5` | Maximum number of concurrent interactive sessions. |
68
+ | `SCRAPER_SESSION_TTL_MS` | No | `600000` | Inactivity TTL for sessions in milliseconds (default: 10 minutes). Sessions unused beyond this duration are closed automatically. |
69
+
70
+ ## Configuration
71
+
72
+ Copy `.env.example` to `.env` and configure the variables:
73
+
74
+ ```env
75
+ # Puppeteer options (optional)
76
+ PUPPETEER_HEADLESS=true
77
+ PUPPETEER_TIMEOUT=30000
78
+ PUPPETEER_VIEWPORT_WIDTH=1280
79
+ PUPPETEER_VIEWPORT_HEIGHT=800
80
+ PUPPETEER_DEVICE_SCALE_FACTOR=1
81
+
82
+ # Optional: folder where sites are stored (settings, cookies, activity).
83
+ # COOKIES_DIR is accepted as another name for the same setting.
84
+ # SCRAPER_DATA_DIR=/path/to/scraper-data
85
+
86
+ # GUI (optional) — required to enable the web interface
87
+ # PROXY_URL=http://localhost:3000
88
+ # PROXY_APP_PATH=/simple-scraper-mcp
89
+ # PROXY_APP_NAME=Simple Scraper MCP
90
+ # Optional: groups this app under a collapsible section of the proxy dashboard
91
+ # APP_GROUP=Scraping
92
+ ```
93
+
94
+ ### The process environment wins over `.env`
95
+
96
+ Any variable already set in the environment of the process that starts this MCP
97
+ (a shell `export`, a `claude_desktop_config.json` `env` block, or a supervisor
98
+ such as `@imenam/mcp-gateway-manager`) **takes precedence over the same key in
99
+ this repository's `.env`**. This is dotenv's default behaviour, and the usual
100
+ Unix convention: the caller wins.
101
+
102
+ The `.env` is still reloaded on the fly — the GUI writes to it and the change is
103
+ picked up without restarting the server — but that reload can no longer clobber
104
+ what the caller injected. Concretely, an `APP_GROUP=Scraping` line in this
105
+ `.env` no longer overrides an `APP_GROUP` passed in by a supervisor; it only
106
+ applies when nobody passed one.
107
+
108
+ To change a variable that the caller provides, change it where the caller sets
109
+ it; editing `.env` will have no effect on that key.
110
+
111
+ ## Usage with Claude Desktop
112
+
113
+ Add the following to your `claude_desktop_config.json`. Full example with all available options:
114
+
115
+ ```json
116
+ {
117
+ "mcpServers": {
118
+ "simple-scraper": {
119
+ "command": "npx",
120
+ "args": ["@imenam/simple-scraper"],
121
+ "env": {
122
+ "PUPPETEER_HEADLESS": "true",
123
+ "PUPPETEER_TIMEOUT": "30000",
124
+ "SCRAPER_DATA_DIR": "/path/to/your/scraper-data",
125
+ "MCP_LOG_DIR": "/path/to/your/logs",
126
+ "PROXY_URL": "http://localhost:4500",
127
+ "PROXY_APP_PATH": "/simple-scraper",
128
+ "PROXY_APP_NAME": "Simple Scraper"
129
+ }
130
+ }
131
+ }
132
+ }
133
+ ```
134
+
135
+ To use logged-in sites, add `SCRAPER_DATA_DIR` (see [Sites](#sites-connected-accounts)):
136
+
137
+ ```json
138
+ {
139
+ "mcpServers": {
140
+ "simple-scraper": {
141
+ "command": "npx",
142
+ "args": ["@imenam/simple-scraper"],
143
+ "env": {
144
+ "PUPPETEER_HEADLESS": "true",
145
+ "SCRAPER_DATA_DIR": "/path/to/your/scraper-data"
146
+ }
147
+ }
148
+ }
149
+ }
150
+ ```
151
+
152
+ ## Usage with Cursor
153
+
154
+ In Cursor, MCP servers are configured in `.cursor/mcp.json`. You can pass environment variables directly in the config. Full example with all available options:
155
+
156
+ ```json
157
+ {
158
+ "mcpServers": {
159
+ "simple-scraper": {
160
+ "command": "npx",
161
+ "args": ["-y", "@imenam/simple-scraper"],
162
+ "env": {
163
+ "PUPPETEER_HEADLESS": "true",
164
+ "PUPPETEER_TIMEOUT": "30000",
165
+ "SCRAPER_DATA_DIR": "/path/to/your/scraper-data",
166
+ "MCP_LOG_DIR": "/path/to/your/logs",
167
+ "PROXY_URL": "http://localhost:4500",
168
+ "PROXY_APP_PATH": "/simple-scraper",
169
+ "PROXY_APP_NAME": "Simple Scraper"
170
+ }
171
+ }
172
+ }
173
+ }
174
+ ```
175
+
176
+ > **Note:** The `-y` flag in `args` avoids the interactive confirmation prompt when using `npx`.
177
+
178
+ ## MCP Tools
179
+
180
+ ### `scrape_page`
181
+
182
+ Navigate to a URL and return the full rendered HTML.
183
+
184
+ | Parameter | Type | Required | Description |
185
+ |-----------|------|----------|-------------|
186
+ | `url` | string | ✅ | URL of the page to scrape |
187
+ | `wait_for` | string | | CSS selector to wait for before capturing HTML |
188
+ | `timeout` | number | | Timeout in ms (default: 30000) |
189
+
190
+ ### `execute_js`
191
+
192
+ Navigate to a URL and execute custom JavaScript in the page context.
193
+
194
+ The `script` parameter is executed as the body of a JavaScript function in the browser page context, equivalent to:
195
+
196
+ ```js
197
+ new Function(script)();
198
+ ```
199
+
200
+ To return data from the tool, the script must use an explicit `return`. A bare expression such as `document.title` will evaluate but the tool will receive `undefined`.
201
+
202
+ Example:
203
+
204
+ ```js
205
+ return {
206
+ title: document.title,
207
+ url: window.location.href,
208
+ text: document.body.innerText.slice(0, 500)
209
+ };
210
+ ```
211
+
212
+ For asynchronous work, return a promise, for example with an async IIFE:
213
+
214
+ ```js
215
+ return (async () => {
216
+ const response = await fetch('/api/data');
217
+ return await response.json();
218
+ })();
219
+ ```
220
+
221
+ Returned objects and arrays are serialized as formatted JSON. Primitive values are returned as text.
222
+
223
+ | Parameter | Type | Required | Description |
224
+ |-----------|------|----------|-------------|
225
+ | `url` | string | ✅ | URL of the page |
226
+ | `script` | string | ✅ | JavaScript function body to execute in the page context. Use `return` to send a result back to the tool. |
227
+ | `wait_for` | string | | CSS selector to wait for before executing |
228
+ | `timeout` | number | | Timeout in ms (default: 30000) |
229
+
230
+ ### `get_page_inputs`
231
+
232
+ Extract all form inputs from a page as a structured JSON object.
233
+
234
+ | Parameter | Type | Required | Description |
235
+ |-----------|------|----------|-------------|
236
+ | `url` | string | ✅ | URL of the page |
237
+ | `selector` | string | | CSS selector to scope the search (e.g. `#my-form`) |
238
+ | `wait_for` | string | | CSS selector to wait for before extracting |
239
+ | `show_hidden` | boolean | | Include `input[type=hidden]` fields (default: false) |
240
+ | `timeout` | number | | Timeout in ms (default: 30000) |
241
+
242
+ ### `get_show_page`
243
+
244
+ Parse a detail page and extract key-value blocks and tables as structured JSON.
245
+
246
+ | Parameter | Type | Required | Description |
247
+ |-----------|------|----------|-------------|
248
+ | `url` | string | ✅ | URL of the page |
249
+ | `keys_map` | object | | Map of HTML label → JS key for field name translation |
250
+ | `box_selector` | string | | CSS selector for section containers (default: `.box.box-primary`) |
251
+ | `tables_max_items` | number | | Max rows per table (default: 2) |
252
+ | `wait_for` | string | | CSS selector to wait for before extraction |
253
+ | `timeout` | number | | Timeout in ms (default: 30000) |
254
+
255
+ ---
256
+
257
+ ## Interactive Sessions
258
+
259
+ Interactive sessions let you keep a browser page alive across multiple tool calls, so you can bring the page into the exact state you need before extracting data or taking a screenshot.
260
+
261
+ ### Typical workflow
262
+
263
+ ```
264
+ open_session → session_click / session_type / session_evaluate → screenshot / session_html → close_session
265
+ ```
266
+
267
+ ### `open_session`
268
+
269
+ Open a persistent browser session. Returns a `session_id` to use with all `session_*` tools and `screenshot`.
270
+
271
+ | Parameter | Type | Required | Description |
272
+ |-----------|------|----------|-------------|
273
+ | `url` | string | ✅ | URL to navigate to |
274
+ | `wait_for` | string | | CSS selector to wait for before the session is considered ready |
275
+ | `timeout` | number | | Timeout in ms (default: 30000) |
276
+ | `viewport` | object | | Viewport override for this session, applied before navigation: `{ width, height, device_scale_factor }`. Omitted fields fall back to the server defaults. |
277
+
278
+ ### `close_session`
279
+
280
+ Close a session and free its resources. Always call this when you are done.
281
+
282
+ | Parameter | Type | Required | Description |
283
+ |-----------|------|----------|-------------|
284
+ | `session_id` | string | ✅ | Session ID returned by `open_session` |
285
+
286
+ ### `list_sessions`
287
+
288
+ List all currently active sessions with their IDs and timestamps. No parameters.
289
+
290
+ ### `session_goto`
291
+
292
+ Navigate the session to a new URL without closing it.
293
+
294
+ | Parameter | Type | Required | Description |
295
+ |-----------|------|----------|-------------|
296
+ | `session_id` | string | ✅ | Session ID |
297
+ | `url` | string | ✅ | URL to navigate to |
298
+ | `wait_for` | string | | CSS selector to wait for after navigation |
299
+ | `timeout` | number | | Timeout in ms (default: 30000) |
300
+
301
+ ### `session_click`
302
+
303
+ Click an element in the session page.
304
+
305
+ | Parameter | Type | Required | Description |
306
+ |-----------|------|----------|-------------|
307
+ | `session_id` | string | ✅ | Session ID |
308
+ | `selector` | string | ✅ | CSS selector of the element to click |
309
+ | `timeout` | number | | Timeout in ms to wait for the element (default: 30000) |
310
+
311
+ ### `session_type`
312
+
313
+ Type text into an input element in the session page.
314
+
315
+ | Parameter | Type | Required | Description |
316
+ |-----------|------|----------|-------------|
317
+ | `session_id` | string | ✅ | Session ID |
318
+ | `selector` | string | ✅ | CSS selector of the input element |
319
+ | `text` | string | ✅ | Text to type |
320
+ | `clear` | boolean | | Clear the field before typing (default: false) |
321
+ | `timeout` | number | | Timeout in ms to wait for the element (default: 30000) |
322
+
323
+ ### `session_wait_for`
324
+
325
+ Wait for a CSS selector to appear in the session page.
326
+
327
+ | Parameter | Type | Required | Description |
328
+ |-----------|------|----------|-------------|
329
+ | `session_id` | string | ✅ | Session ID |
330
+ | `selector` | string | ✅ | CSS selector to wait for |
331
+ | `timeout` | number | | Timeout in ms (default: 30000) |
332
+
333
+ ### `session_evaluate`
334
+
335
+ Execute JavaScript in the context of the session page. Same conventions as `execute_js`.
336
+
337
+ | Parameter | Type | Required | Description |
338
+ |-----------|------|----------|-------------|
339
+ | `session_id` | string | ✅ | Session ID |
340
+ | `script` | string | ✅ | JavaScript function body. Use `return` to get a result back. |
341
+ | `wait_for` | string | | CSS selector to wait for before executing |
342
+ | `timeout` | number | | Timeout in ms (default: 30000) |
343
+
344
+ ### `session_html`
345
+
346
+ Return the current full rendered HTML of the session page.
347
+
348
+ | Parameter | Type | Required | Description |
349
+ |-----------|------|----------|-------------|
350
+ | `session_id` | string | ✅ | Session ID |
351
+
352
+ ### `screenshot`
353
+
354
+ Capture a screenshot of a page. Use `session_id` to capture an active session in its current state, or `url` for a one-shot capture.
355
+
356
+ The capture area is resolved by precedence: `selector` → `clip` → `full_page` → the visible viewport.
357
+
358
+ | Parameter | Type | Required | Description |
359
+ |-----------|------|----------|-------------|
360
+ | `session_id` | string | | Session ID. If provided, `url` is ignored and the current page state is captured. |
361
+ | `url` | string | | URL for a one-shot screenshot. Required if `session_id` is not provided. |
362
+ | `wait_for` | string | | CSS selector to wait for (one-shot mode only) |
363
+ | `timeout` | number | | Timeout in ms (default: 30000) |
364
+ | `selector` | string | | CSS selector of a specific element to capture |
365
+ | `clip` | object | | Arbitrary pixel region `{ x, y, width, height }` in CSS pixels, measured from the top-left of the page. May extend below the visible viewport. Ignored when `selector` is set; cannot be combined with `full_page`. |
366
+ | `viewport` | object | | Viewport override for this capture: `{ width, height, device_scale_factor }`. For a session, the previous viewport is restored afterwards. |
367
+ | `full_page` | boolean | | Capture the full scrollable page height (default: false, ignored when `selector` or `clip` is provided) |
368
+ | `format` | `png` \| `jpeg` | | Image format (default: `png`) |
369
+ | `output` | `inline` \| `file` \| `both` | ✅ | `inline` embeds the image in the response, `file` writes it on the agent machine, `both` does both |
370
+ | `destination_path` | string | ⚠️ | **Absolute directory** on the agent machine where the image is written. Created if missing. Required when `output` is `file` or `both`, except behind the relay, which keeps it on the agent side and only forwards `filename` |
371
+ | `filename` | string | ⚠️ | Name the image gets there, e.g. `home.png`. No path separators. Required when `output` is `file` or `both` |
372
+ | `destination_overwrite` | boolean | | Replace the destination file if it exists (default: `false`) |
373
+ | `destination_relay` | boolean | | Filled in by the mcp-http-gateway relay, never by the agent |
374
+
375
+ > **Where the file lands.** There is no default destination: one would resolve on *this
376
+ > server's* disk, which is not necessarily the agent's — a file nobody finds rather than an
377
+ > error. In stdio the server writes it itself; behind
378
+ > [`@imenam/mcp-http-gateway`](https://www.npmjs.com/package/@imenam/mcp-http-gateway) it
379
+ > returns the bytes and the relay, which runs on the agent machine, writes them at
380
+ > `destination_path`. That path requires `GATEWAY_INLINE_WRITE_ROOTS` in the relay's `env`
381
+ > block. The image never passes through the conversation unless `output` includes `inline`.
382
+
383
+ ---
384
+
385
+ ## Sites (connected accounts)
386
+
387
+ A **site** is an account the scraper uses while logged in: a name, the domains it covers, its login page and the sign that proves a page is seen logged in. Sites are stored in the data folder (`SCRAPER_DATA_DIR`, or `COOKIES_DIR` under its other name) and managed from the GUI (its labels are in French).
388
+
389
+ ### How cookies are used
390
+
391
+ - When the shared browser starts, it loads the cookies of every site. Any tool (`scrape_page`, `execute_js`, `open_session`, `screenshot`…) visiting one of a site's domains is therefore logged in, with nothing to pass to the tool.
392
+ - After each page closes, and every 5 minutes, the cookies the browser holds for each site's domains are written back to that site: cookies renewed by the site are kept, cookies it deleted are removed. Session cookies (no expiry date) are kept too, so a login survives a restart of the MCP.
393
+
394
+ ### Login sign
395
+
396
+ The sign tells the scraper whether a page is seen logged in:
397
+
398
+ - **L'adresse contient** (the address contains): the page address (host and path, without query or anchor) contains the value, e.g. `crm.example.com/app`;
399
+ - **Un élément est présent** (an element is present): a selector that only matches once logged in, e.g. `.user-menu`. Puppeteer's extended selectors are accepted, so an element can be matched by its text: `.user-menu span::-p-text(Galadrim)`.
400
+
401
+ **Choisir sur la page** opens the visited page as the scraper sees it logged in; clicking an element (your name, for instance) proposes selectors for it, from the most precise (its text inside its container) to the most general. **Tester** checks the sign as it is typed. Both check each selector twice: it must be found on the visited page with the site's cookies, and absent from the same page without cookies; a selector passing both is a reliable login sign.
402
+
403
+ ### Assisted login
404
+
405
+ **Se reconnecter** opens the site's login page in a headless Chromium on a blank temporary profile, on the machine running the MCP, and shows it in the GUI. You log in there yourself (credentials, two-factor authentication, SSO): clicks, typing, pasting and scrolling on the capture are replayed in the page, and the address bar allows going back or opening another address. No display is needed, so this works the same on a remote server. As soon as the login sign appears, the browser's cookies are saved for the site and it closes; **Je suis connecté** saves them without waiting for the sign. **Tout reconnecter** chains every site to reconnect, one after the other.
406
+
407
+ What you type travels from the GUI to the MCP (through the proxy when the GUI is reached remotely, which should then be served over HTTPS); it is never stored. Some sites detect headless browsers and may show a captcha or refuse the login.
408
+
409
+ Every browser of the scraper starts with Chromium's sandbox disabled (`--no-sandbox`): under a service account, on a Linux that restricts unprivileged user namespaces (Ubuntu 23.10+ with AppArmor), the sandbox cannot start.
410
+
411
+ ### Keep-alive
412
+
413
+ When enabled, the keep-alive visits the site's **Page visitée** at a fixed interval (5 min to 1 h), day and night, so that the session does not expire from inactivity. Each visit is also a check: if the login sign no longer appears, the site is marked **À reconnecter**, shown in the banner of the Sites page (unless disabled for that site), and the keep-alive stops visiting it until the next login. The visited page is also used by **Vérifier maintenant**.
414
+
415
+ The keep-alive cannot prevent a logout the site imposes on its own schedule (e.g. every night): it only avoids inactivity timeouts. After such a logout, the assisted login takes a few seconds per site.
416
+
417
+ ### Data folder layout
418
+
419
+ | Path | Content |
420
+ |------|---------|
421
+ | `sites.json` | Settings and state of every site |
422
+ | `events.json` | Activity: checks, lost sessions, logins, imports (last 1000 events) |
423
+ | `cookies/<site id>.json` | Cookies of each site |
424
+
425
+ Netscape cookie files (`.txt`) placed in this folder are not loaded. To start from an exported file, open the site and use **Importer cookies**.
426
+
427
+ ## GUI (Optional)
428
+
429
+ When `PROXY_URL` is set, a web interface is registered with the MCP proxy:
430
+
431
+ - **Sites** — every site with its state (logged in, to reconnect, not checked), its session and its keep-alive; banner and **Tout reconnecter** when sessions are lost; assisted login in a remotely controlled view of the login page, which can be shown full screen.
432
+ - **Site page** — domains, login page, login sign (picked on the page and tested), keep-alive (interval, visited page), recent activity, cookie import and **Effacer la session**.
433
+ - **Sessions** — the sessions opened by the agent, with a live view (refresh rate selectable from 0.5 s to 10 s, 2.5 s by default; can be paused or shown full screen), the last action, the matching site and the console messages.
434
+ - **Activity** — the history of every site, filterable by site.
435
+
436
+ The interface refreshes by polling: no connection stays open.
437
+
438
+ ### Network exposure
439
+
440
+ The GUI listens on `127.0.0.1` only: other machines reach it through the proxy or the gateway manager. A request guard from [`@imenam/mcp-gui-interface`](https://www.npmjs.com/package/@imenam/mcp-gui-interface) answers `403` to any request whose `Host` header is not `localhost`, `127.0.0.1` or `::1` (DNS rebinding protection), and to modifying requests (`POST`, `DELETE`…) sent from another site (foreign `Sec-Fetch-Site` or `Origin`).
441
+
442
+ ## License
443
+
444
+ ISC