iT邦幫忙

2025 iThome 鐵人賽

DAY 23
0
生成式 AI

當 .NET 遇見 AI Agents:用 Semantic Kernel × MCP 打造智慧協作應用系列 第 23

Day 23: Semantic Kernel 使用 Streamable HTTP 模式串接 MCP Server

  • 分享至 

  • xImage
  •  

在 Day 22 我們介紹了 MCP 的基本概念和核心組成,今天直接來實作一個簡單的範例,使用 Microsoft 的 Semantic Kernel 來串接一個 MCP Server,並透過 Streamable HTTP 模式來進行通訊。這個範例會展示如何設定 Semantic Kernel 作為 MCP Client,串接 Context7 MCP Server (一個開放的 MCP Server),測試是否能成功通訊取得 MCP Server 所暴露的工具。

什麼是 Context7

Context7 是由 Upstash 團隊開發的開源工具,專門為 AI 程式開發助手提供最新、版本特定的官方文檔和程式碼範例。 它的目的在於解決大型語言模型(LLM)經常生成過時或錯誤程式碼的問題,尤其是在模型訓練截止日期之後發布或更新的程式,是許多開發人員在使用 AI Coding 工具時重要的資源。

Context7 的工作原理是動態將最新的官方文件直接注入到你的提示詞中,所以當你在 VS-Code 、 Cursor、Claude Desktop、Windsurf 等支援 MCP(Model Context Protocol)的編輯器中使用時,只需在問題中加入 "use context7",系統就會自動獲取相關程式庫的最新文檔,並將其整合到 AI 助手的上下文視窗中,以減少程式碼錯誤的可能性。

使用 Semantic Kernel 串接 MCP Server

  • 安裝必要的 MCP 官方.NET 套件
dotnet add package ModelContextProtocol --version 0.4.0-preview.1
  • 建立 Kernel ,這裡我們使用 OpenAI 的 GPT-4.1 模型作為 LLM,並設定 API Key 和 Model ID
 Kernel kernel = Kernel.CreateBuilder()
                .AddOpenAIChatCompletion(
                    apiKey: Config.OpenAI_ApiKey,
                    modelId: Config.ModelId)
                .Build();
  • 配置 MCP Server 的連線,這裡我們使用 Context7 提供的 MCP Server,並設定為 Streamable HTTP 模式。如果你的用量比較大,可以採用API Key方式連接,免費帳號也可以使用,但有流量限制。如果只是測試,可以不帶 API Key 直接連接。
 // 連線到 MCP Server (Streamable HTTP,原 SSE模式請建議改用 Streamable HTTP取代)
var clientTransport = new HttpClientTransport(new()
{
    Endpoint = new Uri("https://mcp.context7.com/mcp"),

    Name = "Context7Server",
    AdditionalHeaders = new Dictionary<string, string>
    {
        { "Authorization", "Bearer xx-your-api-token" }
    }
});
  • 建立 MCP Client,並將其加入到 Kernel 中
 await using var mcpClient = await McpClient.CreateAsync(clientTransport!);
  • 檢視是否成功連接到 MCP Server,並取得可用的工具清單
// 取得 MCP Server 工具清單
var tools = await mcpClient.ListToolsAsync();
// 工具清單顯示
foreach (var tool in tools)
{
Console.WriteLine($"Connected to Context7 MCP server with tools: {tool.Name}");
}

  • 將 Context7 MCP Server 暴露的工具加入到 Kernel 中
// 匯入工具並組裝 Agent
kernel.Plugins.AddFromFunctions("McpTools", tools.Select(t => t.AsKernelFunction()));
  • 建立 Agent,並使用 MCP 工具來回答問題
ChatCompletionAgent agent =
new(){
        Name = "ProgramerAgent",
        Description = "一個可以回答C#程式碼的助手",
        Instructions =
        """
        你是一個熟悉 C#/.NET 的程式碼撰寫助理,角色定位是快速、準確的輸出程式碼,一律使用 context7 工具確認程式碼正確性。

        ## 你的任務是:
        — 必須使用 context 7 工具來確認程式碼的正確性。
        - 依照使用者的指示,產出正確、可編譯的 C# 程式碼。
        - 程式碼中採用正確的語法、命名與常見 C# 實務(例如 async/await、可空參考、正確 using 區塊)
        - 除非使用者要求解釋,否則只輸出程式碼區塊,不多加贅述。
        - 如果你不確定程式碼是否正確,請使用 context 7 工具來驗證。
        - 如果使用者要求解釋,請簡要說明程式碼的功能和邏輯。
        - 不得輸出惡意、危險或繞過安全機制的內容。
        
        ## 輸出格式:
        ```csharp
        ...(程式碼)
        ```

        """,
        Kernel = kernel,
        Arguments = new(new PromptExecutionSettings { FunctionChoiceBehavior = FunctionChoiceBehavior.Auto() })
    };
  • 使用 Agent 來回答問題,並加入追蹤 function calling 是否被調用
// 建立對話歷史 thread
ChatHistoryAgentThread agentThread = new();

Console.Write("User > ");
string? userInput;
while ((userInput = Console.ReadLine()) is not null)
{
    if (string.IsNullOrWhiteSpace(userInput) || userInput.Equals("exit", StringComparison.OrdinalIgnoreCase))
        break;

    ChatMessageContent message = new(AuthorRole.User, userInput);

    bool isFirst = false;

    await foreach (StreamingChatMessageContent response in agent.InvokeStreamingAsync(message, agentThread))
    {
        if (string.IsNullOrEmpty(response.Content))
        {
            StreamingFunctionCallUpdateContent? functionCall = response.Items.OfType<StreamingFunctionCallUpdateContent>().SingleOrDefault();

            //追蹤function calling調用
            if (!string.IsNullOrEmpty(functionCall?.Name))
            {
                Console.WriteLine($"\n# trace {response.Role} - {response.AuthorName ?? "*"}: FUNCTION CALL - {functionCall.Name}");
            }
            continue;
        }

        if (!isFirst)
        {
            Console.Write($"{response.Role} - {response.AuthorName ?? "*"} > ");
            isFirst = true;
        }

        Console.Write($"{response.Content}");
    }
    Console.WriteLine();
    Console.WriteLine($"\n# trace chat thread with agent: {agent.Name} - {agent.Description},threadId: {agentThread.Id} \n");
    Console.Write("User > ");
}

  • 執行結果
    可以看到當順利連接到 Context7 MCP Server 後,系統會列出可用的工具清單,並且當我們輸入問題後,Agent 會自動調用 MCP 工具來取得最新的程式碼範例,並回覆給使用者。
Connected to Context7 MCP server with tools: resolve-library-id
Connected to Context7 MCP server with tools: get-library-docs

User > qdranmt 向量資料庫範例

# trace Assistant - ProgramerAgent: FUNCTION CALL - McpTools-resolve-library-id

# trace Assistant - ProgramerAgent: FUNCTION CALL - McpTools-get-library-docs
assistant - ProgramerAgent > ```csharp
// 使用 Qdrant 向量資料庫的 C# 範例(僅示範用 REST API 與 HttpClient 基本用法)
// 官方沒有 C# Client,可直接呼叫 REST API

using System.Net.Http;
using System.Net.Http.Json;
using System.Text.Json;
using System.Threading.Tasks;

public class QdrantVector
{
    public int Id { get; set; }
    public float[] Vector { get; set; }
    public Dictionary<string, object>? Payload { get; set; }
}
....(以下省略)

結語

透過這個範例,示範如何使用 Semantic Kernel 開發作為 MCP Client的 Agent,串接外部的 Context7 MCP Server,並利用 Streamable HTTP 模式來進行通訊。這種方式能夠動態獲取最新的程式碼範例和官方文檔,提升 AI 助手的準確性和實用性。未來可以將這個架構應用到更多場景中,例如結合其他 MCP Server 或擴展更多功能,打造更強大的 AI Agent。

注意

在 0.4.0-preview.1 版本中,原本使用的 SSE 模式已被標記為過時,建議改用 Streamable HTTP 模式來取代。Streamable HTTP 提供了更穩定和高效的通訊方式,適合在各種網路環境下使用。如果你正在使用舊版本的 MCP 套件,升級 ModelContextProtocol 後,必須改用 HttpClientTransport 取代 SseClientTransport,而原本的McpClientFactory.CreateAsync方法也改為 McpClient.CreateAsync 方法。


上一篇
Day 22: 一文認識 Model Context Protocol (MCP)
系列文
當 .NET 遇見 AI Agents:用 Semantic Kernel × MCP 打造智慧協作應用23
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言