MCP e strumenti collegati
Collega Nessie ai server MCP, e abbina un agente esterno perché possa lavorare in Nessie per tuo conto.
Che cos’è MCP
Il Model Context Protocol è una convenzione piccola e aperta per descrivere strumenti a un modello linguistico e richiamarli. Un server dichiara ciò che sa fare (un elenco di strumenti con nome, ciascuno con uno schema JSON per i propri argomenti), e un client scopre quell’elenco e invoca gli strumenti per conto del modello. È volutamente semplice: il valore sta nel fatto che un’integrazione scritta una sola volta funziona con ogni modello e ogni prodotto che lo parla.
Nessie sta da entrambe le parti
Vale la pena essere precisi, perché le due metà sono facili da confondere e vivono su percorsi deliberatamente diversi.
- In uscita. Nessie è un client MCP. Colleghi server gestiti da altri, e gli strumenti che espongono diventano strumenti che i tuoi agenti possono usare. La superficie di gestione è
/api/mcp/*. - In entrata. Nessie è anche un server MCP. Un agente che gira altrove, come Claude Code o Codex sulla macchina di uno sviluppatore, può richiamare le tue bacheche e i tuoi documenti. Quell’endpoint è
POST /mcp, fuori da/apidi proposito, così i due significati opposti non stanno a un solo segmento di distanza nel percorso.
Collegare un server MCP a Nessie
Voci di catalogo e istanze
Ci sono due oggetti, e la distinzione conta:
- Una voce di catalogo è la definizione di un server: il suo nome, il suo trasporto, il modo in cui si autentica. Viene scritta una volta sola e può essere condivisa.
- Un’istanza è quella voce installata a un certo ambito, con le credenziali che la raggiungono. Installare la stessa voce per due team diversi produce due istanze.
La maggior parte delle persone non tocca direttamente nessuno dei due. Il punto d’accesso nell’admin è lo store delle app su /admin/apps: sfoglia lo stesso catalogo con i dettagli di connessione nascosti, e Connect su una scheda crea un’istanza. Gli operatori che vogliono gli oggetti grezzi usano /api/mcp/catalog e /api/mcp/instances.
Se un server non è ancora nel catalogo, POST /api/mcp/discover riceve un URL e restituisce ciò che il server dichiara di sé, e POST /api/mcp/library/import importa una voce dalla libreria pubblica dei server. Una connessione al primo avvio può anche essere creata direttamente da un URL con POST /api/apps/custom.
Trasporti
Nessie si connette a server remoti tramite HTTP. Funzionano due trasporti: HTTP streamable (il trasporto MCP attuale) e il più vecchio trasporto HTTP+SSE. Scegli http, a meno che il server non offra solo sse.
Il trasporto stdio è rifiutato per i connettori che crei tu. Con stdio il server MCP è un processo locale avviato dall’host, e far eseguire programmi arbitrari dentro il server Nessie non è qualcosa che un operatore possa valutare in modo sensato. Per lo stesso motivo i server pubblicati solo come pacchetto da eseguire in locale vengono esclusi dalle importazioni dalla libreria. Un valore ws esiste nel campo del protocollo ma non è implementato: una connessione che lo usa fallisce quando Nessie prova ad aprirla.
Come Nessie si autentica presso il server
Una voce di catalogo dichiara uno di cinque metodi: none, api_key, bearer, basic oppure oauth2.
api_key è l’iniezione di un header, e la voce indica quale header e quale prefisso: quindi Authorization: Bearer …, X-API-Key: … e X-Auth-Token: Token … sono lo stesso metodo configurato in modi diversi. La chiave viene incollata una volta sola con POST /api/mcp/instances/:instanceId/secret e non è più leggibile; nessuna risposta delle rotte delle istanze contiene un riferimento alla credenziale.
oauth2 ha due forme. Un server con endpoint fissi li ha nella propria voce di catalogo. Un server che pubblica metadati standard non richiede alcuna configurazione: Nessie legge i documenti di protected resource e authorization server, e si crea da sé un client tramite dynamic client registration oppure tramite il documento di metadati del client ID che pubblica al proprio percorso well-known. In entrambi i casi il flusso è POST /api/mcp/instances/:instanceId/oauth/start, seguito dal redirect del provider verso GET /api/mcp/oauth/callback. Il token di stato è monouso, conservato nel database e valido per dieci minuti, e si usa sempre PKCE.
Una regola sorprende spesso: nemmeno un proprietario dell’organizzazione può collegare a un’altra persona un token personale o OAuth. Una credenziale condivisa è possibile solo per una voce con chiave API che è stata convalidata come tale; tutto il resto viene rifiutato. Una credenziale che appartiene a una persona resta una credenziale che appartiene a quella persona.
Dove si trovano le credenziali
I segreti dei connettori e i pacchetti di token OAuth sono memorizzati nel tuo database Postgres, in buste AES-256-GCM vincolate allo scopo, sotto il key ring di cifratura del deployment, che ha una versione indipendente, e sono indirizzati solo tramite riferimenti opachi secret_*. Sono volutamente non nel vault esterno dei segreti che contiene gli altri segreti di Nessie. Un deployment di produzione che non ha configurato lo store cifrato rifiuta di avviarsi, invece di completare un handshake OAuth che poi perderebbe per strada.
Dove arriva una connessione
Un’istanza è installata a uno di sei ambiti: system, organization, project, team, channel oppure user. Quell’ambito è un limite massimo rigido su quali esecuzioni possono usarla, e le concessioni possono solo restringerlo, mai allargarlo. Così un connettore installato con il tuo account non può diventare silenziosamente uno a livello di organizzazione.
Chi può installare dove segue la stessa logica: i proprietari e gli admin dell’organizzazione gestiscono le installazioni a ogni ambito; tutti gli altri installano connettori al proprio ambito user e possono vedere le installazioni condivise a cui hanno diritto di accesso.
Dare uno strumento a un agente
Collegare un server non consegna i suoi strumenti a nessuno. Quando un’istanza viene installata, Nessie la sonda e proietta ogni strumento che pubblica nel registro degli strumenti, che è ciò che l’admin mostra su /admin/advanced/tools: strumenti integrati, strumenti MCP, strumenti di bundle e strumenti dell’executor in un unico elenco, ciascuno con la propria origine e il proprio stato.
Uno strumento proiettato ha uno di tre stati: active, pending_review o disabled. Gli strumenti di un’installazione con ambito condiviso arrivano come pending_review e devono essere approvati su quella pagina prima che un agente li veda. Gli strumenti della tua installazione con ambito user sono attivi subito, perché l’unica persona esposta sei tu. La revisione è ricorrente e non è un adempimento una tantum: se un sondaggio successivo rileva che la descrizione o lo schema di uno strumento è cambiato, lo strumento torna in pending_review e smette di essere offerto finché qualcuno non controlla la modifica.
Quali agenti possono richiamare uno strumento attivo è deciso in due modi:
- Una connessione creata tramite lo store delle app richiede una concessione esplicita. Un agente ottiene lo strumento solo quando una concessione lo nomina, e la concessione viene verificata rispetto all’impronta attuale dello strumento: uno strumento modificato richiede quindi una nuova decisione.
- Altrimenti lo strumento è attivo per impostazione predefinita per gli agenti raggiungibili dal suo ambito, e i singoli agenti vengono disattivati dal pannello di dettaglio dello strumento.
Una concessione nomina esattamente un principale, un ruolo oppure un agente, mai entrambi, e un divieto prevale su un’autorizzazione. Per una connessione con ambito user la domanda non si pone: qualunque agente con cui quella persona parla può usarla, e un disattivamento esplicito è l’unica cosa che lo impedisce.
Una cosa facile da cercare nel posto sbagliato: /settings/accounts nell’admin sono gli account collegati, cioè Slack, caselle di posta, abbonamenti ai modelli e i link OAuth a Linear, Jira, GitHub e Trello che alimentano le bacheche esterne. I connettori MCP si trovano su /admin/apps, e gli strumenti che producono su /admin/advanced/tools.
Blocchi di approvazione sulle chiamate agli strumenti
Alcune chiamate agli strumenti si fermano e aspettano una persona. Quando succede, l’esecuzione non fallisce: la chiamata viene congelata (il nome dello strumento, un hash dei suoi argomenti e lo stato sufficiente a riprenderla) e una richiesta di approvazione compare in /api/approvals, perché qualcuno risponda. La ripresa è idempotente, quindi un’approvazione duplicata non può eseguire la chiamata due volte. La persona che decide vede un riepilogo limitato di ciò che viene chiesto; gli argomenti esatti e l’esecuzione di origine restano lato server.
Ci sono due gate distinti, e sono configurati in modo diverso:
- I gate strutturali sono una proprietà di alcuni strumenti integrati e non sono configurabili. Sono gestiti così l’invio di posta dalla casella di un agente o da una casella collegata, l’invio di una bozza Gmail, la disconnessione di un account di posta, la creazione, la modifica o l’annullamento di un evento di calendario, e un’azione del browser che scriverebbe su un sito su cui il browser non è autenticato. Hanno una finestra di 24 ore per ricevere risposta, invece dei soliti 30 minuti.
- I gate di policy derivano dalle regole di policy sulla coppia
tool/invoke. Una regola che consente un’invocazione può avererequiresApproval, e senza un’approvazione verificata la valutazione restituisceAPPROVAL_REQUIREDinvece di eseguire. Le regole sono valutate con il divieto per primo e ordinate per ambito.
Non siamo riusciti a confermare quale schermata dell’admin crea una policy requiresApproval per uno strumento: il modello dei dati e l’applicazione sono entrambi presenti, ma la schermata che scrive una regola del genere non è stata individuata.
Collegare un agente esterno a Nessie
L’altra direzione. Nessie gestisce un proprio server MCP su POST /mcp, tramite HTTP streamable, ed è stateless: ogni chiamata porta la propria credenziale e risolve il proprio attore, quindi non c’è una sessione da legare a una replica. ChatGPT, Claude, Claude Code, Codex o un agente sul laptop di qualcuno possono lavorare sulle tue bacheche, sui documenti e sui clienti dall’interno di qualunque strumento quella persona usi già. La guida passo passo per ciascuna app è Collega ChatGPT, Claude e altre app AI.
Che cos’è davvero una credenziale abbinata
È la parte da capire bene, perché il modello mentale più ovvio, una chiave API con dei permessi allegati, è quello sbagliato.
Una credenziale abbinata non è mai un’identità. Nomina una persona, e ogni chiamata agli strumenti viene eseguita come quella persona, sugli stessi servizi che chiamano le rotte HTTP. Un agente quindi non può raggiungere nulla che la persona che gliel’ha prestata non potrebbe raggiungere cliccando. Gli ambiti restringono soltanto quella portata; non esiste alcun ambito che la allarghi.
La validità viene riletta a ogni singola chiamata, mai data per buona dal token: revoca, scadenza, la versione del token dell’utente, la sua appartenenza all’organizzazione e il suo ruolo attuale. Un declassamento, una disattivazione o «Esci da tutti i dispositivi» colpiscono la chiamata successiva dell’agente, non la scadenza della credenziale.
Il token è opaco, con prefisso nag1_, memorizzato solo come hash SHA-256, e vale 90 giorni. Viene rifiutato con un 403 specifico su qualunque rotta diversa dall’endpoint MCP. Presentarlo altrove non è un successo parziale da ritentare: è ciò che impedisce che «ho prestato a un agente le mie bacheche» significhi «ho prestato il mio account».
Due modi di collegarsi
Un’app che può aprire un browser (ChatGPT, Claude, Claude Code, Codex) usa il profilo di autorizzazione MCP: OAuth 2.1 con PKCE (S256), dynamic client registration su POST /mcp/oauth/register, refresh token e resource indicators. L’app manda la persona a /settings/security, dove sceglie che cosa l’app può fare e a quali dei suoi team arriva, e il browser torna all’app con un codice. Il token di accesso dura un’ora ed è rinnovato; la connessione dura 90 giorni.
Un agente a riga di comando non controlla alcun browser e non può ospitare un URL di callback, quindi si abbina tramite il device authorization grant (RFC 8628).
- L’agente chiama
POST /mcp/auth/devicecon unclientNamee gliscopesche vuole. Riceve undevice_code, unuser_codebreve, unverification_urie unverification_uri_completecon il codice già nella query, più l’intervaldi polling e unexpires_in. Stampa l’URI. - Una persona apre quell’URI mentre è connessa, su
/settings/security. Vede quale agente chiede l’accesso, a nome di quale account lavorerebbe, fino a quando, ed esattamente che cosa potrebbe fare. Poi sceglie Consenti oppure Non consentire. - L’agente interroga
POST /mcp/auth/tokencon ildeviceCode, gestendoauthorization_pending,slow_down,expired_tokeneaccess_denied. Al successo riceve{ access_token, token_type, scope, expires_at }.
In entrambi i casi c’è un passaggio umano, perché la credenziale eredita i diritti di una persona, quindi una persona deve scegliere di prestarli. Qui nulla concede accesso dal nulla. Il collegamento può anche essere disattivato per un’intera organizzazione su /admin/security?tab=programs, e quella risposta viene verificata quando qualcuno consente una connessione, non quando un agente ne avvia una.
Scoperta
Un POST /mcp non autenticato risponde 401 con un header WWW-Authenticate che punta a /.well-known/oauth-protected-resource (RFC 9728), il quale indica questa origine come authorization server. I suoi metadati su /.well-known/oauth-authorization-server (RFC 8414) indicano gli endpoint di registrazione, autorizzazione, token e revoca. Questa catena è tutto ciò che serve a un client una volta che ha l’indirizzo. Per trovare l’indirizzo a partire da un dominio, un agente legge /.well-known/ai-catalog.json, che indica la Server Card su /mcp/server-card (MCP Server Cards, SEP-2127). Gli endpoint del device grant sono elencati nel documento della protected resource sotto x-nessie-device-authorization.
Un deployment può anche rispondere a un secondo indirizzo, più corto: https://nessie.works/mcp di Nessie Cloud viene inoltrato all’API, e un client arrivato in quel modo riceve come risorsa lo stesso indirizzo, mentre l’accesso resta sull’API. Un redirect non basterebbe, perché un client rifiuta metadati che nominano un indirizzo diverso da quello con cui è stato contattato. L’operatore elenca queste origini in NESSIE_MCP_ALIAS_ORIGINS.
Ambiti e strumenti
Gli ambiti sono volutamente grossolani: un ambito che nessuno sa spiegare è un ambito che nessuno imposta correttamente. Una connessione che raggiunge più di un team li elenca con nessie_team_list, e ogni altro strumento indica poi il proprio teamId.
| Ambito | Raggiunge |
|---|---|
boards_read | Progetti, bacheche e ticket, con i loro commenti, file, etichette, tipi e checklist |
boards_write | Creazione, modifica e spostamento di ticket, e tutto ciò che vi sta sopra |
documents_read | Knowledge space, documenti e fogli di calcolo |
documents_write | Redazione e modifica di documenti, e richiesta di pubblicazione di uno di essi |
clients_read | L’inbox dei clienti, i contatti, le liste di contatti, le newsletter e i moduli di contatto |
clients_write | Note, presa in carico, assegnazione e chiusura delle conversazioni, liste di contatti e preparazione di newsletter |
clients_send | Tutto ciò che un cliente riceve: una risposta, un primo messaggio email o un SMS. Non viene mai attivato senza che la persona lo attivi |
website_tools | Gli strumenti di pagina del sito registrato del tuo team, usati in un browser ospitato che puoi controllare. Non viene mai attivato senza che la persona lo attivi |
Una chiamata senza l’ambito di cui ha bisogno torna come risultato dello strumento, che indica quale ambito chiedere, e non come errore di trasporto. Così il modello può riferire qualcosa di utile invece di riprovare contro un muro.
Non esiste una famiglia separata di strumenti per i tracker esterni. Una bacheca è una bacheca, che i suoi task nascano in Nessie o siano replicati da Linear, Jira, GitHub o Trello, quindi un unico insieme di strumenti copre entrambi, e ogni task dichiara da dove viene. La differenza sta nella scrittura: una bacheca replicata da una fonte in sola lettura rifiuta una scrittura a parole, dicendo all’agente che l’altro sistema possiede il ticket e che riprovare non servirà.
Pubblicare un documento è un’approvazione, mai un ambito
Gli agenti redigono e una persona pubblica. Questa regola è applicata agli agenti di Nessie rifiutando del tutto un attore agente, ma una credenziale abbinata si risolve come persona, quindi quel rifiuto non può intercettarla. Il controllo deve trovarsi altrove.
Quindi nessie_doc_publish non pubblica nulla. Apre un’approvazione knowledge.page.publish, la stessa che apre un agente di Nessie, e restituisce { status: "awaiting_approval", approvalId }. Interrogarlo restituisce la stessa richiesta invece di aprirne una seconda. La decisione viene presa come vengono prese tutte le altre decisioni di pubblicazione in Nessie: da una persona, su quel documento, nel momento in cui esiste.
Non esiste deliberatamente un ambito di pubblicazione. Ce n’era uno: una spunta al momento dell’abbinamento che diceva che questo agente poteva pubblicare. È stato ritirato. Decideva, una volta e per novanta giorni, una domanda che il prodotto pone per ogni documento in tutti gli altri punti, e la decideva prima che il documento esistesse, quindi la persona che spuntava la casella non poteva sapere che cosa stava approvando. nessie_doc_publish richiede documents_write, perché chiedere non è gratuito (legge la pagina e mette una decisione davanti a qualcuno), ma quell’ambito non concede nulla sulla pubblicazione.
Sulla richiesta vengono registrate due identità, e la distinzione è portante. Il richiedente è la credenziale, mai la persona per conto della quale agisce. L’approvatore richiesto è quella persona, e solo lei può rispondere. Se la richiesta indicasse la persona come richiedente, la regola che impedisce a chiunque di approvare la propria richiesta escluderebbe proprio l’unica persona autorizzata a decidere.
Vedere e revocare ciò che è abbinato
Le credenziali abbinate di una persona sono elencate su /settings/security, con un’etichetta e un controllo di revoca per ciascuna. Un proprietario o un admin dell’organizzazione vede ogni credenziale dell’organizzazione su /admin/security?tab=programs (come si chiama ciascuna, che cosa può fare, se è attiva e a nome di quale account opera) e può revocarne qualsiasi. L’elenco personale resta riservato al proprietario: un elenco di credenziali attive è un elenco di punti d’appoggio, non una lettura generale.
Le scritture fatte tramite una credenziale sono attribuite alla persona il cui account viene usato e portano l’id della credenziale nei metadati di audit, così il registro può distinguere una modifica personale da una che il suo agente ha fatto per lei.
Cosa non è ancora disponibile
Meglio essere espliciti, perché il divario tra le capacità di un protocollo e quelle di un dato server è il punto in cui la documentazione di solito non dice il vero:
- Chat, canali, esecuzioni e gestione degli agenti non sono esposti tramite MCP.
- Un programma prepara una newsletter e una persona la invia: nulla invia, pianifica o elimina una campagna, e l’email stessa viene scritta nel designer.
- Collegare e unire i contatti, modificare lo schema del CRM, importazioni e configurazione dei canali restano affidati a una persona nel browser.
- L’interruttore dei collegamenti è un’impostazione a livello di organizzazione. Le impostazioni a livello di team e le eccezioni personali non possono essere impostate oggi da un team o da una persona.