给个人程序加上MCP翅膀
背景
最近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