当前位置: 首页 > news >正文

给个人程序加上MCP翅膀

背景

最近MCP这个词真是到处都是,看起来特别高大上。我平时没事的时候也一直在关注这方面的技术,知道它是怎么一回事,也懂该怎么去实现。但可惜一直抽不出时间来自己动手搞一个MCP服务。网上关于MCP的教程一搜一大把,但基本上都是些简单的Demo,而且大部分还是拿天气查询来做例子的,没什么新意,看多了都让人觉得无聊。

MCP服务器实现语言有pythonTypeScriptJavaC#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服务端
  1. 在个人的C#程序下打开终端,输入命令
## 如果安装不了,可能要给nuget更换国内镜像
dotnet add package ModelContextProtocol --prerelease
  1. 让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}";}}}
} 
  1. 在程序主程入口添加
  private void StartMcpServerInBackground(){Task.Run(async () =>{var builder = Host.CreateEmptyApplicationBuilder(settings: null);builder.Services.AddMcpServer().WithStdioServerTransport().WithToolsFromAssembly();await builder.Build().RunAsync();});}
  1. 调整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

相关文章:

  • 基于labview的声音采集、存储、处理
  • GitHub 趋势日报 (2025年05月17日)
  • C++(243~263)STL常用算法、遍历算法(for_each,Transform)、查找算法、拷贝和替换、常用算术生成,常用集合算法。
  • C++学习:六个月从基础到就业——C++17:if/switch初始化语句
  • 【随机过程】贝叶斯估计
  • 【计算机网络】第一章:计算机网络体系结构
  • TIMER免疫浸润分析
  • 轻量级视频剪辑方案:FFmpeg图形化工具体验
  • 国内人工智能行业研究报告 投资要点
  • Spring Cloud 技术实战
  • 非线性1 修改
  • 23种设计模式解释+记忆
  • 5.18本日总结
  • VMware虚拟机磁盘扩容与LVM分区操作指南
  • GC全场景分析
  • Redis进阶知识
  • 服务端高并发分布式结构演进之路
  • 51单片机,两路倒计时,LCD1602 ,Proteus仿真
  • ubuntu的虚拟机上的网络图标没有了
  • Go语言中函数 vs 方法
  • 中方是否担忧美国主权信用评级下调?外交部:美国应采取负责任的政策措施
  • 俄乌刚谈完美国便筹划与两国领导人通话,目的几何?
  • “上海-日喀则”援藏入境旅游包机在沪首航
  • 解读|战国子弹库帛书漂泊海外79年今归国,追索仍将继续
  • 多少Moreless:向世界展示现代中式家具的生活美学
  • 新闻1+1丨强对流天气频繁组团来袭,该如何更好应对?