{"_id":"@dpezzettone-memori/mcp-ms-loop","_rev":"6-e1e184d7adb7696dcb77a9a86104310f","name":"@dpezzettone-memori/mcp-ms-loop","dist-tags":{"latest":"1.0.5"},"versions":{"1.0.0":{"name":"@dpezzettone-memori/mcp-ms-loop","version":"1.0.0","_id":"@dpezzettone-memori/mcp-ms-loop@1.0.0","maintainers":[{"name":"dpezzettone-memori","email":"daniel.pezzettone@memori.ai"}],"bin":{"mcp-ms-loop":"src/index.js"},"dist":{"shasum":"01d2024bdb13682cdf0af4f41c3849848eab7e7d","tarball":"https://registry.npmjs.org/@dpezzettone-memori/mcp-ms-loop/-/mcp-ms-loop-1.0.0.tgz","fileCount":5,"integrity":"sha512-oXZ5IwEuHvPFWdDD5elmEeOah6tebDkObciyR3fG7KqC9GwmbZCCCImq4M9XUeloSj6U3F/1SjhYFwdGfCVhPw==","signatures":[{"sig":"MEYCIQD4t91LlrktLZtCByCy6/nQrehps4j34NFf77U1vS85AgIhAOVTrP0fRWM9Ei5QKWg6Bk+YdUTH2xyUZ0Eab/8Clzlp","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":21948},"main":"src/index.js","type":"module","engines":{"node":">=18"},"scripts":{"start":"node src/index.js"},"_npmUser":{"name":"dpezzettone-memori","email":"daniel.pezzettone@memori.ai"},"_npmVersion":"10.8.2","description":"MCP server for Microsoft Loop files: retrieve Loop content as HTML via Microsoft Graph API.","directories":{},"_nodeVersion":"20.17.0","dependencies":{"axios":"1.13.4","@modelcontextprotocol/sdk":"^0.6.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/mcp-ms-loop_1.0.0_1779103038099_0.0739382935712567","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@dpezzettone-memori/mcp-ms-loop","version":"1.0.1","_id":"@dpezzettone-memori/mcp-ms-loop@1.0.1","maintainers":[{"name":"dpezzettone-memori","email":"daniel.pezzettone@memori.ai"}],"bin":{"mcp-ms-loop":"src/index.js"},"dist":{"shasum":"acec11444a72a0b44d7cd565af3f03f22a302e6b","tarball":"https://registry.npmjs.org/@dpezzettone-memori/mcp-ms-loop/-/mcp-ms-loop-1.0.1.tgz","fileCount":5,"integrity":"sha512-JaKBBmuo/JXaoxOCGRGoAbSbrfAekjgOAiPshmdBfRC1FBDKMQIhUi+ziSBiOERGHanf7F1VI5rf4GS2ukCdkg==","signatures":[{"sig":"MEUCIFx0AGtF1fNCKl+h6Ym1g2CfVDHJ5aZe3aSO2/k5gSClAiEA8EZoz3A6qLiPT2EdRgNnYDEqgsP3TCHDHWhsc/0U2vI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":24623},"main":"src/index.js","type":"module","engines":{"node":">=18"},"scripts":{"start":"node src/index.js"},"_npmUser":{"name":"dpezzettone-memori","email":"daniel.pezzettone@memori.ai"},"_npmVersion":"10.8.2","description":"MCP server for Microsoft Loop files: retrieve Loop content as HTML via Microsoft Graph API.","directories":{},"_nodeVersion":"20.17.0","dependencies":{"axios":"1.13.4","@modelcontextprotocol/sdk":"^0.6.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/mcp-ms-loop_1.0.1_1779176195584_0.2544659128389961","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@dpezzettone-memori/mcp-ms-loop","version":"1.0.2","_id":"@dpezzettone-memori/mcp-ms-loop@1.0.2","maintainers":[{"name":"dpezzettone-memori","email":"daniel.pezzettone@memori.ai"}],"bin":{"mcp-ms-loop":"src/index.js"},"dist":{"shasum":"b8d44792e17702b6081ea3add9a2f17fee6e1e41","tarball":"https://registry.npmjs.org/@dpezzettone-memori/mcp-ms-loop/-/mcp-ms-loop-1.0.2.tgz","fileCount":5,"integrity":"sha512-TkW7cEqN4ABbG2Oabosf50NqRUFwbBCTJNKpG1fCv5lYi4x3yWow+wOTzFZRVdTfoKLRsGuLxU9VkXqxGAHW1Q==","signatures":[{"sig":"MEQCIGZ5F0VmSGXFmLJr2SQAtVKjyyMADIUU7+UyR05fB7Y9AiA+gSxAD6AP1SP6e8hUkEuGlBk23wYi8djppBrl500qAA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":26024},"main":"src/index.js","type":"module","engines":{"node":">=18"},"scripts":{"start":"node src/index.js"},"_npmUser":{"name":"dpezzettone-memori","email":"daniel.pezzettone@memori.ai"},"_npmVersion":"10.8.2","description":"MCP server for Microsoft Loop files: retrieve Loop content as HTML via Microsoft Graph API.","directories":{},"_nodeVersion":"20.17.0","dependencies":{"axios":"1.13.4","@modelcontextprotocol/sdk":"^0.6.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/mcp-ms-loop_1.0.2_1779176840058_0.7308193759685397","host":"s3://npm-registry-packages-npm-production"}},"1.0.3":{"name":"@dpezzettone-memori/mcp-ms-loop","version":"1.0.3","_id":"@dpezzettone-memori/mcp-ms-loop@1.0.3","maintainers":[{"name":"dpezzettone-memori","email":"daniel.pezzettone@memori.ai"}],"bin":{"mcp-ms-loop":"src/index.js"},"dist":{"shasum":"08011c4b145ca9d251db37d1bff6e104ac3a180f","tarball":"https://registry.npmjs.org/@dpezzettone-memori/mcp-ms-loop/-/mcp-ms-loop-1.0.3.tgz","fileCount":5,"integrity":"sha512-eDUReRjBIM4emtB8/HjEZzdMocU/sUGFs0WHfcSO9iIOo/t9xeJpyQ6m0byDgbwL5evxCCS6yx6oVU+sv2/3ew==","signatures":[{"sig":"MEQCIHfspyVvXCNJcQRSzsSEdW/wxRahuucRANz2Rmt5fb1jAiAyml8/t7pgPluNVH6x//37Rd94bWZ7f6zGDyl1ygsdtA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":26533},"main":"src/index.js","type":"module","engines":{"node":">=18"},"scripts":{"start":"node src/index.js"},"_npmUser":{"name":"dpezzettone-memori","email":"daniel.pezzettone@memori.ai"},"_npmVersion":"10.8.2","description":"MCP server for Microsoft Loop files: retrieve Loop content as HTML via Microsoft Graph API.","directories":{},"_nodeVersion":"20.17.0","dependencies":{"axios":"1.13.4","@modelcontextprotocol/sdk":"^0.6.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/mcp-ms-loop_1.0.3_1779177625549_0.2866884924963","host":"s3://npm-registry-packages-npm-production"}},"1.0.4":{"name":"@dpezzettone-memori/mcp-ms-loop","version":"1.0.4","_id":"@dpezzettone-memori/mcp-ms-loop@1.0.4","maintainers":[{"name":"dpezzettone-memori","email":"daniel.pezzettone@memori.ai"}],"bin":{"mcp-ms-loop":"src/index.js"},"dist":{"shasum":"2b2d8305206c0bd437de3578d4e2952a82f4ad0d","tarball":"https://registry.npmjs.org/@dpezzettone-memori/mcp-ms-loop/-/mcp-ms-loop-1.0.4.tgz","fileCount":5,"integrity":"sha512-1Xc7hv+NpDzfVeTJPbAqyrfBx2MN+1c+yzy6duJJDRDrbXEDVF3cTcQ75FG7wJ23EUVwTHSyUNK5UFDK7VJBKA==","signatures":[{"sig":"MEUCIQDZaEMNBXIHYGa+rAhFiab1x8dxOfkhnQNI4RiI8CvXfgIgVjBC2hEXEaWJJ4KBK7Hf/a5yJqUpGDRqXf2jwY2pb1g=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":29210},"main":"src/index.js","type":"module","engines":{"node":">=18"},"scripts":{"start":"node src/index.js"},"_npmUser":{"name":"dpezzettone-memori","email":"daniel.pezzettone@memori.ai"},"_npmVersion":"10.8.2","description":"MCP server for Microsoft Loop files: retrieve Loop content as HTML via Microsoft Graph API.","directories":{},"_nodeVersion":"20.17.0","dependencies":{"axios":"1.13.4","@modelcontextprotocol/sdk":"^0.6.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/mcp-ms-loop_1.0.4_1779199047503_0.9824346639970103","host":"s3://npm-registry-packages-npm-production"}},"1.0.5":{"name":"@dpezzettone-memori/mcp-ms-loop","version":"1.0.5","description":"MCP server for Microsoft Loop files: retrieve Loop content as HTML via Microsoft Graph API.","type":"module","main":"src/index.js","bin":{"mcp-ms-loop":"src/index.js"},"scripts":{"start":"node src/index.js"},"dependencies":{"@modelcontextprotocol/sdk":"^0.6.0","axios":"1.13.4"},"engines":{"node":">=18"},"_id":"@dpezzettone-memori/mcp-ms-loop@1.0.5","_nodeVersion":"20.17.0","_npmVersion":"10.8.2","dist":{"integrity":"sha512-eWv3TZMyzz5m5gSn+W6fMDQ0vb+NxTn3xj4N2tM+aa0KrSphZbG6444+xM6V/hm++fwij3/v0afqFAT81CgV7Q==","shasum":"fa6e0b05df7884c8f6066720c61f19ac62fe5572","tarball":"https://registry.npmjs.org/@dpezzettone-memori/mcp-ms-loop/-/mcp-ms-loop-1.0.5.tgz","fileCount":5,"unpackedSize":38998,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIGyax9TNrIWtzm1sfSh3fHgi9X+f2IDpQNuSD+qdhpPVAiBM+ae3pIyA3Viw2WuVsRiFk0kSn+uQNq+Hr5T8wJ7/Dw=="}]},"_npmUser":{"name":"dpezzettone-memori","email":"daniel.pezzettone@memori.ai"},"directories":{},"maintainers":[{"name":"dpezzettone-memori","email":"daniel.pezzettone@memori.ai"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/mcp-ms-loop_1.0.5_1779199543063_0.7148940734332687"},"_hasShrinkwrap":false}},"time":{"created":"2026-05-18T11:17:18.027Z","modified":"2026-05-19T14:05:43.337Z","1.0.0":"2026-05-18T11:17:18.263Z","1.0.1":"2026-05-19T07:36:35.743Z","1.0.2":"2026-05-19T07:47:20.193Z","1.0.3":"2026-05-19T08:00:25.707Z","1.0.4":"2026-05-19T13:57:27.651Z","1.0.5":"2026-05-19T14:05:43.208Z"},"description":"MCP server for Microsoft Loop files: retrieve Loop content as HTML via Microsoft Graph API.","maintainers":[{"name":"dpezzettone-memori","email":"daniel.pezzettone@memori.ai"}],"readme":"# MCP MS Loop — Guida completa per system integrator\n\nServer MCP che permette agli Agenti AI di leggere i file **Microsoft Loop** via Microsoft Graph API, con autenticazione **app-only** (client credentials). Funziona per file Loop ovunque siano salvati:\n\n- OneDrive personale\n- Siti SharePoint (canali Teams)\n- **App Microsoft Loop** (SharePoint Embedded, container `CSP_…`)\n\n---\n\n## Indice\n\n1. [Panoramica architetturale](#1-panoramica-architetturale)\n2. [Prerequisiti](#2-prerequisiti)\n3. [Creare l'App Registration su Azure](#3-creare-lapp-registration-su-azure)\n4. [Assegnare i permessi API](#4-assegnare-i-permessi-api)\n5. [Registrazione SPE — passaggio obbligatorio per l'app Loop](#5-registrazione-spe--passaggio-obbligatorio-per-lapp-loop)\n6. [Configurare l'MCP nel gateway](#6-configurare-lmcp-nel-gateway)\n7. [Tool disponibili](#7-tool-disponibili)\n8. [Permessi minimi necessari](#8-permessi-minimi-necessari)\n9. [Troubleshooting](#9-troubleshooting)\n\n---\n\n## 1. Panoramica architetturale\n\n```\nAgente AI\n   │\n   ▼\nMCP Gateway (Rails)\n   │  inietta TENANT_ID, CLIENT_ID, CLIENT_SECRET\n   │  come variabili d'ambiente\n   ▼\nnpx @dpezzettone-memori/mcp-ms-loop   ← questo pacchetto\n   │\n   ▼\nMicrosoft Graph API\n   │\n   ├── /drives/{driveId}/items/{itemId}/content?format=html\n   │     ↓ redirect a westeurope1-mediap.svc.ms (converter HTML)\n   │\n   └── /v1.0/search/query  (per discovery dei workspace)\n```\n\nLe credenziali **non passano mai dall'LLM**: vengono iniettate dal gateway come variabili d'ambiente, invisibili all'Agente.\n\n---\n\n## 2. Prerequisiti\n\n| Requisito | Dettaglio |\n|---|---|\n| Accesso Azure Portal | Ruolo **Application Administrator** o superiore sul tenant |\n| Accesso Global Admin | Necessario solo per il passaggio PowerShell (§5), una volta sola |\n| PowerShell con `pwsh` | Per il passaggio SPE. Funziona su Windows (nativo) e Linux/macOS via GitHub Codespaces o Azure Cloud Shell |\n| Tenant Microsoft 365 | Con licenza che include Microsoft Loop (M365 Business Standard/Premium, E3/E5) |\n\n---\n\n## 3. Creare l'App Registration su Azure\n\n1. Vai su **[portal.azure.com](https://portal.azure.com)** → **Microsoft Entra ID** → **App registrations** → **New registration**\n2. Impostazioni:\n   - **Name**: es. `MCP MS Loop`\n   - **Supported account types**: `Accounts in this organizational directory only`\n   - **Redirect URI**: lascia vuoto (non serve per app-only)\n3. Clicca **Register**\n4. Dalla pagina dell'app, annota:\n   - **Application (client) ID** → `CLIENT_ID`\n   - **Directory (tenant) ID** → `TENANT_ID`\n5. Vai su **Certificates & secrets** → **New client secret**\n   - Description: es. `mcp-loop-secret`\n   - Expires: scegli la scadenza appropriata (es. 24 mesi)\n   - Clicca **Add** e copia subito il **Value** → `CLIENT_SECRET`\n\n> ⚠️ Il `CLIENT_SECRET` è visibile solo al momento della creazione. Copialo subito.\n\n---\n\n## 4. Assegnare i permessi API\n\nDalla pagina dell'app → **API permissions** → **Add a permission**:\n\n### Permessi richiesti (minimi)\n\n| API | Tipo | Permesso | Admin consent |\n|---|---|---|---|\n| Microsoft Graph | Application | `Files.Read.All` | Sì |\n| Microsoft Graph | Application | `FileStorageContainer.Selected` | Sì |\n\n### Permesso temporaneo (solo per §5, poi rimuovibile)\n\n| API | Tipo | Permesso | Admin consent |\n|---|---|---|---|\n| SharePoint | Application | `Sites.FullControl.All` | Sì |\n\nDopo aver aggiunto tutti i permessi:\n- Clicca **Grant admin consent for \\<tenant\\>**\n- Verifica che tutti mostrino lo stato ✅ **Granted**\n\n> ℹ️ `Sites.FullControl.All` serve solo per eseguire `Connect-SPOService` in PowerShell (§5). Una volta completato quel passaggio, può essere **rimosso**.\n\n---\n\n## 5. Registrazione SPE — passaggio obbligatorio per l'app Loop\n\nI file creati nell'**app Microsoft Loop** vivono in container **SharePoint Embedded (SPE)**. Questi container hanno un modello di autorizzazione separato: non basta avere permessi Graph, bisogna registrare l'app come \"guest application\" sul container type di Loop tramite PowerShell.\n\nQuesto passaggio:\n- Si esegue **una sola volta** per tenant\n- Richiede un account **Global Admin**\n- Non è sostituibile via Graph API o interfaccia Azure\n\n### ID del container type di Loop (costante per tutti i tenant)\n\n```\na187e399-0c36-4b98-8f04-1edc167a0996\n```\n\n---\n\n### Opzione A — Windows (più semplice)\n\nApri PowerShell come amministratore:\n\n```powershell\n# Installa il modulo SPO\nInstall-Module Microsoft.Online.SharePoint.PowerShell -Force\nImport-Module Microsoft.Online.SharePoint.PowerShell\n\n# Connetti con login interattivo (apre il browser)\nConnect-SPOService -Url \"https://<TENANT_NAME>-admin.sharepoint.com\" -Interactive\n\n# Registra l'app come guest sul container type di Loop\nSet-SPOApplicationPermission `\n  -OwningApplicationId \"a187e399-0c36-4b98-8f04-1edc167a0996\" `\n  -GuestApplicationId  \"<CLIENT_ID>\" `\n  -PermissionAppOnly   \"readcontent\"\n```\n\nSostituisci:\n- `<TENANT_NAME>` con il prefisso del tuo tenant (es. `contoso`)\n- `<CLIENT_ID>` con l'Application ID dell'app creata al §3\n\nSe il comando non dà output → ha funzionato. L'assenza di output è il successo.\n\n---\n\n### Opzione B — Linux / macOS / GitHub Codespaces\n\n`Connect-SPOService -Interactive` non funziona su Linux. Usa l'autenticazione via **certificato**.\n\n#### B1. Genera un certificato self-signed e caricalo su Azure\n\n```bash\n# Genera chiave privata e certificato (1 sola volta)\nopenssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem \\\n  -days 730 -nodes -subj \"/CN=mcp-loop\"\n\n# Crea il .pfx (con password) per PowerShell\nopenssl pkcs12 -export \\\n  -inkey key.pem -in cert.pem \\\n  -out cert.pfx -passout pass:temp123\n\n# Mostra il fingerprint SHA1 per confrontarlo su Azure\nopenssl x509 -in cert.pem -fingerprint -sha1 -noout\n```\n\nSu **Azure Portal** → App Registration → **Certificates & secrets** → **Certificates** → **Upload certificate**:\n- Carica `cert.pem`\n- Verifica che il thumbprint mostrato su Azure corrisponda all'output del comando `openssl x509 … -fingerprint`\n\n#### B2. Installa PowerShell e il modulo SPO\n\n```bash\n# Installa pwsh (se non presente)\n# Su Debian/Ubuntu:\nsudo apt-get install -y powershell\n\n# In GitHub Codespaces è già disponibile, avvia la shell:\npwsh\n```\n\n```powershell\nInstall-Module Microsoft.Online.SharePoint.PowerShell -Force\nImport-Module Microsoft.Online.SharePoint.PowerShell -Force\n```\n\n#### B3. Risolvi la dipendenza MSAL (solo Linux)\n\nIl modulo SPO su Linux necessita di una DLL che non viene inclusa automaticamente:\n\n```bash\n# Dalla bash (non da pwsh), individua dove è installato il modulo:\nSPOMOD=$(pwsh -c \"Split-Path (Get-Module -ListAvailable Microsoft.Online.SharePoint.PowerShell | Select-Object -First 1).Path\")\necho \"Modulo in: $SPOMOD\"\n\n# Crea un progetto dotnet temporaneo per scaricare la DLL\nmkdir -p /tmp/getmsal && cd /tmp/getmsal\ndotnet new console -n getmsal --force\ncd getmsal\ndotnet add package Microsoft.Identity.Client --version 4.74.1\ndotnet build -o out\n\n# Copia la DLL nella directory del modulo SPO\ncp out/Microsoft.Identity.Client.dll \"$SPOMOD/\"\n```\n\n#### B4. Connetti e registra\n\n```powershell\nImport-Module Microsoft.Online.SharePoint.PowerShell -Force\n\nConnect-SPOService `\n  -Url             \"https://<TENANT_NAME>-admin.sharepoint.com\" `\n  -ClientId        \"<CLIENT_ID>\" `\n  -TenantId        \"<TENANT_ID>\" `\n  -CertificatePath \"/path/to/cert.pfx\" `\n  -CertificatePassword (ConvertTo-SecureString \"temp123\" -AsPlainText -Force)\n\nSet-SPOApplicationPermission `\n  -OwningApplicationId \"a187e399-0c36-4b98-8f04-1edc167a0996\" `\n  -GuestApplicationId  \"<CLIENT_ID>\" `\n  -PermissionAppOnly   \"readcontent\"\n```\n\n> ℹ️ `Connect-SPOService` richiede `Sites.FullControl.All` (Application) sull'app (aggiunto al §4). Dopo aver completato questo passaggio, puoi **rimuovere** quel permesso da Azure se vuoi ridurre la superficie di attacco.\n\n---\n\n## 6. Configurare l'MCP nel gateway\n\n### Comando di avvio (url_command_hidden)\n\n```\nnpx -y @dpezzettone-memori/mcp-ms-loop\n```\n\nL'opzione `-y` fa sì che npx scarichi sempre l'ultima versione pubblicata senza chiedere conferma.\n\n### Parametri personalizzati (JSON da inserire nella sezione \"Parametri\" del gateway)\n\n```json\n{\n  \"TENANT_ID\": \"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\",\n  \"CLIENT_ID\": \"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\",\n  \"CLIENT_SECRET\": \"il-valore-del-secret-NON-l-id\"\n}\n```\n\n> ⚠️ `CLIENT_SECRET` è il **Value** del secret (la stringa lunga come `abc123~XYZ...`), non l'ID/UUID che compare nell'elenco secrets su Azure.\n\nQuesti valori vengono iniettati come variabili d'ambiente nel processo Node.js. Non compaiono mai nei messaggi scambiati con l'LLM.\n\n---\n\n## 7. Tool disponibili\n\n### `getLoopByShareUrl`\n\nRecupera il contenuto completo di un file Loop a partire dal link di condivisione.\n\n**Parametri:**\n\n| Parametro | Tipo | Obbligatorio | Descrizione |\n|---|---|---|---|\n| `shareUrl` | string | Sì | Link completo del file Loop (quello che apri nel browser) |\n| `includeText` | boolean | No (default `true`) | Se `true`, restituisce anche il testo plain (HTML strippato) |\n\n**Risposta:**\n\n```json\n{\n  \"name\": \"1. Procedure commerciali.loop\",\n  \"driveId\": \"b!Fx9UIEaVjk-...\",\n  \"itemId\": \"01GO3C7SLOD...\",\n  \"webUrl\": \"https://memorisrl.sharepoint.com/...\",\n  \"lastModified\": \"2026-05-10T14:23:00Z\",\n  \"size\": 63529,\n  \"mimeType\": \"application/octet-stream\",\n  \"html\": \"<html><meta name=\\\"GENERATOR\\\" content=\\\"Microsoft Loop\\\">...</html>\",\n  \"text\": \"1. Procedure commerciali\\n\\nPREMESSA\\nÈ fondamentale...\",\n  \"truncated\": false,\n  \"textTruncated\": false\n}\n```\n\n---\n\n### `getLoopByItemId`\n\nVariante diretta: usa `driveId` e `itemId` se già noti (più veloce, salta la risoluzione del link).\n\n**Parametri:**\n\n| Parametro | Tipo | Obbligatorio | Descrizione |\n|---|---|---|---|\n| `driveId` | string | Sì | ID del drive contenente il file |\n| `itemId` | string | Sì | ID del file |\n| `includeText` | boolean | No (default `true`) | Include versione testuale |\n\n---\n\n### `listLoopContainers`\n\nScopre tutti i workspace Microsoft Loop accessibili all'app. Usa la Microsoft 365 Search API per trovare tutti i file `.loop` e raggrupparli per drive/workspace.\n\n**Nessun parametro richiesto.**\n\n**Risposta:**\n\n```json\n[\n  {\n    \"driveId\": \"b!Fx9UIEaVjk-...\",\n    \"name\": \"Presales\",\n    \"webUrl\": \"https://memorisrl.sharepoint.com/contentstorage/CSP_.../Document%20Library\",\n    \"loopFileCount\": 8\n  },\n  {\n    \"driveId\": \"b!zjdElsus6ka...\",\n    \"name\": \"OneDrive\",\n    \"webUrl\": \"https://memorisrl-my.sharepoint.com/personal/.../Documents\",\n    \"loopFileCount\": 2\n  }\n]\n```\n\n---\n\n### `listLoopFilesInDrive`\n\nElenca tutti i file `.loop` e `.fluid` dentro un drive. La scansione è **ricorsiva** (i file Loop nell'app Loop sono salvati dentro la sottocartella `LoopAppData/`).\n\n**Parametri:**\n\n| Parametro | Tipo | Obbligatorio | Descrizione |\n|---|---|---|---|\n| `driveId` | string | Sì | ID del drive da scansionare (ottenuto da `listLoopContainers`) |\n| `path` | string | No (default `root`) | Percorso di partenza dentro il drive |\n\n**Risposta:**\n\n```json\n[\n  {\n    \"id\": \"01GO3C7SLODTQUBW...\",\n    \"name\": \"1. Procedure commerciali.loop\",\n    \"driveId\": \"b!Fx9UIEaVjk-...\",\n    \"size\": 63529,\n    \"webUrl\": \"https://...\",\n    \"lastModified\": \"2026-05-10T14:23:00Z\",\n    \"mimeType\": \"application/octet-stream\"\n  }\n]\n```\n\n---\n\n## 8. Permessi minimi necessari\n\nUna volta completata la registrazione SPE (§5), la configurazione **finale** dell'app deve avere solo questi permessi:\n\n| API | Tipo | Permesso | Motivo |\n|---|---|---|---|\n| Microsoft Graph | Application | `Files.Read.All` | Leggere i file Loop |\n| Microsoft Graph | Application | `FileStorageContainer.Selected` | Accedere ai container SPE (workspace Loop) |\n\nTutto il resto (delegated, `Sites.Read.All`, `User.Read`, `offline_access`, `Sites.FullControl.All`) può essere rimosso.\n\n---\n\n## 9. Troubleshooting\n\n### `403 accessDenied` su file nell'app Loop\n\nIl passaggio §5 (`Set-SPOApplicationPermission`) non è stato eseguito o non ha avuto effetto. Verificare di aver usato il `CLIENT_ID` corretto e di essersi connessi come Global Admin. La propagazione può richiedere qualche minuto.\n\n### `400 failed to parse filter parameter` su `listLoopContainers`\n\nVersione vecchia del pacchetto (≤ 1.0.3). Aggiorna all'ultima versione: il tool ora usa la Search API invece dell'API SPE container, che non è accessibile con i permessi minimi.\n\n### `Connect-SPOService: Object reference not set to an instance of an object`\n\nStai usando `Connect-SPOService -Interactive` su Linux. Non funziona. Usa l'autenticazione via certificato (§5 Opzione B).\n\n### `Could not load file or assembly 'Microsoft.Identity.Client'`\n\nLa DLL MSAL manca nell'ambiente Linux. Segui il passaggio B3 della §5.\n\n### `Connect-SPOService: (401) Unauthorized` (con certificato)\n\nL'app non ha il permesso `SharePoint > Sites.FullControl.All` (Application) con admin consent. Aggiungilo temporaneamente, esegui `Set-SPOApplicationPermission`, poi rimuovilo.\n\n### `listLoopContainers` restituisce array vuoto `[]`\n\nLa Search API non ha trovato file Loop accessibili. Cause possibili:\n1. Il passaggio §5 non è stato fatto → file SPE non accessibili\n2. Non ci sono file `.loop` nel tenant\n3. Il tenant usa una region diversa da EMEA/NAM/APAC — contatta supporto Microsoft\n\n### Il `CLIENT_SECRET` è scaduto\n\nAzure mostra la data di scadenza nella sezione **Certificates & secrets**. Se scaduto, genera un nuovo secret, aggiorna il JSON dei parametri nel gateway.\n\n---\n\n## Riferimenti\n\n- [Microsoft Graph — Drive Items](https://learn.microsoft.com/en-us/graph/api/driveitem-get)\n- [SharePoint Embedded — Guida tecnica Loop export](https://wals.pro/blogs/news/microsoft-loop-to-html-export-technical-guide)\n- [Set-SPOApplicationPermission (Microsoft Docs)](https://learn.microsoft.com/en-us/powershell/module/sharepoint-online/set-spoapplicationpermission)\n- [Microsoft 365 Search API — App-only](https://learn.microsoft.com/en-us/graph/search-concept-searchall)\n","readmeFilename":"README.md"}