Skip to main content
Glama
document-get-raw.ts5.15 kB
import {z} from 'zod'; import type {McpServer} from '@modelcontextprotocol/sdk/server/mcp.js'; import type {Config} from './types.js'; import {makeDocsApiCall} from '../utils/docs-api.js'; import {jsonResult} from '../utils/response.js'; const inputSchema = { documentId: z.string().describe('The ID of the document to retrieve'), suggestionsViewMode: z.enum(['DEFAULT_FOR_CURRENT_ACCESS', 'SUGGESTIONS_INLINE', 'PREVIEW_SUGGESTIONS_ACCEPTED', 'PREVIEW_WITHOUT_SUGGESTIONS']).optional().describe('The suggestions view mode to apply to the document'), }; // Recursive schema for document structure elements const textStyleSchema = z.object({ bold: z.boolean().optional(), italic: z.boolean().optional(), underline: z.boolean().optional(), strikethrough: z.boolean().optional(), fontSize: z.object({ magnitude: z.number().optional(), unit: z.string().optional(), }).optional(), foregroundColor: z.unknown().optional(), backgroundColor: z.unknown().optional(), link: z.object({ url: z.string().optional(), bookmarkId: z.string().optional(), headingId: z.string().optional(), }).optional(), }).passthrough(); const textRunSchema = z.object({ content: z.string().optional(), textStyle: textStyleSchema.optional(), }); const paragraphElementSchema = z.object({ startIndex: z.number().optional(), endIndex: z.number().optional(), textRun: textRunSchema.optional(), autoText: z.unknown().optional(), pageBreak: z.unknown().optional(), columnBreak: z.unknown().optional(), footnoteReference: z.unknown().optional(), horizontalRule: z.unknown().optional(), equation: z.unknown().optional(), inlineObjectElement: z.unknown().optional(), person: z.unknown().optional(), richLink: z.unknown().optional(), }).passthrough(); const paragraphStyleSchema = z.object({ headingId: z.string().optional(), namedStyleType: z.string().optional(), alignment: z.string().optional(), lineSpacing: z.number().optional(), direction: z.string().optional(), spacingMode: z.string().optional(), spaceAbove: z.unknown().optional(), spaceBelow: z.unknown().optional(), borderBetween: z.unknown().optional(), borderTop: z.unknown().optional(), borderBottom: z.unknown().optional(), borderLeft: z.unknown().optional(), borderRight: z.unknown().optional(), indentFirstLine: z.unknown().optional(), indentStart: z.unknown().optional(), indentEnd: z.unknown().optional(), tabStops: z.array(z.unknown()).optional(), keepLinesTogether: z.boolean().optional(), keepWithNext: z.boolean().optional(), avoidWidowAndOrphan: z.boolean().optional(), shading: z.unknown().optional(), pageBreakBefore: z.boolean().optional(), }).passthrough(); const paragraphSchema = z.object({ elements: z.array(paragraphElementSchema).optional(), paragraphStyle: paragraphStyleSchema.optional(), bullet: z.unknown().optional(), positionedObjectIds: z.array(z.string()).optional(), }); const structuralElementSchema = z.object({ startIndex: z.number().optional(), endIndex: z.number().optional(), paragraph: paragraphSchema.optional(), sectionBreak: z.unknown().optional(), table: z.unknown().optional(), tableOfContents: z.unknown().optional(), }).passthrough(); const bodySchema = z.object({ content: z.array(structuralElementSchema).optional(), }); // Tab schema const tabSchema = z.object({ tabProperties: z.object({ tabId: z.string().optional(), title: z.string().optional(), index: z.number().optional(), nestingLevel: z.number().optional(), parentTabId: z.string().optional(), }).passthrough().optional(), documentTab: z.object({ body: bodySchema.optional(), headers: z.record(z.unknown()).optional(), footers: z.record(z.unknown()).optional(), footnotes: z.record(z.unknown()).optional(), documentStyle: z.unknown().optional(), namedStyles: z.unknown().optional(), inlineObjects: z.record(z.unknown()).optional(), positionedObjects: z.record(z.unknown()).optional(), }).passthrough().optional(), childTabs: z.array(z.unknown()).optional(), }).passthrough(); const outputSchema = z.object({ documentId: z.string(), title: z.string().optional(), tabs: z.array(tabSchema).optional(), revisionId: z.string().optional(), suggestionsViewMode: z.string().optional(), }).passthrough(); export function registerDocumentGetRaw(server: McpServer, config: Config): void { server.registerTool( 'document_get_raw', { title: 'Get document (raw)', description: 'Get the full raw JSON structure of a Google Doc, including all tabs, formatting, headers, footers, and styles. Warning: responses can be very large. Consider using jq to extract specific fields, or use document_get_text for plain text content.', inputSchema, outputSchema, annotations: { readOnlyHint: true, }, }, async ({documentId, suggestionsViewMode}) => { const params = new URLSearchParams(); params.set('includeTabsContent', 'true'); if (suggestionsViewMode) { params.set('suggestionsViewMode', suggestionsViewMode); } const result = await makeDocsApiCall('GET', `/documents/${documentId}?${params.toString()}`, config.token); return jsonResult(outputSchema.parse(result)); }, ); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/domdomegg/google-docs-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server