diff --git a/examples/pdf-server/src/mcp-app.ts b/examples/pdf-server/src/mcp-app.ts index c8281c03..6a59407c 100644 --- a/examples/pdf-server/src/mcp-app.ts +++ b/examples/pdf-server/src/mcp-app.ts @@ -3875,7 +3875,11 @@ async function loadPdfProgressively(urlToLoad: string): Promise<{ requestDataRange(begin: number, end: number) { fetchRange(urlToLoad, begin, end) .then((result) => { - this.onDataRange(begin, result.bytes); + // PDF.js transfers the ArrayBuffer to its worker, detaching it. + // Pass a copy so the rangeCache entry stays valid for re-requests + // (iOS/WKWebView re-requests ranges under memory pressure and + // throws "Buffer is already detached" on the cached original). + this.onDataRange(begin, result.bytes.slice()); }) .catch((err: unknown) => { log.error(`Error fetching range ${begin}-${end}:`, err); diff --git a/tests/e2e/pdf-annotations.spec.ts b/tests/e2e/pdf-annotations.spec.ts index 8008f559..9d4ab958 100644 --- a/tests/e2e/pdf-annotations.spec.ts +++ b/tests/e2e/pdf-annotations.spec.ts @@ -50,7 +50,7 @@ async function extractViewUUID(page: Page): Promise { const resultText = (await resultContent.textContent()) ?? ""; // Extract viewUUID from the JSON result - // The text content includes: "Displaying PDF (viewUUID: ): ..." + // The text content includes: "PDF opened. viewUUID: " const match = resultText.match(/viewUUID["\s:]+([a-f0-9-]{36})/); if (!match) { throw new Error( @@ -107,7 +107,7 @@ test.describe("PDF Server - Annotations", () => { // (interact action list lives in the tool description, not the runtime result). expect(resultText).toContain("viewUUID"); expect(resultText).toContain("interactEnabled"); - expect(resultText).toContain("Displaying PDF"); + expect(resultText).toContain("PDF opened"); }); test("interact tool is available in tool dropdown", async ({ page }) => {