@sylphlab/tools-pdf
Version:
Core logic for MCP PDF tools (text extraction, etc.)
125 lines (123 loc) • 4.53 kB
JavaScript
// src/tools/getTextTool.ts
import { readFile } from "node:fs/promises";
import { defineTool } from "@sylphlab/tools-core";
import { jsonPart, validateAndResolvePath } from "@sylphlab/tools-core";
import * as mupdfjs from "mupdf/mupdfjs";
import { z as z2 } from "zod";
// src/tools/getTextTool.schema.ts
import { z } from "zod";
var GetTextItemSchema = z.object({
id: z.string().optional(),
filePath: z.string().min(1, "filePath cannot be empty.")
// Add options like page range later if needed
});
var getTextToolInputSchema = z.object({
items: z.array(GetTextItemSchema).min(1, "At least one PDF item is required.")
// allowOutsideWorkspace is handled by ToolExecuteOptions
});
// src/tools/getTextTool.ts
import { BaseContextSchema } from "@sylphlab/tools-core";
async function extractPdfText(pdfBuffer) {
let doc;
try {
doc = mupdfjs.PDFDocument.openDocument(pdfBuffer, "application/pdf");
const numPages = doc.countPages();
const pageTexts = [];
for (let i = 0; i < numPages; i++) {
let page;
try {
page = doc.loadPage(i);
pageTexts.push(page.getText());
} finally {
page?.destroy();
}
}
return pageTexts.join("\n").trim();
} finally {
doc?.destroy();
}
}
var GetTextResultItemSchema = z2.object({
id: z2.string().optional(),
path: z2.string(),
// Added path to result schema
success: z2.boolean(),
result: z2.string().optional(),
error: z2.string().optional(),
suggestion: z2.string().optional()
});
var GetTextToolOutputSchema = z2.array(GetTextResultItemSchema);
async function processSinglePdfGetText(item, options) {
const { id, filePath: inputFilePath } = item;
const resultItem = { id, path: inputFilePath, success: false };
const { workspaceRoot, allowOutsideWorkspace } = options;
let resolvedPath;
try {
const validationResult = validateAndResolvePath(
inputFilePath,
workspaceRoot,
allowOutsideWorkspace
);
if (typeof validationResult !== "string") {
throw new Error(
`Path validation failed: ${validationResult.error} ${validationResult.suggestion ?? ""}`
);
}
resolvedPath = validationResult;
const buffer = await readFile(resolvedPath);
const extractedText = await extractPdfText(buffer);
resultItem.success = true;
resultItem.result = extractedText;
resultItem.suggestion = "Successfully extracted text from PDF.";
} catch (e) {
resultItem.success = false;
const errorMsg = e instanceof Error ? e.message : String(e);
resultItem.error = `Failed to get text from PDF '${inputFilePath}': ${errorMsg}`;
if (errorMsg.includes("Path validation failed")) {
resultItem.suggestion = errorMsg.split("Suggestion: ")[1] ?? "Check path validity and workspace settings.";
} else if (e && typeof e === "object" && "code" in e) {
if (e.code === "ENOENT") {
resultItem.suggestion = "Ensure the file path is correct and the file exists.";
} else if (e.code === "EACCES") {
resultItem.suggestion = "Check file read permissions.";
} else {
resultItem.suggestion = "Ensure the file is a valid, uncorrupted PDF and check permissions.";
}
} else if (errorMsg.toLowerCase().includes("pdf")) {
resultItem.suggestion = "Ensure the file is a valid, uncorrupted PDF document.";
} else {
resultItem.suggestion = "Check file path, permissions, and file validity.";
}
}
return resultItem;
}
var getTextTool = defineTool({
name: "get-text",
description: "Extracts text content from one or more PDF files.",
inputSchema: getTextToolInputSchema,
contextSchema: BaseContextSchema,
// Add context schema
execute: async ({ context, args }) => {
const parsed = getTextToolInputSchema.safeParse(args);
if (!parsed.success) {
const errorMessages = Object.entries(parsed.error.flatten().fieldErrors).map(([field, messages]) => `${field}: ${messages.join(", ")}`).join("; ");
throw new Error(`Input validation failed: ${errorMessages}`);
}
if (!context?.workspaceRoot) {
throw new Error("Workspace root is not available in context.");
}
const { items } = parsed.data;
const results = [];
for (const item of items) {
const result = await processSinglePdfGetText(item, context);
results.push(result);
}
return [jsonPart(results, GetTextToolOutputSchema)];
}
});
export {
extractPdfText,
getTextTool,
getTextToolInputSchema
};
//# sourceMappingURL=index.js.map