// Google Docs MCP tools
import { z } from 'zod';
import type { DocsService } from '../services/docs.js';
// ─────────────────────────────────────────────────────────────────────────────
// SCHEMAS
// ─────────────────────────────────────────────────────────────────────────────
export const CreateGoogleDocSchema = z.object({
name: z.string().describe('Document name'),
content: z.string().describe('Document content'),
parentFolder: z.string().optional().describe('Parent folder ID or path'),
});
export const UpdateGoogleDocSchema = z.object({
documentId: z.string().describe('Document ID'),
content: z.string().describe('New content (replaces existing)'),
});
export const GetGoogleDocContentSchema = z.object({
documentId: z.string().describe('Document ID'),
});
export const FormatGoogleDocTextSchema = z.object({
documentId: z.string().describe('Document ID'),
startIndex: z.number().describe('Start index (1-based)'),
endIndex: z.number().describe('End index'),
bold: z.boolean().optional().describe('Make text bold'),
italic: z.boolean().optional().describe('Make text italic'),
underline: z.boolean().optional().describe('Underline text'),
strikethrough: z.boolean().optional().describe('Strikethrough text'),
fontSize: z.number().optional().describe('Font size in points'),
foregroundColor: z.object({
red: z.number().min(0).max(1).optional(),
green: z.number().min(0).max(1).optional(),
blue: z.number().min(0).max(1).optional(),
}).optional().describe('Text color (RGB 0-1)'),
});
export const FormatGoogleDocParagraphSchema = z.object({
documentId: z.string().describe('Document ID'),
startIndex: z.number().describe('Start index (1-based)'),
endIndex: z.number().describe('End index'),
alignment: z.enum(['START', 'CENTER', 'END', 'JUSTIFIED']).optional().describe('Text alignment'),
lineSpacing: z.number().optional().describe('Line spacing (100 = single)'),
spaceAbove: z.number().optional().describe('Space above in points'),
spaceBelow: z.number().optional().describe('Space below in points'),
});
// ─────────────────────────────────────────────────────────────────────────────
// TOOL DEFINITIONS
// ─────────────────────────────────────────────────────────────────────────────
export const docsTools = [
{
name: 'createGoogleDoc',
description: 'Create a new Google Doc with content',
inputSchema: {
type: 'object' as const,
properties: {
name: { type: 'string', description: 'Document name' },
content: { type: 'string', description: 'Document content' },
parentFolder: { type: 'string', description: 'Parent folder ID or path' },
},
required: ['name', 'content'],
},
},
{
name: 'updateGoogleDoc',
description: 'Update content of an existing Google Doc (replaces all content)',
inputSchema: {
type: 'object' as const,
properties: {
documentId: { type: 'string', description: 'Document ID' },
content: { type: 'string', description: 'New content' },
},
required: ['documentId', 'content'],
},
},
{
name: 'getGoogleDocContent',
description: 'Get the content of a Google Doc as plain text',
inputSchema: {
type: 'object' as const,
properties: {
documentId: { type: 'string', description: 'Document ID' },
},
required: ['documentId'],
},
},
{
name: 'formatGoogleDocText',
description: 'Apply text formatting (bold, italic, color, etc) to a range in a Google Doc',
inputSchema: {
type: 'object' as const,
properties: {
documentId: { type: 'string', description: 'Document ID' },
startIndex: { type: 'number', description: 'Start index (1-based)' },
endIndex: { type: 'number', description: 'End index' },
bold: { type: 'boolean', description: 'Make text bold' },
italic: { type: 'boolean', description: 'Make text italic' },
underline: { type: 'boolean', description: 'Underline text' },
strikethrough: { type: 'boolean', description: 'Strikethrough text' },
fontSize: { type: 'number', description: 'Font size in points' },
foregroundColor: {
type: 'object',
description: 'Text color (RGB 0-1)',
properties: {
red: { type: 'number' },
green: { type: 'number' },
blue: { type: 'number' },
},
},
},
required: ['documentId', 'startIndex', 'endIndex'],
},
},
{
name: 'formatGoogleDocParagraph',
description: 'Apply paragraph formatting (alignment, spacing) to a range in a Google Doc',
inputSchema: {
type: 'object' as const,
properties: {
documentId: { type: 'string', description: 'Document ID' },
startIndex: { type: 'number', description: 'Start index (1-based)' },
endIndex: { type: 'number', description: 'End index' },
alignment: { type: 'string', enum: ['START', 'CENTER', 'END', 'JUSTIFIED'], description: 'Text alignment' },
lineSpacing: { type: 'number', description: 'Line spacing (100 = single)' },
spaceAbove: { type: 'number', description: 'Space above in points' },
spaceBelow: { type: 'number', description: 'Space below in points' },
},
required: ['documentId', 'startIndex', 'endIndex'],
},
},
];
// ─────────────────────────────────────────────────────────────────────────────
// HANDLERS
// ─────────────────────────────────────────────────────────────────────────────
export function createDocsHandlers(docsService: DocsService) {
return {
createGoogleDoc: async (args: z.infer<typeof CreateGoogleDocSchema>) => {
const params = CreateGoogleDocSchema.parse(args);
return docsService.createDoc(params.name, params.content, params.parentFolder);
},
updateGoogleDoc: async (args: z.infer<typeof UpdateGoogleDocSchema>) => {
const params = UpdateGoogleDocSchema.parse(args);
return docsService.updateDoc(params.documentId, params.content);
},
getGoogleDocContent: async (args: z.infer<typeof GetGoogleDocContentSchema>) => {
const params = GetGoogleDocContentSchema.parse(args);
return docsService.getDocContent(params.documentId);
},
formatGoogleDocText: async (args: z.infer<typeof FormatGoogleDocTextSchema>) => {
const params = FormatGoogleDocTextSchema.parse(args);
await docsService.formatText(
params.documentId,
params.startIndex,
params.endIndex,
{
bold: params.bold,
italic: params.italic,
underline: params.underline,
strikethrough: params.strikethrough,
fontSize: params.fontSize,
foregroundColor: params.foregroundColor,
}
);
return { success: true };
},
formatGoogleDocParagraph: async (args: z.infer<typeof FormatGoogleDocParagraphSchema>) => {
const params = FormatGoogleDocParagraphSchema.parse(args);
await docsService.formatParagraph(
params.documentId,
params.startIndex,
params.endIndex,
{
alignment: params.alignment,
lineSpacing: params.lineSpacing,
spaceAbove: params.spaceAbove,
spaceBelow: params.spaceBelow,
}
);
return { success: true };
},
};
}