mcp-google-multi 6.0.0-alpha.5 → 6.0.0-alpha.6
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/tools/drive.d.ts +1 -0
- package/dist/tools/drive.js +44 -22
- package/dist/tools/gmail.js +1 -1
- package/package.json +1 -1
package/dist/tools/drive.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ToolRegistry } from '../registry.js';
|
|
2
2
|
export declare function isTextualMime(mimeType: string): boolean;
|
|
3
|
+
export declare function resolveConvertTarget(convertTo: string | undefined): string | undefined;
|
|
3
4
|
export declare const DRIVE_QUERY_HINT: string;
|
|
4
5
|
export declare function normalizeDriveQuery(raw: string): string;
|
|
5
6
|
export declare function isDriveInvalidQuery(error: any): boolean;
|
package/dist/tools/drive.js
CHANGED
|
@@ -48,6 +48,29 @@ export function isTextualMime(mimeType) {
|
|
|
48
48
|
return TEXTUAL_EXACT.has(bare);
|
|
49
49
|
}
|
|
50
50
|
const BINARY_READ_HINT = 'Binary content cannot be inlined. Use drive_download to save the file to disk, or drive_export for Google Workspace files.';
|
|
51
|
+
// Accepted alongside the full application/vnd.google-apps.* ids so the obvious
|
|
52
|
+
// short spelling ("document") works; the enum advertises both.
|
|
53
|
+
const CONVERT_SHORTHANDS = {
|
|
54
|
+
document: 'application/vnd.google-apps.document',
|
|
55
|
+
spreadsheet: 'application/vnd.google-apps.spreadsheet',
|
|
56
|
+
presentation: 'application/vnd.google-apps.presentation',
|
|
57
|
+
drawing: 'application/vnd.google-apps.drawing',
|
|
58
|
+
};
|
|
59
|
+
export function resolveConvertTarget(convertTo) {
|
|
60
|
+
if (!convertTo)
|
|
61
|
+
return undefined;
|
|
62
|
+
return CONVERT_SHORTHANDS[convertTo] ?? convertTo;
|
|
63
|
+
}
|
|
64
|
+
const CONVERT_TO_VALUES = [
|
|
65
|
+
'document',
|
|
66
|
+
'spreadsheet',
|
|
67
|
+
'presentation',
|
|
68
|
+
'drawing',
|
|
69
|
+
'application/vnd.google-apps.document',
|
|
70
|
+
'application/vnd.google-apps.spreadsheet',
|
|
71
|
+
'application/vnd.google-apps.presentation',
|
|
72
|
+
'application/vnd.google-apps.drawing',
|
|
73
|
+
];
|
|
51
74
|
// Comment/Reply fields list — Drive API requires explicit `fields` on every call.
|
|
52
75
|
const COMMENT_BASE_FIELDS = 'id,kind,content,htmlContent,createdTime,modifiedTime,resolved,anchor,author,deleted,quotedFileContent';
|
|
53
76
|
const REPLY_SUBFIELDS = 'id,content,action,createdTime,modifiedTime,author,deleted';
|
|
@@ -279,15 +302,10 @@ export function registerDriveTools(server) {
|
|
|
279
302
|
description: 'Upload a local file to Google Drive. Pass `convertTo` to import it as a native, editable Google Doc/Sheet/Slides/Drawing instead of storing the raw bytes.',
|
|
280
303
|
inputSchema: {
|
|
281
304
|
account: accountEnum.describe('Google account alias'),
|
|
282
|
-
localPath: z.string().describe('Absolute path
|
|
305
|
+
localPath: z.string().describe('Absolute path of the SOURCE file on disk to upload (on the machine running the server; this is not savePath)'),
|
|
283
306
|
filename: z.string().describe('Name as it appears in Drive'),
|
|
284
307
|
mimeType: z.string().optional().describe('Source MIME type of the local file (inferred from extension if omitted). With `convertTo`, this is the format Drive imports from.'),
|
|
285
|
-
convertTo: z.enum(
|
|
286
|
-
'application/vnd.google-apps.document',
|
|
287
|
-
'application/vnd.google-apps.spreadsheet',
|
|
288
|
-
'application/vnd.google-apps.presentation',
|
|
289
|
-
'application/vnd.google-apps.drawing',
|
|
290
|
-
]).optional().describe('Convert the upload into this native Google Workspace type on import (e.g. upload .md/.html/.docx/.txt with convertTo=...google-apps.document to get a real Google Doc). Source must be an importable format. Omit to store the file as-is.'),
|
|
308
|
+
convertTo: z.enum(CONVERT_TO_VALUES).optional().describe('Convert the upload into this native Google Workspace type on import: "document" | "spreadsheet" | "presentation" | "drawing" (full application/vnd.google-apps.* ids also accepted). E.g. upload .md/.html/.docx/.txt with convertTo=document to get a real Google Doc. Source must be an importable format. Omit to store the file as-is.'),
|
|
291
309
|
parentFolderId: z.string().optional().describe('Parent folder ID (defaults to My Drive root)'),
|
|
292
310
|
},
|
|
293
311
|
}, async ({ account, localPath, filename, mimeType: mimeTypeArg, convertTo, parentFolderId }) => {
|
|
@@ -301,7 +319,7 @@ export function registerDriveTools(server) {
|
|
|
301
319
|
name: filename,
|
|
302
320
|
parents: parentFolderId ? [parentFolderId] : undefined,
|
|
303
321
|
// Setting a google-apps target type makes Drive convert the media on import.
|
|
304
|
-
...(convertTo ? { mimeType: convertTo } : {}),
|
|
322
|
+
...(convertTo ? { mimeType: resolveConvertTarget(convertTo) } : {}),
|
|
305
323
|
},
|
|
306
324
|
media: {
|
|
307
325
|
mimeType: resolvedMime,
|
|
@@ -323,14 +341,17 @@ export function registerDriveTools(server) {
|
|
|
323
341
|
inputSchema: {
|
|
324
342
|
account: accountEnum.describe('Google account alias'),
|
|
325
343
|
fileId: z.string().describe('Google Drive file ID'),
|
|
326
|
-
savePath: z.string().describe('Absolute
|
|
327
|
-
filename: z.string().describe('Filename to save as'),
|
|
344
|
+
savePath: z.string().describe('Absolute DIRECTORY path to save into (created if missing, on the machine running the server); the file name comes from `filename`'),
|
|
345
|
+
filename: z.string().optional().describe('Filename to save as (defaults to the file name in Drive)'),
|
|
328
346
|
},
|
|
329
347
|
}, async ({ account, fileId, savePath, filename }) => {
|
|
330
348
|
try {
|
|
331
349
|
const auth = await getClient(account);
|
|
332
350
|
const drive = driveClient({ version: 'v3', auth });
|
|
333
|
-
const
|
|
351
|
+
const name = filename
|
|
352
|
+
?? (await drive.files.get({ fileId, fields: 'name', supportsAllDrives: true })).data.name
|
|
353
|
+
?? fileId;
|
|
354
|
+
const dest = prepareLocalDest(savePath, name);
|
|
334
355
|
const res = await drive.files.get({ fileId, alt: 'media', supportsAllDrives: true }, { responseType: 'stream' });
|
|
335
356
|
// pipeline destroys both streams on source/sink error; raw .pipe leaks the partial file.
|
|
336
357
|
await pipeline(res.data, fs.createWriteStream(dest, { mode: 0o600 }));
|
|
@@ -349,14 +370,20 @@ export function registerDriveTools(server) {
|
|
|
349
370
|
account: accountEnum.describe('Google account alias'),
|
|
350
371
|
fileId: z.string().describe('Google Drive file ID'),
|
|
351
372
|
mimeType: z.string().describe('Target export MIME type (e.g. "application/pdf", "text/markdown", "application/vnd.openxmlformats-officedocument.wordprocessingml.document")'),
|
|
352
|
-
savePath: z.string().describe('Absolute
|
|
353
|
-
filename: z.string().describe('Filename to save as'),
|
|
373
|
+
savePath: z.string().describe('Absolute DIRECTORY path to save into (created if missing, on the machine running the server); the file name comes from `filename`'),
|
|
374
|
+
filename: z.string().optional().describe('Filename to save as (defaults to the Drive name plus the extension implied by mimeType)'),
|
|
354
375
|
},
|
|
355
376
|
}, async ({ account, fileId, mimeType: exportMime, savePath, filename }) => {
|
|
356
377
|
try {
|
|
357
378
|
const auth = await getClient(account);
|
|
358
379
|
const drive = driveClient({ version: 'v3', auth });
|
|
359
|
-
|
|
380
|
+
let name = filename;
|
|
381
|
+
if (!name) {
|
|
382
|
+
const meta = await drive.files.get({ fileId, fields: 'name', supportsAllDrives: true });
|
|
383
|
+
const ext = mime.extension(exportMime);
|
|
384
|
+
name = `${meta.data.name ?? fileId}${ext ? `.${ext}` : ''}`;
|
|
385
|
+
}
|
|
386
|
+
const dest = prepareLocalDest(savePath, name);
|
|
360
387
|
const res = await drive.files.export({ fileId, mimeType: exportMime }, { responseType: 'stream' });
|
|
361
388
|
// pipeline destroys both streams on source/sink error; raw .pipe leaks the partial file.
|
|
362
389
|
await pipeline(res.data, fs.createWriteStream(dest, { mode: 0o600 }));
|
|
@@ -404,14 +431,9 @@ export function registerDriveTools(server) {
|
|
|
404
431
|
fileId: z.string().describe('Google Drive file ID'),
|
|
405
432
|
newName: z.string().optional().describe('New filename'),
|
|
406
433
|
newParentFolderId: z.string().optional().describe('Move to this folder'),
|
|
407
|
-
localPath: z.string().optional().describe('Replace file content with this local file'),
|
|
434
|
+
localPath: z.string().optional().describe('Replace file content with this local file (path on the machine running the server)'),
|
|
408
435
|
mimeType: z.string().optional().describe('MIME type of the replacement file (required if localPath is provided)'),
|
|
409
|
-
convertTo: z.enum(
|
|
410
|
-
'application/vnd.google-apps.document',
|
|
411
|
-
'application/vnd.google-apps.spreadsheet',
|
|
412
|
-
'application/vnd.google-apps.presentation',
|
|
413
|
-
'application/vnd.google-apps.drawing',
|
|
414
|
-
]).optional().describe('When replacing content via localPath, convert the new content into this native Google Workspace type on import (e.g. replace a Google Doc body from a local .docx). Source must be an importable format.'),
|
|
436
|
+
convertTo: z.enum(CONVERT_TO_VALUES).optional().describe('When replacing content via localPath, convert the new content into this native Google Workspace type on import: "document" | "spreadsheet" | "presentation" | "drawing" (full application/vnd.google-apps.* ids also accepted).'),
|
|
415
437
|
},
|
|
416
438
|
}, async ({ account, fileId, newName, newParentFolderId, localPath: localPathArg, mimeType: mimeTypeArg, convertTo }) => {
|
|
417
439
|
try {
|
|
@@ -437,7 +459,7 @@ export function registerDriveTools(server) {
|
|
|
437
459
|
body: await openLocalReadStream(localPathArg),
|
|
438
460
|
};
|
|
439
461
|
if (convertTo)
|
|
440
|
-
requestBody.mimeType = convertTo;
|
|
462
|
+
requestBody.mimeType = resolveConvertTarget(convertTo);
|
|
441
463
|
}
|
|
442
464
|
const res = await drive.files.update(params);
|
|
443
465
|
return {
|
package/dist/tools/gmail.js
CHANGED
|
@@ -665,7 +665,7 @@ export function registerGmailTools(server) {
|
|
|
665
665
|
messageId: z.string().describe('The Gmail message ID'),
|
|
666
666
|
attachmentId: z.string().describe('The attachment ID from gmail_read response'),
|
|
667
667
|
filename: z.string().describe('Filename to save as (e.g. report.xlsx)'),
|
|
668
|
-
savePath: z.string().describe('Absolute
|
|
668
|
+
savePath: z.string().describe('Absolute DIRECTORY path to save into (created if missing, on the machine running the server), e.g. /home/user/Downloads; the file name comes from `filename`'),
|
|
669
669
|
},
|
|
670
670
|
}, async ({ account, messageId, attachmentId, filename, savePath }) => {
|
|
671
671
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-google-multi",
|
|
3
|
-
"version": "6.0.0-alpha.
|
|
3
|
+
"version": "6.0.0-alpha.6",
|
|
4
4
|
"description": "Local MCP server for Google Workspace (Gmail, Drive, Calendar, Sheets, Docs, Contacts, Tasks, Meet, Search Console, +Forms/Chat/Admin) across multiple accounts — OAuth-only, encrypted token storage, deny-by-default writes.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|