File size: 3,395 Bytes
7dc28be
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import type { FastMCP } from 'fastmcp';
import { UserError } from 'fastmcp';
import { z } from 'zod';
import { drive_v3 } from 'googleapis';
import { getDriveClient, getSheetsClient } from '../../clients.js';
import * as SheetsHelpers from '../../googleSheetsApiHelpers.js';
import { SpreadsheetCellValueSchema } from '../../types.js';

export function register(server: FastMCP) {
  server.addTool({
    name: 'createSpreadsheet',
    description:
      'Creates a new spreadsheet. Optionally places it in a specific folder and populates it with initial data.',
    parameters: z.strictObject({
      title: z.string().min(1).describe('Title for the new spreadsheet.'),
      parentFolderId: z
        .string()
        .optional()
        .describe(
          'ID of folder where spreadsheet should be created. If not provided, creates in Drive root.'
        ),
      initialData: z
        .array(z.array(SpreadsheetCellValueSchema))
        .optional()
        .describe(
          'Optional initial data to populate in the first sheet. Each inner array represents a row.'
        ),
    }),
    execute: async (args, { log }) => {
      const drive = await getDriveClient();
      const sheets = await getSheetsClient();
      log.info(`Creating new spreadsheet "${args.title}"`);

      try {
        // Create the spreadsheet file in Drive
        const spreadsheetMetadata: drive_v3.Schema$File = {
          name: args.title,
          mimeType: 'application/vnd.google-apps.spreadsheet',
        };

        if (args.parentFolderId) {
          spreadsheetMetadata.parents = [args.parentFolderId];
        }

        const driveResponse = await drive.files.create({
          requestBody: spreadsheetMetadata,
          fields: 'id,name,webViewLink',
          supportsAllDrives: true,
        });

        const spreadsheetId = driveResponse.data.id;
        if (!spreadsheetId) {
          throw new UserError('Failed to create spreadsheet - no ID returned.');
        }

        let initialDataStatus: string | undefined;

        // Add initial data if provided
        if (args.initialData && args.initialData.length > 0) {
          try {
            await SheetsHelpers.writeRange(
              sheets,
              spreadsheetId,
              'A1',
              args.initialData,
              'USER_ENTERED'
            );
            initialDataStatus = 'added';
          } catch (contentError: any) {
            log.warn(`Spreadsheet created but failed to add initial data: ${contentError.message}`);
            initialDataStatus = 'failed';
          }
        }

        return JSON.stringify(
          {
            id: spreadsheetId,
            name: driveResponse.data.name,
            url: driveResponse.data.webViewLink,
            ...(initialDataStatus ? { initialData: initialDataStatus } : {}),
          },
          null,
          2
        );
      } catch (error: any) {
        log.error(`Error creating spreadsheet: ${error.message || error}`);
        if (error.code === 404)
          throw new UserError('Parent folder not found. Check the folder ID.');
        if (error.code === 403)
          throw new UserError(
            'Permission denied. Make sure you have write access to the destination folder.'
          );
        throw new UserError(`Failed to create spreadsheet: ${error.message || 'Unknown error'}`);
      }
    },
  });
}