pilot_pdf
Save the current webpage as a downloadable A4 PDF document. Use to export receipts, archive pages, or create offline copies.
Instructions
Save the current page as a PDF document in A4 format. Use when the user wants to export the page as a downloadable PDF, save a receipt, or archive a page for offline reading.
Parameters:
output_path: File path to save the PDF (default: /tmp/pilot-page.pdf). Must be within the allowed output directory
Returns: Confirmation with the file path where the PDF was saved.
Errors:
"Output path must be within ...": The path is outside the allowed directory. Set PILOT_OUTPUT_DIR or use /tmp.
"Page is not HTML": The current page is a non-HTML resource (e.g., a binary download) and cannot be exported as PDF.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| output_path | No | Output file path |
Implementation Reference
- src/tools/visual.ts:126-150 (handler)The pilot_pdf tool handler registered via server.tool(). It takes an optional output_path, validates it, saves the page as A4 PDF using Playwright's page.pdf(), and returns confirmation.
server.tool( 'pilot_pdf', `Save the current page as a PDF document in A4 format. Use when the user wants to export the page as a downloadable PDF, save a receipt, or archive a page for offline reading. Parameters: - output_path: File path to save the PDF (default: /tmp/pilot-page.pdf). Must be within the allowed output directory Returns: Confirmation with the file path where the PDF was saved. Errors: - "Output path must be within ...": The path is outside the allowed directory. Set PILOT_OUTPUT_DIR or use /tmp. - "Page is not HTML": The current page is a non-HTML resource (e.g., a binary download) and cannot be exported as PDF.`, { output_path: z.string().optional().describe('Output file path') }, async ({ output_path }) => { await bm.ensureBrowser(); try { const pdfPath = output_path ? validateOutputPath(output_path) : path.join(TEMP_DIR, 'pilot-page.pdf'); await bm.getPage().pdf({ path: pdfPath, format: 'A4' }); return { content: [{ type: 'text' as const, text: `PDF saved: ${pdfPath}` }] }; } catch (err) { return { content: [{ type: 'text' as const, text: wrapError(err) }], isError: true }; } } ); - src/tools/visual.ts:139-139 (schema)Zod schema for pilot_pdf: optional string parameter 'output_path' with description 'Output file path'.
{ output_path: z.string().optional().describe('Output file path') }, - src/tools/register.ts:82-82 (registration)Registration of all visual tools (including pilot_pdf) via registerVisualTools() in the registerAllTools function.
registerVisualTools(effectiveServer, bm); - src/tools/visual.ts:13-39 (helper)Helper function validateOutputPath used by pilot_pdf to ensure the output path is within the allowed directory (PILOT_OUTPUT_DIR or /tmp).
export function validateOutputPath(outputPath: string): string { const allowed = process.env.PILOT_OUTPUT_DIR || os.tmpdir(); let normalizedAllowed: string; try { normalizedAllowed = fs.realpathSync(path.resolve(allowed)); } catch { normalizedAllowed = path.resolve(allowed); } try { const parentDir = path.dirname(outputPath); const realParent = fs.realpathSync(parentDir); const resolved = path.resolve(realParent, path.basename(outputPath)); if (!resolved.startsWith(normalizedAllowed + path.sep) && resolved !== normalizedAllowed) { throw new Error(`Output path must be within ${normalizedAllowed}: ${outputPath}`); } return resolved; } catch (err) { if (err instanceof Error && err.message.includes('Output path must be within')) { throw err; } const resolved = path.resolve(outputPath); if (!resolved.startsWith(normalizedAllowed + path.sep) && resolved !== normalizedAllowed) { throw new Error(`Output path must be within ${normalizedAllowed}: ${outputPath}`); } return resolved; } }