clickshot-mcp 0.1.2 → 0.1.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.
- package/README.md +6 -2
- package/package.json +1 -1
- package/server.js +51 -5
package/README.md
CHANGED
|
@@ -49,8 +49,12 @@ extension ingest port.
|
|
|
49
49
|
|
|
50
50
|
## Tools
|
|
51
51
|
|
|
52
|
-
- `get_recent_activity(limit)` — last N
|
|
53
|
-
|
|
52
|
+
- `get_recent_activity(limit)` — last N frames as screenshots + a log (URL, page
|
|
53
|
+
title, clicked element/text; periodic frames are labeled)
|
|
54
|
+
- `start_watching(task)` — Claude asks to watch the user perform a task. Turns on
|
|
55
|
+
recording + periodic frames in the extension (with a visible "Claude is watching"
|
|
56
|
+
indicator). The MCP client prompts the user to approve this.
|
|
57
|
+
- `stop_watching()` — end the watch session
|
|
54
58
|
- `clear_activity()` — wipe the buffer
|
|
55
59
|
|
|
56
60
|
## Ingest API (used by the extension)
|
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -18,7 +18,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
18
18
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
19
19
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
20
20
|
|
|
21
|
-
const VERSION = "0.1.
|
|
21
|
+
const VERSION = "0.1.3";
|
|
22
22
|
|
|
23
23
|
const WATCH_INTERVAL_MS = 4000; // periodic-frame cadence the extension uses while watching
|
|
24
24
|
|
|
@@ -54,18 +54,49 @@ const MAX_BUFFER = 200; // keep the most recent N captures in memory
|
|
|
54
54
|
const captures = [];
|
|
55
55
|
let nextId = 1;
|
|
56
56
|
|
|
57
|
-
// Claude-initiated "watch" session state. The extension
|
|
58
|
-
// starts recording (+ periodic frames) when `on` is true.
|
|
59
|
-
// start_watching tool (which the MCP client gates with a user
|
|
60
|
-
// and off by stop_watching or by the user via the extension.
|
|
57
|
+
// Claude-initiated "watch" session state. The extension holds an SSE stream
|
|
58
|
+
// (GET /events) and starts recording (+ periodic frames) when `on` is true.
|
|
59
|
+
// Turned on by the start_watching tool (which the MCP client gates with a user
|
|
60
|
+
// approval prompt) and off by stop_watching or by the user via the extension.
|
|
61
61
|
const watch = { on: false, task: null, since: null };
|
|
62
62
|
|
|
63
|
+
// SSE clients (the extension's background worker). The stream keeps the MV3
|
|
64
|
+
// service worker alive and lets the server push state changes + frame ticks.
|
|
65
|
+
const sseClients = new Set();
|
|
66
|
+
|
|
67
|
+
function sseSend(res, event, data) {
|
|
68
|
+
try {
|
|
69
|
+
res.write(`event: ${event}\ndata: ${JSON.stringify(data)}\n\n`);
|
|
70
|
+
} catch (e) {
|
|
71
|
+
/* client gone; cleaned up on 'close' */
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function broadcast(event, data) {
|
|
76
|
+
for (const res of sseClients) sseSend(res, event, data);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function watchState() {
|
|
80
|
+
return { watching: watch.on, task: watch.task, since: watch.since, intervalMs: WATCH_INTERVAL_MS };
|
|
81
|
+
}
|
|
82
|
+
|
|
63
83
|
function setWatch(on, task) {
|
|
64
84
|
watch.on = !!on;
|
|
65
85
|
watch.task = on ? task || null : null;
|
|
66
86
|
watch.since = on ? Date.now() : null;
|
|
87
|
+
broadcast("state", watchState()); // push the change to the extension immediately
|
|
67
88
|
}
|
|
68
89
|
|
|
90
|
+
// One process-wide ticker drives the push channel:
|
|
91
|
+
// • every second: while watching, emit a frame tick on the 4s cadence
|
|
92
|
+
// • every ~12s: emit a state heartbeat so the worker stays alive even when idle
|
|
93
|
+
let tick = 0;
|
|
94
|
+
setInterval(() => {
|
|
95
|
+
tick++;
|
|
96
|
+
if (watch.on && tick % Math.round(WATCH_INTERVAL_MS / 1000) === 0) broadcast("frame", { t: tick });
|
|
97
|
+
if (tick % 12 === 0) broadcast("state", watchState());
|
|
98
|
+
}, 1000);
|
|
99
|
+
|
|
69
100
|
// ---------------------------------------------------------------------------
|
|
70
101
|
// MCP server definition (tools)
|
|
71
102
|
// ---------------------------------------------------------------------------
|
|
@@ -229,6 +260,21 @@ function buildIngestApp() {
|
|
|
229
260
|
res.json({ ok: true, watching: watch.on });
|
|
230
261
|
});
|
|
231
262
|
|
|
263
|
+
// SSE push channel. The extension holds this open; it keeps the MV3 service
|
|
264
|
+
// worker alive and receives `state` (watch on/off) and `frame` (capture now)
|
|
265
|
+
// events. Replaces the old setInterval polling, which died when the worker slept.
|
|
266
|
+
app.get("/events", (req, res) => {
|
|
267
|
+
res.set({
|
|
268
|
+
"Content-Type": "text/event-stream",
|
|
269
|
+
"Cache-Control": "no-cache, no-transform",
|
|
270
|
+
Connection: "keep-alive",
|
|
271
|
+
});
|
|
272
|
+
res.flushHeaders?.();
|
|
273
|
+
sseClients.add(res);
|
|
274
|
+
sseSend(res, "state", watchState()); // sync current state on connect
|
|
275
|
+
req.on("close", () => sseClients.delete(res));
|
|
276
|
+
});
|
|
277
|
+
|
|
232
278
|
return app;
|
|
233
279
|
}
|
|
234
280
|
|