Federico Mantua

Team Leader / Software Engineer Microsoft Solution c# .net

  • Cos’è MCP?

    A partire da novembre 2024 Anthropic a rilasciato il Model Context Protocol (MCP), in modo tale di permettere agli LLM di reperire informazioni dalle nostre applicazioni locali, operazione che prima si poteva fare soltanto definendo dei tool all’interno dei nostri applicativi.

    Vantaggi rispetto ai tools

    Ovviamente le stesse operazioni possono essere fatte tramite i tools, ma un server MCP ci da in più la riusabilità e il disaccopiamento.
    In sintesi Non dobbiamo cambiare il codice dei nostri agent e possiamo esporre un server Mcp a più agent.

    Implementazione di un MCP Server Custom in C#

    Ora andremo a vedere come possiamo implementare un MCP Server Custom e farlo utilizzare al nostro agente

    Setup del progetto

    per l’implementazione è necessario usare il pacchetto ModelContextProtocol presente su Nuget in Preview La libreria oltre ad essere disponibile in c# è disponibile anche per altri linguaggi (Typescript,Python,Java,ecc….) Ma partiamo con lo sviluppo: Creiamo il nostro progetto, in c# (io ho usa la RC1 di .net10) e importiamo i pacchetti nuget

    ModelContextProtocol
    ModelContextProtocol.AspNetCore
    

    Implementazione dei tools

    Per implementare i tool del nostro server MCP sarà sufficiente andare ad implementare una classe e utilizzare il decoratore:

    McpServerToolType
    

    e su ogni singolo tool da esporre usiamo il decoratore

    McpServerTool
    

    è importante anche utilizzare delle descrizioni chiare, che danno più indicazioni possibili su cosa fa il nostro tool. Per far si che i nostri agent, siano in grado di riconoscere quali tool andare a chiamare, qui vi mostro una classe con all’interno un tool come esempio, che si limita a tornare la stringa ricevuta in input con una personalizzazine.

    using ModelContextProtocol.Server;
    
    namespace McpHttpServer.tools
    {
        /// 
        /// MCP Tools collection for this server
        /// 
        [McpServerToolType]
    
        public class McpSampleTools
        {
            private readonly ServerConfig _config;
    
            public McpSampleTools(ServerConfig config)
            {
                _config = config;
                Console.WriteLine("McpSampleTools initialized with configuration.");
                Console.WriteLine("Tool settings:"+ _config.ServerSettings.Name);
            }
            /// 
            /// Echo tool - returns the provided text
            /// 
            /// The text to echo back
            /// The echoed text
                    [McpServerTool]
            [Description("Echo back the provided text")]
            public  string Echo(
                [Description("The text to echo back")] string text)
            {
                Console.WriteLine($"Echo called with text: {text} Config Server Name: {_config.ServerSettings.Name}");
                return $"Dal server mcp {_config.ServerSettings.Name}: {text} ";
            }
        }
    
    }
    
    Implementazione Server MCP Server

    Una volta implementati i nostri tool, non ci resta che tirare su allo startup della nostra applicazione il nostro server MCP e questo lo facciamo con le righe di codice che seguono:

    uilder.Services.AddMcpServer(options =>
    {
        options.ServerInfo = new()
        { 
            Name = config.ServerSettings.Name,
            Version = config.ServerSettings.Version
        };
    })
        .WithHttpTransport() // Use HTTP transport
        .WithToolsFromAssembly(); // Register tools from the current assembly
    
    
    
    var app = builder.Build();
    
    // Map MCP endpoints
    app.MapMcp();
    

    In estrema sintesi quello che andiamo a fare è definire un serverMCP (“AddMcpServer”) e poi gli diciamo che dobbiamo recuperare i tool dall’assembly “WithToolsFromAssembly” questo metodo, recupera i tools con i decoratori e li espone nell’mcp server, e infine gli indichiamo il trasporto che deve essere http, ci sono anche altri tipi di trasporti (stdio,sse).

    Nel mio codice ho aggiunto anche app.MapMcp appunto per andare a mappare l’endpoint dedicato al nostro MCP Server quindi avremo url della nostra applicazione /MCP

    Utilizzo Server MCP

    Bene ma una volta che abbiamo eseguito lo sviluppo e esponiamo come andiamo a testare il nostro server mcp? la soluzione più rapida è quella di andarlo ad integrare all’interno della finestra del nostro client in visual studio code, quindi all’interno della forder .vscode aggiungiamo un file denominato mcp.json e aggiungiamo le seguenti righe:

    {
        "servers": {
        "nomemioserver": {
            "type": "http", //Transport Type
            "url": "http://urlmioserver/"
        }
    }
    }
    

  •  Ciao a tutti,

    In questo post voglio condividere come implementare un agent in c# sfruttando il semantic Kernel.

    Ma partiamo dalle basi, cos’ è un Agent? e a cosa ci serve?

    Cos’è un Agent?

    Un agent può essere inteso come un sistema in grado di prendere decisioni in modo autonomo, seguendo obiettivi e regole che gli sono stati dati, sfruttando le informazioni in un suo possesso.

    A Cosa ci servono gli Agent?

    Gli agent ci possono aiutare ad automatizzare tutta una serie di operazioni e a velocizzare il nostro lavoro quotidiano. 
    Il caso più banale è quello dell’operatore di customer care, che deve recuperare e verificare la situazione del cliente, a seguito della richiesta del cliente, bene queste sono operazioni che può eseguire un Agent addestrato a fare ciò.

    Cos’è Il Semantic Kernel ?

    Il Semantic Kernel è un Framework che permette l’integrazione dell’AI all’interno di vari linguaggi di programmazione questo ci permette appunto di sviluppare agent, ma non solo gli agent sono solo una parte di ciò che possiamo fare con il Semantic Kernel

    Costruiamo un semplice agente

    Bene a questo punto vi mostro gli step per costruire un agent.

    Per sviluppare questo piccolo progetto, ho usato come modello “llama3.2” su un Container con Ollama,

    STEP 1 Creazione del progetto e aggiunta dei pacchetti necessari.

    Creiamo una console e andiamo ad aggiungere i seguenti pacchetti nuget

    
    Microsoft.SemanticKernel
    Microsoft.SemanticKernel.Core
    Microsoft.SemanticKernel.Agents.Core
    Microsoft.SemanticKernel.Connectors.Ollama  → in pre-release
    
    

    STEP 2 Creazione dell’agent

    Ora possiamo già procedere con la creazione dell’agent,

    Andremo a Instanziare l’agent e a dargli le istruzioni, nel mio caso gli ho detto di inventare storie divertenti.

    
    using System.ComponentModel;
    using Microsoft.SemanticKernel;
    using Microsoft.SemanticKernel.Agents;
    using Microsoft.SemanticKernel.ChatCompletion;
    
    var builder = Kernel.CreateBuilder();
    
    // Add the Ollama chat completion service
    // Ensure you have Ollama running and the model "llama3.2:3b" is available
    // You can change the model name and URI as needed
    builder.AddOllamaChatCompletion("llama3.2:3b", new Uri("http://localhost:11434"));
    
    var kernel = builder.Build();
    
    ChatCompletionAgent agent = new() // 👈🏼 Definition of the agent
    {
        Instructions = "You are an agent who creates funny stories.",
        Name = "Story Agent",
        Description = "This agent can create funny stories based on user input.",
        Kernel = kernel
    };
    
    

    STEP 3 Interazione con l’agent

    è il momento di scrivere l’interazione con l’agent, io ho simulato un chatbot botta e risposta giusto per divertirmi un po

    
    string userMessage = string.Empty;
    
    do
    {
        Console.WriteLine("What kind of story would you like me to tell you? Type 'exit' to stop the chat.");
        userMessage = Console.ReadLine();
    
        if (!string.IsNullOrEmpty(userMessage) && userMessage != "exit")
        {
            ChatHistory chat =
            [
                new ChatMessageContent(AuthorRole.User, userMessage)
            ];
    
            await foreach (var response in agent.InvokeAsync(chat))
            {
                chat.Add(response);
                Console.WriteLine(response.Message.Content);
            }
    
            userMessage = string.Empty;
        }
    
    }
    while (userMessage != "exit");
    
    

    A questo punto la console può essere eseguita e testata.

    Integrazione con Function

    Ovviamente per rendere l’agent più centrato sui nostri obiettivi, possiamo definire delle funzioni custom con le quali lui andrà a recuperare le informazioni. 
    Ad esempio il recupero delle informazioni relative al cliente stesso, all’interno dei sistemi. Di seguito ho simulato un esempio dell’utilizzo delle funzioni

    STEP 4 Definire le funzioni

    
    [Description("Get the residence city from the user")]
    string GetCity(string name)
    {
        return "Roma";
    }
    
    [Description("Get the age of a user")]
    int GetUserAge(string name)
    {
        return 25;
    }
    
    

    Definite le funzioni le associamo al nostro agent

    Andiamo ad aggiungere ai plugin le funzioni che abbiamo scritto sopra, in modo tale che questo possa invocarle quando necessario

    
    agent.Kernel.Plugins.Add(GetCity);
    agent.Kernel.Plugins.Add(GetUserAge);
    
    

    Definire gli arguments nella definizione dell’agent

    
    ChatCompletionAgent agent = new() // 👈🏼 Definition of the agent
    {
        Instructions = "You are an agent who creates funny stories. If you find any 
           information related to the user through plugins or tools, include it in 
           the story to make it more personal and engaging.",
        Name = "Story Agent",
        Description = "This agent can create funny stories based on user input.",
        Kernel = kernel,
        Arguments = new KernelArguments(new PromptExecutionSettings
        {
            FunctionChoiceBehavior = FunctionChoiceBehavior.Auto()
        }) // 👈🏼 Set the function choice behavior to auto
    };
    
    

    In questo modo abbiamo detto al nostro agent, che può recuperare informazioni tramite le  funzioni che abbiamo definito.

    Conclusioni

    Con questo post volevo, condividere come implementare un Agent, e le sue potenzialità..  Ovviamente anche io sto ancora studiando e questo progetto di test è in continua evoluzione, per cui vi lascio anche il link al Repository github.

  • Ciao a tutti, sono Federico.

    Appassionato di informatica e tecnologia fin da bambino, mio padre ha sempre detto che ho imparato prima a usare il computer e poi a leggere.

    “Leggevo i comandi su un fogliettino e lanciavo i giochi in autonomia, a soli 5 anni.”

    Ho smanettato con il vecchio 386 di mio padre fino a farlo morire. Inizialmente l’obiettivo era espanderlo, quindi giocavo con fkdisk, memmaker e altri tool che oggi non ricordo. Poi passai all’upgrade da Windows 3.1 a Windows 95… e alla fine tentai l’impresa:

    “Smontai tutto il PC e provai a rimontarlo. Purtroppo qualcosa andò storto e il computer non si riaccese più. Ricordo ancora il fumo dal processore. Errori di gioventù… del resto, sbagliando si impara, no?”

    Sono cresciuto tra Pascal, C e qualche sito web creato per divertimento durante l’adolescenza, senza dimenticare Access, con cui mi divertivo a sviluppare applicazioni di data entry.

    I primi soldi li ho guadagnati proprio aggiustando PC ai colleghi di papà.

    Oggi ho la fortuna di fare per lavoro, da ormai 20 anni, ciò che è da sempre la mia passione: lo sviluppatore software. Ho sempre lavorato su tecnologie Microsoft, mi piace imparare cose nuove e affrontare nuove sfide.

    Apro questo blog per condividere qualcosa con chi avrà il piacere di leggermi, perché credo che la condivisione, le community e il networking siano fondamentali e vadano alimentati—specie per chi fa questo lavoro, ma ancor di più per chi ha passione per ciò che fa.

    Spero di poter essere d’aiuto a qualcuno, e sono sempre disponibile per un confronto o anche solo per scambiare quattro chiacchiere.