三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

单页面 mcp客户端,直接嵌入各类界面终端 包括Teamcenter AWC、Teamcenter 客户端、Teamcenter与各类CAD工具集成 - 张永全

单页面 mcp客户端,直接嵌入各类界面终端  包括Teamcenter AWC、Teamcenter 客户端、Teamcenter与各类CAD工具集成 - 张永全

https://gitee.com/zhyqmn/mcp-client-page.git  单页面 mcp客户端,直接嵌入各类界面终端

1.Teamcenter AWC:

4d10168b-f651-480f-83db-e8d1dcd396f3

RAG:

171d00f6-f045-444d-bb00-c143e52a4501

PADS集成客户端..................

 

 

 

1. 九个关键决策点:推荐与理由

1.1 WebView2 引入方式:NuGet 包 Microsoft.Web.WebView2(packages.config 风格)

  • 该统一包对 net462 同时提供 Core + WinForms 程序集(lib\net462),官方支持 .NET Framework 4.6.2+;其 build targets 会按 $(PlatformTarget)runtimes\win-x86|win-x64\native 拷出架构匹配的 WebView2Loader.dll(x86 进程必须配 x86 loader,这是最常见的坑,包自己处理)。
  • 用 VS 的 NuGet UI 装(项目已用 packages.config 模式);若无网或想手工:在 packages.config 加 <package id="Microsoft.Web.WebView2" version="1.0.2903.40" targetFramework="net462" />,csproj 加两个 Reference(HintPath 指向 ..\packages\Microsoft.Web.WebView2.1.0.2903.40\lib\net462\*.dll)并手工 <Import> 其 build\Microsoft.Web.WebView2.targets。不用手工拷贝 loader 到 Libs(版本升级与架构选择容易出错)。

1.2 宿主页面承载:自托管微型静态服务器 on 127.0.0.1:8023(TcpListener 实现),origin = http://127.0.0.1:8023 —— 不用 SetVirtualHostNameToFolderMapping,不用 NavigateToString

  • SetVirtualHostNameToFolderMapping 的 origin 是 https://appassets.example:HTTPS 页 fetch http://127.0.0.1:10099 会踩 Private Network Access(PNA)——Chromium 把虚拟域名当作 public address space,向 loopback 发请求要 Access-Control-Allow-Private-Network 预检,而 starlette CORS 不吐该头(WebView2 社区大量同类踩坑记录);绕法 --disable-features=BlockInsecurePrivateNetworkRequests 随 Chromium 版本漂移,脆弱。
  • loopback origin 一劳永逸http://127.0.0.1:8023 属 potentially trustworthy origin——无 mixed content、无 PNA(同 address space)、localStorage/secure APIs 可用;组件本身就是在 http://localhost:5173(Vite)开发验证的,该形态是它的原生环境。
  • 不用 HttpListener 而用 TcpListener 手写 60 行静态服务:http.sys 对非管理员用户绑端口要 netsh http add urlacl,TcpListener 绑定 127.0.0.1 无任何 ACL 要求;只服务 2 个静态文件(index.html + 460KB iife.js),每次响应后 Connection: close 即可,无需处理 keep-alive。端口 8023 被占时自动 +1 重试(但要与 CORS 白名单联动,见 §1.7)。
  • NavigateToString 的 origin 是 null/opaque,CORS 白名单没法干净配置,排除。

1.3 C# ↔ JS 桥

  • C# → JS(配置/指令)CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync("window.mcpChatHost = {llm:{...}, servers:[...]};")——在任何页面脚本前执行,满足组件"组件创建前设置"要求,承载 LLM 默认与 servers 自动连接(不放 apiKey);NavigationCompleted 后再 ExecuteScriptAsync 注入 setConfig({apiKey, system, maxTurns, maxTokens, adaptiveThinking})registerSkill(...)
  • JS → C#(事件):宿主页 document.addEventListener(name, e => window.chrome.webview.postMessage({kind:'mcp-event', name, detail}), true) 捕获全部 12 个事件(bubbles+composed 穿透 Shadow DOM),C# 侧 WebMessageReceived 解析。detail 中 tool-result.result 可能很大,桥里截断(如 JSON.stringify(detail).slice(0, 4000))避免超大消息。
  • C# 调组件方法ExecuteScriptAsync 调用宿主页暴露的 window.aiHost.* 函数(publishBom/runCheck/getSnapshot/applyServerConfig),参数用 Newtonsoft 序列化后作为 JSON 字符串传入,JS 侧 JSON.parse 还原——彻底规避字符串转义问题。

1.4 AI 界面形态:新建独立 Form(AIAssistantForm)+ 托盘菜单"AI 助手"

  • 主窗体是 421x400 的日志窗,塞 WebView2 太挤;独立 Form 可 1000x800 全屏聊天+顶部工具栏(选 BOM CSV / 执行检查 / 清空 / MCP 管理 / 状态条)。
  • 生命周期:单例、OnFormClosinge.Cancel=true; Hide()(与主窗体一致),进程退出时 Dispose;托盘 contextMenuStrip1 在 Reset 之前插入"AI 助手"菜单项。
  • 组件内置 ⚙ 设置面板承担 LLM key/端点/模型/联通测试,宿主不需要重复造;MCP 服务器管理(组件面板只读展示)补一个轻量 C# 对话框(见 Step 7)。

1.5 BOM 提取与注入:复用 BomCsvHelper.ReadFile → 按 PartNumber 聚合 → publish() + /pads-bom-check Skill 触发

  • 聚合后行数从"每个位号一行"降到"每个唯一料号一行":PN<TAB>总量<TAB>位号列表<TAB>厂商<TAB>名称,默认上限 500 个唯一料号,超出截断并在 text 中声明"仅注入前 500 种",完整明细放 publish().data(不占 token)。
  • publish({type:'pads-bom', text: 紧凑表, data: 完整行}) 后,send("/pads-bom-check 检查已加载的 BOM 并输出报告")——需要 registerSkillpads-bom-check(enabled=false)把检查流程沉淀为命名指令,斜杠触发时仅对本次调用注入流程 prompt,避免每次对话都背着长流程;用户事后可手动重跑。加载新 CSV 时同 type publish 自动替换旧上下文(组件语义)。
  • 检查提示词要点(写进 Skill prompt):① 存在性 tc_biz_item_get_by_id(item_id=PN,可给 object_type 提示如 EDAComPart,查不到再用 tc_biz_search 兜底);② 属性完整性 tc_biz_item_get_props_many 批量读 object_name/v9_manuname/v9_devicetype/v9_devicepreferlev/v9_isprice/v9_restricstate/v9_disablereason,与 BOM 厂商比对;③ 禁用料:先 tc_biz_pref_getVMAX_PADSCheckRules,按规则核对并输出 禁止/提示 分级结论;④ 输出 Markdown 报告(存在性/属性缺失/禁用/价格/汇总统计);⑤ 明确要求批量调用、uid 引用、减少往返。

1.6 配置持久化:独立 ai_config.json(exe 同目录),不用 App.config

  • 理由:嵌套结构(servers 数组 + llm 对象 + 端口)在 appSettings 里要摊平成恶心字符串;json 不用重新编译即可改,且是组件配置的自然形状;App.config 已是 TCSocketServer.exe.config、改动它风险面大。程序启动时若 json 缺失,从内置模板自动生成 ai_config.default.json 结构落盘。
  • API key 安全:默认从环境变量 ANTHROPIC_AUTH_TOKEN 读取(任务已说明 key 在该环境变量),绝不写进 json;组件默认 persistKey:false(仅内存),用户手工在 ⚙ 面板输 key 也只在组件内存。key 不在日志/UI 明文回显。
  • 组件 ⚙ 面板的 LLM 修改与 localStorage 历史存在 WebView2 用户数据目录(%LOCALAPPDATA%\TCSocketServer\WebView2),与 ai_config.json 分层:json = 部署基线(servers + LLM 默认),localStorage = 用户运行时微调

1.7 MCP CORS 联动与 plm-bridge

  • tc-server(必做):改 D:\WorkSpace\agent\dist-win-onefile\tc_mcp_config.jsoncors_origins,追加 "http://127.0.0.1:8023";然后重启:taskkill /PID 17340 /F 后运行 start-tc-server-onefile-http.bat(本机实测 403 已证明白名单生效,追加后即通)。若改宿主端口,需同步改这里。
  • 跨机部署:若 TCSocketServer.exe 跑在 192.168.26.148 而 tc-server 在本机,需把 config 里 server.http_host 改为 0.0.0.0,ai_config.json 的 URL 改为 http://<本机IP>:10099/mcp,CORS 白名单同样加 http://127.0.0.1:8023(origin 只看浏览器侧)。
  • plm-bridge:v1 不接入。其 config.yaml 无 CORS 配置(浏览器侧必被拦),且它是 RAG/onyx 连接器,与"PADS BOM → TC 检查"无直接关系;ai_config.json 的 servers 数组天然支持将来接入(届时需给它前置 CORS 反代或改其 Go 中间件)。当前预置仅 tc-server 一台。

1.8 构建与部署

  • 维持 packages.config(项目一贯风格,无迁移成本);WebView2 也是 packages.config 引用。
  • Web 资产随 exe 输出:项目内建 AiWeb\ 目录(index.html、host-bridge.js、vendor\mcp-chat.iife.js),csproj 用 None + CopyToOutputDirectory=PreserveNewest(旧式 csproj 最稳写法,见 §2.2)。mcp-chat.iife.js一次性拷贝进项目的构建产物(460KB;非 git 仓库,直接入库即可,README 里注明升级时从 D:\WorkSpace\MCPClient\dist\ 重拷)。
  • 部署物变化:exe 目录多出 AiWeb\ai_config.jsonMicrosoft.Web.WebView2.Core.dllMicrosoft.Web.WebView2.WinForms.dllWebView2Loader.dll。WebView2 Runtime 已确认装好,无需分发。

1.9 与 SocketServer/托盘并存注意点

  • UI 线程:WebView2 的一切(EnsureCoreWebView2Async、ExecuteScriptAsync、事件回调)都必须在主 UI 线程;托盘菜单点击本来就在 UI 线程,天然满足。SocketServer 的日志仍走 listView.Invoke(现有模式不动)。
  • 退出清理:现有 退出ToolStripMenuItem_Click 直接 Environment.Exit(0)——在它之前补 AIAssistantForm.DisposeInstance()(内部 webView21.Dispose() + 停 AiAssetsServer)。静态服务器线程必须 IsBackground=true,否则阻塞退出。不用改 SocketServer 的退出语义。
  • WebView2 初始化CoreWebView2Environment.CreateAsync(null, userDataFolder) 指定用户数据目录(exe 目录在 D:\Siemens 可写,但独立到 %LOCALAPPDATA% 更干净、避免与下次部署文件混淆);初始化是异步的,NavigationCompleted 前显示"加载中"占位。
  • 不要在 AI 代码路径弹 MessageBox(组件事件频率高,弹窗会卡 UI);状态一律走状态条/主窗体 listView1 日志。BOM CSV 解析同步做(现有 CheckInDialog 同款模式,几千行 GB2312 CSV 毫秒级)。
← 返回列表