File size: 3,778 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
99
100
101
102
103
104
105
106
107
108
109
import type { FastMCP } from 'fastmcp';
import { UserError } from 'fastmcp';
import { z } from 'zod';
import { drive_v3 } from 'googleapis';
import { getDriveClient, getDocsClient } from '../../clients.js';
import { insertMarkdown, formatInsertResult } from '../../markdown-transformer/index.js';

export function register(server: FastMCP) {
  server.addTool({
    name: 'createDocument',
    description:
      'Creates a new empty Google Document. Optionally places it in a specific folder and adds initial text content.',
    parameters: z.strictObject({
      title: z.string().min(1).describe('Title for the new document.'),
      parentFolderId: z
        .string()
        .optional()
        .describe(
          'ID of folder where document should be created. If not provided, creates in Drive root.'
        ),
      initialContent: z
        .string()
        .optional()
        .describe(
          'Initial content to add to the document. By default, markdown syntax is converted to formatted Google Docs content (headings, bold, italic, links, lists, etc.).'
        ),
      contentFormat: z
        .enum(['markdown', 'raw'])
        .optional()
        .default('markdown')
        .describe(
          "How to interpret initialContent. 'markdown' (default) converts markdown to formatted Google Docs content. 'raw' inserts the text as-is without any conversion."
        ),
    }),
    execute: async (args, { log }) => {
      const drive = await getDriveClient();
      log.info(`Creating new document "${args.title}"`);

      try {
        const documentMetadata: drive_v3.Schema$File = {
          name: args.title,
          mimeType: 'application/vnd.google-apps.document',
        };

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

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

        const document = response.data;

        // Add initial content if provided
        if (args.initialContent) {
          try {
            const docs = await getDocsClient();
            if (args.contentFormat === 'raw') {
              await docs.documents.batchUpdate({
                documentId: document.id!,
                requestBody: {
                  requests: [
                    {
                      insertText: {
                        location: { index: 1 },
                        text: args.initialContent,
                      },
                    },
                  ],
                },
              });
            } else {
              const result = await insertMarkdown(docs, document.id!, args.initialContent, {
                startIndex: 1,
                firstHeadingAsTitle: true,
              });
              log.info(formatInsertResult(result));
            }
          } catch (contentError: any) {
            log.warn(`Document created but failed to add initial content: ${contentError.message}`);
          }
        }

        return JSON.stringify(
          {
            id: document.id,
            name: document.name,
            url: document.webViewLink,
          },
          null,
          2
        );
      } catch (error: any) {
        log.error(`Error creating document: ${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 document: ${error.message || 'Unknown error'}`);
      }
    },
  });
}