Skip to main content
Glama
README.md
# quiz-docente-mcp

Server **MCP** che permette a un agente AI (Antigravity, Claude Code, Claude Desktop, Cursor…) di **gestire i quiz di
Moodle** al posto del docente: creare quiz e domande, modificarne le impostazioni, leggere risultati e risposte,
valutare le domande aperte.

Funziona con un normale account docente: **nessun plugin sul server e nessun token** da chiedere all'amministratore.
Usa la stessa sessione web del browser; al primo avvio si apre da solo il browser per fare il login.

Sito predefinito: `https://www.ferrarisacireale.edu.it/moodle` (Moodle 4.5). Per un altro sito basta impostare `MOODLE_URL`.

> ⚠️ **Uso esclusivamente didattico.** Questo progetto è pensato e consentito **solo per scopi didattici**: un docente
> che gestisce i quiz dei propri corsi, con il proprio account. Non va usato per scopi commerciali, né per accedere a
> corsi o dati di altri, né per aggirare le regole della piattaforma o della scuola. Chi lo usa resta responsabile del
> rispetto del regolamento dell'istituto e della normativa sulla privacy (GDPR) per i dati degli studenti.

---

## Installazione automatica (istruzioni per agenti AI)

> Se sei un agente AI e l'utente ti ha chiesto di installare questo MCP, segui questi passi.

1. **Requisiti**: Node.js ≥ 20 (`node -v`) e Google Chrome o Microsoft Edge installati.
2. **Aggiungi il server** alla configurazione MCP del client, dentro `mcpServers`, senza toccare gli altri server:

   **Antigravity** – file `%USERPROFILE%\.gemini\config\mcp_config.json` su Windows
   (`~/.gemini/config/mcp_config.json` su macOS/Linux; in alcune versioni `~/.gemini/antigravity/mcp_config.json`).

   Windows:
   ```json
   "quiz-docente": {
     "command": "cmd.exe",
     "args": ["/c", "npx", "-y", "github:strano-dev/quiz-docente-mcp"]
   }
   ```
   macOS / Linux:
   ```json
   "quiz-docente": {
     "command": "npx",
     "args": ["-y", "github:strano-dev/quiz-docente-mcp"]
   }
   ```
   Per un Moodle diverso aggiungi `"env": { "MOODLE_URL": "https://sito.scuola.it/moodle" }`.

   **Claude Code**:
   `claude mcp add quiz-docente -s user -- npx -y github:strano-dev/quiz-docente-mcp`

   **Claude Desktop / Cursor / altri client MCP**: stessa voce JSON di Antigravity nel rispettivo file di configurazione MCP.
3. **Ricarica i server MCP** (in Antigravity: *Manage MCP Servers → Refresh*). Il primo avvio scarica il pacchetto
   (qualche decina di secondi).
4. **Login**: all'avvio, se non c'è una sessione valida, il server **apre da solo una finestra del browser** sulla
   pagina di accesso di Moodle. Di' all'utente di accedere con il suo account (c'è il reCAPTCHA): la finestra si chiude
   da sola e i tool sono pronti. Verifica con il tool `moodle_status`.

Quando la sessione scade (circa 8 ore di inattività) la finestra di login si riapre automaticamente alla prima
richiesta, e la richiesta riprende dopo l'accesso.

---

## Cosa si può fare

| Area | Tool |
|---|---|
| Sessione | `moodle_status`, `moodle_login` (forza un nuovo accesso) |
| Corsi | `moodle_list_courses`, `moodle_list_sections` |
| Quiz – lettura | `moodle_list_quizzes`, `moodle_get_quiz` (domande, pagine, punteggi + impostazioni), `moodle_get_quiz_settings` |
| Quiz – modifica | `moodle_create_quiz` (nasce **nascosto** se non si chiede `visible: true`), `moodle_update_quiz_settings` (date, durata, tentativi, valutazione, navigazione, comportamento, password, opzioni di revisione, visibilità), `moodle_add_questions_to_quiz`, `moodle_add_random_questions`, `moodle_remove_quiz_slots`, `moodle_set_slot_mark`, `moodle_move_quiz_slot`, `moodle_set_quiz_max_grade`, `moodle_repaginate_quiz` |
| Banca domande | `moodle_list_question_categories`, `moodle_create_question_category`, `moodle_list_questions`, `moodle_get_question` (Moodle XML completo), `moodle_export_questions` (GIFT/XML), `moodle_create_questions` (da JSON: scelta multipla, vero/falso, risposta breve, numerica, aperta, corrispondenza, descrizione), `moodle_import_questions` (GIFT, Moodle XML, Aiken, Cloze: qualsiasi tipo), `moodle_update_question` |
| Risultati | `moodle_get_quiz_grades`, `moodle_get_quiz_responses`, `moodle_get_attempt_review`, `moodle_grade_attempt_question` (voto e commento manuale, es. domande aperte), `moodle_get_quiz_statistics` |

### Scelta di progetto: niente eliminazioni

Non esistono tool per **eliminare quiz o domande**: le eliminazioni le fa sempre il docente, a mano, da Moodle.
`moodle_remove_quiz_slots` toglie una domanda da un quiz ma la lascia nella banca domande.
Un quiz che ha già tentativi degli studenti non permette di aggiungere o togliere domande (vincolo di Moodle).

### Identificativi

- `courseid`: id del corso (`course/view.php?id=…`)
- `cmid`: id del quiz come modulo del corso (`mod/quiz/view.php?id=…`)
- `slot_id`: posizione di una domanda nel quiz, da `moodle_get_quiz`
- `category_id`, `question_id`: dai tool della banca domande, che accettano `courseid` (banca del corso) oppure
  `cmid` (banca propria del quiz)

---

## Configurazione

| Variabile | Default | Significato |
|---|---|---|
| `MOODLE_URL` | `https://www.ferrarisacireale.edu.it/moodle` | URL del sito Moodle |
| `MOODLE_AUTO_LOGIN` | `1` | `1` = apre il login all'avvio e quando la sessione scade; `ondemand` = solo quando serve a un tool; `0` = mai |
| `MOODLE_READ_ONLY` | – | `1` = espone solo i tool di lettura |
| `MOODLE_MCP_DIR` | `~/.moodle-mcp` | dove vengono salvati sessione e profilo del browser di login |
| `MOODLE_BROWSER_PATH` | – | percorso di chrome.exe / msedge.exe se non vengono trovati |
| `MOODLE_LOGIN_TIMEOUT_MS` | `300000` | attesa massima per l'accesso |

La sessione è salvata in `~/.moodle-mcp/session.json` e contiene il cookie di accesso: **non condividerla**.
Login manuale da terminale: `npx -y -p github:strano-dev/quiz-docente-mcp quiz-docente-mcp-login`.

## Sviluppo

```bash
git clone https://github.com/strano-dev/quiz-docente-mcp
cd quiz-docente-mcp
npm install
npm test           # test unitari (Vitest)
npm run check      # typecheck + test con copertura + build: da eseguire prima di ogni commit
npm run build      # compila src/ in dist/ (dist/ è versionata: serve a npx per avviare senza build)
npm run login      # login manuale
npm start          # avvia il server MCP su stdio
```

### Regola: si procede sempre in TDD

Ogni modifica al codice segue il ciclo **Test-Driven Development**, senza eccezioni:

1. **Red** – scrivi prima un test in `test/` che descrive il comportamento voluto e verifica che **fallisca**.
2. **Green** – scrivi in `src/` il codice minimo che lo fa passare.
3. **Refactor** – migliora il codice tenendo tutti i test verdi.

Regole pratiche:

- ogni bug si corregge partendo da un test che lo riproduce;
- nessuna nuova funzione o nuovo tool MCP senza i relativi test;
- i test unitari **non chiamano mai il Moodle reale**: `test/helpers/fake-moodle.ts` simula il sito intercettando
  `fetch`, `test/helpers/moodle-html.ts` genera pagine sintetiche con la stessa struttura di Moodle 4.5 (nessun dato reale),
  Playwright viene sostituito con un mock;
- prima di ogni commit `npm run check` deve passare; le soglie minime di copertura (righe 90%, rami 80%) sono
  configurate in `vitest.config.ts` e fanno fallire la suite se non rispettate;
- dopo aver modificato `src/` ricompila (`npm run build`) e versiona anche `dist/`.

| File di test | Cosa copre |
|---|---|
| `test/client.test.ts` | cookie, redirect, sessione scaduta, `sesskey`, chiamate AJAX, file di sessione, `parseNum` |
| `test/forms.test.ts` | lettura e invio dei form Moodle (checkbox avanzate, select, editor, date, durate, errori) |
| `test/courses.test.ts` | corsi e sezioni |
| `test/quizzes.test.ts` | struttura del quiz, impostazioni, creazione, slot, domande casuali, voto massimo, pagine |
| `test/questions.test.ts` | categorie, elenco/export, conversione JSON → Moodle XML, import con upload, modifica domande |
| `test/reports.test.ts` | voti, risposte, revisione tentativi, valutazione manuale, statistiche |
| `test/auth.test.ts` | finestra di login (Chrome/Edge), timeout, lock contro finestre multiple |
| `test/server.test.ts` | elenco tool, modalità sola lettura, errori, login automatico con nuovo tentativo, mappatura argomenti |
| `test/login-runner.test.ts`, `test/config.test.ts` | comando di login e variabili d'ambiente |

## Come funziona

Moodle non espone ai docenti API per creare quiz e domande, quindi il server usa gli stessi endpoint dell'interfaccia web,
ricavati analizzando il traffico del browser:

| Funzione | Endpoint Moodle |
|---|---|
| corsi, sezioni, quiz di un corso | AJAX `core_course_get_enrolled_courses_by_timeline_classification`, `core_courseformat_get_state` |
| struttura del quiz | `mod/quiz/edit.php` |
| punteggio, rimozione, spostamento delle domande nel quiz | `mod/quiz/edit_rest.php` |
| aggiunta domande, voto massimo, ripaginazione | POST `mod/quiz/edit.php` |
| domande casuali | AJAX `mod_quiz_add_random_questions` |
| impostazioni e creazione quiz | form `course/modedit.php` (letto, modificato, reinviato) |
| categorie | `question/bank/managecategories/category.php`, AJAX `core_form_dynamic_form` |
| elenco e lettura domande | `question/edit.php`, `question/bank/exporttoxml/exportone.php`, `pluginfile.php/…/question/export/…` |
| creazione / import domande | upload `repository/repository_ajax.php` + form `question/bank/importquestions/import.php` |
| modifica domanda | form `question/bank/editquestion/question.php` (Moodle salva una nuova versione) |
| voti e risposte | `mod/quiz/report.php?mode=overview|responses&download=json` |
| revisione e valutazione manuale | `mod/quiz/review.php`, `mod/quiz/comment.php` |

Testato su Moodle 4.5.11. I report voti/risposte sono stati verificati solo su quiz senza tentativi di studenti
(le anteprime del docente non compaiono nei report).

## Licenza

MIT (vedi `LICENSE`). Resta valida l'indicazione d'uso esclusivamente didattico riportata all'inizio.