Skip to main content
Glama
PSPDFKit

Nutrient Document Engine MCP Server

by PSPDFKit
routes.ts6.58 kB
import { Request, Response } from 'express'; import multer from 'multer'; import basicAuth from 'express-basic-auth'; import { DocumentEngineClient } from '../api/Client.js'; import { getEnvironment } from '../utils/Environment.js'; import { logger } from '../utils/Logger.js'; import { dashboardTemplate } from './templates/dashboard.js'; import { uploadResultsTemplate } from './templates/uploadResults.js'; import { errorTemplate } from './templates/error.js'; import { formatFileSize } from '../utils/Common.js'; // Set up multer for file uploads export const upload = multer({ storage: multer.memoryStorage(), limits: { fileSize: 50 * 1024 * 1024 }, // 50MB limit }); /** * Create basic auth middleware for dashboard routes */ export function createAuthMiddleware() { const env = getEnvironment(); if (!env.DASHBOARD_USERNAME || !env.DASHBOARD_PASSWORD) { throw new Error( 'DASHBOARD_USERNAME and DASHBOARD_PASSWORD must be provided to enable dashboard' ); } return basicAuth({ users: { [env.DASHBOARD_USERNAME]: env.DASHBOARD_PASSWORD }, challenge: true, realm: 'Document Engine Dashboard', }); } /** * Dashboard home page handler */ export async function dashboardHandler(client: DocumentEngineClient, req: Request, res: Response) { try { // Get list of documents const response = await client['list-documents']({ page_size: 100, order_by: 'created_at', order_direction: 'desc', }); const documents = response.data.data || []; // Get message from query parameters if present const message = req.query.message as string | undefined; // Render HTML dashboard res.send(dashboardTemplate(documents, formatFileSize, message)); } catch (error) { logger.error(null, 'Dashboard error', { error }); res .status(500) .send( errorTemplate( `An error occurred while loading the dashboard: ${error instanceof Error ? error.message : 'Unknown error'}` ) ); } } /** * File upload handler */ export async function uploadHandler(client: DocumentEngineClient, req: Request, res: Response) { try { if (!req.files || req.files.length === 0) { return res.status(400).send(errorTemplate('No files were uploaded.')); } const results = []; const files = Array.isArray(req.files) ? req.files : Object.values(req.files).flat(); for (const file of files) { try { // Create FormData for file upload const formData = new FormData(); const blob = new Blob([file.buffer], { type: 'application/octet-stream' }); formData.append('file', blob, file.originalname); // Upload file to Document Engine with proper content type // @ts-expect-error We can pass FormData to this endpoint. const response = await client['upload-document']({}, formData, { headers: { 'Content-Type': 'multipart/form-data', }, }); const documentId = response.data.data?.document_id; if (!documentId) { throw new Error('No document ID returned from upload'); } results.push({ filename: file.originalname, success: true, documentId: documentId, }); } catch (fileError) { results.push({ filename: file.originalname, success: false, error: fileError instanceof Error ? fileError.message : 'Upload failed', }); } } // Transform results to match the expected type for the template const templateResults = results.map(result => { if ('documentId' in result) { return { filename: result.filename as string, success: result.success, }; } else { return { filename: result.filename as string, success: result.success, error: result.error, }; } }); // Render upload results res.send(uploadResultsTemplate(templateResults)); } catch (error) { logger.error(null, 'File upload error', { error }); res .status(500) .send( errorTemplate( `An error occurred during file upload: ${error instanceof Error ? error.message : 'Unknown error'}` ) ); } } /** * File download handler */ export async function downloadHandler(client: DocumentEngineClient, req: Request, res: Response) { try { const documentId = req.params.id; if (!documentId) { return res.status(400).send(errorTemplate('Document ID is required')); } // Get document info to get the title for the filename const documentInfo = await client['fetch-document-info']({ documentId }); // Check if document info exists and has title const documentData = documentInfo.data.data; if (!documentData) { throw new Error(`No document data returned for document ID: ${documentId}`); } const documentTitle = documentData.title || 'document'; const safeFilename = documentTitle.replace(/[^a-z0-9]/gi, '_').toLowerCase() + '.pdf'; // Download the document as PDF with proper binary response handling const response = await client['download-document-pdf']({ documentId }, undefined, { responseType: 'arraybuffer', }); // Set headers for file download res.setHeader('Content-Type', 'application/pdf'); res.setHeader('Content-Disposition', `attachment; filename="${safeFilename}"`); res.send(Buffer.from(response.data)); } catch (error) { logger.error(null, 'Document download error', { error }); res .status(500) .send( errorTemplate( `An error occurred while downloading the document: ${error instanceof Error ? error.message : 'Unknown error'}` ) ); } } /** * File delete handler */ export async function deleteHandler(client: DocumentEngineClient, req: Request, res: Response) { try { const documentId = req.params.id; if (!documentId) { return res.status(400).send(errorTemplate('Document ID is required')); } // Delete the document await client['delete-document']({ documentId }); // Redirect back to dashboard with success message res.redirect('/dashboard?message=Document+deleted+successfully'); } catch (error) { logger.error(null, 'Document delete error', { error }); res .status(500) .send( errorTemplate( `An error occurred while deleting the document: ${error instanceof Error ? error.message : 'Unknown error'}` ) ); } }

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