MentorAgent Docs
Menu

ConceptPackages: Novior.MentorAgent, Novior.MentorAgent.Server, Novior.MentorAgent.Blazor

Canali: come i client arrivano all'agente

Scegli come i client raggiungono il tuo agente: il widget della chat, SignalR o HTTP dal tuo front end, o un protocollo per altri agenti e strumenti AI.

On this page

Un canale è il modo in cui un client raggiunge il tuo agente, dai tuoi sistemi fino a dove si trovano i tuoi utenti. L'agente gira sempre nella tua applicazione: nel tuo host ASP.NET Core, oppure dentro la tua app .NET MAUI. Il client non deve per forza essere .NET: un'app React, Angular o Vue, un'app mobile nativa, uno script o un altro agente raggiungono le stesse azioni.

Le tue azioni e le loro regole sono le stesse su ogni canale. Un canale senza una persona dall'altra parte non può chiedere una conferma: vedi Dove non risponde nessuno. Su tutti i canali tranne uno, alla richiesta risponde il coordinatore, cioè l'agente principale. L'eccezione è il server Model Context Protocol (MCP): lì è il modello del client a chiamare direttamente le tue azioni. Da un canale all'altro cambiano il client, il trasporto, dove vive la conversazione e chi può confermare un'azione.

Il widget è il componente di chat già pronto per le app Blazor e .NET MAUI. SignalR è la libreria di ASP.NET Core per le comunicazioni in tempo reale. Il Glossary spiega gli altri termini della tabella.

CanaleClientPacchettiTrasportoChi confermaConfigurazione
Blazor Server<ChatWidget /> nel tuo layoutNovior.MentorAgentDentro il processo del server, attraverso il circuito BlazorL'utente, nel widgetBlazor Server app
Blazor WebAssembly e Auto<ChatWidget /> nel progetto clientNovior.MentorAgent.Server sul server, Novior.MentorAgent.Blazor nel clientHub SignalR, e HTTP per le confermeL'utente, nel widgetBlazor WebAssembly and Auto
.NET MAUI<ChatWidget /> nel layout Blazor HybridNovior.MentorAgentDentro l'appL'utente, nel widget.NET MAUI
Hub SignalRLa tua interfaccia: React, Angular, Vue o qualunque app JavaScript, oppure un client SignalR .NET, Java o di un altro linguaggioNovior.MentorAgent.ServerSignalR su /mentor-hubL'utente, nel tuo client, attraverso POST /mentor/approveAny front end
Server-Sent Eventsfetch, curl o qualunque client HTTP, in qualunque linguaggioNovior.MentorAgent.ServerGET o POST /mentor/chatL'utente, nel tuo client, attraverso POST /mentor/approveAny front end
Server MCPClaude Desktop, VS Code o qualunque client MCPNovior.MentorAgent.ServerMCP via HTTP su /mcpNessuno: le azioni che chiedono conferma non vengono pubblicateMCP server
Server Agent-to-Agent (A2A)Altri agenti, e orchestratori (programmi che dividono un lavoro fra più agenti)Novior.MentorAgent.ServerA2A su /a2a, agent card su /.well-known/agent-card.jsonNessuno: le azioni che chiedono conferma vengono rifiutateA2A server
Client MCP e A2AIl tuo agente, che chiama altri sistemiNovior.MentorAgentChiamate dal tuo agente ai server MCP e agli agenti A2AIl tuo utente, per i tool MCP che metti dietro una confermaMcpServers, RemoteAgents

Il pacchetto Novior.MentorAgent.Server contiene il lato server di questi canali: l'hub SignalR, i Server-Sent Events, il server MCP e il server A2A. Contiene anche gli endpoint HTTP per le conferme, Stop, le sessioni, il tour e le metriche. Un'app Blazor Server che pubblica MCP o A2A, ma non ha un hub, aggiunge Novior.MentorAgent.Server e registra solo quello che le serve: AddMentorAgentMcp() o AddMentorAgentA2A(). I client MCP e A2A restano in Novior.MentorAgent.

Choose your packages elenca cosa contiene ogni pacchetto.

  • Un'app Blazor: il widget. Blazor Server è la scelta più semplice; scegli WebAssembly quando il widget deve girare nel browser.
  • Un'app .NET MAUI: il widget in un'app Blazor Hybrid, compilata per Android e Windows. In alternativa l'app può essere un client .NET dell'hub SignalR, su un server che ospiti tu.
  • Un front end React, Angular o Vue: l'hub SignalR per una chat, oppure i Server-Sent Events per domande singole.
  • Un'app nativa, mobile o desktop, o uno script: l'hub, con il client SignalR della sua piattaforma, oppure i Server-Sent Events da qualunque linguaggio.
  • Un assistente AI come Claude Desktop o VS Code: il server MCP, che gli pubblica le tue azioni.
  • Un altro agente o un orchestratore: il server A2A, che gli risponde con il tuo agente.
  • Al tuo agente servono tool o agenti di altri sistemi: i client MCP e A2A.

Il widget e l'agente girano nello stesso processo del server, quindi si parlano senza passare dalla rete. Il browser raggiunge il widget attraverso un circuito Blazor: la connessione che Blazor Server tiene con ogni scheda del browser. Per questo il widget deve stare in un layout reso in modo interattivo. In una pagina resa in modo statico il suo pulsante compare, ma non fa niente.

Ogni circuito ha il suo coordinatore e la sua conversazione. La chiave del modello non esce mai dal server.

In un'app con interattività Auto, la soluzione più semplice è dare al widget la sua modalità di rendering InteractiveServer, così che giri sul server. Il widget usa allora questo canale, mentre il resto dell'app può girare in WebAssembly.

Questa soluzione richiede un layout reso dal server. Funziona quindi con l'opzione Interactivity location del template impostata su Per page/component. Con Global il layout gira in WebAssembly e non può ospitare un componente server: usa Novior.MentorAgent.Blazor, descritto qui sotto.

Quando il widget stesso gira nel browser, il progetto client usa Novior.MentorAgent.Blazor e il progetto server Novior.MentorAgent.Server. L'agente gira comunque sul server. Il widget lo raggiunge attraverso l'hub SignalR, e manda conferme e Stop via HTTP.

Specialisti, retrieval-augmented generation sui tuoi documenti, MCP, A2A, memoria e conferma girano tutti sul server, e la chiave del modello non arriva mai al browser. L'hub legge l'utente collegato dalla connessione, quindi il controllo dei ruoli funziona anche in una Blazor Web App: vedi Blazor WebAssembly and Auto.

AddMentorAgent() va solo nel progetto server. In un'app standalone, la pagina che ospita l'app (index.html) collega da sé il foglio di stile e lo script del widget, con ?v= e la versione del pacchetto, così che dopo un aggiornamento i browser carichino i file nuovi. In una Blazor Web App li aggiunge il widget prerenderizzato. Un client servito da un'altra origine ha bisogno del Cross-Origin Resource Sharing (CORS) sul server e di un URL assoluto per l'hub.

In un'app .NET MAUI Blazor Hybrid tutto MentorAgent gira dentro l'app, con il solo pacchetto Novior.MentorAgent. Un'app del genere si compila per Android e Windows. iOS e Mac Catalyst non sono stati verificati. Il widget non ha bisogno di una modalità di rendering, perché un BlazorWebView è sempre interattivo. Non c'è un server web e non c'è un utente di ASP.NET Core. Questo ha tre effetti:

  • un'azione con RequiredRoles non viene offerta a nessuno, e viene rifiutata se chiamata, a meno che l'app registri un AuthenticationStateProvider che restituisce l'utente collegato;
  • c'è un solo coordinatore e una sola conversazione per tutta l'app, fino al riavvio;
  • la dashboard, il server MCP e l'agente A2A non sono disponibili, perché hanno bisogno di un host web. Il server MCP e l'agente A2A stanno in Novior.MentorAgent.Server, che un'app MAUI non usa. I client MCP e A2A funzionano comunque.

Il template MAUI ha bisogno del foglio di stile e dello script del widget in wwwroot/index.html: .NET MAUI spiega i passaggi. In alternativa un'app MAUI può essere un client dell'hub SignalR, su un server che ospiti tu.

Novior.MentorAgent.Server mappa un hub SignalR su /mentor-hub per i tuoi client. Possono essere app JavaScript (@microsoft/signalr), app .NET (Microsoft.AspNetCore.SignalR.Client), oppure app native con il client Java o Swift: vedi Any front end. L'hub porta gli eventi del widget: il testo in streaming, le azioni, le richieste di conferma, la navigazione, le azioni dell'interfaccia, l'attività dei team e lo stato.

La conversazione dura quanto la connessione. Una riconnessione è una connessione nuova e una conversazione nuova, a meno che il client non la salvi e la ripristini attraverso /mentor/session. GET /mentor/session restituisce uno snapshot della conversazione, che il client non può leggere né cambiare. Il client conserva lo snapshot come testo e lo rimanda così com'è. Solo l'utente che l'ha salvato può ripristinarlo.

Conferme e Stop passano via HTTP, a POST /mentor/approve e POST /mentor/cancel, e mai come chiamate all'hub. Il motivo è che SignalR esegue una sola chiamata alla volta per connessione: una chiamata all'hub fatta durante una risposta aspetterebbe per sempre.

Finché una connessione autenticata è aperta, solo il suo utente può rispondere. Quando la connessione si chiude, finisce anche il turno che gira su di essa, e con il turno anche la sua conferma.

POST /mentor/approve risponde 404 quando nessun turno aspetta più la risposta. Tratta 404 come "non c'è più niente a cui rispondere" e chiudi la tua finestra di dialogo.

GET /mentor/chat manda la risposta in streaming come Server-Sent Events, senza una libreria client: bastano fetch o curl. Un POST allo stesso percorso prende un corpo JSON, per i messaggi con immagini. Ogni richiesta è una conversazione a sé: il modello non vede i turni precedenti, e non ci sono né il contesto della pagina né le azioni dell'interfaccia.

I frame portano il testo, la fine del turno, gli errori, le card, la navigazione e le richieste di conferma. A una conferma si risponde su POST /mentor/approve, e lo stream riprende. Usa i Server-Sent Events per domande singole; per una chat, usa l'hub.

La tua applicazione diventa un server MCP su /mcp quando accendi McpServerEnabled e chiami AddMentorAgentMcp() e MapMentorAgentMcp(). I due metodi stanno in Novior.MentorAgent.Server, e AddMentorAgentServer() chiama il primo. I client MCP, come Claude Desktop, VS Code o Cursor, vedono le tue azioni come tool e le chiamano direttamente. Quale tool chiamare lo decide il modello del client: il tuo agente e il tuo modello non intervengono.

Vengono pubblicate solo le azioni di livello 1: i metodi degli specialisti no. Due regole decidono quali azioni di livello 1 vengono pubblicate:

  • le azioni che chiedono conferma non vengono mai pubblicate, perché dall'altra parte nessuno può rispondere. Vale anche per una [MentorAction] che non dichiara niente: vedi Ogni dichiarazione, su ogni canale;
  • le azioni con RequiredRoles vengono pubblicate solo a un chiamante che, secondo McpCallerPrincipal, ha il ruolo.

MentorAgent crea ogni classe di azioni una sola volta per tutta l'applicazione, e ogni chiamante MCP condivide quell'istanza: tieni le classi delle azioni senza stato.

Ogni chiamata passa da OnToolResult e conta per RateLimitPerUser, come un tool chiamato dal modello. L'endpoint non ha una policy CORS, perché i client MCP non sono browser. Un client che gira in un browser ha bisogno di una policy CORS che aggiungi tu: vedi MCP server.

Gli altri agenti possono trovare il tuo agente e chiamarlo quando accendi A2AServerEnabled e chiami AddMentorAgentA2A() e MapMentorAgentA2A(). I due metodi stanno in Novior.MentorAgent.Server, e AddMentorAgentServer() chiama il primo. L'agent card su /.well-known/agent-card.json descrive loro il tuo agente. Elenca una skill A2A per ogni nome di tool, dalle azioni delle classi registrate nella dependency injection che non chiedono né un ruolo né una conferma. /a2a riceve i task: in A2A ogni richiesta si chiama task.

Ogni task esegue un turno completo sul tuo modello, in una sessione nuova. Chi chiama riceve la risposta completa alla fine, non in streaming. Su un task nessuno può confermare:

  • le azioni che chiedono conferma vengono rifiutate subito;
  • le azioni con RequiredRoles vengono offerte, ed eseguite, solo per un chiamante autenticato che ha il ruolo. Per un chiamante anonimo vengono tolte, e rifiutate se chiamate.

Un task gira con l'identità dell'utente della richiesta. Quell'utente è collegato solo se il tuo host autentica l'endpoint /a2a: vedi Secure the endpoints. Per default un chiamante anonimo riceve un'identità nuova per ogni task, quindi RateLimitPerUser non può contare i task di un solo chiamante.

A una richiesta arrivata via A2A risponde il tuo agente, che non la passa mai agli agenti remoti che conosce.

Nell'altra direzione, il tuo agente usa quello che offrono altri sistemi:

  • Server MCP. I server in McpServers aggiungono i loro tool al coordinatore, accanto alle tue azioni. Per chiedere al tuo utente una conferma prima che parta uno dei loro tool, usa MentorMcpServer.RequiresConfirmation o RequiresApproval.
  • Agenti remoti. Gli agenti in RemoteAgents entrano nel workflow di handoff come gli specialisti, e hanno bisogno di un ChatClient.
    • Un agente remoto non ha un suo controllo dei ruoli: qualunque utente raggiunga il tuo agente può raggiungerlo.
    • Per limitarlo, proteggi l'endpoint /a2a sull'host remoto e dai i ruoli alle azioni che stanno lì. Oppure non configurare l'agente remoto sugli host i cui utenti non possono usarlo.

Un host ASP.NET Core può servire più canali insieme. L'host dell'esempio serve l'hub SignalR e i Server-Sent Events per i tuoi client, il server MCP per gli assistenti AI e il server A2A per gli altri agenti. AddMentorAgentServer() registra anche il server MCP e l'agente A2A, perché le loro opzioni sono accese:

Program.cs
builder.Services.AddScoped<CaseService>();
builder.Services.AddMentorAgent(options =>
{
    options.AppName = "Case management";
    options.AppDescription = "Tracks customer support cases and their status";
    options.ChatClient = chatClient;
    options.ScanAssemblies = [typeof(CaseService).Assembly];
    options.McpServerEnabled = true;    // MCP server
    options.A2AServerEnabled = true;    // A2A server
});
// SignalR hub, Server-Sent Events, MCP server and A2A agent
builder.Services.AddMentorAgentServer();

var app = builder.Build();
app.MapMentorAgentServer();     // /mentor-hub, /mentor/chat, /mentor/approve
app.MapMentorAgentMcp();        // /mcp
app.MapMentorAgentA2A();        // /a2a and /.well-known/agent-card.json

Per i canali Blazor ti servono solo AddMentorAgent e il widget nel layout. Ruoli, conferma e governance riassume cosa fa ogni canale con un'azione che chiede un ruolo o una conferma.

  • Ruoli, conferma e governance — Ruoli e approvazione human-in-the-loop per i tool di un agente AI in .NET: controlli nel codice, non nel prompt, su ogni canale, e cosa resta a te.
  • Choose your packages — Which MentorAgent package to install for Blazor, MAUI, or a backend for React, Angular, Vue and mobile apps, and what each one contains.
  • Secure the endpoints — Protect the SignalR hub, Server-Sent Events, /mcp and /a2a endpoints with authentication and CORS before you expose them.