2025年7月18日 星期五

如何製作簡易版的MCP SERVER (最快3分鐘)

      MCP Server (Model Context Proptocol) 是為了LLM 可以外部擴充它的知識和相關可運用的工具的最新方式,例如你詢問LLM : 【今天的天氣如何?】,LLM 的知識是預訓練完成的,怎麼會得知今天或明天的天氣如何? 所以透過 相關的MCP SERVER 讓LLM 去調用相關內容的function 去取得相關的內容,並透過LLM 的分析,並將結果回傳。

如下圖所示: 

MCP Client :連接 LLM 和 MCP 服務器的橋樑。嵌入在 LLM 中


MCP Server: 具有MCP Protocol協定的 SERVER,負責根據 LLM 的請求,例如事先寫好相應的「工具」或「功能」(Function)。例如,如果 LLM 詢問天氣,MCP Server 會調用預先註冊好的「天氣查詢」功能。

前提安裝條件

    本人安裝的環境 .net 9 SDK 也能建置 MCP  SERVER 


一、安裝 MCP 伺服器範本

dotnet new install Microsoft.Extensions.AI.Templates


二、使用 dotnet 指令建立新的 MCP 伺服器應用程式的範本

dotnet new mcpserver -n SampleMcpServer

三、用Vistul studio 開啟專案

SampleMcpServer

├── 相依性(Dependencies

├── .mcp

   └── server.json

├── Tools

   └── RandomNumberTools.cs

├── Program.cs

└── README.md

這是一個典型的 C# 專案結構,說明如下: 

.mcp/server.json:是 MCP Server 的設定檔。 

Tools/RandomNumberTools.cs:應該是封裝隨機數工具的程式碼檔。 

Program.cs:主執行進入點。 

README.md:說明文件。



     沒有寫一行程式碼,這個專案SampleMCP SERVER 已具有基本的框架,也可以測試執行
接下來我們來看看進面的程式碼是什麼吧! 

檔名: Programe.cs
// 引入必要的命名空間
using Microsoft.Extensions.DependencyInjection;  // 用於注入服務(DI)
using Microsoft.Extensions.Hosting;             // 用於建立主機(主控程式架構)
using Microsoft.Extensions.Logging;             // 用於設定日誌系統(Logging)

// 建立主機建構器(HostBuilder),接收命令列參數
var builder = Host.CreateApplicationBuilder(args);

// 設定所有的 log 訊息輸出到標準錯誤(stderr),
// 因為 stdout 是用來傳輸 MCP 協定訊息的
builder.Logging.AddConsole(o => 
    o.LogToStandardErrorThreshold = LogLevel.Trace // 設定最細的日誌等級(Trace)
);

// 註冊 MCP 伺服器服務:
// - 加入 MCP 伺服器
// - 使用 stdio(標準輸入/輸出)當作資料傳輸通道
// - 註冊要提供的工具:RandomNumberTools
builder.Services
    .AddMcpServer()                 // 註冊 MCP server 基礎功能
    .WithStdioServerTransport()     // 使用 stdio 作為通訊方式(與 IDE / client 互動)
    .WithTools<RandomNumberTools>(); // 提供一個叫 RandomNumberTools 的工具(具體功能要看類別定義)

// 建立並啟動主機,非同步執行直到應用程式結束
await builder.Build().RunAsync();
------------------------------------------------------------------------------------------------------------------------------

檔名: RandomNumberTools.cs  : 建置MCP Server 的function 

// 引入用於工具描述與註解的命名空間
using System.ComponentModel;                  // 提供 DescriptionAttribute 等用來顯示說明文字
using ModelContextProtocol.Server;           // MCP server SDK 所提供的屬性與工具

/// <summary>
/// MCP 工具範例類別,用來展示 MCP server 可供 client 呼叫的方法。
/// MCP client 可以呼叫這些方法來執行對應功能。
/// </summary>
internal class RandomNumberTools
{
    // 定義一個 MCP 工具方法,會自動被 MCP Server 掃描並註冊
    [McpServerTool]
    [Description("在指定的最小值與最大值之間產生一個隨機數字(包含最小,不包含最大)")]
    public int GetRandomNumber(
        [Description("最小值(含)")] int min = 0,
        [Description("最大值(不含)")] int max = 100)
    {
        // 使用 .NET 內建的 Random.Shared 產生一個隨機整數
        return Random.Shared.Next(min, max);
    }
}
------------------------------------------------------------------------------------------------------------------------------
檔名:server.json :可以在NuGet 發佈 MCP套件的設定

{
  "$schema": "https://modelcontextprotocol.io/schemas/draft/2025-07-09/server.json",
  "description": "提供基本隨機數字工具的 MCP Server 範例",
  "name": "io.github.your-username/mcp-randomtools",
  "packages": [
    {
      "registry_name": "nuget",                  // 套件來源(這裡是 NuGet 套件註冊中心)
      "name": "Mcp.RandomTools.Server",          // 你在 NuGet 上發布的套件 ID
      "version": "0.1.0-beta",                   // 套件版本
      "package_arguments": [],                   // 若套件支援 CLI 引數,可列在這(目前留空)
      "environment_variables": []                // 若 MCP server 啟動時需要設定環境變數,可列於此
    }
  ],
  "repository": {
    "url": "https://github.com/your-username/mcp-randomtools",  // GitHub 原始碼位置
    "source": "github"                                          // 表示來源是 GitHub
  },
  "version_detail": {
    "version": "0.1.0-beta"  // MCP server 的版本資訊
  }
}

-----------------------------------------------------------------------------------------------------------------

    如果用戶不是用.net Framework 10 就會出現問題了,此時叫出你的好幫手 copilot ,
並下指令prompt : 我的專案build 不過,如何才能build成功,以下是截圖 ,
記得visual Studio 要更新最新版,才能使用copilot 代理人模式



    
四、如何讓copilot 調用MCP Server 的工具

請先建立資料夾.vscode, 並新增檔案 mcp.json以設定要測試的WEATHER_CHOICES環境變數。

檔名: mcp.json

{
  "servers": {
    // 定義一個 MCP server 名稱叫 "SampleMcpServer"
    // VS Code MCP 擴充功能會用這個名稱來顯示可啟動的伺服器
    "SampleMcpServer": {

      // MCP server 的通訊方式為 stdio(標準輸入/輸出)
      // 適合開發環境中使用,與 IDE 直接互動,不需開啟網路 port
      "type": "stdio",

      // 指定執行 MCP Server 的主命令,這裡使用 .NET CLI
      "command": "dotnet",

      // 執行 dotnet 指令時所附加的參數清單
      "args": [
        "run", // 執行 dotnet run
        "--project", // 指定要執行的專案路徑
        "<RELATIVE PATH TO PROJECT DIRECTORY>" // 專案的相對路徑(請替換為實際目錄)
      ],

      // MCP Server 啟動時設定的環境變數
      // 可以讓 server 程式根據這些變數的值改變行為(如工具回傳內容)
      "env": {
        "WEATHER_CHOICES": "sunny,humid,freezing"
        // MCP 工具可以透過讀取這個環境變數來決定回應的天氣選項
      }
    }
  }
}

透過copilot 的視窗 下面的【選擇工具】,並勾選 sampleMCTServer和get_random_number


        雖然我立刻在copilot 立刻下promp 提問: 【請幫我產生1~99的亂數】,它一直跟我鬼打牆,但後來我重新啟動visual studio ,就可以正常調用MCP Server , 所以不要鐵齒,重開治百病。







參考文章: 
https://blog.logto.io/zh-TW/what-is-mcp

https://www.ibest.com.tw/news-detail/what-is-mcp/

https://learn.microsoft.com/zh-tw/dotnet/ai/quickstarts/build-mcp-server








2025年4月7日 星期一

如何透過playWright作整合測試

 

                  大家有沒有經驗,明明都寫完了程式,也都單元測試完了,但一上線就炸了,QA也都測試過了… 怎麼還是有問題,如何讓程式品質提升或讓RD就時間打怪呢… 決定就是你了【PlayWright


前提大家都有安裝
VS Code ,身為RD 這應該是必備的工具,就不多講述,如果沒安裝,直接下戴安裝即可 https://code.visualstudio.com/download

一、
在擴充點選Playwright test for VSCode








二、在工具列中輸入

> install playwright 


預設值 會支援chromium / Firefox/ WebKit, 選擇OK 即可


呼叫command line : npx playwright codegen http://測址網址


自動會開啟瀏覽器,此時可以作操作畫面,右邊的視窗會自動錄下所有操作的行為


tests\example.spec.ts 將原本的程式碼拿掉,貼上新的代碼即可

點選 左下的水瓶 à 點右箭頭,然後一切就自動化的執行你剛才所做的操作行為囉!!! 























2024年1月18日 星期四

在 ASP.NET Core 中建立 gRPC 用戶端與伺服器

 GRPC 是什麼?  有別於傳統的client 和 server 端的連線,而是持續性且高效能的連線, 連線上的架構是HTTP2 協定,使用Protocol Buffers 作為介面描述語言,連線模式,可以1 (SERVER) 對多 (CLIENT),也可雙向溝通,而一般REST 連線只能作到單向構通

一、 建立GRPC的前置作業

先安裝GRPC的專案, 如果畫面上沒有出現asp.net Core gRPC的服務時,請搜尋GRPC













選擇asp.net Core gRPC服務























按下一步,就完成了…   建立GRPC Server端

二、建立GRPC Server





















Protos/greet.proto:會定義 `Greeter` gRPC,並會用來產生 gRPC 伺服器協定

以下是範例:  


syntax = "proto3";

 option csharp_namespace = "GrpcService1";

 package greet;

 

// server的名稱為 Greeter

service Greeter {

  // Sends a greeting

  rpc SayHello (HelloRequest) returns (HelloReply);

}

 

// The request 參數 name

message HelloRequest {

  string name = 1;

}

 // The response 回傳 message 

message HelloReply {

  string message = 1;

} 

三、建立GRPC Client


這用於client 與server端 的協定,所以clint端也需要相同的.proto, 所以從server端的 Protos/greet.proto copy一份到client端 Protos路徑下













以下是client的內容 ,但與server端略有不同,

選擇.proto 按下右鍵,在 gprc stub Classes 選擇 client Only



syntax = "proto3";

 option csharp_namespace = "GrpcGreeterClient"; //要自已設定clientOnly

 package greet;

 

// server端的server名稱一致

service Greeter {

  // Sends a greeting

  rpc SayHello (HelloRequest) returns (HelloReply);

}

 

// The request message containing the user's name.

message HelloRequest {

  string name = 1;

}

 

// The response message containing the greetings.

message HelloReply {

  string message = 1;

}


四、執行結果

server 端的執行檔




















client 端的執行檔







2023年7月18日 星期二

VUE2 如何監聽DIV中的Scroll 事件

最近的案子是PO要求UI的DIV 要有捲軸,而且要使用者拉Scroll拉到底,才會讓下面checkbox 可以讓使用打勾同意,目的就是要讓使用者強迫看完整篇文章後,才能關閉這視窗… 呵呵,好喔,我們再看vue要如何做到

一、建立DIV 要有捲軸的畫面

 要加上@scroll就可以監聽div內的schroll事件了喔~ 對就是這麼簡單!!!!,如果網有眼尖發現為何有@@小老鼠,因為我用asp.net MVC 所以要再多一個@

<div id="PupupWindow" class="dialogbackground">

    <div class="PupupContent">

        <div class="panel panel-info">

            <div class="panel-heading popupsubject">

            </div>

            <div class="panel-body">

                <div contenteditable='true' class="scroll-div" @@scroll="handleBlScroll">

                    HELLO TEST ABCDE1<br />

                    HELLO TEST ABCDE2<br />

                    HELLO TEST ABCDE3<br />

                    HELLO TEST ABCDE4<br />

                    HELLO TEST ABCDE5<br />

                    HELLO TEST ABCDE6<br />

                    HELLO TEST ABCDE7<br />

                    HELLO TEST ABCDE8<br />

                    HELLO TEST ABCDE9<br />

                    HELLO TEST ABCDE10<br />

                    HELLO TEST ABCDE11<br />

                    HELLO TEST ABCDE12<br />

                    HELLO TEST ABCDE13<br />

                    HELLO TEST ABCDE14<br />

                    HELLO TEST ABCDE15<br />

                    HELLO TEST ABCDE16<br />

                </div>                            

            </div>

                <div class="panel-footer text-center">

                    <input type="checkbox" class="form-control" v-bind:disabled="!checkAgree" />同意

                    <button id="popup-check-button" class="btn btn-primary btn-lg">確認</button>

                </div>

            </div>

    </div>

</div>

 

二、建立監聽的事件

Index.Js

 

var DefaultPage = new Vue({

    el: '#app',

    filters: {  },

    mixins: [Global],

    data: { checkAgree: false },

methods: {

  handleBlScroll(e) {          

            if (e.srcElement.scrollTop + e.srcElement.offsetHeight >= e.srcElement.scrollHeight) {

// 碰到schroll的底

                this.checkAgree = true;

            } else {

                this.checkAgree = false;

            }

        }

})


測試畫面如下: