# Analisi tecnica: supporto Pandoc negli MCP/skill attuali

**Data:** 2026-05-07
**Autore:** ChatGPT per Davide Corona
**Repo target:** `sophiadeveloper/mcp-servers`
**Decisione proposta:** includere Pandoc come capability opzionale, non come dipendenza obbligatoria.

---

## 1. Executive summary

Questa analisi valuta se introdurre supporto a [Pandoc](https://pandoc.org/) negli MCP/skill attuali, con eventuale installazione automatica.

La raccomandazione e':

1. **Aggiungere supporto Pandoc in `office-node`**, tramite un nuovo tool dedicato alla conversione documentale, ad esempio `document_convert`.
2. **Mantenere Pandoc opzionale**: il server deve funzionare anche senza Pandoc installato.
3. **Evitare installazioni automatiche silenziose**: consentire al massimo un comando esplicito tipo `setup_pandoc`, con comportamento conservativo e documentato.
4. **Non sostituire le funzioni esistenti**: `pdf_document.export_text` resta il percorso nativo e stabile per PDF -> Markdown/TXT; Pandoc copre conversioni general-purpose tra Markdown, DOCX, HTML, LaTeX, ODT, RTF, EPUB, PPTX e altri formati.
5. **Aggiornare gli skill di orchestrazione/documentazione**: `mcp-office-expert`, `mcp-docs-navigator` e, se presente, `mcp-master-orchestrator` devono sapere quando usare il backend Pandoc e quando restare sui tool nativi.

Pandoc e' particolarmente utile per i flussi:

- Markdown -> DOCX/HTML/PDF come deliverable;
- DOCX/HTML/ODT/RTF -> Markdown per normalizzazione e indicizzazione;
- Markdown tecnico -> formati distribuibili;
- conversioni documentali ripetibili con template e metadata.

Non e' invece la soluzione migliore per:

- estrazione testuale mirata da PDF pagina/range;
- PDF scannerizzati o image-only;
- editing preciso di DOCX/XLSX;
- modifica in-place di documenti Office.

---

## 2. Stato attuale rilevato

### 2.1 Conversione in Markdown oggi disponibile

Attualmente il percorso esplicito per produrre Markdown e' in `office-node`, nel tool `pdf_document`, action `export_text`.

Shape semplificata:

```json
{
  "name": "pdf_document",
  "arguments": {
    "action": "export_text",
    "file_path": "/path/input.pdf",
    "save_path": "/path/output.md",
    "format": "md"
  }
}
```

Il comportamento corrente e':

- `save_path` e' obbligatorio;
- `format` accetta `md` o `txt`, default `md`;
- il server legge tutte le pagine del PDF;
- se `format === "md"`, produce Markdown tramite formatter interno;
- crea automaticamente la directory di output;
- scrive il file su disco;
- restituisce payload strutturato con almeno `save_path`, `mime_type`, `pages`, `format` e, se disponibile, `resource_link`.

### 2.2 Contratto Office -> Docs

Il repo ha gia' un contratto minimo Office -> Docs basato su artifact testuali:

1. `office-node` esporta un file `.md` o `.txt` su `save_path`;
2. `office-node` registra un artifact `artifact://office/{year}/{month}/{artifact_id}`;
3. `docs-node` indicizza il file usando `docs_management.scan_file` con `file_path = save_path`;
4. la ricerca avviene tramite `docs_navigation.search`.

Questo contratto e' importante perche' evita refactor cross-server prematuri: `artifact://...` resta identificatore resource-oriented, mentre `save_path` resta il ponte locale compatibile con `docs-node`.

### 2.3 Prompt operativo esistente

`office-node` espone anche un prompt MCP `ingest_pdf_into_docs`, che formalizza il bridge PDF -> Markdown -> Docs:

1. esegui `pdf_document(action="export_text", format="md")`;
2. verifica che il file Markdown esista e sia leggibile;
3. esegui `docs_management(action="scan_file")`;
4. verifica la reperibilita' tramite `docs_navigation.search`.

Questo e' un segnale architetturale rilevante: il posto giusto per conversioni documentali resta `office-node`, non `docs-node`.

---

## 3. Che cosa aggiunge Pandoc

Pandoc e' un convertitore universale di documenti. Dal manuale ufficiale:

- supporta conversioni tra markup e formati word-processing, inclusi Markdown, HTML, LaTeX e DOCX;
- usa `-f/--from` per il formato input e `-t/--to` per il formato output;
- puo' dedurre i formati dalle estensioni;
- espone `--list-input-formats` e `--list-output-formats`;
- puo' produrre PDF, ma per default richiede un motore LaTeX installato o un `--pdf-engine` alternativo.

Esempi CLI equivalenti:

```bash
pandoc -f markdown -t docx -s input.md -o output.docx
pandoc -f docx -t gfm input.docx -o output.md
pandoc -f html -t markdown input.html -o output.md
pandoc -f markdown -t pdf input.md -o output.pdf
```

### 3.1 Formati interessanti per il repo

Formati input utili:

- `markdown`, `gfm`, `commonmark`, `commonmark_x`;
- `docx`;
- `html`;
- `odt`;
- `rtf`;
- `latex`;
- `epub`;
- `pptx`;
- `xlsx` in alcuni scenari, ma da valutare con cautela.

Formati output utili:

- `markdown`, `gfm`, `commonmark`;
- `docx`;
- `html`, `html5`;
- `pdf`;
- `odt`;
- `rtf`;
- `epub`;
- `pptx`.

### 3.2 Valore rispetto ai tool attuali

| Scenario | Tool attuale | Limite attuale | Pandoc utile? | Note |
|---|---|---|---|---|
| PDF -> Markdown | `pdf_document.export_text` | Solo testo estraibile, struttura semplice per pagina | Poco / no | Mantenere nativo: e' gia' integrato con artifact e docs |
| DOCX -> Markdown | `word_document` | Lettura/modifica, ma non export Markdown general-purpose | Si' | Pandoc puo' normalizzare in Markdown indicizzabile |
| Markdown -> DOCX | Nessun tool general-purpose | Serve generare deliverable Word | Si' | Caso d'uso forte |
| Markdown -> HTML | Nessun tool general-purpose | Serve output web/shareable | Si' | Caso semplice e robusto |
| Markdown -> PDF | Non coperto in modo general-purpose | Richiede motore PDF/LaTeX | Si', ma opzionale | Serve gestione dipendenze |
| HTML -> Markdown | Non coperto | Utile per import documentale | Si' | Caso forte |
| XLSX -> Markdown | `excel_document` legge/scrive celle | Conversione semantica spesso ambigua | Forse | Meglio mantenere Excel nativo per dati tabellari |
| PPTX -> Markdown | Non coperto | Supporto Pandoc non sempre perfetto | Forse | Utile come estrazione outline, non come conversione fedele |

---

## 4. Proposta architetturale

### 4.1 Nuovo tool in `office-node`: `document_convert`

Proporre un tool separato da `pdf_document`, `word_document` ed `excel_document`.

Motivazioni:

- evita di sovraccaricare `pdf_document` con responsabilita' non PDF;
- espone una superficie chiara: conversione documentale general-purpose;
- consente fallback e detection Pandoc senza contaminare i tool nativi;
- mantiene stabile il contratto PDF -> Markdown gia' esistente.

Tool proposto:

```ts
name: "document_convert"
```

Azioni:

```ts
action: "status" | "list_formats" | "convert" | "setup_pandoc"
```

### 4.2 `status`

Scopo: verificare se Pandoc e' disponibile.

Input:

```json
{
  "action": "status"
}
```

Output atteso:

```json
{
  "ok": true,
  "tool": "document_convert",
  "action": "status",
  "pandoc": {
    "available": true,
    "version": "pandoc 3.x.x",
    "path": "/usr/bin/pandoc"
  },
  "pdf": {
    "available": "unknown",
    "note": "PDF output may require a PDF engine such as LaTeX, typst, wkhtmltopdf, weasyprint, or similar."
  }
}
```

Se Pandoc non e' disponibile:

```json
{
  "ok": true,
  "tool": "document_convert",
  "action": "status",
  "pandoc": {
    "available": false,
    "version": null,
    "path": null
  },
  "next_actions": [
    "Install pandoc manually",
    "Run setup_pandoc if explicitly enabled",
    "Use existing native tools where applicable"
  ]
}
```

### 4.3 `list_formats`

Scopo: esporre i formati supportati dalla versione installata.

Implementazione:

- `pandoc --list-input-formats`;
- `pandoc --list-output-formats`.

Input:

```json
{
  "action": "list_formats"
}
```

Output atteso:

```json
{
  "ok": true,
  "input_formats": ["markdown", "docx", "html"],
  "output_formats": ["markdown", "docx", "html", "pdf"]
}
```

### 4.4 `convert`

Scopo: convertire un documento tramite Pandoc.

Input minimo:

```json
{
  "action": "convert",
  "input_path": "/abs/input.md",
  "output_path": "/abs/output.docx",
  "from": "markdown",
  "to": "docx",
  "standalone": true
}
```

> **Validazione server-side:** quando `action === "convert"`, il server deve verificare esplicitamente la presenza di `input_path` e `output_path` e restituire un errore actionable (non un crash runtime). Lo schema MCP dichiara solo `required: ["action"]` per compatibilita' con client severi che non supportano `oneOf`/`if-then`.

Input esteso:

```json
{
  "action": "convert",
  "input_path": "/abs/input.md",
  "output_path": "/abs/output.docx",
  "from": "markdown",
  "to": "docx",
  "standalone": true,
  "metadata": {
    "title": "Report tecnico",
    "author": "Sophia Informatica"
  },
  "reference_doc_path": "/abs/reference.docx",
  "template_path": null,
  "resource_paths": ["/abs/assets"],
  "pdf_engine": null
}
```

Output atteso:

```json
{
  "ok": true,
  "tool": "document_convert",
  "action": "convert",
  "backend": "pandoc",
  "input_path": "/abs/input.md",
  "output_path": "/abs/output.docx",
  "from": "markdown",
  "to": "docx",
  "mime_type": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
  "pandoc_version": "pandoc 3.x.x",
  "warnings": []
}
```

Se `output_path` termina in `.md` o `.txt`, il tool puo' registrare un artifact testuale analogo a `pdf_document.export_text`, usando lo stesso registry Office.

### 4.5 `setup_pandoc`

Scopo: supportare installazione assistita, ma solo con consenso esplicito.

Input proposto:

```json
{
  "action": "setup_pandoc",
  "setup_mode": "instructions_only"
}
```

> **Nota:** il parametro si chiama `setup_mode` (non `mode`) per coerenza con il nome usato nello schema MCP del tool.

Modalita' ammesse:

- `instructions_only`: ritorna istruzioni OS-specifiche;
- `local_download`: scarica binario/zip in directory controllata dal progetto, se implementato;
- `package_manager`: usa package manager solo se esplicitamente richiesto;
- `docker_hint`: suggerisce `pandoc/core` o `pandoc/latex` per CI/container;
- `pdf_engine_hint`: restituisce istruzioni dedicate per `xelatex`, `typst` e alternative PDF, senza eseguire installer.

La modalita' default deve essere `instructions_only`.

---

## 5. Installazione automatica: valutazione

### 5.1 Perche' evitare installazione automatica silenziosa

Pandoc puo' essere installato con installer ufficiali, package manager, Conda Forge, Docker o build da sorgente. Tuttavia:

- su Windows l'installer puo' modificare il PATH;
- su Linux spesso servono permessi amministrativi per package manager di sistema;
- per output PDF serve quasi sempre un engine aggiuntivo;
- installazioni multiple possono creare ambiguita' di versione;
- filtri Lua o dipendenze esterne possono richiedere setup addizionale;
- un MCP server non dovrebbe modificare l'ambiente globale senza consenso esplicito.

### 5.2 Strategia raccomandata

1. **Detection first**: `status` verifica `pandoc --version`.
2. **Fail actionable**: se manca Pandoc, errore non bloccante con istruzioni precise.
3. **Setup opt-in**: `setup_pandoc` non parte mai automaticamente durante `convert`.
4. **No sudo implicito**: il server non deve eseguire `sudo`, `apt`, `brew`, `winget`, `choco` o installer MSI senza richiesta esplicita.
5. **CI/container preferiti**: in pipeline usare immagini ufficiali o preinstallazione dichiarativa.

### 5.3 Suggerimenti OS-specifici

#### Windows

Opzioni:

- installer ufficiale Pandoc;
- `winget install --source winget --exact --id JohnMacFarlane.Pandoc`;
- `choco install pandoc`;
- zip portabile in directory locale.

Raccomandazione MCP:

- non lanciare MSI automaticamente;
- preferire `instructions_only` o zip portabile se si vuole una modalita' locale controllata.

#### macOS

Opzioni:

- installer ufficiale;
- `brew install pandoc`;
- MacPorts;
- zip portabile.

Raccomandazione MCP:

- non eseguire `brew install` automaticamente senza flag esplicito;
- per PDF, documentare BasicTeX/TinyTeX o engine alternativo.

#### Linux

Opzioni:

- package manager distro;
- `.deb`/tarball ufficiale;
- Conda Forge;
- Docker.

Raccomandazione MCP:

- evitare `sudo apt install` automatico;
- supportare tarball locale solo se implementato in modo ripetibile;
- in CI preferire immagine Docker o step esplicito di setup.

#### Docker/CI

Opzioni:

- `pandoc/core`: contiene Pandoc;
- `pandoc/latex`: contiene Pandoc + LaTeX minima per PDF.

Raccomandazione:

- documentare un esempio CI/smoke dedicato;
- non rendere i test Pandoc obbligatori se Pandoc non e' installato, a meno che la pipeline lo preveda.

---

## 6. Integrazione con skill/MCP attuali

### 6.1 `office-node`

Modifiche consigliate:

- aggiungere `document_convert`;
- usare Pandoc come backend opzionale;
- registrare artifact testuali quando output e' `.md` o `.txt`;
- mantenere compatibilita' con `save_path`;
- aggiungere resources/read se l'artifact viene registrato;
- aggiungere smoke test con skip se Pandoc non disponibile.

### 6.2 `mcp-office-expert`

Aggiornare istruzioni:

- usare tool nativi per editing preciso Word/Excel e lettura PDF mirata;
- usare `pdf_document.export_text` per PDF -> Markdown destinato a `docs-node`;
- usare `document_convert` quando serve conversione tra formati documentali general-purpose;
- non promettere fedelta' perfetta in conversioni ricche;
- segnalare dipendenze mancanti per PDF output.

Esempi trigger:

- "converti questo Markdown in DOCX";
- "trasforma questo DOCX in Markdown indicizzabile";
- "genera HTML da questo report Markdown";
- "crea un PDF da questo Markdown".

### 6.3 `mcp-docs-navigator`

Aggiornare istruzioni:

- non convertire direttamente documenti non Markdown;
- se riceve DOCX/HTML/ODT, delegare a `mcp-office-expert`/`office-node.document_convert` per produrre Markdown;
- poi usare `docs_management.scan_file`;
- mantenere `save_path` come ponte operativo.

### 6.4 `mcp-master-orchestrator`

Aggiornare routing:

- task documentali/conversione -> `mcp-office-expert`;
- indicizzazione/ricerca -> `mcp-docs-navigator`;
- flussi misti -> office conversion/export prima, docs scan/search poi.

---

## 7. Sicurezza e robustezza

### 7.1 Esecuzione processo

Usare `spawn` o `execFile`, non concatenazione shell.

Esempio Node.js:

```js
import { spawn } from "node:child_process";

const PANDOC_TIMEOUT_MS = 60_000; // configurabile

function runPandoc(args, options) {
  return new Promise((resolve, reject) => {
    const controller = new AbortController();
    const timer = setTimeout(() => {
      controller.abort();
      reject(new Error(`pandoc timed out after ${PANDOC_TIMEOUT_MS}ms`));
    }, options.timeoutMs ?? PANDOC_TIMEOUT_MS);

    const child = spawn("pandoc", args, {
      cwd: options.cwd,
      env: options.env,
      shell: false,
      windowsHide: true,
      signal: controller.signal
    });

    let stdout = "";
    let stderr = "";

    // Forza UTF-8 anche su Windows (evita CP1252 da stdout/stderr)
    child.stdout.setEncoding("utf8");
    child.stderr.setEncoding("utf8");

    child.stdout.on("data", chunk => { stdout += chunk; });
    child.stderr.on("data", chunk => { stderr += chunk; });

    child.on("error", err => { clearTimeout(timer); reject(err); });
    child.on("close", code => {
      clearTimeout(timer);
      if (code !== 0) {
        reject(new Error(`pandoc exited with code ${code}: ${stderr}`));
      } else {
        resolve({ stdout, stderr });
      }
    });
  });
}
```

### 7.2 Timeout e limiti

Vedi implementazione `runPandoc` sopra. Parametri raccomandati:

- `timeoutMs`: default `60000` (60 s), configurabile per documenti grandi;
- limite dimensione input: validare prima di lanciare il processo (es. max 50 MB);
- limite dimensione output: troncare `stderr` a 2000 caratteri nel messaggio di errore;
- in caso di abort per timeout, Pandoc viene terminato e l'output parziale scartato.

### 7.3 Path handling

Regole consigliate:

- risolvere `input_path` e `output_path` con `path.resolve`;
- verificare che `input_path` esista;
- creare directory output se necessario;
- bloccare path traversal se viene introdotta una workspace root;
- non sovrascrivere file esistenti senza opzione `overwrite: true` oppure policy documentata;
- validare estensione output rispetto al formato `to`.

### 7.4 Argomenti Pandoc ammessi

Consentire solo un subset esplicito:

- `--from` / `-f`;
- `--to` / `-t`;
- `--output` / `-o`;
- `--standalone`;
- `--metadata` per coppie semplici;
- `--reference-doc` per DOCX;
- `--template` solo path locale validato;
- `--resource-path` solo path locale validato;
- `--pdf-engine` da allowlist;
- `--toc` opzionale;
- `--number-sections` opzionale.

Bloccare di default:

- filtri Lua arbitrari (`--lua-filter`);
- filtri eseguibili (`--filter`);
- input URL remoti;
- opzioni raw non validate tipo `extra_args` libero.

Se in futuro servono filtri, introdurre `allow_filters: true` con allowlist di path e documentazione di sicurezza.

### 7.5 Gestione `list_formats`

L'output di `pandoc --list-input-formats` e `pandoc --list-output-formats` deve essere processato come segue:

```js
const formats = stdout.split("\n").map(s => s.trim()).filter(Boolean);
```

Non fidarsi del raw stdout: righe vuote o trailing whitespace possono causare formati vuoti nell'array di risposta.

---

## 8. Contratto artifact per output Markdown/TXT

Per output testuali generati da Pandoc, riusare il contratto Office -> Docs.

Quando `to` produce `.md`, `.markdown`, `.txt` o MIME `text/*`:

```json
{
  "ok": true,
  "tool": "document_convert",
  "action": "convert",
  "backend": "pandoc",
  "save_path": "/abs/output.md",
  "resource_link": "artifact://office/2026/05/...",
  "mime_type": "text/markdown",
  "format": "md"
}
```

Questo permette:

1. conversione DOCX/HTML/ODT -> Markdown;
2. registrazione artifact Office;
3. ingestione in `docs-node` usando `save_path`;
4. lettura resource tramite `office-node.resources/read`.

Non serve cambiare subito `docs-node` per accettare `artifact://...` come input. Quella puo' restare una milestone futura.

---

## 9. Error model suggerito

### 9.1 Pandoc non installato

```json
{
  "content": [
    {
      "type": "text",
      "text": "Errore: Pandoc non disponibile nel PATH. Esegui document_convert status o setup_pandoc con setup_mode=\"instructions_only\"."
    }
  ],
  "isError": true,
  "structuredContent": {
    "ok": false,
    "error_code": "PANDOC_NOT_AVAILABLE",
    "recoverable": true
  }
}
```

### 9.2 Formato non supportato

```json
{
  "ok": false,
  "error_code": "PANDOC_FORMAT_UNSUPPORTED",
  "from": "docx",
  "to": "unknown",
  "hint": "Use action=list_formats to inspect supported formats."
}
```

### 9.3 PDF engine mancante

```json
{
  "ok": false,
  "error_code": "PANDOC_PDF_ENGINE_MISSING",
  "hint": "PDF output requires a PDF engine. Install LaTeX/Typst/wkhtmltopdf/weasyprint or pass a supported pdf_engine."
}
```

### 9.4 Conversione lossy

Non e' sempre un errore. Inserire warning:

```json
{
  "ok": true,
  "warnings": [
    "Conversion may be lossy: complex tables, layout, headers/footers or embedded objects may not be preserved."
  ]
}
```

---

## 10. Test e criteri di accettazione

### 10.1 Unit test wrapper Pandoc

Testare:

- costruzione argomenti senza shell;
- validazione formati;
- validazione path;
- gestione Pandoc mancante;
- timeout;
- mapping MIME.

### 10.2 Smoke test opzionale

Aggiungere `tests/smoke/office-node-pandoc.smoke.mjs`.

Comportamento raccomandato:

- se Pandoc non e' installato: stampare `[SKIP] office-node pandoc`;
- se Pandoc e' installato:
  1. creare Markdown temporaneo;
  2. convertire Markdown -> HTML;
  3. convertire Markdown -> DOCX se supportato;
  4. convertire DOCX -> Markdown;
  5. verificare contenuto atteso;
  6. se output Markdown e' registrato, verificare registry e resources/read.

### 10.3 Bridge test Docs

Estendere lo smoke Office -> Docs esistente con variante Pandoc:

1. creare DOCX o HTML sorgente;
2. `document_convert` -> Markdown;
3. `docs_management.scan_file`;
4. `docs_navigation.search` trova contenuto indicizzato.

### 10.4 Criteri di accettazione PR

- `office-node` parte senza Pandoc installato;
- `document_convert.status` ritorna stato corretto;
- `document_convert.convert` converte almeno Markdown -> HTML quando Pandoc e' disponibile;
- output Markdown/TXT puo' essere registrato come artifact;
- smoke test non fallisce in ambienti senza Pandoc, salvo flag CI dedicato;
- nessuna shell interpolation;
- documentazione aggiornata;
- skill/orchestrator aggiornati.

---

## 11. Roadmap proposta

### PR 1 - Detection e conversione minima

Scope:

- aggiungere `document_convert.status`;
- aggiungere `document_convert.list_formats`;
- aggiungere `document_convert.convert` per Markdown -> HTML e Markdown -> DOCX;
- test wrapper;
- smoke opzionale con skip.

No setup automatico in PR 1.

### PR 2 - Artifact e Docs bridge

Scope:

- registrare output Markdown/TXT nel registry Office;
- riusare schema `save_path` + `resource_link`;
- aggiungere bridge smoke DOCX/HTML -> Markdown -> Docs;
- documentare integrazione con `docs-node`.

### PR 3 - Output PDF controllato

Scope:

- supportare `to: "pdf"`;
- allowlist `pdf_engine`;
- errori chiari per engine mancante;
- documentazione su LaTeX/Typst/wkhtmltopdf/weasyprint;
- test condizionali.

### PR 4 - Setup assistito esplicito

Scope:

- aggiungere `setup_pandoc` in modalita' `instructions_only`;
- opzionale: zip portabile in directory locale;
- opzionale: istruzioni package manager;
- nessun `sudo` o installer globale automatico.

### PR 5 - Template e reference doc

Scope:

- `reference_doc_path` per DOCX;
- template HTML/LaTeX validati;
- resource path controllati;
- policy esplicita per asset e immagini.

---

## 12. Bozza schema tool MCP

```js
{
  name: "document_convert",
  description: "Convert documents using Pandoc when available. Supports status, format listing, conversion, and explicit setup guidance. Pandoc is optional; native office-node tools remain preferred for PDF text extraction and precise Office editing.",
  inputSchema: {
    type: "object",
    properties: {
      action: {
        type: "string",
        enum: ["status", "list_formats", "convert", "setup_pandoc"]
      },
      input_path: {
        type: "string",
        description: "Absolute or locally resolvable input file path. Required for convert."
      },
      output_path: {
        type: "string",
        description: "Absolute or locally resolvable output file path. Required for convert."
      },
      from: {
        type: "string",
        description: "Pandoc input format, e.g. markdown, gfm, docx, html. Optional if inferred."
      },
      to: {
        type: "string",
        description: "Pandoc output format, e.g. markdown, gfm, docx, html, pdf. Optional if inferred."
      },
      standalone: {
        type: "boolean",
        default: true
      },
      overwrite: {
        type: "boolean",
        default: false
      },
      metadata: {
        type: "object",
        additionalProperties: { type: "string" }
      },
      reference_doc_path: {
        type: "string"
      },
      template_path: {
        type: "string"
      },
      resource_paths: {
        type: "array",
        items: { type: "string" }
      },
      toc: {
        type: "boolean",
        description: "Include a table of contents in the output."
      },
      number_sections: {
        type: "boolean",
        description: "Number section headings in the output."
      },
      pdf_engine: {
        type: "string",
        enum: ["pdflatex", "xelatex", "lualatex", "typst", "wkhtmltopdf", "weasyprint"]
      },
      setup_mode: {
        type: "string",
        enum: ["instructions_only", "docker_hint", "local_download", "package_manager", "pdf_engine_hint"],
        default: "instructions_only"
      }
    },
    required: ["action"]
  }
}
```

---

## 13. Bozza implementazione conversione

```js
function buildPandocArgs(args) {
  const pandocArgs = [];

  if (args.from) pandocArgs.push("--from", args.from);
  if (args.to) pandocArgs.push("--to", args.to);
  if (args.standalone !== false) pandocArgs.push("--standalone");
  if (args.toc) pandocArgs.push("--toc");
  if (args.number_sections) pandocArgs.push("--number-sections");

  if (args.reference_doc_path) {
    pandocArgs.push("--reference-doc", path.resolve(args.reference_doc_path));
  }

  if (args.template_path) {
    pandocArgs.push("--template", path.resolve(args.template_path));
  }

  for (const resourcePath of args.resource_paths || []) {
    pandocArgs.push("--resource-path", path.resolve(resourcePath));
  }

  if (args.pdf_engine) {
    pandocArgs.push("--pdf-engine", args.pdf_engine);
  }

  // Pandoc usa ':' come separatore per --metadata (non '=')
  for (const [key, value] of Object.entries(args.metadata || {})) {
    pandocArgs.push("--metadata", `${key}:${value}`);
  }

  // Input file come primo argomento posizionale, prima di --output
  pandocArgs.push(path.resolve(args.input_path));
  pandocArgs.push("--output", path.resolve(args.output_path));

  return pandocArgs;
}
```

---

## 14. Aggiornamenti documentazione suggeriti

### README principale

Aggiungere sezione sotto `office-node`:

```md
* `document_convert`: converte documenti tramite Pandoc, se disponibile. Usare per conversioni general-purpose come Markdown -> DOCX/HTML/PDF o DOCX/HTML -> Markdown. Pandoc e' opzionale: il server funziona anche senza installazione. Per PDF -> Markdown destinato a docs-node resta preferibile `pdf_document.export_text`.
```

### `docs/office-docs-artifact-contract.md`

Aggiungere una sottosezione:

```md
## Produzione Markdown via Pandoc

Oltre a `pdf_document.export_text`, anche `document_convert.convert` puo' produrre artifact testuali (`.md`, `.txt`) registrabili nel registry Office. L'ingestione in `docs-node` continua a usare `save_path` come `file_path`.
```

### Skill `mcp-office-expert`

Aggiungere:

```md
Usa `document_convert` quando il task richiede conversione documentale general-purpose. Prima chiama `status` se Pandoc potrebbe non essere disponibile. Non usare Pandoc per modifiche precise in-place a DOCX/XLSX o per lettura PDF mirata pagina/range.
```

### Skill `mcp-docs-navigator`

Aggiungere:

```md
Per sorgenti non Markdown, delega la normalizzazione a `office-node`: PDF tramite `pdf_document.export_text`; DOCX/HTML/ODT/RTF tramite `document_convert` se Pandoc e' disponibile. Poi indicizza con `docs_management.scan_file` usando `save_path`.
```

---

## 15. Policy PDF engine

`document_convert` mantiene i PDF engine opzionali e non installa nulla automaticamente.

Allowlist supportata: `pdflatex`, `xelatex`, `lualatex`, `typst`, `wkhtmltopdf`, `weasyprint`.

Ordine preferito quando `pdf_engine` non e' specificato:

1. `xelatex` - raccomandato per PDF aziendali, Unicode e font di sistema.
2. `typst` - opzione leggera e moderna per setup rapido.
3. `lualatex` - utile per layout/font avanzati in ambiente LaTeX.
4. `pdflatex` - fallback LaTeX classico.
5. `weasyprint` - HTML/CSS moderno -> PDF.
6. `wkhtmltopdf` - HTML legacy -> PDF.

`document_convert.status` espone:

```json
{
  "pdf": {
    "available": true,
    "engines": ["xelatex"],
    "recommended_engine": "xelatex",
    "preferred_order": ["xelatex", "typst", "lualatex", "pdflatex", "weasyprint", "wkhtmltopdf"],
    "engine_details": [],
    "install_hint": "..."
  }
}
```

Esempi MCP:

```json
{ "action": "convert", "input_path": "C:\\tmp\\report.md", "output_path": "C:\\tmp\\report.pdf", "from": "markdown", "to": "pdf", "pdf_engine": "xelatex", "overwrite": true }
```

```json
{ "action": "convert", "input_path": "C:\\tmp\\report.md", "output_path": "C:\\tmp\\report.pdf", "from": "markdown", "to": "pdf", "pdf_engine": "typst", "overwrite": true }
```

Se `pdf_engine` e' omesso e almeno un engine e' disponibile, `office-node` seleziona automaticamente il primo secondo l'ordine preferito e lo ritorna in `structuredContent.pdf_engine`.

L'output PDF resta binario (`application/pdf`) e non viene registrato come artifact testuale per `docs-node`; per indicizzazione usare Markdown/TXT o `pdf_document.export_text`.

## 16. Helper Node locali

Seguendo il pattern della skill SVG, e' utile fornire helper Node locali per diagnostica e smoke, senza duplicare `document_convert`.

Collocazione:

```text
skills/mcp-office-expert/tools/
  pandoc-status.js
  pandoc-convert-smoke.js
  catalog.json
  README.md
```

Policy:

- `document_convert` resta la API MCP ufficiale;
- gli helper servono solo a distinguere problemi runtime/PATH da problemi MCP;
- output JSON machine-readable;
- nessuna installazione automatica;
- zero dipendenze npm aggiuntive.

Uso previsto:

```bash
node skills/mcp-office-expert/tools/pandoc-status.js --pretty
node skills/mcp-office-expert/tools/pandoc-convert-smoke.js --out C:\tmp\pandoc-smoke --pretty
node skills/mcp-office-expert/tools/pandoc-convert-smoke.js --pdf --engine typst --out C:\tmp\pandoc-smoke --pretty
```

Gli helper sono particolarmente utili quando il server MCP vede un PATH diverso dal terminale o quando serve validare rapidamente un PDF engine prima del riavvio del server.

## 17. Rischi e mitigazioni

| Rischio | Impatto | Mitigazione |
|---|---|---|
| Pandoc non installato | Conversioni non disponibili | `status`, skip test, errore actionable |
| PDF output fallisce per mancanza LaTeX | Utente confuso | Messaggio dedicato `PANDOC_PDF_ENGINE_MISSING` |
| Conversione lossy | Perdita formattazione | Warning esplicito e test su casi reali |
| Installazione modifica ambiente globale | Rischio operativo | Setup solo opt-in, default instructions-only |
| Filtri Pandoc eseguono codice | Rischio sicurezza | Bloccare `--filter`/`--lua-filter` by default |
| Path traversal/sovrascrittura | Rischio file system | path resolve, workspace root, overwrite policy |
| Smoke test fragili in CI | Build intermittenti | Test Pandoc opzionale con skip se mancante |

---

## 18. Decisione consigliata

Procedere con Pandoc, ma come **backend opzionale e controllato**.

Implementazione consigliata:

1. nuovo tool `document_convert` in `office-node`;
2. `status`, `list_formats`, `convert` in prima iterazione;
3. nessuna installazione automatica nella prima PR;
4. output Markdown/TXT registrato come artifact Office;
5. integrazione Docs tramite `save_path`, senza cambiare `docs-node`;
6. aggiornamento skill e documentazione;
7. setup assistito solo in una PR successiva e solo opt-in.

Questa strada massimizza il valore pratico di Pandoc senza compromettere la stabilita' degli MCP attuali. Mantiene inoltre coerente l'architettura gia' presente: `office-node` produce/trasforma artifact documentali, `docs-node` indicizza e ricerca, gli skill orchestrano il workflow.

---

## 19. Fonti e riferimenti

### Repo interno

- `office-node/index.js`: implementazione di `pdf_document.export_text`, inclusi `save_path`, `format`, Markdown/TXT e payload strutturato.
- `docs/office-docs-artifact-contract.md`: contratto minimo Office -> Docs basato su `save_path`, `artifact://office/...` e `docs_management.scan_file`.
- `office-node/index.js`: prompt MCP `ingest_pdf_into_docs` e `convert_document_into_docs`, con pipeline PDF -> Markdown -> Docs e Pandoc -> Markdown -> Docs.
- `tests/smoke/office-docs-bridge.smoke.mjs`: smoke end-to-end Office export -> Docs ingest -> search.
- `docs/server-capability-matrix.md`: matrice capacita' MCP, con `office-node` dotato di tools/resources/prompts e `save_path` via `pdf_document.export_text`.

### Documentazione Pandoc

- Pandoc User's Guide: https://pandoc.org/MANUAL.html
- Installing Pandoc: https://pandoc.org/installing.html
- Getting started with Pandoc: https://pandoc.org/getting-started.html
- Docker images Pandoc: https://github.com/pandoc/dockerfiles
