notebooklm-mcp-server 1.0.9 → 1.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/dist/auth.js +12 -26
- package/dist/index.js +1 -1
- package/dist/server.js +31 -20
- package/package.json +1 -1
package/dist/auth.js
CHANGED
|
@@ -22,39 +22,25 @@ export class AuthManager {
|
|
|
22
22
|
if (onStatus)
|
|
23
23
|
onStatus('Waiting for Google Login...');
|
|
24
24
|
// Wait for the user to be logged in.
|
|
25
|
-
// We check for either the URL pattern or the presence of session cookies
|
|
26
25
|
let isDone = false;
|
|
27
26
|
try {
|
|
28
27
|
await Promise.race([
|
|
29
|
-
|
|
28
|
+
// Wait for redirect to dashboard or notebook
|
|
29
|
+
page.waitForURL(url => url.origin === 'https://notebooklm.google.com' &&
|
|
30
|
+
(url.pathname.includes('/notebook') || url.pathname === '/'), { timeout: 300000 }).then(() => { isDone = true; }),
|
|
31
|
+
// Wait for user icon or other logged-in indicia
|
|
32
|
+
page.waitForSelector('button[aria-label*="Account"], img[src*="googleusercontent.com"]', { timeout: 300000 })
|
|
33
|
+
.then(() => { isDone = true; }),
|
|
34
|
+
// Safety fallback: if we see the landing page, we might already be logged in
|
|
30
35
|
page.waitForFunction(() => {
|
|
36
|
+
const body = document.body.innerText;
|
|
31
37
|
return window.location.href.includes('notebooklm.google.com') &&
|
|
32
|
-
!
|
|
38
|
+
!body.includes('Sign in') &&
|
|
39
|
+
(body.includes('Notebooks') || body.includes('Create new'));
|
|
33
40
|
}, { polling: 2000, timeout: 300000 }).then(() => { isDone = true; }),
|
|
34
|
-
// Fallback: check if we have the critical cookies
|
|
35
|
-
new Promise((resolve) => {
|
|
36
|
-
const checkCookies = async () => {
|
|
37
|
-
if (isDone)
|
|
38
|
-
return;
|
|
39
|
-
try {
|
|
40
|
-
const cookies = await context.cookies();
|
|
41
|
-
const sessionCookie = cookies.find(c => c.name === '__Secure-3PSID' || c.name === 'SID');
|
|
42
|
-
if (sessionCookie && page.url().includes('notebooklm.google.com')) {
|
|
43
|
-
isDone = true;
|
|
44
|
-
resolve(true);
|
|
45
|
-
}
|
|
46
|
-
else {
|
|
47
|
-
if (!isDone)
|
|
48
|
-
setTimeout(checkCookies, 2000);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
catch (e) {
|
|
52
|
-
isDone = true;
|
|
53
|
-
}
|
|
54
|
-
};
|
|
55
|
-
checkCookies();
|
|
56
|
-
})
|
|
57
41
|
]);
|
|
42
|
+
// Small delay to ensure all session cookies are synced
|
|
43
|
+
await page.waitForTimeout(2000);
|
|
58
44
|
}
|
|
59
45
|
catch (e) {
|
|
60
46
|
throw new Error('Authentication timed out or browser was closed.');
|
package/dist/index.js
CHANGED
package/dist/server.js
CHANGED
|
@@ -6,7 +6,7 @@ import { AuthManager } from "./auth.js";
|
|
|
6
6
|
import chalk from "chalk";
|
|
7
7
|
const server = new Server({
|
|
8
8
|
name: "notebooklm-mcp-server",
|
|
9
|
-
version: "1.0
|
|
9
|
+
version: "1.1.0",
|
|
10
10
|
}, {
|
|
11
11
|
capabilities: {
|
|
12
12
|
tools: {},
|
|
@@ -262,6 +262,11 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
262
262
|
required: ["notebook_id"],
|
|
263
263
|
},
|
|
264
264
|
},
|
|
265
|
+
{
|
|
266
|
+
name: "refresh_auth",
|
|
267
|
+
description: "Open browser to refresh Google Session cookies (interactive)",
|
|
268
|
+
inputSchema: { type: "object", properties: {} },
|
|
269
|
+
},
|
|
265
270
|
],
|
|
266
271
|
};
|
|
267
272
|
});
|
|
@@ -271,76 +276,82 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
271
276
|
switch (name) {
|
|
272
277
|
case "notebook_list":
|
|
273
278
|
const notebooks = await client.listNotebooks();
|
|
274
|
-
return { content: [{ type: "text", text: JSON.stringify(notebooks, null, 2) }] };
|
|
279
|
+
return { content: [{ type: "text", text: JSON.stringify({ notebooks }, null, 2) }] };
|
|
275
280
|
case "notebook_create":
|
|
276
281
|
const newId = await client.createNotebook(args?.title);
|
|
277
|
-
return { content: [{ type: "text", text:
|
|
282
|
+
return { content: [{ type: "text", text: JSON.stringify({ status: "success", notebook_id: newId }) }] };
|
|
278
283
|
case "notebook_delete":
|
|
279
284
|
await client.deleteNotebook(args?.notebook_id);
|
|
280
|
-
return { content: [{ type: "text", text: `Deleted notebook ${args?.notebook_id}` }] };
|
|
285
|
+
return { content: [{ type: "text", text: JSON.stringify({ status: "success", message: `Deleted notebook ${args?.notebook_id}` }) }] };
|
|
281
286
|
case "notebook_rename":
|
|
282
287
|
await client.renameNotebook(args?.notebook_id, args?.title);
|
|
283
|
-
return { content: [{ type: "text", text: `Renamed notebook to ${args?.title}` }] };
|
|
288
|
+
return { content: [{ type: "text", text: JSON.stringify({ status: "success", message: `Renamed notebook to ${args?.title}` }) }] };
|
|
284
289
|
case "notebook_add_url":
|
|
285
290
|
const sourceIdUrl = await client.addUrlSource(args?.notebook_id, args?.url);
|
|
286
|
-
return { content: [{ type: "text", text:
|
|
291
|
+
return { content: [{ type: "text", text: JSON.stringify({ status: "success", source_id: sourceIdUrl }) }] };
|
|
287
292
|
case "notebook_add_text":
|
|
288
293
|
const sourceIdText = await client.addTextSource(args?.notebook_id, args?.title, args?.content);
|
|
289
|
-
return { content: [{ type: "text", text:
|
|
294
|
+
return { content: [{ type: "text", text: JSON.stringify({ status: "success", source_id: sourceIdText }) }] };
|
|
290
295
|
case "notebook_query":
|
|
291
296
|
const queryResult = await client.query(args?.notebook_id, args?.query, undefined, args?.conversation_id);
|
|
292
297
|
return {
|
|
293
298
|
content: [
|
|
294
|
-
{ type: "text", text: queryResult
|
|
295
|
-
{ type: "text", text: `\n\n(Conversation ID: ${queryResult.conversation_id})` }
|
|
299
|
+
{ type: "text", text: JSON.stringify(queryResult, null, 2) }
|
|
296
300
|
]
|
|
297
301
|
};
|
|
298
302
|
case "research_start":
|
|
299
303
|
const taskInfo = await client.startResearch(args?.notebook_id, args?.query, args?.source || 'web', args?.mode || 'fast');
|
|
300
|
-
return { content: [{ type: "text", text:
|
|
304
|
+
return { content: [{ type: "text", text: JSON.stringify({ status: "success", task: taskInfo }, null, 2) }] };
|
|
301
305
|
case "research_poll":
|
|
302
306
|
const researchResult = await client.pollResearch(args?.notebook_id);
|
|
303
307
|
return { content: [{ type: "text", text: JSON.stringify(researchResult, null, 2) }] };
|
|
304
308
|
case "research_import":
|
|
305
309
|
const imported = await client.importResearchSources(args?.notebook_id, args?.task_id, args?.sources);
|
|
306
|
-
return { content: [{ type: "text", text:
|
|
310
|
+
return { content: [{ type: "text", text: JSON.stringify({ status: "success", imported_count: imported.length, sources: imported }, null, 2) }] };
|
|
307
311
|
case "mind_map_generate":
|
|
308
312
|
const mmData = await client.generateMindMap(args?.source_ids);
|
|
309
313
|
return { content: [{ type: "text", text: JSON.stringify(mmData, null, 2) }] };
|
|
310
314
|
case "mind_map_save":
|
|
311
315
|
const savedMm = await client.saveMindMap(args?.notebook_id, args?.mind_map_json, args?.source_ids, args?.title);
|
|
312
|
-
return { content: [{ type: "text", text:
|
|
316
|
+
return { content: [{ type: "text", text: JSON.stringify({ status: "success", mind_map: savedMm }, null, 2) }] };
|
|
313
317
|
case "mind_map_list":
|
|
314
318
|
const maps = await client.listMindMaps(args?.notebook_id);
|
|
315
|
-
return { content: [{ type: "text", text: JSON.stringify(maps, null, 2) }] };
|
|
319
|
+
return { content: [{ type: "text", text: JSON.stringify({ mind_maps: maps }, null, 2) }] };
|
|
316
320
|
case "mind_map_delete":
|
|
317
321
|
await client.deleteMindMap(args?.notebook_id, args?.mind_map_id);
|
|
318
|
-
return { content: [{ type: "text", text: "Mind Map deleted." }] };
|
|
322
|
+
return { content: [{ type: "text", text: JSON.stringify({ status: "success", message: "Mind Map deleted." }) }] };
|
|
319
323
|
case "notebook_add_local_file":
|
|
320
324
|
const fileSourceId = await client.uploadLocalFile(args?.notebook_id, args?.path);
|
|
321
|
-
return { content: [{ type: "text", text:
|
|
325
|
+
return { content: [{ type: "text", text: JSON.stringify({ status: "success", source_id: fileSourceId }) }] };
|
|
322
326
|
case "notebook_add_drive":
|
|
323
327
|
const driveId = await client.addDriveSource(args?.notebook_id, args?.file_id);
|
|
324
|
-
return { content: [{ type: "text", text:
|
|
328
|
+
return { content: [{ type: "text", text: JSON.stringify({ status: "success", source_id: driveId }) }] };
|
|
325
329
|
case "source_delete":
|
|
326
330
|
await client.deleteSource(args?.notebook_id, args?.source_id);
|
|
327
|
-
return { content: [{ type: "text", text: `Source ${args?.source_id} deleted successfully.` }] };
|
|
331
|
+
return { content: [{ type: "text", text: JSON.stringify({ status: "success", message: `Source ${args?.source_id} deleted successfully.` }) }] };
|
|
328
332
|
case "source_sync":
|
|
329
333
|
await client.syncDriveSource(args?.notebook_id, args?.source_id);
|
|
330
|
-
return { content: [{ type: "text", text: `Sync triggered for source ${args?.source_id}.` }] };
|
|
334
|
+
return { content: [{ type: "text", text: JSON.stringify({ status: "success", message: `Sync triggered for source ${args?.source_id}.` }) }] };
|
|
331
335
|
case "audio_overview_create":
|
|
332
336
|
const audioInfo = await client.createAudioOverview(args?.notebook_id, args?.source_ids || [], args?.language || 'en');
|
|
333
|
-
return { content: [{ type: "text", text:
|
|
337
|
+
return { content: [{ type: "text", text: JSON.stringify({ status: "success", audio_info: audioInfo }, null, 2) }] };
|
|
334
338
|
case "studio_poll":
|
|
335
339
|
const studioStatus = await client.pollStudioStatus(args?.notebook_id);
|
|
336
340
|
return { content: [{ type: "text", text: JSON.stringify(studioStatus, null, 2) }] };
|
|
341
|
+
case "refresh_auth":
|
|
342
|
+
const auth = new AuthManager();
|
|
343
|
+
await auth.runAuthentication();
|
|
344
|
+
// After auth is successful, we need to update our client
|
|
345
|
+
const newCookies = auth.getSavedCookies();
|
|
346
|
+
client = new NotebookLMClient(newCookies);
|
|
347
|
+
return { content: [{ type: "text", text: JSON.stringify({ status: "success", message: "Authentication refreshed successfully." }) }] };
|
|
337
348
|
default:
|
|
338
349
|
throw new Error(`Unknown tool: ${name}`);
|
|
339
350
|
}
|
|
340
351
|
}
|
|
341
352
|
catch (error) {
|
|
342
353
|
return {
|
|
343
|
-
content: [{ type: "text", text:
|
|
354
|
+
content: [{ type: "text", text: JSON.stringify({ status: "error", error: error.message }) }],
|
|
344
355
|
isError: true,
|
|
345
356
|
};
|
|
346
357
|
}
|