从 LINQPad 到 MCP:打造 CRM 智能助手的实战记录

从 LINQPad 到 MCP:打造 CRM 智能助手的实战记录

2026 年 7 月 30 日 · 约 15 分钟阅读

一、缘起

日常工作涉及 Dynamics 365 CRM 的开发和运维,经常需要查询实体元数据、管理解决方案、迁移组件。这些操作传统上依赖 LINQPad 脚本------一个强大的 .NET 交互式编程工具。但随着 AI 编程助手(如 OpenCode)的普及,一个想法自然浮现:能不能让 AI 直接帮我查 CRM 实体、管理解决方案?

答案是肯定的。MCP(Model Context Protocol)应运而生,它定义了 AI 客户端与工具服务器之间的通信标准。我们只需要把 LINQPad 脚本包装成 MCP 服务器,AI 就能通过标准接口调用这些能力。
📌 什么是 MCP?

MCP(Model Context Protocol)是一种开放协议,允许 AI 模型通过标准化的接口与外部工具和数据源交互。它类似于 AI 世界的 USB 协议------定义好接口,工具就能即插即用。OpenCode、Claude Desktop 等客户端都支持 MCP。

二、从 LINQPad 脚本开始

在开始 MCP 之前,我们已经积累了大量 LINQPad 脚本。其中最核心的是 A生成数据字典.linq,它能够:

  • 连接 CRM 服务(通过 Dynamic365.GetService_YFT_Dev()
  • 查询所有实体的元数据
  • 遍历字段,解析选项集、关联、类型等信息
  • 生成 Markdown 和带大纲侧边栏的 HTML 数据字典

基于这个脚本,我们首先开发了 CRM 实体属性查看器------一个 WinForms 桌面应用,左侧实体列表、右侧字段详情,支持搜索、导出等功能。但用户反馈:"我不喜欢在 LINQPad 里直接 Dump 控件"。

于是我们改为独立的 WinForms 窗体,用 Form.ShowDialog() 展示,体验接近 Visual Studio 的解决方案管理器。这个过程中遇到了几个典型问题:
⚠️ 坑 1:WinForms 控件序列化失败

Dump()TableLayoutPanel 等复杂容器控件会抛出 SerializationException。解决方法是:要么单独 Dump 每个控件,要么改用 TabControl 作为容器,或者干脆用独立的 Form。
⚠️ 坑 2:Label 命名冲突

System.Windows.Forms.LabelMicrosoft.Xrm.Sdk.Label 存在歧义。修复:方法参数使用完全限定名 Microsoft.Xrm.Sdk.Label,WinForms 控件则用 System.Windows.Forms.Label
⚠️ 坑 3:Invoke 必须在窗口句柄创建后调用

Task.Run 的回调中调用 Control.Invoke,如果控件尚未渲染,会抛出异常。解决方案:添加 SafeInvoke 方法检查 IsHandleCreated,或使用 Timer 延迟启动异步操作。

三、第一个 MCP 服务器:CRM 实体查询

学会了 WinForms 控件的各种坑之后,我们决定转向 MCP 方案。MCP 服务器通过 stdio(标准输入/输出)与 AI 客户端通信,使用 JSON-RPC 2.0 协议。这意味着:

  • AI 客户端通过 stdin 发送 JSON 请求
  • 服务器处理请求,通过 stdout 返回 JSON 响应
  • 完全不需要图形界面

第一个 MCP 服务器 CRM_MCP_Server.linq 提供了四个工具:

工具名称 功能 参数
list_entities 列出实体,支持搜索过滤 search(可选)
get_entity_fields 获取实体字段详情 entity_name(必填)
get_entity_info 获取实体元数据概要 entity_name(必填)
search_entities 按关键词搜索实体 keyword(必填)

在 OpenCode 中配置 MCP 服务器非常简单,只需在 opencode.json 中添加:

复制代码
// opencode.json
{
  "mcp": {
    "crm-entity": {
      "type": "local",
      "command": [
        "D:\\...\\lprun.exe",
        "-format=text",
        "D:\\...\\CRM_MCP_Server.linq"
      ],
      "enabled": true
    }
  }
}

配置完成后,AI 就可以直接调用这些工具。例如:"查询 Case 相关的实体有多少个"------AI 会调用 search_entities(keyword="case"),返回 34 个匹配实体。
✅ 实战验证

通过 MCP 服务器,AI 成功查询到"非标差价"实体的逻辑名为 new_nonstandardpricedifference,并展示了其 35 个字段的详细信息,包括 Base Ean、Cost Adder、Resale Adder 等业务字段,以及 State/Status 选项集的值。

四、第二个 MCP 服务器:解决方案管理

实体查询成功后,我们扩展了 MCP 的能力,开发了 CRM_Solution_MCP_Server.linq,功能涵盖:

工具名称 功能
list_solutions 查询解决方案列表(倒序,默认 50 个)
get_today_solution 获取当日解决方案(YFT_20260730)是否存在
create_solution 创建当日解决方案
add_component 添加组件(Web 资源/程序集/步骤/实体等)
remove_component 从解决方案中移除组件
search_components 搜索可添加的组件
migrate_to_uat 迁移解决方案到 UAT 环境
migrate_to_prod 迁移解决方案到 PROD 环境
get_solution_components 查询解决方案中的组件列表

这个服务器的实现复用了现有 LINQPad 脚本中的 Solution 类,包括创建解决方案、导出/导入解决方案、轮询异步作业等逻辑。最复杂的部分是迁移功能,它需要:

  1. 确保解决方案存在------如果不存在则自动创建
  2. 导出------从 DEV 环境导出为 .zip 文件
  3. 导入 ------通过 ExecuteAsync 提交异步导入任务
  4. 轮询------每 5 秒检查一次导入状态
  5. 发布 ------导入成功后提交 PublishAllXml 请求

⚠️ 坑 4:NuGet 包引用与编译问题

在 LINQPad 5 中,通过 lprun -compileonly 编译时,NuGet 包可能不会自动解析。更严重的是,ExportSolutionRequest 等类型在 Microsoft.Crm.Sdk.Messages 命名空间中,但 ExecuteAsyncRequest 却在 Microsoft.Xrm.Sdk.Messages 中。最终我们使用 Microsoft.CrmSdk.XrmTooling.CoreAssembly NuGet 包,并避免使用 $ 字符串插值(LINQPad 5 的编译器对中文 + 插值的兼容性有问题),改用 + 拼接。

五、Skill:把经验固化下来

随着多个脚本和 MCP 服务器的开发,我们创建了 LINQPad 调试 Skill,用于指导 AI 在涉及 LINQPad 5 脚本和 Dynamics 365 CRM 时的行为。Skill 包含了:

  • 环境信息------LINQPad 版本、安装路径、扩展脚本位置
  • 编译检查命令 ------lprun -compileonly
  • 运行时测试命令 ------lprun -format=text
  • 可用 UI 控件------WinForms 控件直接 Dump、Util 辅助方法
  • 常见编译错误及修复------Label 歧义、序列化失败、丢弃参数不支持等
  • 组织服务连接注意事项 ------使用已有的 Dynamic365.GetService_YFT_Dev()
  • MCP 服务器说明------实体查询和解决方案管理两个 MCP 服务器的配置和使用

Skill 的核心价值在于:让 AI 知道"这个项目有哪些工具、怎么用、有哪些坑"。当 AI 需要编写新的 LINQPad 脚本时,Skill 提供了完整的上下文,避免重复踩坑。

六、架构总结

整个系统的架构如下:

复制代码
┌─────────────────────────────────────────────────────┐
│                   AI 客户端 (OpenCode)                │
│  ┌─────────────────────────────────────────────────┐ │
│  │  MCP Client (发起 JSON-RPC 请求)               │ │
│  └──────────────┬──────────────────────────────────┘ │
└─────────────────┼────────────────────────────────────┘
                  │ stdin / stdout (JSON-RPC 2.0)
    ┌─────────────┼──────────────┐
    │             │              │
    ▼             ▼              ▼
┌─────────┐ ┌──────────┐ ┌──────────────┐
│ CRM     │ │ CRM      │ │ 其他 MCP     │
│ 实体查询 │ │ 解决方案  │ │ 服务器...    │
│ MCP     │ │ MCP      │ │              │
│ 服务器   │ │ 服务器   │ │              │
└────┬────┘ └────┬─────┘ └──────────────┘
     │           │
     ▼           ▼
┌─────────────────────────────────────────┐
│  lprun.exe (LINQPad 命令行运行器)        │
│  ┌─────────────────────────────────────┐ │
│  │  Dynamic365.GetService_YFT_Dev()    │ │
│  │  → IOrganizationService             │ │
│  │  → RetrieveAllEntitiesRequest       │ │
│  │  → ExportSolutionRequest            │ │
│  │  → AddSolutionComponentRequest      │ │
│  └─────────────────────────────────────┘ │
└─────────────────────────────────────────┘
     │
     ▼
┌─────────────────────────────────────────┐
│  Dynamics 365 CRM (开发/UAT/生产)        │
└─────────────────────────────────────────┘

七、经验与教训

7.1 技术选型

  • LINQPad 5 是快速原型开发的利器,但 C# 版本较旧(约 C# 6),不支持 ValueTuple丢弃参数 等新语法
  • MCP 协议简单高效,stdio 传输方式适合命令行工具,不需要额外的网络配置
  • WinForms 在 LINQPad 中可以作为独立窗体运行,体验接近原生桌面应用

7.2 踩坑清单

# 问题 解决
1 Label 命名歧义 使用完全限定名
2 WinForms 序列化失败 改用独立 Form 或分开 Dump
3 Invoke 窗口句柄未创建 SafeInvoke + IsHandleCreated 检查
4 NuGet 包编译不通过 使用 Microsoft.CrmSdk.XrmTooling.CoreAssembly
5 $ 字符串插值 + 中文兼容问题 改用 + 拼接
6 MCP 中文乱码 设置 Console.InputEncodingOutputEncoding 为 UTF-8

7.3 最佳实践

  • 不要重复造轮子 ------项目中已有 Dynamic365 类和 Solution 类,直接复用
  • 编译检查是底线 ------每次修改后运行 lprun -compileonly,避免运行时才发现语法错误
  • 文本模式测试 ------lprun -format=text 可以快速验证运行时是否有异常
  • Skill 是团队的记忆------把踩过的坑、环境信息、常用命令都写在 Skill 里,AI 和人类都能受益

八、未来展望

目前我们已经有两个 MCP 服务器在运行,覆盖了 CRM 实体查询和解决方案管理两大场景。接下来可以考虑:

  • Web 资源管理------自动发布前端代码到 CRM
  • 数据迁移------Excel 导入导出、数据清洗
  • 自动化测试 ------调用 CRM 的 WhoAmI 等基础 API 验证环境连通性
  • 多环境批量操作------一键同步 DEV → UAT → PROD

MCP 生态正在快速发展。从 OpenCode 到 Claude Desktop,越来越多的 AI 客户端支持 MCP 协议。而 LINQPad 作为 .NET 生态中最灵活的脚本工具,与 MCP 的结合为 CRM 开发运维提供了全新的可能性。
🔑 核心感悟

**AI 不是替代开发者,而是放大开发者的能力。**MCP 服务器就像给 AI 装上了一双"手"------它能看到 CRM 的数据、能操作解决方案、能执行迁移。而我们要做的,就是定义好这双手能做哪些事情,以及如何正确地做。Skill 就是这份"使用说明书"。
© 2026 · 基于 LINQPad 5 + Dynamics 365 CRM 的 MCP 实战记录

相关推荐
久久学姐2 小时前
基础转码学 AI:Java+Python 双语言入门,3 个月可落地实战项目
java·python·ai·转码·实战项目
武子康4 小时前
MCP 2026-07-28 无状态核心之后:身份、任务、幂等与审计状态到底放在哪里?
人工智能·llm·mcp
Python私教4 小时前
我只写了一个 add 工具,终于把 MCP 的 Host、Client、Server 跑明白了
python·ai编程·mcp
曦尧4 小时前
Pascal Editor:基于 React Three Fiber + WebGPU 的开源浏览器端 3D 建筑编辑器深度解析
ai·自动化
FIT2CLOUD飞致云4 小时前
移动端审批功能上线,导入功能持续增强,Cordys CRM发布v1.8.0版本
ai·开源·crm·销售管理·ai crm·cordys crm
奋飛5 小时前
AI 应用工程:Tool、MCP、Skill 与 Workflow 如何接入 Agent?——搭建一个可运行的需求影响面分析 Agent
agent·workflow·skill·tool·mcp
曦尧6 小时前
用版本化 CSV + Liquibase `loadUpdateData` 安全管理数据库参考数据回滚
ai·自动化
俊哥V7 小时前
AI一周事件 · 2026-07-22 至 2026-07-28
人工智能·ai
人间凡尔赛7 小时前
2026年AI编程新范式:从Copilot到Agentic Coding的实战指南
ai·编程·agent·工具·效率