1. 为什么我会盯上 FreeCAD 加 MCP 这套组合
第一次听说 MCP 是在一个做 AI Agent 的朋友群里,有人丢了一句“现在连 CAD 都能用嘴画图了”,配了张 FreeCAD 里自动生成法兰盘的截图。我当时第一反应是怀疑——参数化建模这东西,尺寸、约束、特征顺序环环相扣,靠自然语言真能驱动?后来自己动手把 FreeCAD 的 MCP 服务跑起来,用几句话让它在 Python 控制台里建了个带倒角的方块,才确认这条路是通的。
这篇内容聊的就是FreeCAD MCP 实战:怎么把 FreeCAD 这个开源参数化 CAD 软件,通过 MCP 协议接到 AI 大模型上,让你用中文自然语言去驱动建模、改参数、跑批量脚本。核心关键词就几个——FreeCAD、MCP、CAD、AI、自然语言。它解决的是一个很具体的痛点:传统 CAD 建模要么手点工具栏,要么写 Python 脚本,前者慢、后者有学习门槛,而自然语言驱动相当于给这两条路中间架了座桥。
适合谁来参考?三类人。一是机械、结构方向的工程师,日常要出大量相似零件,想用脚本和 AI 提效;二是做 AI Agent 方向的开发者,想找一个有真实几何约束、能验证工具调用能力的落地场景;三是 CAD 初学者,想借自然语言降低上手门槛,边聊边学建模逻辑。不管你是哪类,只要机器上能装 FreeCAD、能跑 Python,这套流程就能复现。
需要先说明一点:MCP 本身是一个让 AI 模型调用外部工具和数据的协议层,它不负责“理解几何”,真正干活的是 FreeCAD 自己的 Python API。MCP 干的事,是把“用户说的一句话”翻译成“一次工具调用”,再把 FreeCAD 返回的结果喂回给模型。理解这个分工,后面配置和排错会顺很多。
2. 整体设计思路:MCP 到底在 FreeCAD 里扮演什么角色
2.1 先搞清楚 MCP 的 Host、Server、Client 三层结构
很多人一上来就被 MCP 的名词绕晕。我用一个类比讲清楚:把 AI 大模型想象成一个只会动嘴的顾问,它很聪明但手不能动;FreeCAD 是一个工具箱,里面有各种工具但没人指挥;MCP 就是那个跑腿的助理,负责把顾问的指令翻译成“去工具箱拿哪把扳手、拧几圈”,再把结果回报给顾问。
具体到技术层面,MCP 分三层:
- MCP Host:承载 AI 模型的应用,比如你用的 AI 编程工具或聊天客户端,它负责发起对话、决定什么时候调用工具。
- MCP Client:Host 内部用来和 Server 通信的模块,通常你不需要单独配置,Host 会自动管理。
- MCP Server:真正暴露工具能力的一端。在 FreeCAD 场景里,这个 Server 跑在 FreeCAD 进程内,把“创建立方体”“修改参数”“导出 STEP”这些操作注册成一个个可被调用的工具。
所以整套链路是:你在 Host 里说“帮我建一个 50 毫米的立方体”,Host 把这句话连同可用工具列表发给模型,模型决定调用create_box这个工具并填参数length=50,Client 把调用请求发给 FreeCAD 里的 Server,Server 执行 FreeCAD Python API,把结果返回,模型再用自然语言告诉你“建好了”。
提示:MCP Server 必须和 FreeCAD 跑在同一个进程或能访问 FreeCAD 的 Python 环境里,否则它拿不到
FreeCAD和Part这些模块。这是新手最容易踩的坑。
2.2 为什么选 FreeCAD 而不是别的 CAD
选 FreeCAD 做这件事,不是因为它比商业 CAD 强,而是因为它有三个别人替代不了的条件。
第一,完全开源且 Python 原生。FreeCAD 的几乎所有操作都能通过 Python 脚本完成,Part、Sketcher、Draft这些工作台都暴露了完整的 API。这意味着 MCP Server 要做的只是“把 API 包装成工具”,不需要逆向任何私有接口。
第二,参数化建模天然适合自然语言映射。参数化建模的本质是“特征加参数”,比如“拉伸一个草图,长度 20”。这种结构化的表达和自然语言的“帮我拉 20 毫米”几乎是一一对应的,模型很容易把口语翻译成参数。
第三,本地运行、数据不出机器。对于涉及产品结构、专利图纸的场景,把模型文件传到云端是很多团队不能接受的。FreeCAD 加本地 MCP Server 的组合,几何数据全程在本地,只有自然语言指令和工具调用结果在模型侧流转,可控性强得多。
2.3 方案选型:自己写 Server 还是用现成的
网上能搜到一些现成的 FreeCAD MCP 实现,但我的建议是:先跑通现成的,再按自己需求改。原因很简单,现成实现帮你解决了最麻烦的进程通信和工具注册问题,你能快速看到效果,建立信心;等你熟悉了工具注册的写法,再往里加自己的建模函数,比如公司内部的专用零件库。
自己从零写 Server 也不是不行,核心就是几件事:在 FreeCAD 的 Python 环境里启动一个通信服务,把函数注册成工具,处理调用请求。但如果你对 MCP 协议细节不熟,这一步会耗掉大量时间在调试通信上,而不是建模本身。我的做法是拿一个开源实现当骨架,把工具列表换成自己常用的操作。
3. 环境搭建:从零把 FreeCAD MCP 跑起来
3.1 FreeCAD 安装与 Python 环境确认
第一步是装 FreeCAD。官网下载对应系统的安装包即可,Windows 用户建议选带 Python 的完整安装版,不要选精简版,否则后面调用 API 会缺模块。装完之后,最关键的一步是确认 FreeCAD 自带的 Python 环境能正常导入核心模块。
打开 FreeCAD,在菜单里找到 Python 控制台(一般在“视图 - 面板”里可以调出),输入下面两行:
import FreeCAD import Part print(FreeCAD.Version())如果能看到版本号输出,说明 Python 环境没问题。这一步看着简单,但很多人卡在这里——要么装的是不带 Python 的版本,要么系统里有多个 Python 导致路径混乱。
注意:FreeCAD 用的是自己捆绑的 Python,不是你系统里的 Python。所以你在系统终端里
pip install的东西,FreeCAD 里不一定能用。反过来也一样。后面装 MCP 相关依赖时,一定要装进 FreeCAD 的 Python 环境。
3.2 MCP Server 的获取与依赖安装
拿到 MCP Server 的代码后,先看它的依赖清单。通常需要 MCP 协议的 Python SDK,可能还有pydantic之类的数据校验库。安装方式有两种:
一种是在 FreeCAD 的 Python 控制台里直接用pip安装。FreeCAD 较新版本支持在控制台执行:
import subprocess, sys subprocess.check_call([sys.executable, "-m", "pip", "install", "mcp"])另一种是找到 FreeCAD 捆绑 Python 的路径,用那个解释器在系统终端里装。Windows 下通常在安装目录的bin文件夹里,Linux 下可能是/usr/lib/freecad/bin/python。
装完之后验证一下:
import mcp print(mcp.__version__)能打印出版本号就说明依赖到位了。
3.3 把 Server 挂进 FreeCAD 并验证工具注册
接下来是把 Server 代码加载进 FreeCAD。常见做法是在 FreeCAD 的宏目录或启动脚本里加一段引导代码,让 FreeCAD 启动时自动运行 Server。也可以手动在 Python 控制台里执行 Server 的入口脚本。
加载成功后,Server 会开始监听来自 MCP Client 的连接。这时候你需要在 Host 那边配置好 Server 的连接信息,通常是一个命令加参数的形式,告诉 Host “去启动或连接这个 Server”。
验证是否成功,最直接的办法是在 Host 里问一句“你现在有哪些工具可以用”。如果模型能列出create_box、create_cylinder、export_step这类工具名,说明整条链路通了。
我实测下来,第一次配置最容易出问题的地方是路径和启动命令。Host 启动 Server 时用的工作目录可能和你手动测试时不一样,导致找不到脚本或模块。解决办法是在配置里写绝对路径,别用相对路径。
4. 核心实操:用自然语言完成一次完整建模
4.1 从一句话到一个立方体:最小可用示例
先做最简单的验证。在 Host 里输入:
帮我创建一个长宽高都是 50 毫米的立方体。
模型会调用类似create_box的工具,参数是length=50, width=50, height=50。执行成功后,FreeCAD 的 3D 视图里会出现一个立方体,模型会回复你“已创建”。
这一步的意义在于验证三件事:自然语言能被正确解析成参数、工具能被正确调用、FreeCAD 能正确执行并返回结果。三件事缺一不可。
如果没成功,按这个顺序排查:先看 Host 有没有发出工具调用请求,再看 Server 有没有收到,最后看 FreeCAD 控制台有没有报错。报错信息通常会告诉你缺哪个模块或哪个参数类型不对。
4.2 参数化修改:让 AI 帮你改尺寸而不是重建
真正体现价值的是修改,而不是从零创建。比如你接着说:
把这个立方体的高度改成 80 毫米。
这里有个关键点:模型需要知道“这个立方体”指的是哪个对象。好的 MCP Server 实现会维护一个对象引用机制,比如给每个创建的对象一个名字或 ID,模型在后续对话里用这个名字来引用。
如果 Server 没做这个机制,模型可能会重新创建一个新立方体,而不是修改旧的。这是很多简易实现的通病。我的做法是在 Server 里加一个对象注册表,每次创建对象时记录名字,修改时按名字查找。
# 简化示意:对象注册与查找 _object_registry = {} def create_box(name, length, width, height): box = Part.makeBox(length, width, height) obj = FreeCAD.ActiveDocument.addObject("Part::Feature", name) obj.Shape = box _object_registry[name] = obj FreeCAD.ActiveDocument.recompute() return f"已创建 {name}" def resize_box(name, height): obj = _object_registry.get(name) if obj is None: return f"找不到对象 {name}" # 实际修改逻辑需根据建模方式调整 return f"已修改 {name} 的高度"提示:参数化修改的难点在于 FreeCAD 里对象的建模历史。如果是用 Part 工作台直接生成的形状,改参数相对简单;如果是 Sketcher 草图加 Pad 特征,改的是草图约束或 Pad 的长度属性。Server 要针对不同建模方式写不同的修改函数。
4.3 批量操作:一次对话生成一组零件
自然语言驱动最爽的场景是批量。比如:
帮我生成 5 个圆柱,直径分别是 10、20、30、40、50 毫米,高度都是 100 毫米,沿 X 轴等距排列。
这句话里包含了循环、参数列表和位置计算。模型会把它拆成多次工具调用,或者调用一个支持批量参数的函数。如果 Server 只提供了单个创建函数,模型可能会连续调用 5 次,每次填不同参数,再调用移动函数调整位置。
我更推荐在 Server 里直接提供批量函数,把循环和排列逻辑放在 Python 侧,减少模型调用次数,也降低出错概率。因为模型每次调用都有失败可能,调用次数越多,整体成功率越低。
def create_cylinder_row(diameters, height, spacing): results = [] for i, d in enumerate(diameters): cyl = Part.makeCylinder(d / 2.0, height) obj = FreeCAD.ActiveDocument.addObject("Part::Feature", f"Cyl_{i}") obj.Shape = cyl obj.Placement.Base.x = i * spacing results.append(f"Cyl_{i}") FreeCAD.ActiveDocument.recompute() return f"已创建 {len(results)} 个圆柱"4.4 导出与后续处理:把 AI 建好的模型接进工作流
建完模型总要用起来。常见的后续操作是导出 STEP 或 STL,方便进 CAM 或 3D 打印。在 Host 里说:
把刚才那排圆柱导出成 STEP 文件,放到桌面。
模型会调用导出工具,Server 执行Part.export或Mesh.export。这里要注意文件路径的写法,跨平台时路径分隔符不一样,最好在 Server 里做一次规范化处理。
导出之后,你还可以继续让 AI 帮你做检查,比如“统计一下当前文档里有多少个对象”“列出所有对象的体积”。这些只读操作风险低,很适合让 AI 频繁调用,帮你快速了解模型状态。
5. 常见问题与排查技巧实录
5.1 工具调用失败:从报错信息倒推问题
工具调用失败是最常见的问题,报错信息通常分几类。第一类是模块导入失败,比如No module named 'Part',说明 Server 没跑在 FreeCAD 的 Python 环境里。第二类是参数类型错误,比如传了字符串给需要浮点数的参数,这通常是模型填参数时没做类型转换。第三类是对象不存在,比如修改一个还没创建的对象。
我的排查习惯是:先在 FreeCAD 控制台手动执行一遍对应的 Python 代码,确认代码本身没问题;再看 Server 日志里收到的参数是什么;最后对比手动执行和工具调用的差异。大部分问题出在参数上,而不是 FreeCAD 本身。
5.2 模型“幻觉”出不存在的工具或参数
模型有时候会调用一个 Server 根本没注册的工具,或者给一个函数填了它不支持的参数。这不是模型坏了,而是它在“猜”。解决办法有两个:一是把工具描述写清楚,包括每个参数的类型、单位、取值范围;二是在 Server 侧做严格校验,收到不认识的工具或参数直接返回明确错误,让模型知道错了并重试。
工具描述的质量直接决定调用成功率。我见过把描述写成“创建一个盒子”的,模型根本不知道参数叫什么。好的描述应该像这样:
create_box: 创建一个长方体 参数: length (float): 长度,单位毫米 width (float): 宽度,单位毫米 height (float): 高度,单位毫米 name (str, 可选): 对象名称 返回: 创建结果描述5.3 中文指令解析偏差与单位问题
中文里“五十毫米”和“50mm”模型都能理解,但“五公分”这种口语表达有时会被解析成 5 而不是 50。单位混淆是高频问题,尤其是毫米和厘米混用的时候。我的做法是在 Server 的工具描述里明确写“所有长度单位均为毫米”,并在系统提示里也强调一遍。
另外,中文的“长宽高”对应到参数时,模型偶尔会把顺序搞反。如果对方向有要求,最好在指令里说清楚“X 方向长度、Y 方向宽度、Z 方向高度”,减少歧义。
5.4 性能与稳定性:大批量操作时的注意事项
一次让 AI 创建几百个对象,FreeCAD 的 recompute 会变慢,甚至卡死界面。我的经验是:批量操作时先在 Server 侧关闭自动 recompute,全部创建完再统一 recompute 一次。另外,频繁的跨进程通信也有开销,能合并的调用尽量合并。
还有一个稳定性技巧:给每个工具调用加超时和异常捕获。FreeCAD 的某些操作在特定几何条件下会抛异常,如果不捕获,整个 Server 可能挂掉。捕获后返回错误信息给模型,模型可以换个方式重试。
| 问题现象 | 可能原因 | 排查方向 |
|---|---|---|
| 工具列表为空 | Server 未启动或连接失败 | 检查 Host 配置的启动命令和路径 |
| 调用报模块缺失 | Python 环境不对 | 确认 Server 跑在 FreeCAD 的 Python 里 |
| 参数类型错误 | 模型未做类型转换 | 在 Server 侧强制转换并校验 |
| 对象找不到 | 引用机制缺失 | 增加对象注册表,用名字引用 |
| 界面卡死 | 批量操作未优化 | 关闭自动 recompute,批量后统一刷新 |
| 中文单位解析错 | 口语表达歧义 | 工具描述和系统提示里明确单位 |
6. 进阶玩法:把 MCP 接进更大的自动化链路
6.1 和 AI Agent 结合做多步任务
单次对话建一个零件只是起点。真正的价值在于让 AI Agent 做多步任务,比如“读取这个 CSV 里的尺寸列表,为每一行生成一个零件,导出 STEP,再生成一份清单”。这种任务里,MCP 提供的是“手”,Agent 提供的是“脑”和“记忆”。
实现上,Agent 会先调用文件读取工具拿到 CSV 内容,再循环调用 FreeCAD 的建模工具,最后调用导出工具。整个过程你只需要给一个目标,中间步骤由 Agent 规划。这对 Server 的要求是工具要足够原子化,每个工具只做一件事,方便 Agent 组合。
6.2 本地模型部署下的隐私与可控性
如果模型文件涉及未公开的产品结构,用云端模型始终有顾虑。这时候可以把模型换成本地部署的开源大模型,MCP 链路不变,只是 Host 从云端应用换成本地推理服务。本地模型在工具调用能力上可能弱一些,但通过优化工具描述和减少单次任务复杂度,实测也能跑通大部分建模场景。
本地部署的另一个好处是响应稳定,不受网络波动影响。代价是需要一定的显卡资源,以及对模型做工具调用能力的微调或提示词优化。
6.3 把常用建模逻辑沉淀成自定义工具
用久了你会发现,某些建模操作反复出现,比如“生成带倒角的法兰”“生成标准齿轮”。与其每次让模型从头拼参数,不如把这些逻辑封装成 Server 里的自定义工具,模型只需要填几个关键尺寸。
这样做的好处是:建模逻辑固化在 Python 里,稳定可靠;模型只负责理解你的意图和填参数,出错概率大幅降低。我目前维护了一个小工具库,涵盖常用的标准件生成、批量阵列、格式转换,日常建模效率比纯手点快了不止一个量级。
7. 我在实际使用中踩过的坑和几点体会
第一个坑是环境隔离。我一开始在系统 Python 里装依赖,结果 FreeCAD 里死活导入不了,折腾了半天才意识到要用 FreeCAD 自带的 Python。这个坑几乎每个新手都会踩,记住一句话:FreeCAD 的事,就在 FreeCAD 的 Python 里办。
第二个坑是工具描述太随意。早期我写的工具描述很简略,模型经常填错参数。后来把每个参数的类型、单位、示例都写清楚,调用成功率从大概六成提到了九成以上。工具描述就是给模型看的说明书,写得越清楚,它越不容易犯错。
第三个体会是别指望一次对话搞定复杂模型。自然语言驱动适合做参数化、批量化的任务,不适合从零设计一个复杂装配体。我的用法是:复杂结构还是手动搭骨架,把重复性的、参数明确的部分交给 AI 批量生成。分工明确,效率最高。
最后一个建议:从只读操作开始建立信任。刚配好环境时,先让 AI 做“列出对象”“统计体积”这类不会改坏文件的操作,确认链路稳定、模型理解准确,再逐步放开写操作。这样即使出问题,也不会把辛苦建的模型搞乱。