Skip to main content
Glama
PSPDFKit

Nutrient Document Engine MCP Server

by PSPDFKit
renderDocumentPage.ts5.54 kB
import { DocumentEngineClient } from '../../api/Client.js'; import { DocumentFingerprintSchema } from '../schemas/DocumentFingerprintSchema.js'; import { z } from 'zod'; import { MCPToolOutput } from '../../mcpTools.js'; import { getDocumentInfo, renderDocumentPage as renderDocumentPageWithLayer, } from '../../api/DocumentLayerAbstraction.js'; /** * Schema for render_document_page tool */ export const RenderDocumentPageSchema = { document_fingerprint: DocumentFingerprintSchema, pages: z.array(z.number()).describe('Array of page indices to render (0-based)'), width: z .number() .optional() .describe( 'The width of the rendered image in pixels. If width nor height is given, the render size defaults to the page size.' ), height: z .number() .optional() .describe( 'The height of the rendered image in pixels. If width nor height is given, the render size defaults to the page size.' ), }; export const RenderDocumentPageInputSchema = z.object(RenderDocumentPageSchema); export type RenderDocumentPageInput = z.infer<typeof RenderDocumentPageInputSchema>; /** * Render one or more pages of a document as images */ export async function renderDocumentPage( client: DocumentEngineClient, params: RenderDocumentPageInput ): Promise<MCPToolOutput> { try { // Validate input const validatedParams = RenderDocumentPageInputSchema.parse(params); const { document_fingerprint, pages, width, height } = validatedParams; // Get document info to validate page indices const docInfo = await getDocumentInfo(client, document_fingerprint); const pageCount = docInfo.pageCount || 0; // Use the pages array directly const pagesToRender: number[] = [...pages]; // Validate all page indices for (const idx of pagesToRender) { if (idx < 0 || idx >= pageCount) { throw new Error( `Page index ${idx} is out of bounds (document has ${pageCount} pages, valid indices are 0-${pageCount - 1})` ); } } // Prepare query parameters const queryParams: Record<string, string> = {}; // Handle different cases for width and height if (width !== undefined && height !== undefined) { // If both are provided, use width (prioritize width over height) queryParams.width = width.toString(); } else if (width !== undefined) { // If only width is provided, use it queryParams.width = width.toString(); } else if (height !== undefined) { // If only height is provided, use it queryParams.height = height.toString(); } else { // If no dimensions are available, use a reasonable default queryParams.width = '800'; } // Create dimension text for markdown let dimensionsText = ''; if (width !== undefined) { dimensionsText = `Width: ${width}px`; } else if (height !== undefined) { dimensionsText = `Height: ${height}px`; } else { dimensionsText = `Width: 800px (default)`; } // Render each page const renderedPages = await Promise.all( pagesToRender.map(async pageIdx => { // Get page dimensions from document info const pageInfo = docInfo.pages?.[pageIdx]; const pageWidth = pageInfo?.width; const pageHeight = pageInfo?.height; // Get the rendered page image const response = await renderDocumentPageWithLayer( client, document_fingerprint, pageIdx, queryParams, { responseType: 'arraybuffer', headers: { Accept: 'image/png', }, } ); // Get the content type from the response const contentType = response.headers['content-type'] || 'image/png'; // Convert the binary data to base64 const buffer = response.data; const base64 = Buffer.from(buffer).toString('base64'); return { pageIndex: pageIdx, pageNumber: pageIdx + 1, contentType, base64, pageWidth, pageHeight, }; }) ); // Create markdown description let markdown = `# Document Page Render\n\n` + `📄 **Document ID:** ${document_fingerprint.document_id}\n` + (document_fingerprint.layer ? `🔀 **Layer:** ${document_fingerprint.layer}\n` : '') + `📄 **Total Pages Rendered:** ${renderedPages.length} of ${pageCount} total pages\n` + `🖼️ **Image Format:** ${renderedPages[0]?.contentType || 'image/png'}\n` + `📏 **Dimensions:** ${dimensionsText}\n\n`; // Add details for each rendered page markdown += `## Page Details\n\n`; renderedPages.forEach((page, index) => { markdown += `### Page ${page.pageNumber} of ${pageCount}\n` + `📐 **Original Page Size:** ${page.pageWidth && page.pageHeight ? `${page.pageWidth} × ${page.pageHeight} points` : 'Unknown'}\n\n`; if (index < renderedPages.length - 1) { markdown += `---\n\n`; } }); return { markdown, images: renderedPages.map(page => ({ mimeType: page.contentType, base64: page.base64, pageIndex: page.pageIndex, })), }; } catch (error) { // Provide a user-friendly error message return { markdown: `# Error Rendering Pages\n\nAn error occurred while trying to render the pages: ${error instanceof Error ? error.message : String(error)}\n\nPlease check your parameters and try again.`, }; } }

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/PSPDFKit/nutrient-document-engine-mcp-server'

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