@peekdev/mcp 0.1.0-alpha.1

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.
Files changed (120) hide show
  1. package/NOTICE +10 -0
  2. package/dist/db/index.d.ts +3 -0
  3. package/dist/db/index.d.ts.map +1 -0
  4. package/dist/db/index.js +7 -0
  5. package/dist/db/index.js.map +1 -0
  6. package/dist/db/migrate.d.ts +37 -0
  7. package/dist/db/migrate.d.ts.map +1 -0
  8. package/dist/db/migrate.js +86 -0
  9. package/dist/db/migrate.js.map +1 -0
  10. package/dist/db/migrations/0001_initial.sql +102 -0
  11. package/dist/db/migrations/0002_network_bodies.sql +15 -0
  12. package/dist/db/open.d.ts +57 -0
  13. package/dist/db/open.d.ts.map +1 -0
  14. package/dist/db/open.js +74 -0
  15. package/dist/db/open.js.map +1 -0
  16. package/dist/index.d.ts +10 -0
  17. package/dist/index.d.ts.map +1 -0
  18. package/dist/index.js +58 -0
  19. package/dist/index.js.map +1 -0
  20. package/dist/mcp/action-schema.d.ts +223 -0
  21. package/dist/mcp/action-schema.d.ts.map +1 -0
  22. package/dist/mcp/action-schema.js +97 -0
  23. package/dist/mcp/action-schema.js.map +1 -0
  24. package/dist/mcp/event-blobs.d.ts +32 -0
  25. package/dist/mcp/event-blobs.d.ts.map +1 -0
  26. package/dist/mcp/event-blobs.js +65 -0
  27. package/dist/mcp/event-blobs.js.map +1 -0
  28. package/dist/mcp/event-walker.d.ts +86 -0
  29. package/dist/mcp/event-walker.d.ts.map +1 -0
  30. package/dist/mcp/event-walker.js +398 -0
  31. package/dist/mcp/event-walker.js.map +1 -0
  32. package/dist/mcp/host-bridge.d.ts +80 -0
  33. package/dist/mcp/host-bridge.d.ts.map +1 -0
  34. package/dist/mcp/host-bridge.js +88 -0
  35. package/dist/mcp/host-bridge.js.map +1 -0
  36. package/dist/mcp/index.d.ts +8 -0
  37. package/dist/mcp/index.d.ts.map +1 -0
  38. package/dist/mcp/index.js +32 -0
  39. package/dist/mcp/index.js.map +1 -0
  40. package/dist/mcp/playwright-repro.d.ts +19 -0
  41. package/dist/mcp/playwright-repro.d.ts.map +1 -0
  42. package/dist/mcp/playwright-repro.js +78 -0
  43. package/dist/mcp/playwright-repro.js.map +1 -0
  44. package/dist/mcp/queries.d.ts +73 -0
  45. package/dist/mcp/queries.d.ts.map +1 -0
  46. package/dist/mcp/queries.js +139 -0
  47. package/dist/mcp/queries.js.map +1 -0
  48. package/dist/mcp/roots.d.ts +50 -0
  49. package/dist/mcp/roots.d.ts.map +1 -0
  50. package/dist/mcp/roots.js +97 -0
  51. package/dist/mcp/roots.js.map +1 -0
  52. package/dist/mcp/rrweb-types.d.ts +3 -0
  53. package/dist/mcp/rrweb-types.d.ts.map +1 -0
  54. package/dist/mcp/rrweb-types.js +7 -0
  55. package/dist/mcp/rrweb-types.js.map +1 -0
  56. package/dist/mcp/selector.d.ts +54 -0
  57. package/dist/mcp/selector.d.ts.map +1 -0
  58. package/dist/mcp/selector.js +209 -0
  59. package/dist/mcp/selector.js.map +1 -0
  60. package/dist/mcp/server.d.ts +49 -0
  61. package/dist/mcp/server.d.ts.map +1 -0
  62. package/dist/mcp/server.js +469 -0
  63. package/dist/mcp/server.js.map +1 -0
  64. package/dist/mcp/summary.d.ts +26 -0
  65. package/dist/mcp/summary.d.ts.map +1 -0
  66. package/dist/mcp/summary.js +74 -0
  67. package/dist/mcp/summary.js.map +1 -0
  68. package/dist/native-host/action-protocol.d.ts +49 -0
  69. package/dist/native-host/action-protocol.d.ts.map +1 -0
  70. package/dist/native-host/action-protocol.js +36 -0
  71. package/dist/native-host/action-protocol.js.map +1 -0
  72. package/dist/native-host/audit.d.ts +69 -0
  73. package/dist/native-host/audit.d.ts.map +1 -0
  74. package/dist/native-host/audit.js +85 -0
  75. package/dist/native-host/audit.js.map +1 -0
  76. package/dist/native-host/config.d.ts +18 -0
  77. package/dist/native-host/config.d.ts.map +1 -0
  78. package/dist/native-host/config.js +56 -0
  79. package/dist/native-host/config.js.map +1 -0
  80. package/dist/native-host/extension-ids.json +6 -0
  81. package/dist/native-host/host.d.ts +30 -0
  82. package/dist/native-host/host.d.ts.map +1 -0
  83. package/dist/native-host/host.js +96 -0
  84. package/dist/native-host/host.js.map +1 -0
  85. package/dist/native-host/index.d.ts +4 -0
  86. package/dist/native-host/index.d.ts.map +1 -0
  87. package/dist/native-host/index.js +8 -0
  88. package/dist/native-host/index.js.map +1 -0
  89. package/dist/native-host/ingest.d.ts +83 -0
  90. package/dist/native-host/ingest.d.ts.map +1 -0
  91. package/dist/native-host/ingest.js +283 -0
  92. package/dist/native-host/ingest.js.map +1 -0
  93. package/dist/native-host/installer.d.ts +64 -0
  94. package/dist/native-host/installer.d.ts.map +1 -0
  95. package/dist/native-host/installer.js +110 -0
  96. package/dist/native-host/installer.js.map +1 -0
  97. package/dist/native-host/manifest.d.ts +64 -0
  98. package/dist/native-host/manifest.d.ts.map +1 -0
  99. package/dist/native-host/manifest.js +117 -0
  100. package/dist/native-host/manifest.js.map +1 -0
  101. package/dist/native-host/policy.d.ts +60 -0
  102. package/dist/native-host/policy.d.ts.map +1 -0
  103. package/dist/native-host/policy.js +116 -0
  104. package/dist/native-host/policy.js.map +1 -0
  105. package/dist/native-host/request-registry.d.ts +55 -0
  106. package/dist/native-host/request-registry.d.ts.map +1 -0
  107. package/dist/native-host/request-registry.js +111 -0
  108. package/dist/native-host/request-registry.js.map +1 -0
  109. package/dist/native-host/transport.d.ts +54 -0
  110. package/dist/native-host/transport.d.ts.map +1 -0
  111. package/dist/native-host/transport.js +113 -0
  112. package/dist/native-host/transport.js.map +1 -0
  113. package/dist/postinstall.d.ts +3 -0
  114. package/dist/postinstall.d.ts.map +1 -0
  115. package/dist/postinstall.js +72 -0
  116. package/dist/postinstall.js.map +1 -0
  117. package/package.json +59 -0
  118. package/src/db/migrations/0001_initial.sql +102 -0
  119. package/src/db/migrations/0002_network_bodies.sql +15 -0
  120. package/src/native-host/extension-ids.json +6 -0
@@ -0,0 +1,469 @@
1
+ // The peek MCP server (Tasks 3.11-3.14). Builds an `McpServer` with the Level-1
2
+ // READ-ONLY tool surface (PRD §B3): seven session/query tools plus the
3
+ // Playwright repro generator. Writes/action-execution (execute_action,
4
+ // request_authorization) are Phase 3d — not registered here.
5
+ //
6
+ // Design notes:
7
+ // • DB is opened read-only and lazily (openReadonlyDb) so a server can start
8
+ // even before any native host has created ~/.peek/sessions.db; tools then
9
+ // return a clear "no sessions recorded yet" rather than throwing.
10
+ // • Roots scoping is resolved once on `oninitialized` (with the §B5 1s
11
+ // timeout fallback) and applied as a soft origin filter to session lists.
12
+ // • Every tool returns compact JSON text + ids for drill-in, respecting the
13
+ // §B3 token budgets (counts not dumps; truncated fields; capped lists).
14
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
15
+ import { z } from 'zod';
16
+ import { openReadonlyDb } from '../db/open.js';
17
+ import { recordAuditEntry, } from '../native-host/audit.js';
18
+ import { ActionSchema } from './action-schema.js';
19
+ import { SessionEventsError, loadSessionEvents } from './event-blobs.js';
20
+ import { queryDomHistory, reconstructDomAt, userActionsBeforeError } from './event-walker.js';
21
+ import { MissingHostBridge } from './host-bridge.js';
22
+ import { generatePlaywrightRepro } from './playwright-repro.js';
23
+ import { getConsoleErrors, getConsoleEventTs, getNetworkErrors, getSessionBlobRef, getSessionSummaryRow, listRecentSessions, } from './queries.js';
24
+ import { resolveRootsScope } from './roots.js';
25
+ import { buildSessionSummary } from './summary.js';
26
+ export const SERVER_NAME = 'peek-mcp';
27
+ export const SERVER_INSTRUCTIONS = 'Inspect locally-recorded browser sessions and (Level 3+) execute actions ' +
28
+ "in the user's browser. Start with list_recent_sessions, then drill in by " +
29
+ 'sessionId: get_session_summary for a narrative, get_session_console_errors / ' +
30
+ 'get_session_network_errors for failures, get_user_action_before_error to ' +
31
+ 'see what the user did before an error, get_dom_snapshot / query_dom_history ' +
32
+ 'to inspect the DOM over time, and generate_playwright_repro to turn a ' +
33
+ 'session into a Playwright test. The write tools — execute_action and ' +
34
+ 'request_authorization — are gated by a five-level per-origin permission ' +
35
+ 'model with a destructive-action override; consult the user via ' +
36
+ 'request_authorization before high-impact actions.';
37
+ /** A `content: [{ type: 'text' }]` MCP tool result wrapping `value` as pretty JSON. */
38
+ function jsonResult(value) {
39
+ return { content: [{ type: 'text', text: JSON.stringify(value, null, 2) }] };
40
+ }
41
+ /** A plain-text MCP tool result. */
42
+ function textResult(text) {
43
+ return { content: [{ type: 'text', text }] };
44
+ }
45
+ const NO_DB_MESSAGE = 'No sessions recorded yet. Record a session with the peek browser extension first ' +
46
+ '(the native host creates ~/.peek/sessions.db on first capture).';
47
+ /** Truncate a long string for token-budget safety, marking the cut. */
48
+ function clip(s, max) {
49
+ if (s === null || s === undefined)
50
+ return null;
51
+ return s.length <= max ? s : `${s.slice(0, max)}… [+${s.length - max} chars]`;
52
+ }
53
+ /**
54
+ * Build the peek MCP server with all Level-1 read tools registered. Call
55
+ * `.server.connect(transport)` to start it. The DB is opened lazily on the
56
+ * first tool call (and reused), so construction never fails on a missing store.
57
+ */
58
+ export function createPeekMcpServer(options = {}) {
59
+ const server = new McpServer({ name: SERVER_NAME, version: '0.1.0-alpha.0' }, { instructions: SERVER_INSTRUCTIONS });
60
+ let db;
61
+ let dbResolved = false;
62
+ let rootsScope;
63
+ /** Open (once) the read-only DB; undefined when no store exists yet. */
64
+ function getDb() {
65
+ if (!dbResolved) {
66
+ const result = openReadonlyDb(options.dbPath);
67
+ db = result.exists ? result.db : undefined;
68
+ dbResolved = true;
69
+ }
70
+ return db;
71
+ }
72
+ /**
73
+ * Load a session's decoded event stream. Returns `{ ok:true, events }` (empty
74
+ * when no blob / missing), or `{ ok:false, message }` when the blob exists but
75
+ * is corrupt — the event-using tools surface that as a clean error result
76
+ * rather than letting the throw bubble out as an opaque internal error.
77
+ */
78
+ function eventsFor(sessionId) {
79
+ const handle = getDb();
80
+ if (!handle)
81
+ return { ok: true, events: [] };
82
+ const ref = getSessionBlobRef(handle, sessionId);
83
+ if (!ref)
84
+ return { ok: true, events: [] };
85
+ try {
86
+ return { ok: true, events: loadSessionEvents(ref.blobPath, options.eventsDir) };
87
+ }
88
+ catch (err) {
89
+ if (err instanceof SessionEventsError)
90
+ return { ok: false, message: err.message };
91
+ throw err;
92
+ }
93
+ }
94
+ const refreshRootsScope = async (timeoutMs) => {
95
+ rootsScope = await resolveRootsScope(server.server, {
96
+ timeoutMs: timeoutMs ?? options.rootsTimeoutMs ?? 1000,
97
+ });
98
+ return rootsScope;
99
+ };
100
+ // Resolve roots once the client finishes initializing (PRD §B5). Defensive:
101
+ // resolveRootsScope never throws and times out per claude-code #3315.
102
+ server.server.oninitialized = () => {
103
+ void refreshRootsScope().catch(() => {
104
+ // Already swallowed inside resolveRootsScope; belt-and-suspenders.
105
+ });
106
+ };
107
+ registerTools();
108
+ return {
109
+ server,
110
+ close() {
111
+ db?.close();
112
+ },
113
+ refreshRootsScope,
114
+ get rootsScope() {
115
+ return rootsScope;
116
+ },
117
+ };
118
+ function registerTools() {
119
+ // 1. list_recent_sessions ------------------------------------------------
120
+ server.registerTool('list_recent_sessions', {
121
+ description: "List the user's recently recorded browser sessions, newest first. " +
122
+ 'Returns compact rows with ids to pass to the get_session_* tools.',
123
+ inputSchema: {
124
+ limit: z.number().int().min(1).max(50).default(10),
125
+ origin: z.string().optional(),
126
+ },
127
+ }, ({ limit, origin }) => {
128
+ const handle = getDb();
129
+ if (!handle)
130
+ return textResult(NO_DB_MESSAGE);
131
+ // Apply the roots soft-scope: if the client scoped to origins and the
132
+ // caller didn't ask for a specific one, restrict to the first scoped
133
+ // origin set by filtering post-query (origins are few).
134
+ const rows = listRecentSessions(handle, {
135
+ limit,
136
+ ...(origin !== undefined ? { origin } : {}),
137
+ });
138
+ const scoped = origin === undefined && rootsScope?.allowedOrigins
139
+ ? rows.filter((r) => r.origin !== null && rootsScope?.allowedOrigins?.includes(r.origin))
140
+ : rows;
141
+ // Clip free-text fields for budget consistency with the other tools.
142
+ return jsonResult(scoped.map((r) => ({
143
+ ...r,
144
+ origin: clip(r.origin, 100),
145
+ url: clip(r.url, 300),
146
+ title: clip(r.title, 200),
147
+ })));
148
+ });
149
+ // 2. get_session_summary -------------------------------------------------
150
+ server.registerTool('get_session_summary', {
151
+ description: 'Get an LLM-readable narrative summary of one session: pages visited, ' +
152
+ 'click/input counts, navigations, and error counts.',
153
+ inputSchema: { sessionId: z.string() },
154
+ }, ({ sessionId }) => {
155
+ const handle = getDb();
156
+ if (!handle)
157
+ return textResult(NO_DB_MESSAGE);
158
+ const row = getSessionSummaryRow(handle, sessionId);
159
+ if (!row)
160
+ return textResult(`No session found with id '${sessionId}'.`);
161
+ const ev = eventsFor(sessionId);
162
+ if (!ev.ok)
163
+ return textResult(ev.message);
164
+ const summary = buildSessionSummary(handle, row, ev.events);
165
+ return jsonResult(summary);
166
+ });
167
+ // 3. get_session_console_errors -----------------------------------------
168
+ server.registerTool('get_session_console_errors', {
169
+ description: 'List console error messages recorded in a session, oldest first. ' +
170
+ 'Each row has an id usable with get_user_action_before_error.',
171
+ inputSchema: {
172
+ sessionId: z.string(),
173
+ since: z.number().int().optional(),
174
+ limit: z.number().int().min(1).max(200).default(50),
175
+ },
176
+ }, ({ sessionId, since, limit }) => {
177
+ const handle = getDb();
178
+ if (!handle)
179
+ return textResult(NO_DB_MESSAGE);
180
+ const rows = getConsoleErrors(handle, sessionId, {
181
+ limit,
182
+ ...(since !== undefined ? { since } : {}),
183
+ });
184
+ return jsonResult(rows.map((r) => ({
185
+ id: r.id,
186
+ ts: r.ts,
187
+ level: r.level,
188
+ message: clip(r.message, 500),
189
+ stack: clip(r.stack, 800),
190
+ })));
191
+ });
192
+ // 4. get_session_network_errors -----------------------------------------
193
+ server.registerTool('get_session_network_errors', {
194
+ description: 'List failed/notable network requests in a session (status >= statusGte ' +
195
+ 'or a network error), oldest first.',
196
+ inputSchema: {
197
+ sessionId: z.string(),
198
+ statusGte: z.number().int().min(100).max(599).default(400),
199
+ limit: z.number().int().min(1).max(200).default(50),
200
+ },
201
+ }, ({ sessionId, statusGte, limit }) => {
202
+ const handle = getDb();
203
+ if (!handle)
204
+ return textResult(NO_DB_MESSAGE);
205
+ const rows = getNetworkErrors(handle, sessionId, { statusGte, limit });
206
+ return jsonResult(rows.map((r) => ({
207
+ id: r.id,
208
+ ts: r.ts,
209
+ method: r.method,
210
+ url: clip(r.url, 300),
211
+ status: r.status,
212
+ statusText: r.statusText,
213
+ resourceType: r.resourceType,
214
+ durationMs: r.durationMs,
215
+ errorText: clip(r.errorText, 300),
216
+ })));
217
+ });
218
+ // 5. get_user_action_before_error ---------------------------------------
219
+ server.registerTool('get_user_action_before_error', {
220
+ description: 'Show the last N user actions (click/type/navigate) before a console ' +
221
+ 'error, to reconstruct what the user did. errorId comes from ' +
222
+ 'get_session_console_errors.',
223
+ inputSchema: {
224
+ sessionId: z.string(),
225
+ errorId: z.number().int(),
226
+ window: z.number().int().min(1).max(50).default(10),
227
+ },
228
+ }, ({ sessionId, errorId, window }) => {
229
+ const handle = getDb();
230
+ if (!handle)
231
+ return textResult(NO_DB_MESSAGE);
232
+ const errorTs = getConsoleEventTs(handle, sessionId, errorId);
233
+ if (errorTs === undefined) {
234
+ return textResult(`No console error with id ${errorId} in session '${sessionId}'.`);
235
+ }
236
+ const ev = eventsFor(sessionId);
237
+ if (!ev.ok)
238
+ return textResult(ev.message);
239
+ const actions = userActionsBeforeError(ev.events, errorTs, window);
240
+ return jsonResult({ errorId, errorTs, actions });
241
+ });
242
+ // 6. generate_playwright_repro ------------------------------------------
243
+ server.registerTool('generate_playwright_repro', {
244
+ description: 'Generate a runnable Playwright test from the user actions in a session ' +
245
+ '(optionally limited to a [startTs, endTs] window).',
246
+ inputSchema: {
247
+ sessionId: z.string(),
248
+ startTs: z.number().int().optional(),
249
+ endTs: z.number().int().optional(),
250
+ },
251
+ }, ({ sessionId, startTs, endTs }) => {
252
+ const handle = getDb();
253
+ if (!handle)
254
+ return textResult(NO_DB_MESSAGE);
255
+ const row = getSessionSummaryRow(handle, sessionId);
256
+ if (!row)
257
+ return textResult(`No session found with id '${sessionId}'.`);
258
+ const ev = eventsFor(sessionId);
259
+ if (!ev.ok)
260
+ return textResult(ev.message);
261
+ const script = generatePlaywrightRepro(ev.events, {
262
+ title: row.title ?? `peek session ${sessionId}`,
263
+ ...(startTs !== undefined ? { startTs } : {}),
264
+ ...(endTs !== undefined ? { endTs } : {}),
265
+ });
266
+ return textResult(script);
267
+ });
268
+ // 7. get_dom_snapshot ----------------------------------------------------
269
+ server.registerTool('get_dom_snapshot', {
270
+ description: 'Reconstruct the DOM at a timestamp (or a selector subtree within it) ' +
271
+ 'and return it as HTML. v1 applies structural/attribute/text mutations ' +
272
+ 'on top of the nearest full snapshot.',
273
+ inputSchema: {
274
+ sessionId: z.string(),
275
+ ts: z.number().int(),
276
+ selector: z.string().optional(),
277
+ },
278
+ }, ({ sessionId, ts, selector }) => {
279
+ const handle = getDb();
280
+ if (!handle)
281
+ return textResult(NO_DB_MESSAGE);
282
+ const ev = eventsFor(sessionId);
283
+ if (!ev.ok)
284
+ return textResult(ev.message);
285
+ const snap = reconstructDomAt(ev.events, ts, selector);
286
+ if (!snap) {
287
+ return textResult(`No DOM snapshot available at ts ${ts} for session '${sessionId}' (no full snapshot at or before that time).`);
288
+ }
289
+ // Cap the HTML to keep within the ~10K-token budget.
290
+ return jsonResult({
291
+ baseSnapshotTs: snap.baseSnapshotTs,
292
+ mutationsApplied: snap.mutationsApplied,
293
+ html: clip(snap.html, 24000),
294
+ });
295
+ });
296
+ // 8. query_dom_history ---------------------------------------------------
297
+ server.registerTool('query_dom_history', {
298
+ description: "Timeline of attribute and/or text changes for a selector's node over " +
299
+ 'a session. op restricts to attributeChanges or innerText.',
300
+ inputSchema: {
301
+ sessionId: z.string(),
302
+ selector: z.string(),
303
+ op: z.enum(['attributeChanges', 'innerText']).optional(),
304
+ limit: z.number().int().min(1).max(500).default(100),
305
+ },
306
+ }, ({ sessionId, selector, op, limit }) => {
307
+ const handle = getDb();
308
+ if (!handle)
309
+ return textResult(NO_DB_MESSAGE);
310
+ const ev = eventsFor(sessionId);
311
+ if (!ev.ok)
312
+ return textResult(ev.message);
313
+ const changes = queryDomHistory(ev.events, selector, {
314
+ limit,
315
+ ...(op !== undefined ? { op } : {}),
316
+ });
317
+ return jsonResult({ selector, changes });
318
+ });
319
+ // 9. request_authorization (Task 3.24) -----------------------------------
320
+ // Level-3 confirmation step: the AI calls this to PROMPT the user via the
321
+ // side-panel banner. The host bridges to the SW, which surfaces the
322
+ // banner. On Allow the host returns a one-shot confirmToken the AI passes
323
+ // to execute_action. EVERY call (including denied ones) is audit-logged.
324
+ server.registerTool('request_authorization', {
325
+ description: 'Ask the user to authorize an action in their browser via the side-' +
326
+ 'panel banner (Level 3 act-with-confirm). Returns a one-shot ' +
327
+ 'confirmToken to pass to execute_action, or denies the request. ' +
328
+ 'Every call is recorded to ~/.peek/audit.log.',
329
+ inputSchema: {
330
+ sessionId: z.string(),
331
+ action: ActionSchema,
332
+ },
333
+ }, async ({ sessionId, action }) => {
334
+ return await dispatchActTool({
335
+ tool: 'request_authorization',
336
+ sessionId,
337
+ action,
338
+ });
339
+ });
340
+ // 10. execute_action (Task 3.24) -----------------------------------------
341
+ // The actual DOM mutation. Gated by the per-origin permission level;
342
+ // destructive blocklist overrides Level 4. confirmToken (optional) is the
343
+ // token returned by a prior request_authorization, used to skip the
344
+ // banner step at Level 3. Without it: Level 3 raises a banner; Level 4
345
+ // proceeds (unless destructive); Level <3 denies.
346
+ server.registerTool('execute_action', {
347
+ description: "Execute an action in the user's browser. Requires per-origin " +
348
+ 'permission Level 3+ (Level 3 prompts unless confirmToken is passed; ' +
349
+ 'Level 4 auto-allows non-destructive). The destructive-action ' +
350
+ 'override (delete/remove/transfer/send/pay/purchase/buy/confirm/' +
351
+ 'subscribe/logout/sign out/unsubscribe/cancel subscription/wire/' +
352
+ 'withdraw) always prompts, even at Level 4. Every call is ' +
353
+ 'recorded to ~/.peek/audit.log.',
354
+ inputSchema: {
355
+ sessionId: z.string(),
356
+ action: ActionSchema,
357
+ confirmToken: z.string().optional(),
358
+ },
359
+ }, async ({ sessionId, action, confirmToken }) => {
360
+ return await dispatchActTool({
361
+ tool: 'execute_action',
362
+ sessionId,
363
+ action,
364
+ ...(confirmToken !== undefined ? { confirmToken } : {}),
365
+ });
366
+ });
367
+ }
368
+ // --- Act-tool dispatch (shared between execute_action + request_authorization) ---
369
+ async function dispatchActTool(input) {
370
+ const bridge = options.hostBridge ?? new MissingHostBridge();
371
+ const clientImpl = server.server.getClientVersion();
372
+ const client = clientImpl?.name ?? 'unknown';
373
+ const requestStartedAtMs = Date.now();
374
+ let response;
375
+ let bridgeError;
376
+ try {
377
+ response = await bridge.request({
378
+ tool: input.tool,
379
+ sessionId: input.sessionId,
380
+ action: input.action,
381
+ client,
382
+ ...(input.confirmToken !== undefined ? { confirmToken: input.confirmToken } : {}),
383
+ });
384
+ }
385
+ catch (err) {
386
+ bridgeError = err;
387
+ // Synthesize a denied/error response so we still audit-log + return a
388
+ // structured reply.
389
+ response = {
390
+ verdict: 'deny',
391
+ result: 'error',
392
+ approver: 'user',
393
+ error: err instanceof Error ? err.message : String(err),
394
+ };
395
+ }
396
+ // Audit-log the call — even when the bridge errored / denied. The audit
397
+ // log is the trust surface and must never miss a write.
398
+ const auditResult = response.result;
399
+ let auditWriteFailed = false;
400
+ try {
401
+ const auditWriteOptions = options.auditLogPath !== undefined ? { path: options.auditLogPath } : {};
402
+ recordAuditEntry({
403
+ tool: input.tool,
404
+ action: input.action,
405
+ approver: response.approver,
406
+ client,
407
+ sessionId: input.sessionId,
408
+ result: auditResult,
409
+ nowMs: requestStartedAtMs,
410
+ ...(response.approvalMs !== undefined ? { approvalMs: response.approvalMs } : {}),
411
+ ...(response.destructiveTerm !== undefined
412
+ ? { destructiveTerm: response.destructiveTerm }
413
+ : {}),
414
+ ...(response.error !== undefined ? { error: response.error } : {}),
415
+ }, auditWriteOptions);
416
+ }
417
+ catch (err) {
418
+ auditWriteFailed = true;
419
+ console.error(`peek-mcp: audit log write failed — ${err instanceof Error ? err.message : String(err)}`);
420
+ }
421
+ // Surface the result to the AI as JSON. confirmToken (when present) is
422
+ // the only field the AI re-uses; the rest is for diagnostic display.
423
+ //
424
+ // If the audit-log write failed, downgrade the tool response to
425
+ // `result: 'error'` so the AI sees the broken audit chain. The underlying
426
+ // action may already have been dispatched by the SW (irreversible at this
427
+ // point) — but the AI's view of the outcome must accurately reflect that
428
+ // the audit chain was broken, since the audit log is the trust surface.
429
+ const body = {
430
+ tool: input.tool,
431
+ verdict: response.verdict,
432
+ result: auditWriteFailed ? 'error' : response.result,
433
+ approver: response.approver,
434
+ };
435
+ if (response.confirmToken !== undefined)
436
+ body.confirmToken = response.confirmToken;
437
+ if (response.destructiveTerm !== undefined)
438
+ body.destructiveTerm = response.destructiveTerm;
439
+ if (auditWriteFailed) {
440
+ body.error = 'audit log write failed';
441
+ }
442
+ else if (response.error !== undefined) {
443
+ body.error = response.error;
444
+ }
445
+ if (response.details !== undefined)
446
+ body.details = response.details;
447
+ if (bridgeError !== undefined) {
448
+ // Make sure errors propagate visibly to the AI as well.
449
+ body.bridgeError = bridgeError instanceof Error ? bridgeError.message : String(bridgeError);
450
+ }
451
+ return jsonResult(body);
452
+ }
453
+ }
454
+ /** The tool names this server registers, for smoke tests / docs. */
455
+ export const PEEK_MCP_TOOLS = [
456
+ // Read tools (Phase 3c, Level 1+).
457
+ 'list_recent_sessions',
458
+ 'get_session_summary',
459
+ 'get_session_console_errors',
460
+ 'get_session_network_errors',
461
+ 'get_user_action_before_error',
462
+ 'generate_playwright_repro',
463
+ 'get_dom_snapshot',
464
+ 'query_dom_history',
465
+ // Write tools (Phase 3d, Level 3+).
466
+ 'request_authorization',
467
+ 'execute_action',
468
+ ];
469
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import type { Database } from 'better-sqlite3';
2
+ import { type SessionSummaryRow } from './queries.js';
3
+ import type { eventWithTime } from './rrweb-types.js';
4
+ export interface SessionSummary {
5
+ readonly id: string;
6
+ readonly origin: string | null;
7
+ readonly title: string | null;
8
+ readonly startedAt: number;
9
+ readonly durationMs: number;
10
+ readonly pagesVisited: string[];
11
+ readonly clicks: number;
12
+ readonly inputs: number;
13
+ readonly navigations: number;
14
+ readonly consoleErrorCount: number;
15
+ readonly networkErrorCount: number;
16
+ /** A one-paragraph natural-language narrative for the model. */
17
+ readonly narrative: string;
18
+ }
19
+ /**
20
+ * Build the session summary from its metadata row + decoded event stream. The
21
+ * caller supplies `events` (already decompressed via the blob loader) so this
22
+ * stays pure / testable; pass `[]` when the blob is missing and the summary
23
+ * falls back to metadata + SQL counts only.
24
+ */
25
+ export declare function buildSessionSummary(db: Database, row: SessionSummaryRow, events: eventWithTime[]): SessionSummary;
26
+ //# sourceMappingURL=summary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"summary.d.ts","sourceRoot":"","sources":["../../src/mcp/summary.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE/C,OAAO,EAAE,KAAK,iBAAiB,EAA0C,MAAM,cAAc,CAAC;AAC9F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,EAAE,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,gEAAgE;IAChE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAcD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,EAAE,EAAE,QAAQ,EACZ,GAAG,EAAE,iBAAiB,EACtB,MAAM,EAAE,aAAa,EAAE,GACtB,cAAc,CAoDhB"}
@@ -0,0 +1,74 @@
1
+ // get_session_summary (PRD §B3): a compact, LLM-readable narrative of a
2
+ // session — pages visited, click/input counts, error counts, key URLs. Combines
3
+ // the structured SQL rows (fast) with a pass over the event stream for the
4
+ // interaction tallies. Kept well under the ~2K-token budget by counting rather
5
+ // than listing.
6
+ import { extractUserActions } from './event-walker.js';
7
+ import { countConsoleErrors, countNetworkErrors } from './queries.js';
8
+ const MAX_PAGES = 20;
9
+ /** Max chars for free-text page metadata embedded in the summary (budget guard). */
10
+ const MAX_TITLE = 200;
11
+ const MAX_ORIGIN = 100;
12
+ const MAX_URL = 300;
13
+ /** Truncate a string for token-budget safety, marking the cut; null passes through. */
14
+ function clip(s, max) {
15
+ if (s === null)
16
+ return null;
17
+ return s.length <= max ? s : `${s.slice(0, max)}… [+${s.length - max} chars]`;
18
+ }
19
+ /**
20
+ * Build the session summary from its metadata row + decoded event stream. The
21
+ * caller supplies `events` (already decompressed via the blob loader) so this
22
+ * stays pure / testable; pass `[]` when the blob is missing and the summary
23
+ * falls back to metadata + SQL counts only.
24
+ */
25
+ export function buildSessionSummary(db, row, events) {
26
+ const actions = extractUserActions(events);
27
+ const clicks = actions.filter((a) => a.type === 'click').length;
28
+ const inputs = actions.filter((a) => a.type === 'input').length;
29
+ const navActions = actions.filter((a) => a.type === 'navigate');
30
+ // Pages visited: the initial URL + every navigation target, de-duped, capped
31
+ // (each clipped so a pathological URL can't blow the budget).
32
+ const pages = [];
33
+ const seen = new Set();
34
+ const pushPage = (u) => {
35
+ if (!u || seen.has(u) || pages.length >= MAX_PAGES)
36
+ return;
37
+ seen.add(u);
38
+ pages.push(clip(u, MAX_URL));
39
+ };
40
+ pushPage(row.url);
41
+ for (const nav of navActions)
42
+ pushPage(nav.url);
43
+ // Accurate COUNT(*) — not a capped re-fetch — so a session with >1000 errors
44
+ // reports the true total in the primary narrative.
45
+ const consoleErrorCount = countConsoleErrors(db, row.id);
46
+ const networkErrorCount = countNetworkErrors(db, row.id);
47
+ // Clip free-text page metadata for budget consistency with the other tools.
48
+ const title = clip(row.title, MAX_TITLE);
49
+ const origin = clip(row.origin, MAX_ORIGIN);
50
+ const durationSec = Math.round(row.durationMs / 1000);
51
+ const titlePart = title ? ` ("${title}")` : '';
52
+ const originPart = origin ? ` on ${origin}` : '';
53
+ const acrossPart = navActions.length > 0 ? `, across ${navActions.length} navigation(s)` : '';
54
+ const errorsSentence = consoleErrorCount > 0 || networkErrorCount > 0
55
+ ? ` Recorded ${consoleErrorCount} console error(s) and ${networkErrorCount} network error(s).`
56
+ : ' No console or network errors were recorded.';
57
+ const visited = `The user visited ${pages.length} page(s), made ${clicks} click(s) and ${inputs} input(s)${acrossPart}.`;
58
+ const narrative = `Session ${row.id}${titlePart}${originPart} lasted ~${durationSec}s. ${visited}${errorsSentence}`;
59
+ return {
60
+ id: row.id,
61
+ origin,
62
+ title,
63
+ startedAt: row.startedAt,
64
+ durationMs: row.durationMs,
65
+ pagesVisited: pages,
66
+ clicks,
67
+ inputs,
68
+ navigations: navActions.length,
69
+ consoleErrorCount,
70
+ networkErrorCount,
71
+ narrative,
72
+ };
73
+ }
74
+ //# sourceMappingURL=summary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"summary.js","sourceRoot":"","sources":["../../src/mcp/summary.ts"],"names":[],"mappings":"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"}