Come usare cipi/agent in Laravel — MCP di progetto per debug e seeder
Di Andrea Pollastri · Ultimo aggiornamento: · lettura gratuita, nessun paywall
Entrare in SSH in produzione per un migrate:status, un failed job o un seeder di staging è lento, non si condivide e un assistente AI non può aiutarti. Il package Laravel ufficiale cipi/agent mette webhook, health check e — la parte che usi tutti i giorni — un MCP di progetto dentro l'app, così Cursor legge i log, lancia Artisan e interroga il database in HTTPS.
Perché un agent dentro l'app
Cipi già gestisce il server: Nginx, PHP, database, SSL, deploy zero-downtime. Quella è infrastruttura. Un'app Laravel ha un altro mondo — modelli Eloquent, seeder, code Horizon, rotazione dei log, lo stato delle migration. Un'AI che vede solo il repo indovina. Un'AI che può chiamare tool sull'app in esecuzione smette di indovinare.
Serve a questo l'MCP di progetto. Vive su POST /cipi/mcp sul dominio dell'app, parla MCP 2024-11-05 su HTTPS ed espone sei tool limitati a quella applicazione. Niente SSH da root. Niente chiave di deploy nell'IDE. L'assistente chiede lo health, legge laravel.log, lancia db:seed --class=RoleSeeder in staging e verifica le righe con db_query.
Health check e MCP funzionano su qualsiasi host Laravel 12+. I deploy da webhook e i log extra (nginx, php, worker, deploy) si aspettano un ambiente gestito da Cipi. Il riferimento tecnico è nella documentazione Cipi Agent.
Installare cipi/agent
Requisiti: PHP 8.3+ e Laravel 12 o 13. Lo service provider è auto-discovered — non toccare config/app.php.
$ composer require cipi/agent
$ php artisan cipi:status # config + connettività DB liveSu una VPS Cipi, cipi app create inietta già CIPI_APP_USER, CIPI_WEBHOOK_TOKEN e i path di deploy. Accendi solo i servizi opzionali che ti servono. Fuori da Cipi, pubblica il config se vuoi default diversi:
$ php artisan vendor:publish --tag=cipi-configCommit e push. Il deploy successivo prende il package. Dal pannello non c'è altro da cablare.
Cosa fa davvero il package
| Funzione | Endpoint | Quando la usi |
|---|---|---|
| Deploy da webhook | POST /cipi/webhook | Il push GitHub / GitLab scrive .deploy-trigger; Deployer parte come utente app entro un minuto |
| Health check | GET /cipi/health | UptimeRobot / Grafana: app, database, cache, coda, ultimo commit |
| MCP di progetto | POST /cipi/mcp | Cursor / VS Code / Claude: health, log, SQL, Artisan, deploy — questa guida |
| Anonymizer DB | POST /cipi/db | Dump GDPR-safe per locale/QA, transform Faker, download firmato da 15 minuti |
Ogni funzione ha un Bearer token suo e si spegne da sola. Un endpoint disabilitato risponde 404 — per uno scanner non esiste.
Accendere l'MCP di progetto
Il server MCP è spento di default. Accendilo, genera un token dedicato, poi stampa gli snippet per i client:
$ php artisan cipi:service mcp --enable
$ php artisan cipi:generate-token mcp
$ php artisan cipi:mcpcipi:mcp stampa i sei tool e il JSON pronto per Cursor (HTTP nativo), VS Code / Copilot e Claude Desktop (via mcp-remote). Il token finisce in .env come CIPI_MCP_TOKEN. Non riusare il secret del webhook.
Collegare Cursor, VS Code o Claude
Su Cursor, metti questo in ~/.cursor/mcp.json (o Impostazioni → MCP). Sostituisci dominio e token dal tuo .env:
{
"mcpServers": {
"cipi-myapp": {
"type": "http",
"url": "https://yourdomain.com/cipi/mcp",
"headers": {
"Authorization": "Bearer YOUR_CIPI_MCP_TOKEN"
}
}
}
}VS Code 1.102+ usa lo stesso trasporto HTTP in .vscode/mcp.json sotto la chiave servers. Claude Desktop ha bisogno del ponte stdio mcp-remote — php artisan cipi:mcp stampa anche quel blocco.
Chiama il server come l'utente app (cipi-myapp, cipi-staging). Un'app Laravel, un MCP. Se hai staging e produzione, registra due server e di' quale intendi.
Debug senza SSH
Questa è la parte che cambia la giornata. Restiamo nell'IDE. L'assistente parla con l'app live.
health — è su, o no?
Stesso payload di GET /cipi/health: versione Laravel, APP_DEBUG, nome database, cache, driver della coda, job in pending, ultimo commit. Chiedi: «Produzione healthy? C'è backlog in coda?» Se checks.app.debug è true su un host pubblico, hai già trovato un problema senza aprire il .env.
logs — gli ultimi errori, non tutto il file
Il tool logs legge le ultime N righe (default 50, max 500) e tiene intatti gli stack trace. Filtri:
type—laravel,nginx,php,worker,deploylevel—error,warning, … (solo Laravel)search— keyword case-insensitive, es.PaymentFailedo una classe job
La rotazione daily (laravel-YYYY-MM-DD.log) viene rilevata da sola. Dopo un 500, il primo prompt utile: «Mostra gli ultimi 100 errori Laravel, poi le righe nginx corrispondenti.»
db_query — guarda, non distruggere
Lettura: SELECT, SHOW, DESCRIBE, EXPLAIN. Scrittura: INSERT, UPDATE, DELETE. Bloccati: DROP, TRUNCATE, GRANT, REVOKE, I/O su file. I risultati tornano come tabella ASCII, massimo 100 righe — abbastanza per confermare un seeder, non per scaricare la tabella users.
# dopo un RoleSeeder in staging
SELECT id, name, created_at FROM roles ORDER BY id;
# le iscrizioni di oggi sono arrivate?
SELECT COUNT(*) FROM users WHERE created_at >= CURRENT_DATE;Seeder, migrate e cache via artisan
Il tool artisan è il motivo per cui questo package merita un posto nel repo Laravel. Esegue qualsiasi comando Artisan tranne quelli long-running o interattivi (serve, tinker, queue:work, queue:listen, schedule:work, horizon, octane:start, reverb:start). Tutto il resto — seeder compresi — è lecito.
Prompt che ti risparmiano un salto in SSH:
- «Lancia
migrate:statussu staging.» - «Seeda solo i ruoli:
db:seed --class=RoleSeeder.» - «Carica gli ordini demo con
DemoDataSeeder, poiSELECT COUNT(*) FROM orders.» - «
queue:failed— job bloccati dall'ultimo deploy?» - «
cache:cleareoptimize:cleardopo il cambio di config.»
Non puntare questo su produzione e scrivere «lancia il DatabaseSeeder». migrate:fresh --seed non è nella lista dei comandi bloccati — il package lo esegue. Usa seeder nominati, in staging, e conferma con db_query. I dati di produzione non diventano un playground solo perché il trasporto è MCP invece di SSH.
Pattern sicuro in staging: una classe seeder per fixture, idempotente dove puoi, chiamata per nome. L'assistente lancia la classe, legge la tabella, e solo dopo promuovi lo stesso seeder in CI. È l'opposto di «dump di produzione e speriamo».
Abbinalo all'anonymizer quando in locale ti serve volume senza PII: anonimizzi un dump a forma di produzione, lo carichi in locale, e tieni i seeder via MCP per le tabelle di riferimento (ruoli, piani, feature flag) che cambiano ogni sprint.
Un loop quotidiano da copiare
Tu: Staging healthy? Job in pending?
Agent: health → healthy, coda 0, debug false, commit a1b2c3d
Tu: Ultimi errori Laravel, search "InvoiceJob"
Agent: logs type=laravel level=error search=InvoiceJob
→ 1 errore, manca la colonna invoices.paid_at
Tu: migrate:status. 2026_08_22_add_paid_at è pending?
Agent: artisan migrate:status → sì, pending
Tu: Dopo il deploy, seeda solo InvoiceStatusSeeder.
Agent: deploy → in coda
artisan db:seed --class=InvoiceStatusSeeder
db_query SELECT id, name FROM invoice_statuses
→ 4 righeNessuna sessione SSH. Nessun copia-incolla da storage/logs. La stessa conversazione funziona per un collega che ha il token MCP e non deve mai avere root sul box — cioè la maggior parte del team.
MCP di progetto vs MCP API del pannello
Cipi spedisce due server MCP. Confonderli è il primo errore tipico.
MCP di progetto (cipi/agent) | MCP API pannello (cipi/api) | |
|---|---|---|
| Dove | POST /cipi/mcp sul dominio dell'app | POST /mcp sul vhost API |
| Scope | Una app Laravel: il suo DB, i log, Artisan, il flag di deploy | Tutto il server: app, SSL, database, PHP, worker |
| Tool | 6 — health, app_info, deploy, logs, db_query, artisan | 50+ — crea app, emette certificati, modifica .env, esegue come utente app |
| Usalo per | Debug, seeder, migrate:status, peek della coda | Provision, SSL, elenco di tutti i database, cockpit server |
Tienili entrambi in Cursor se vuoi. Chiedi all'MCP di progetto di questa app; chiedi all'MCP API del pannello di creare il prossimo clone di staging. La guida allo sviluppo spec-driven copre il loop largo — questa pagina è la metà in-app.
Token, blocchi e least privilege
- Token dedicato.
CIPI_MCP_TOKENnon è il secret del webhook e non è il token health. Se vaga,php artisan cipi:generate-token mcpe riavvia. Chi ha il token può lanciare Artisan e scrivere SQL (entro il cap di 100 righe). - Spento = 404.
php artisan cipi:service mcp --disableoppureCIPI_MCP=false. In produzione lascialo spento finché non ti serve davvero l'IDE collegato. - Artisan bloccati:
serve,tinker,queue:work,queue:listen,schedule:work,horizon,octane:start,reverb:start. - SQL bloccati:
DROP,TRUNCATE,GRANT,REVOKE, I/O su file. - Solo HTTPS, niente SSH. Va bene per uno sviluppatore che deve ispezionare e deployare senza
sudo. Resta un canale privilegiato — tratta il token come una password di produzione.
Prima il package, poi il server
cipi/agent è il companion Laravel. Cipi è la CLI di deploy gratuita e open source che inietta le env e lancia Deployer quando scatta il webhook o il tool MCP deploy.
Domande frequenti
Serve SSH per usare l'MCP di progetto?
No. Una volta deployato il package e acceso CIPI_MCP, l'IDE parla con https://yourdomain.com/cipi/mcp col Bearer token. È il punto per i colleghi che non devono mai entrare come root.
Qual è la differenza tra l'MCP dell'agent e l'MCP API di Cipi?
L'MCP dell'agent sta dentro una singola app Laravel (sei tool: health, log, SQL, Artisan, deploy). L'MCP API del pannello gestisce tutta la VPS — crea app, SSL, database, PHP. Usa l'agent per debug e seeder; usa l'API per provisionare.
Posso lanciare db:seed in produzione via MCP?
Tecnicamente sì — db:seed non è bloccato. In pratica, solo un seeder nominato e revisionato, e mai migrate:fresh --seed sui dati live. Meglio staging, poi conferma con db_query.
Quali comandi Artisan sono bloccati?
serve, tinker, queue:work, queue:listen, schedule:work, horizon, octane:start, reverb:start. I processi long-running e interattivi non stanno su una chiamata HTTP.
cipi/agent funziona senza un server Cipi?
Health check e MCP sì, su qualsiasi host Laravel 12+. I deploy Deployer da webhook e i tipi di log extra si aspettano il layout Cipi sotto /home/<app>/.
Come ruoto un token MCP trapelato?
php artisan cipi:generate-token mcp, riavvia l'app (o ricarica PHP-FPM / Octane), aggiorna ~/.cursor/mcp.json. Il token vecchio muore con la riscrittura del .env.