pagebolt-mcp 1.9.0 → 1.10.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/package.json +1 -1
- package/server.json +2 -2
- package/src/index.mjs +36 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pagebolt-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.0",
|
|
4
4
|
"description": "MCP server for PageBolt — take screenshots, generate PDFs, create OG images, inspect pages, record demo videos with Audio Guide narration, from AI coding assistants like Claude, Cursor, and Windsurf.",
|
|
5
5
|
"main": "src/index.mjs",
|
|
6
6
|
"module": "src/index.mjs",
|
package/server.json
CHANGED
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
"url": "https://github.com/Custodia-Admin/pagebolt-mcp",
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
|
-
"version": "1.
|
|
9
|
+
"version": "1.10.0",
|
|
10
10
|
"packages": [
|
|
11
11
|
{
|
|
12
12
|
"registryType": "npm",
|
|
13
13
|
"identifier": "pagebolt-mcp",
|
|
14
|
-
"version": "1.
|
|
14
|
+
"version": "1.10.0",
|
|
15
15
|
"transport": {
|
|
16
16
|
"type": "stdio"
|
|
17
17
|
},
|
package/src/index.mjs
CHANGED
|
@@ -61,7 +61,7 @@ async function callApi(endpoint, options = {}) {
|
|
|
61
61
|
const method = options.method || 'GET';
|
|
62
62
|
const headers = {
|
|
63
63
|
'x-api-key': API_KEY,
|
|
64
|
-
'user-agent': 'pagebolt-mcp/1.
|
|
64
|
+
'user-agent': 'pagebolt-mcp/1.10.0',
|
|
65
65
|
...(options.body ? { 'Content-Type': 'application/json' } : {}),
|
|
66
66
|
};
|
|
67
67
|
const body = options.body ? JSON.stringify(options.body) : undefined;
|
|
@@ -191,6 +191,29 @@ When building sequences or videos, ALWAYS use inspect_page first to discover rel
|
|
|
191
191
|
|
|
192
192
|
This avoids guessing selectors like "#submit" when the actual element is "#submitBtn".
|
|
193
193
|
|
|
194
|
+
## Handling Dynamic UI: Dropdowns, Popovers, and Modals
|
|
195
|
+
|
|
196
|
+
Clicking menus, avatars, profile icons, "⋯" buttons, hamburger toggles, or anything that opens a dropdown/popover/modal creates an overlay that floats ABOVE the page. This is the #1 cause of broken multi-step automations:
|
|
197
|
+
- Subsequent steps get visually obscured by the still-open overlay.
|
|
198
|
+
- A click intended for the underlying page lands on the overlay (or its backdrop) and navigates somewhere unexpected.
|
|
199
|
+
|
|
200
|
+
Rules:
|
|
201
|
+
1. **Don't open menus you don't need.** For a high-level tour, navigate directly to the destination URL (from inspect_page / observe_page) instead of clicking through a dropdown.
|
|
202
|
+
2. **If you open an overlay, the very next step must commit to it** — either interact with an element INSIDE the overlay, or explicitly close it before continuing. There is no "press_key" action, so close an overlay with an evaluate step (note: max 2 evaluate steps per sequence):
|
|
203
|
+
{ "action": "evaluate", "script": "document.activeElement&&document.activeElement.blur&&document.activeElement.blur();document.dispatchEvent(new KeyboardEvent('keydown',{key:'Escape',bubbles:true}));" }
|
|
204
|
+
(Clicking a blank area can also work, but may hit the overlay backdrop and navigate — prefer the evaluate approach or click a known-safe element.)
|
|
205
|
+
3. **Never chain clicks across a state change you haven't re-perceived.** Selectors gathered before a menu opened or a route changed may now point at the wrong (or covered) element.
|
|
206
|
+
|
|
207
|
+
## Re-perceive Between Actions (avoid getting lost)
|
|
208
|
+
|
|
209
|
+
run_sequence and record_video execute a FIXED, pre-planned list of steps — they do NOT re-check the page between steps. For anything beyond a short, predictable flow, work iteratively instead of blind-batching:
|
|
210
|
+
1. observe_page (or take_screenshot) to see the CURRENT state.
|
|
211
|
+
2. Perform ONE meaningful action (a short run_sequence, or a single click/fill).
|
|
212
|
+
3. observe_page / take_screenshot AGAIN, then choose the next action from the fresh result.
|
|
213
|
+
Repeat. This is how an agent recovers from unexpected popovers, redirects, or layout shifts. Use session_id (create_session, Starter+) on run_sequence to keep cookies/auth/scroll state across these iterations.
|
|
214
|
+
|
|
215
|
+
For record_video specifically (one continuous capture, no mid-recording re-perception): keep the flow short and predictable, use ONLY selectors verified via inspect_page/observe_page, and add a dismiss step after anything that could open an overlay.
|
|
216
|
+
|
|
194
217
|
## Visual Diff
|
|
195
218
|
|
|
196
219
|
Use visual_diff to compare two pages pixel-by-pixel. Returns a diff image with changed pixels highlighted in red.
|
|
@@ -261,7 +284,7 @@ Use blockBanners on almost every request to get clean captures. Combine blockAds
|
|
|
261
284
|
function createConfiguredServer() {
|
|
262
285
|
const srv = new McpServer({
|
|
263
286
|
name: 'pagebolt',
|
|
264
|
-
version: '1.
|
|
287
|
+
version: '1.10.0',
|
|
265
288
|
}, {
|
|
266
289
|
instructions: SERVER_INSTRUCTIONS,
|
|
267
290
|
});
|
|
@@ -873,10 +896,12 @@ server.tool(
|
|
|
873
896
|
blockTrackers: z.boolean().optional().describe('Block tracking scripts'),
|
|
874
897
|
blockRequests: z.array(z.string()).optional().describe('URL patterns to block'),
|
|
875
898
|
blockResources: z.array(z.string()).optional().describe('Resource types to block'),
|
|
899
|
+
// ── Session ──
|
|
900
|
+
session_id: z.string().optional().describe('Inspect the LIVE state of a persistent session (Starter+; create with create_session) instead of a fresh page load. Omit url to inspect the page exactly as the last run_sequence/take_screenshot left it; pass url to navigate within the session first. Ideal for re-perceiving between agent actions.'),
|
|
876
901
|
},
|
|
877
902
|
async (params) => {
|
|
878
|
-
if (!params.url && !params.html) {
|
|
879
|
-
return { content: [{ type: 'text', text: 'Error: Either "url" or "
|
|
903
|
+
if (!params.url && !params.html && !params.session_id) {
|
|
904
|
+
return { content: [{ type: 'text', text: 'Error: Either "url", "html", or "session_id" is required.' }], isError: true };
|
|
880
905
|
}
|
|
881
906
|
|
|
882
907
|
try {
|
|
@@ -1003,10 +1028,12 @@ server.tool(
|
|
|
1003
1028
|
blockAds: z.boolean().optional().describe('Block advertisements on the page'),
|
|
1004
1029
|
blockChats: z.boolean().optional().describe('Block live chat widgets'),
|
|
1005
1030
|
blockTrackers: z.boolean().optional().describe('Block tracking scripts'),
|
|
1031
|
+
// ── Session ──
|
|
1032
|
+
session_id: z.string().optional().describe('Observe the LIVE state of a persistent session (Starter+; create with create_session) instead of a fresh page load. Omit url to observe the page exactly as the last run_sequence/take_screenshot left it; pass url to navigate within the session first. This is the recommended way to re-perceive between agent actions and recover from popovers/redirects.'),
|
|
1006
1033
|
},
|
|
1007
1034
|
async (params) => {
|
|
1008
|
-
if (!params.url && !params.html) {
|
|
1009
|
-
return { content: [{ type: 'text', text: 'Error: Either "url" or "
|
|
1035
|
+
if (!params.url && !params.html && !params.session_id) {
|
|
1036
|
+
return { content: [{ type: 'text', text: 'Error: Either "url", "html", or "session_id" is required.' }], isError: true };
|
|
1010
1037
|
}
|
|
1011
1038
|
|
|
1012
1039
|
try {
|
|
@@ -1454,6 +1481,9 @@ Based on the inspection and the description, plan 5–12 action steps. Rules:
|
|
|
1454
1481
|
{ "action": "wait", "ms": 1500, "live": true }
|
|
1455
1482
|
- Do NOT pad with wait steps between steps that don't need load time — pace handles inter-step timing automatically.
|
|
1456
1483
|
- Do NOT use zoom unless the user explicitly asked for it.
|
|
1484
|
+
- **Avoid opening dropdowns/menus/popovers** unless the demo is specifically about their contents — they stay open and obscure or misdirect later steps. Prefer navigating directly to the target URL (from the inspection) over clicking through a menu. The recording cannot re-check the page between steps, so a stuck-open overlay will break everything after it.
|
|
1485
|
+
- If a step DOES open an overlay, the next step must either act on an element inside it or close it. There is no key-press action; close with an evaluate step (max 2 per video):
|
|
1486
|
+
{ "action": "evaluate", "script": "document.activeElement&&document.activeElement.blur&&document.activeElement.blur();document.dispatchEvent(new KeyboardEvent('keydown',{key:'Escape',bubbles:true}));" }
|
|
1457
1487
|
|
|
1458
1488
|
**Step 3 — Write the narration script**
|
|
1459
1489
|
Write an audioGuide.script that matches the step count. Format:
|