docs: cad-mcp-aec.md 跟进配置改动(mcp_config.json / add_aec_* 命名)
- 工程结构里的描述文件改成 mcp_config.json(运行期配置,cad_mcp_frame 直接读); - 工具清单改用新名字(query_aec_entities / get_aec_entity_detail / add_aec_*), 并说明点用 [x,y] 数组、颜色用 color(ACI)这些与既有工具一致的约定; - 部署章节改成"拷 mcp_config.json 到 arx 同目录"两步,并说明 backend 字段 (type/dll_name/factory_function)与 EXPORT_MCP_TOOL 的对应关系; - 实测表更新为用 mcp_config.json 的这轮结果; - 已知限制补一条:配置里有 10 个工具在当前 cad_mcp_plugins.dll 里没有工厂函数。
This commit is contained in:
1 parent
4f1ea72e4e
commit
c5f9dc6ed0
1 file changed
+64
-45
+64
-45
@@ -13,9 +13,9 @@ SourceCode/Code2026/cad_mcp_aec/
|
||||
├── StdAfx.h / StdAfx.cpp 与 cad_mcp_plugins 同款 MFC 预处理头
|
||||
├── mcp_aec.cpp 入口:EXPORT_MCP_PLUGIN_VERSION()(导出 SDK 版本数据符号)
|
||||
├── aec_mcp_common.h/.cpp 参数解析、handle<->ObjectId、文档锁、结果信封
|
||||
├── aec_mcp_entity_tools.cpp 5 个 create_* + 5 个 update_*
|
||||
├── aec_mcp_query.cpp list_aec_entities / get_aec_entity
|
||||
└── cad-mcp-aec.json 工具描述(合到运行期 cad-mcp-frame.json 的 tools 数组里)
|
||||
├── aec_mcp_entity_tools.cpp 5 个 add_aec_* + 5 个 update_aec_*
|
||||
├── aec_mcp_query.cpp query_aec_entities / get_aec_entity_detail
|
||||
└── mcp_config.json 运行期配置(28 个既有工具 + 本插件的 12 个,cad_mcp_frame 直接读)
|
||||
```
|
||||
|
||||
顶层 `cmakelists.txt` 里挂在 `cad_mcp_frame` 同一处:
|
||||
@@ -46,15 +46,18 @@ if (IS_ZWCAD OR CAD_SDK_VERSION GREATER_EQUAL 20)
|
||||
|
||||
## 3. 工具清单(12 个)
|
||||
|
||||
工具名和参数都按仓库既有工具的写法(`add_line` / `query_entities` / `get_entity_detail`):
|
||||
**动词_名词、点用 `[x,y]` 或 `[x,y,z]` 数组、颜色用 `color`(ACI,256=ByLayer)**。
|
||||
|
||||
| 工具 | 作用 | 关键参数 |
|
||||
| --- | --- | --- |
|
||||
| `list_aec_entities` | 列出管道/墙/板/柱/梁(handle、类型、图层、起终点、包围盒) | `type`(all/pipe/wall/slab/column/beam)、`space`、`limit`、`offset` |
|
||||
| `get_aec_entity` | 按 handle 取详细参数 | `handle` |
|
||||
| `create_aec_pipe` / `update_aec_pipe` | 建/改管道(`AecDbEwPipe`) | `start`/`end`、`dn_mm`、`od_mm`、`wall_thickness_mm`、`system`、`material`、`color_index`、`layer` |
|
||||
| `create_aec_wall` / `update_aec_wall` | 建/改墙(`AecDbXWall`) | `start`/`end`、`thickness`、`height`、`bottom_elevation`、`align`(left/center/right) |
|
||||
| `create_aec_slab` / `update_aec_slab` | 建/改板(`AecDbXSlab`) | `points`([[x,y],...])、`thickness`、`bottom_elevation`、`center` |
|
||||
| `create_aec_column` / `update_aec_column` | 建/改柱(`AecDbColumn`) | `position`、`height`、`length`、`width`、`rotation_deg` |
|
||||
| `create_aec_beam` / `update_aec_beam` | 建/改梁(`AecDbBeam`) | `start`/`end`、`width`、`height` |
|
||||
| `query_aec_entities` | 列出管道/墙/板/柱/梁(handle、类型、图层、起终点、包围盒),分页 | `type`(all/pipe/wall/slab/column/beam)、`space`、`limit`、`offset` |
|
||||
| `get_aec_entity_detail` | 按 handle 取详细参数 | `handle` |
|
||||
| `add_aec_pipe` / `update_aec_pipe` | 建/改管道(`AecDbEwPipe`) | `start`/`end`、`dn_mm`、`od_mm`、`wall_thickness_mm`、`system`、`material`、`color`、`layer`、`space` |
|
||||
| `add_aec_wall` / `update_aec_wall` | 建/改墙(`AecDbXWall`) | `start`/`end`、`thickness`、`height`、`bottom_elevation`、`align`(left/center/right) |
|
||||
| `add_aec_slab` / `update_aec_slab` | 建/改板(`AecDbXSlab`) | `points`([[x,y],...])、`thickness`、`bottom_elevation`、`center` |
|
||||
| `add_aec_column` / `update_aec_column` | 建/改柱(`AecDbColumn`) | `position`、`height`、`length`、`width`、`rotation_deg` |
|
||||
| `add_aec_beam` / `update_aec_beam` | 建/改梁(`AecDbBeam`) | `start`/`end`、`width`、`height` |
|
||||
|
||||
**单位约定**(写进了每个工具的 description):
|
||||
|
||||
@@ -62,7 +65,7 @@ if (IS_ZWCAD OR CAD_SDK_VERSION GREATER_EQUAL 20)
|
||||
- 管道的 `dn_mm` / `od_mm` / `wall_thickness_mm` 用 **mm**,内部按 `AS_MUNIT` 转米,
|
||||
与仓库里所有管道对话框(`BZGDDlg`、`AecPipeLineTool`)一致。
|
||||
|
||||
**返回值**:统一 `{"ok":true, "type":..., "handle":...}`;错误是 MCP 的 error 信道
|
||||
**返回值**:统一 `{"ok":true, "type":..., "handle":...}`;错误走 MCP 的 error 信道
|
||||
(`-32001` 参数非法 / `-32002` 找不到 / `-32004` 类型不对 / `-32603` 内部错误)。
|
||||
|
||||
**update_\*** 只改传入的字段,其余保持原值;管道只给一个端点时,另一端沿用实体现有端点。
|
||||
@@ -78,7 +81,7 @@ MCP 工具是通过 `PostMessage` 在主线程的消息里跑的,**不在命
|
||||
### 4.2 只读实体上取专业数据必须 `kForRead`
|
||||
|
||||
`GetSpecialtyData()` 的**缺省参数是 `AcDb::kForWrite`**。
|
||||
`get_aec_entity` 里实体是按 `kForRead` 打开的,第一次实现没注意,**直接把 acad 崩了**
|
||||
`get_aec_entity_detail` 里实体是按 `kForRead` 打开的,第一次实现没注意,**直接把 acad 崩了**
|
||||
(`%TEMP%\acminidump.dmp`)。现在统一写 `GetSpecialtyData(AcDb::kForRead)`。
|
||||
`AecDbEwPipeBase.h` 的注释里也写着同样的话("在 draw2/3d 中使用必须 kForRead,否则图不能保存")。
|
||||
|
||||
@@ -96,20 +99,21 @@ MCP 工具是通过 `PostMessage` 在主线程的消息里跑的,**不在命
|
||||
|
||||
## 5. 端到端实测(AutoCAD 2020 / R230 Debug)
|
||||
|
||||
做法:临时把 `cad-mcp-aec.json` 的 12 个工具合进部署目录的 `cad-mcp-frame.json`
|
||||
(备份原文件,测完还原),用 `/b` 脚本加载 `cad_mcp_frame.arx`,然后用裸 socket 打 JSON-RPC。
|
||||
做法:把仓库里的 `mcp_config.json`(既有工具 + 本插件 12 个)拷到部署目录,
|
||||
用 `/b` 脚本加载 `cad_mcp_frame.arx`,然后用裸 socket 打 JSON-RPC。
|
||||
`%TEMP%\mcp_plugin_load.log` 里 12 个 `add_aec_*` / `update_aec_*` 工厂都是 `[try ] ... create=... destroy=...` 成功。
|
||||
|
||||
| 用例 | 结果 |
|
||||
| --- | --- |
|
||||
| `tools/list` | ✅ 返回 **30** 个工具(原 18 + 新增 12),`create_aec_pipe` 等描述可见 |
|
||||
| `list_aec_entities` | ✅ pcf_1.dwg 里列出 20 根管道,handle/图层/起终点/包围盒正确 |
|
||||
| `create_aec_pipe` | ✅ 返回 handle `3A0`,起点(0,0,0)→终点(2000,0,0) |
|
||||
| `get_aec_entity` | ✅ 读回 `dn_mm=100 / od_mm=114 / wall_thickness_mm=4` |
|
||||
| `tools/list` | ✅ 返回 **30** 个工具(原 18 + 新增 12),`add_aec_pipe` 等描述可见 |
|
||||
| `query_aec_entities` | ✅ pcf_1.dwg 里列出 20 根管道,handle/图层/起终点/包围盒正确 |
|
||||
| `add_aec_pipe`(点位用 `[x,y,z]`、颜色用 `color`) | ✅ 返回 handle `3A0`,起点(0,0,0)→终点(2000,0,0),`color=1` 读回一致 |
|
||||
| `get_aec_entity_detail` | ✅ 读回 `dn_mm=100 / od_mm=114 / wall_thickness_mm=4` |
|
||||
| `update_aec_pipe` | ✅ 改 `dn_mm=150` + 只给 `end`:终点变 3000,**壁厚仍是 4**(4.3 的修复生效) |
|
||||
| `create_aec_wall` | ✅ `3A1`;get 读回 thickness=200 / height=3000 / align=center |
|
||||
| `create_aec_column` | ✅ `3A2`;get 读回 height=3000 / length=400 / width=400 |
|
||||
| `create_aec_beam` | ✅ `3A3`;get 读回 width=300 / height=500 |
|
||||
| `create_aec_slab` | ✅ `3A0`;get 读回 thickness=100 / bottom_elevation=-500 / material=钢筋混凝土 |
|
||||
| `add_aec_wall` | ✅ `3A1`;get 读回 thickness=200 / height=3000 / align=center |
|
||||
| `add_aec_column` | ✅ `3A2`;get 读回 height=3000 / length=400 / width=400 |
|
||||
| `add_aec_beam` | ✅ `3A3`;get 读回 width=300 / height=500 |
|
||||
| `add_aec_slab` | ✅ `3A0`;get 读回 thickness=100 / bottom_elevation=-500 / material=钢筋混凝土 |
|
||||
| `update_aec_slab`(只改厚度/标高) | ✅ 150 / -300 都生效 |
|
||||
| 类型不匹配 | ✅ `update_aec_wall` 传板的 handle → `-32004`「实体是 XSlab,不是 AecDbXWall」 |
|
||||
| 不存在的 handle | ✅ `-32002` |
|
||||
@@ -117,35 +121,50 @@ MCP 工具是通过 `PostMessage` 在主线程的消息里跑的,**不在命
|
||||
导出表(`dumpbin -exports cad_mcp_aec.dll`):12 个 `Create*/Update*` 工厂 + `Destroy_*`
|
||||
+ `g_mcpPluginApiVersion` 全部在。
|
||||
|
||||
## 6. 部署与启用
|
||||
## 6. 配置与启用
|
||||
|
||||
1. 编译:`cmake --build --preset R230 --config Debug --target CadMcpAec`
|
||||
→ `cad_mcp_aec.dll` 随 Debug 构建自动部署到 `c:\ShangHuaSoft\Envi3D-2026-M\R230\`
|
||||
(与 `cad_mcp_frame.arx` 同目录,`plugin_directory` 是 `"."`)。
|
||||
2. 把 `cad-mcp-aec.json` 里的 `tools` 追加到部署目录的 `cad-mcp-frame.json`:
|
||||
工具描述统一放 `SourceCode/Code2026/cad_mcp_aec/mcp_config.json`(与仓库既有工具同一个文件),
|
||||
每个 `tool` 对象就是标准 MCP 协议字段 + `backend`:
|
||||
|
||||
```python
|
||||
python - <<'EOF'
|
||||
import json
|
||||
cfg = json.load(open('cad-mcp-frame.json', encoding='utf-8'))
|
||||
add = json.load(open('cad-mcp-aec.json', encoding='utf-8'))
|
||||
names = {t['name'] for t in cfg['tools']}
|
||||
cfg['tools'] += [t for t in add['tools'] if t['name'] not in names]
|
||||
json.dump(cfg, open('cad-mcp-frame.json','w',encoding='utf-8'), ensure_ascii=False, indent='\t')
|
||||
EOF
|
||||
```
|
||||
```json
|
||||
{
|
||||
"name": "add_aec_pipe",
|
||||
"description": "...",
|
||||
"inputSchema": { "type": "object", "properties": { ... }, "required": [ ... ] },
|
||||
"backend": { "type": "c++_dll", "dll_name": "cad_mcp_aec.dll",
|
||||
"factory_function": "CreateAecPipeTool" }
|
||||
}
|
||||
```
|
||||
|
||||
`cad-mcp-aec.json` 里**故意不写 `inputSchema`**:插件里
|
||||
`mcp_Tool::private_input_schema()` 已经带了完整 schema,配置留空时框架会自动回落
|
||||
(`inc/mcp_plugin_api.h` 的 `ToLLM()`)。这样描述与代码不会漂移。
|
||||
3. 重启 CAD(或 `/reload`),`tools/list` 里应能看到 12 个 `*_aec_*` 工具。
|
||||
`factory_function` 对应 DLL 里 `EXPORT_MCP_TOOL(ToolClass, FactoryName)` 导出的
|
||||
`FactoryName` / `Destroy_FactoryName`;框架按 `plugin_directory`("."=arx 同目录)
|
||||
拼出 `dll_name` 再 `LoadLibrary`。
|
||||
|
||||
启用两步:
|
||||
|
||||
1. 编译(Debug 会自动部署 DLL):
|
||||
`cmake --build --preset R230 --config Debug --target CadMcpAec`
|
||||
→ `cad_mcp_aec.dll` 落到 `c:\ShangHuaSoft\Envi3D-2026-M\R230\`
|
||||
2. 把 `mcp_config.json` 拷到同一个目录(`cad_mcp_frame` 优先读它,没有才回落
|
||||
`cad-mcp-frame.json`),重启 CAD。
|
||||
|
||||
注意:`set_debug_post_build()` 只拷构建产物,**配置文件不自动部署**,需要手工拷一次。
|
||||
仓库里这份 `mcp_config.json` 是"既有 28 个工具 + 本插件 12 个"的合集,
|
||||
拷过去就等于全量替换。
|
||||
|
||||
## 7. 已知限制
|
||||
|
||||
- 只支持这 5 类实体;其它 `AecDb*` 返回 `-32004`。要扩就照 `aec_mcp_entity_tools.cpp`
|
||||
里"一个 apply 函数 + create/update 两个壳"的写法加。
|
||||
里"一个 apply 函数 + add/update 两个壳"的写法加。
|
||||
- 新建实体后 `bbox` 会是 `±1e20`:自定义实体的几何要等一次 REGEN 才建出来,
|
||||
`getGeomExtents` 在未绘制时返回无效值。不是错误。
|
||||
- 没有事务/撤销包装:调用即改库。批量改图建议先 `list` 拿 handle,再逐条 `update`。
|
||||
- 工具描述的中文来自代码里的 `private_description()`;如果最终以运行期 JSON 为准,
|
||||
记得两边同步(或者干脆像现在这样只在 JSON 里写 name + description + backend)。
|
||||
- 没有事务/撤销包装:调用即改库。批量改图建议先 `query_aec_entities` 拿 handle,再逐条 `update`。
|
||||
- **`mcp_config.json` 里有 10 个工具在当前 `cad_mcp_plugins.dll` 里没有对应工厂函数**
|
||||
(`CreateSetDrawingAreaTool`、`CreateFindCollisionsTool`、`CreateDrawRevisionCloudTool`、
|
||||
`CreateAddTextTool`、`CreateAddMTextTool`、`CreateAddPolylineTool`、`CreateAddLineTool`、
|
||||
`CreateAddLeaderAnnotationTool`、`CreateDeleteEntitiesTool`、`CreateSetEntityPropertiesTool`)。
|
||||
这份配置来自更新一版的插件工程,而仓库里的 `cad_mcp_plugins` 只有 16 个工具,
|
||||
于是这 10 个在 `tools/list` 里会被静默丢掉(实测 `tools/list` = 30 = 18 + 12)。
|
||||
要补齐得先把那 10 个工具的实现补进 `cad_mcp_plugins`。
|
||||
- 插件侧 `private_description()` / `private_input_schema()` 与 `mcp_config.json` 保持同文案;
|
||||
**改描述时两边一起改**(配置里写了 `description` / `inputSchema` 时以配置为准)。
|
||||
Reference in new issue
Block a user