背景
最近MCP這個詞真是到處都是,看起來特別高大上。我平時沒事的時候也一直在關注這方面的技術,知道它是怎么一回事,也懂該怎么去實現。但可惜一直抽不出時間來自己動手搞一個MCP服務。網上關于MCP的教程一搜一大把,但基本上都是些簡單的Demo,而且大部分還是拿天氣查詢來做例子的,沒什么新意,看多了都讓人覺得無聊。
MCP服務器實現語言有python
、TypeScript
、Java
、C#
、Swift
這幾種語言,好家伙,就是沒有C++,但是我大部分底層算法都是基于C++實現。基于此,我只能將我C++的程序封裝成上述的語言,個人平時更多的還是封裝成C#(之前實現的自主CAD程序已經可以在C#上調用),那就基于C#實現自己的MCP服務器吧。
基于MCP服務我想在自己的CAD程序中加入幾個功能,分別是打開Dwg文件
、繪制圖形
、修改顏色
,畫話不多說,直接上手。
C# 官方MCP 概述
在.NET 生態系統中,除了官方提供的 C# MCP SDK 外,還有一些其他與 MCP 相關的技術,比如 MCPSharp 和 mcpdotnet 等。這些工具也為開發者提供了豐富的功能和支持。MCPSharp 是一個專為.NET 設計的庫,旨在幫助開發者輕松構建符合 Model Context Protocol(MCP)標準的服務器和客戶端。它提供了創建合規工具和函數的功能,還支持連接現有的 MCP 服務器,甚至可以將.NET 方法直接暴露為 MCP 端點。而 mcpdotnet 則是一個基于.NET 的模型上下文協議(MCP)實現,能夠讓.NET 應用程序方便地與 MCP 客戶端和服務器進行交互。
不過,相比于這些非官方的實現,C# 官方 MCP SDK 有著顯著的優勢,尤其是在標準化和兼容性方面。作為官方推出的工具,C# MCP SDK 嚴格遵循 MCP 協議標準,確保了不同應用程序和服務之間的交互既一致又可靠。而一些非官方實現可能在某些細節上與標準存在偏差,這可能會在集成過程中引發問題。例如,在與不同的 AI 模型集成時,官方 SDK 能夠更準確地保證數據傳輸和工具調用的可靠性,從而減少因協議不一致而導致的錯誤。
此外,在兼容性方面,C# 官方 MCP SDK 經過了全面的測試和優化,能夠與各種主流的.NET 框架和開發工具無縫協作。無論你使用的是最新版本的.NET,還是其他常用的開發工具,官方 SDK 都能輕松集成,為開發者省去不少麻煩。相比之下,其他相關技術在兼容性上可能會有一定的局限性,有時需要開發者額外花時間解決兼容性問題。因此,選擇官方 SDK 不僅能讓開發過程更加順暢,還能提升項目的穩定性和效率。
MCP服務實戰
編寫C# MCP服務端
- 在個人的C#程序下打開終端,輸入命令
## 如果安裝不了,可能要給nuget更換國內鏡像
dotnet add package ModelContextProtocol --prerelease
- 讓cursor給我們編寫mcp服務
@https://github.com/ModelContextProtocol/csharp-sdk 基于這份開源庫說明,編寫一個CADServer類,實現mcp服務,添加一個打開dwg文件的接口
using ModelContextProtocol.Server;
using mx;
using System.ComponentModel;
using System.IO;
using System.Linq;namespace CimEditor.Common
{[McpServerToolType]public static class CADServer{[McpServerTool, Description("打開指定路徑的DWG文件,并返回是否成功")]public static string OpenDwgFile([Description("DWG文件的完整路徑")] string filePath){if (!File.Exists(filePath)){return $"文件不存在: {filePath}";}try{var graph = CimEditor.Common.Project.Instance.Graph;graph.LoadDwg(filePath);return $"DWG文件已成功打開: {filePath}";}catch (System.Exception ex){return $"打開DWG文件失敗: {ex.Message}";}}[McpServerTool, Description("繪制多段線,points格式為'x1,y1;x2,y2;...',isClosed表示是否閉合")]public static string DrawPolyline([Description("多段線點坐標,格式為'x1,y1;x2,y2;...' ")] string points,[Description("是否閉合")] bool isClosed){try{var graph = CimEditor.Common.Project.Instance.Graph;// 假設Graph有DrawPolyline方法,參數為點數組和是否閉合var pts = points.Split(';').Select(p => {var xy = p.Split(',');return new XDPoint(double.Parse(xy[0]),double.Parse(xy[1]));}).ToList();var polyline = XDPolylineShape.CreateObject();polyline.SetVertices(new XDPoints(pts));polyline.SetClosed(isClosed);graph.AddShape(polyline);return $"多段線已成功繪制,共{pts.Count}個點,閉合:{isClosed}";}catch (System.Exception ex){return $"繪制多段線失敗: {ex.Message}";}}[McpServerTool, Description("繪制圓,center格式為'x,y',radius為半徑")]public static string DrawCircle([Description("圓心坐標,格式為'x,y'")] string center,[Description("半徑")] double radius){try{var graph = CimEditor.Common.Project.Instance.Graph;var xy = center.Split(',');double x = double.Parse(xy[0]);double y = double.Parse(xy[1]);var circle = XDCircleShape.CreateObject(new XDPoint(x, y), radius);graph.AddShape(circle);return $"圓已成功繪制,圓心:({x},{y}), 半徑:{radius}";}catch (System.Exception ex){return $"繪制圓失敗: {ex.Message}";}}[McpServerTool, Description("繪制文字,position格式為'x,y',text為內容,fontSize為字號")]public static string DrawText([Description("文字位置,格式為'x,y'")] string position,[Description("文字內容")] string text,[Description("字號")] double fontSize){try{var graph = CimEditor.Common.Project.Instance.Graph;var xy = position.Split(',');double x = double.Parse(xy[0]);double y = double.Parse(xy[1]);var text_shape = XDTextShape.CreateObject();text_shape.Position = new XDPoint(x, y);text_shape.TextSize = fontSize;return $"文字已成功繪制,位置:({x},{y}), 內容:'{text}', 字號:{fontSize}";}catch (System.Exception ex){return $"繪制文字失敗: {ex.Message}";}}[McpServerTool, Description("設置當前選中圖元的顏色,color格式為'R,G,B'")]public static string SetSelectedShapesColor([Description("顏色,格式為'R,G,B'")] string color){try{var graph = CimEditor.Common.Project.Instance.Graph;var rgb = color.Split(',');if (rgb.Length != 3)return "顏色格式錯誤,應為'R,G,B'";int r = int.Parse(rgb[0]);int g = int.Parse(rgb[1]);int b = int.Parse(rgb[2]);var selected_cells = graph.GetSelectionCells(); // 假設有此方法int count = 0;foreach (var cell in selected_cells){// 假設shape有SetColor方法,參數為r,g,bcell.Geometry.SetColor(new XDColor(r, g, b));count++;}return $"已成功修改{count}個選中圖元的顏色為({r},{g},{b})";}catch (System.Exception ex){return $"修改顏色失敗: {ex.Message}";}}}
}
- 在程序主程入口添加
private void StartMcpServerInBackground(){Task.Run(async () =>{var builder = Host.CreateEmptyApplicationBuilder(settings: null);builder.Services.AddMcpServer().WithStdioServerTransport().WithToolsFromAssembly();await builder.Build().RunAsync();});}
- 調整AI生成不合理的地方,編譯通過即可。
使用Cursor配置mcp客戶端。
{"mcpServers": {"DwgServer": {"command": "D:\\code\\cad\\cimediter\\bin\\CimEditor.exe","args": [],"cwd": "D:\\code\\cad\\cimediter\\bin","env": {"DOTNET_ENVIRONMENT": "Development"}}}
}
驗證成果
mcp.mp4