Spaces:
Sleeping
Sleeping
File size: 3,942 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 | import type { FastMCP } from 'fastmcp';
import { UserError } from 'fastmcp';
import { z } from 'zod';
import { getDocsClient } from '../../clients.js';
import { DocumentIdParameter } from '../../types.js';
import * as GDocsHelpers from '../../googleDocsApiHelpers.js';
export function register(server: FastMCP) {
server.addTool({
name: 'addTab',
description:
"Adds a new tab to a Google Docs document. Optionally set the tab title, position, parent tab (for nesting), and icon emoji. Returns the new tab's ID and properties.",
parameters: DocumentIdParameter.extend({
title: z
.string()
.optional()
.describe(
'The title for the new tab. If not specified, Google Docs assigns a default name.'
),
parentTabId: z
.string()
.optional()
.describe(
'The ID of an existing tab to nest this new tab under as a child. Use listDocumentTabs to get tab IDs. If not specified, the tab is created at the root level.'
),
index: z
.number()
.int()
.min(0)
.optional()
.describe(
'The zero-based position among sibling tabs (within the same parent). If not specified, the tab is added at the end.'
),
iconEmoji: z
.string()
.optional()
.describe('An emoji to display as the tab icon (e.g., "📋").'),
}),
execute: async (args, { log }) => {
const docs = await getDocsClient();
log.info(`Adding new tab to doc ${args.documentId}`);
try {
// If parentTabId is provided, verify it exists
if (args.parentTabId) {
const docInfo = await docs.documents.get({
documentId: args.documentId,
includeTabsContent: true,
fields: 'tabs(tabProperties,documentTab(body))',
});
const parentTab = GDocsHelpers.findTabById(docInfo.data, args.parentTabId);
if (!parentTab) {
throw new UserError(`Parent tab with ID "${args.parentTabId}" not found in document.`);
}
}
const tabProperties: Record<string, unknown> = {};
if (args.title !== undefined) tabProperties.title = args.title;
if (args.parentTabId !== undefined) tabProperties.parentTabId = args.parentTabId;
if (args.index !== undefined) tabProperties.index = args.index;
if (args.iconEmoji !== undefined) tabProperties.iconEmoji = args.iconEmoji;
const response = await docs.documents.batchUpdate({
documentId: args.documentId,
requestBody: {
requests: [
{
addDocumentTab: {
tabProperties,
},
} as any,
],
},
});
const newTabProps = (response.data.replies?.[0] as any)?.addDocumentTab?.tabProperties;
if (newTabProps) {
return JSON.stringify(
{
message: `Successfully added new tab "${newTabProps.title || '(untitled)'}"`,
tabId: newTabProps.tabId,
title: newTabProps.title,
index: newTabProps.index,
parentTabId: newTabProps.parentTabId,
nestingLevel: newTabProps.nestingLevel,
},
null,
2
);
}
return 'Tab created successfully, but could not retrieve the new tab details.';
} catch (error: any) {
log.error(`Error adding tab to doc ${args.documentId}: ${error.message || error}`);
if (error instanceof UserError) throw error;
if (error.code === 404) throw new UserError(`Document not found (ID: ${args.documentId}).`);
if (error.code === 403)
throw new UserError(`Permission denied for document (ID: ${args.documentId}).`);
throw new UserError(`Failed to add tab: ${error.message || 'Unknown error'}`);
}
},
});
}
|