diff --git a/.gitignore b/.gitignore
index 0e7722f..4a58a83 100644
--- a/.gitignore
+++ b/.gitignore
@@ -98,3 +98,7 @@ tmp*.py
node-version/dist/
node-version/node_modules/
node-version/coverage/
+
+
+# Local test documents
+samples/
diff --git a/CLAUDE.md b/CLAUDE.md
index 7bacaca..50a507b 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -13,8 +13,20 @@ MCP server connecting Claude Desktop to Nitro's Document Intelligence Platform A
- `src/handlers/` — `PlatformHandler` (operations) and `FilesHandler` (local I/O)
- `src/tools/` — MCP tool implementations
- `src/auth/` — PKCE auth flow and token management
+- `src/assets/mcp-app.html` — prebuilt single-file Nitro PDF viewer (generated by `scripts/inline-viewer.mjs`, copied to `dist/assets/` by `build.mjs`)
+- `scripts/` — viewer build pipeline (`inline-viewer.mjs`, `viewer-bridge.js`)
- `tests/` — Vitest test suite
+## Inline PDF Viewer
+
+`view_pdf` renders a PDF in Nitro's reader directly inside the Claude conversation (MCP-App iframe — no browser popup, no network, no second login). Implementation: `src/tools/viewer.ts`.
+
+- The viewer is the `nitro-pdf-reader` Angular web component from the frontend repo (`apps/public-reader`, `nx build public-reader`).
+- The MCP-App sandbox has no origin and blocks all network, so `scripts/inline-viewer.mjs` folds the multi-file build into ONE self-contained HTML (`src/assets/mcp-app.html`, ~26 MB): app chunks collapsed via esbuild, worker as Blob URL, Pdfium WASM injected via emscripten `wasmBinary` (sandbox CSP blocks `fetch()` of even `data:` URLs), Kendo CSS + IBM Plex fonts inlined as `data:` URLs.
+- `scripts/viewer-bridge.js` (bundled into the HTML) connects via `@modelcontextprotocol/ext-apps`, receives `{filePath}` from the tool result, calls `get_pdf_for_viewer` over the MCP transport, and assigns the bytes to the component's `file` property.
+- To rebuild the viewer after a frontend change: `node scripts/inline-viewer.mjs