Add an optional MCP server (JSON-RPC 2.0 over Streamable HTTP) exposing an online-host listing tool, protected by a Bearer token. Disabled by default; configured via a new "Extensions > MCP Settings" dialog. - McpServer: httplib + JSON-RPC 2.0 dispatch (initialize/ping/tools/list/tools/call) - McpSettingsDlg: runtime-created dialog for enable/port/bind/token - HostJson: extract single-host JSON serialization shared with WebService - FRP: expose MCP port (union with listening/Web ports) when bound to 0.0.0.0 - i18n: en_US / zh_TW translations Co-Authored-By: deepseek-v4-pro
23 KiB
YAMA 服务端 MCP 支持方案
版本:1.0 状态:Final(定稿) 适用范围:
server/2015Remote/(C++/MFC 服务端,生产主流)
1. 背景与目标
1.1 背景
MCP(Model Context Protocol)是 Anthropic 提出的开放协议,让 AI 助手(Claude Code、Claude Desktop 等)通过标准化的工具调用接口访问外部系统的能力。
YAMA 服务端维护了「在线主机列表」这一核心数据,如果能通过 MCP 暴露出去,用户就能在 Claude Code 里直接问「现在有多少台机器在线?」「列出所有在线的 Windows 主机」等,由 AI 调用工具获取实时数据。
1.2 本期范围(MVP)
只跑通 MCP,只实现一个工具,把可扩展架构搭起来:
- 传输方式:Streamable HTTP(
POST /mcp,JSON-RPC 2.0 over HTTP) - 工具数量:1 个 ——
list_online_hosts(获取在线主机列表) - 暴露范围:启用开关(默认关闭,经「扩展 → MCP设置」对话框开启)+ 绑定地址可配置(默认
127.0.0.1仅本机)+ token 认证(env / THIS_CFG / 随机) - 后续:逐步添加工具(进程列表、命令执行、屏幕截图等),架构不动
1.3 非目标(明确不做)
- 不做 SSE 服务器推送(本期工具调用是 request/response 即可)
- 不做多用户/角色体系(复用现有 WebService 认证或静态 token)
- 不做写操作工具(操控主机的工具属于后续阶段,需单独评审安全边界)
- 不碰现有 Web 控制台的 WebSocket 服务
2. 现状分析
C++ 服务端已有大量可直接复用的资产,MCP 的落地成本因此大幅降低。
| 现成资产 | 位置 | 在 MCP 中的角色 |
|---|---|---|
| HTTP 服务器 | httplib.h(header-only,file_server.h:34 已用) |
MCP 的 HTTP 传输层 |
| JSON 库 | jsoncpp/json.h(WebService.cpp 已用) |
JSON-RPC 编解码 |
| Token 认证 | WebServiceAuth.h(GenerateToken / ValidateToken / ComputeSHA256) |
可选升级路径;MVP 用简单静态 token 比对(见 §3.5) |
| 在线主机列表 → JSON | CWebService::BuildDeviceListJson()(WebService.cpp:1506) |
工具 list_online_hosts 的核心逻辑 |
| 在线主机数据源 | CMy2015RemoteDlg::m_HostList(2015RemoteDlg.h:345,m_cs 保护)+ context::IsLogin() + context::GetClientData() |
取数入口 |
| 配置系统 | THIS_CFG.GetInt/GetStr("settings", ...) |
MCP 端口/token 配置 |
2.1 关键结论
- HTTP、JSON、认证、主机列表 JSON 全部现成,MCP 侧不需要重新造轮子。
- 唯一需要手写的是 MCP 的 JSON-RPC 2.0 协议层,因为 C++ 没有官方 MCP SDK(官方仅有 TS/Python/Java/Kotlin/C#/Go)。
2.2 BuildDeviceListJson 现状
WebService.cpp:1506 的 CWebService::BuildDeviceListJson(const std::string& username) 已实现:
- 遍历
m_pParentDlg->m_HostList,过滤ctx->IsLogin() - 输出字段:
id/name/remark/ip/os/location/rtt/version/activeWindow/online/group/screen/clientType - 已处理 GBK/UTF-8 编码分叉(
activeWindow字段按客户端能力位选择编码页,见WebService.cpp:1581附近的GetClientEncoding)
该方法是 private(WebService.h:160,位于 private 段)。MCP 侧需通过公开入口复用(见 §3.4)。
3. 方案设计
3.1 总体架构
2015Remote.exe(MFC 服务端进程)
├─ IOCP TCP 服务(被控端连接,现有)
├─ WebService(ws::Server,Web 控制台,现有,8080)
└─ McpServer(httplib,新增,默认禁用,经「MCP设置」开启后监听 127.0.0.1:6544)
POST /mcp → JSON-RPC 分发
├─ initialize
├─ tools/list
└─ tools/call
└─ list_online_hosts → 复用 BuildHostJson(公共函数,§3.4)
核心决策:独立起一个 httplib server,不挂到现有 ws::Server。
理由:
- 现有
ws::Server的HttpHandler只有path参数、无 POST body(SimpleWebSocket.h:345),强挂 MCP 需改动其底层,侵入大、有回归风险。 - 独立 server 零耦合、零风险,且天然满足「仅 127.0.0.1」的绑定需求。
3.2 新增文件清单
| 文件 | 职责 | 估算量 |
|---|---|---|
McpServer.h / McpServer.cpp |
httplib 封装、POST /mcp 路由、token 校验、生命周期 |
~120 行 |
McpProtocol.h / McpProtocol.cpp |
JSON-RPC 2.0 协议层:initialize / tools/list / tools/call 分发 |
~250 行 |
McpTools.h / McpTools.cpp |
工具注册表 + list_online_hosts 实现 |
~80 行 |
McpSettingsDlg.h / McpSettingsDlg.cpp |
「MCP设置」配置对话框(启用/端口/绑定/token + 重启提醒) | ~150 行 |
修改 2015RemoteDlg.cpp / .h |
启动/停止 McpServer + 菜单项接线(ID_MCP_SETTINGS → OnMcpSettings) |
~30 行 |
修改 2015Remote.rc / resource.h / UIBranding.h / FeatureFlags.h |
ID_MCP_SETTINGS 菜单项 + IDD_DIALOG_MCP_SETTINGS 对话框资源 + HIDE_MENU_MCP_SETTINGS + MF_MCP_SETTINGS 许可位 |
少量 |
头文件/实现可合并精简,实际以「一个
McpServer类 + 一个工具注册表 + 一个协议分发函数」为最小形态,文件拆分仅为可读性。
3.3 协议层设计(JSON-RPC 2.0)
MCP 是 JSON-RPC 2.0。MVP 只需实现以下方法:
3.3.1 initialize(握手)
请求:
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"claude","version":"..."}}}
响应:
{"jsonrpc":"2.0","id":1,"result":{
"protocolVersion":"2025-06-18",
"capabilities":{"tools":{}},
"serverInfo":{"name":"yama","version":"<VERSION_STR>"}
}}
3.3.2 tools/list
请求:{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}
响应:
{"jsonrpc":"2.0","id":2,"result":{"tools":[{
"name":"list_online_hosts",
"description":"获取当前所有在线主机的列表,包含计算机名、IP、操作系统、版本、备注、分组、活动窗口、延迟等实时信息。",
"inputSchema":{"type":"object","properties":{},"required":[]},
"outputSchema":{
"type":"object",
"properties":{
"hosts":{
"type":"array",
"items":{
"type":"object",
"properties":{
"id":{"type":"string"},
"name":{"type":"string"},
"remark":{"type":"string"},
"ip":{"type":"string"},
"os":{"type":"string"},
"location":{"type":"string"},
"rtt":{"type":"string"},
"version":{"type":"string"},
"activeWindow":{"type":"string"},
"online":{"type":"boolean"},
"group":{"type":"string"},
"screen":{"type":"string"},
"clientType":{"type":"string"}
}
}
}
},
"required":["hosts"]
}
}]}}
3.3.3 tools/call
请求:
{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"list_online_hosts","arguments":{}}}
响应(结构化输出:structuredContent 承载主机数组,content 附带可读摘要):
{"jsonrpc":"2.0","id":3,"result":{
"structuredContent":{
"hosts":[
{"id":"123","name":"DESKTOP-ABC","remark":"我的Windows","ip":"192.168.0.92",
"os":"Windows 10","location":"上海市","rtt":"12","version":"...",
"activeWindow":"WeChat","online":true,"group":"default","screen":"1:1920x1080","clientType":"EXE"}
]
},
"content":[{"type":"text","text":"共 1 台主机在线。"}],
"isError":false
}}
3.3.4 可选实现
ping:返回空 result(便于健康检查)notifications/initialized:客户端通知,可忽略
3.3.5 错误响应(JSON-RPC 2.0 标准)
协议层必须处理以下错误,返回标准 error 结构(id 回填请求 id):
| 场景 | code | message |
|---|---|---|
| 请求体不是合法 JSON | -32700 |
Parse error |
| 请求结构不合法(缺 jsonrpc/method 等) | -32600 |
Invalid Request |
| 方法未实现 | -32601 |
Method not found |
| 参数非法 | -32602 |
Invalid params |
| 内部错误 | -32603 |
Internal error |
示例(方法未实现):
{"jsonrpc":"2.0","id":1,"error":{"code":-32601,"message":"Method not found"}}
3.3.6 传输层约定(Streamable HTTP 最小子集)
- 客户端
POST /mcp,请求头Content-Type: application/json、Accept: application/json, text/event-stream。 - 服务端返回
Content-Type: application/json(MVP 工具调用为 request/response,无需 SSE 流式)。 initialize响应可回填Mcp-Session-Id头用于会话管理;MVP 单会话可省略,实现时对照最新 MCP 规范确认。- 仅接受
POST /mcp,其余路径/方法返回 404/405。
3.4 工具设计:list_online_hosts
取数方案(已定:抽公共函数)
BuildDeviceListJson 目前是 CWebService 的 private 方法,且依赖 m_pParentDlg。为满足「MCP 与 WebService 是平级数据消费者、不互相依赖」的原则,采用方案 C:抽公共函数。
// 公共函数:提取单台在线主机的完整数据(含 GBK/UTF-8 编码处理),返回 UTF-8 的 Json::Value
Json::Value BuildHostJson(context* ctx, _ClientList* clientMap);
CWebService::BuildDeviceListJson内部改调该公共函数,Web 侧签名与输出不变(零回归)。McpServer侧持CMy2015RemoteDlg*(SetParentDlg),在m_cs锁内遍历m_HostList、IsLogin()过滤,对每台主机调BuildHostJson,组装为结构化输出。- 职责边界:用户名/分组过滤(
username→allowed_groups)、m_cs加锁、以及外层结构(Web 的{"cmd","devices"}vs MCP 的{"hosts"})属于调用方,不进公共函数;BuildHostJson只负责「单台主机 →Json::Value」的字段序列化与编码转换。其中remark依赖m_ClientMap->GetClientMapData(id, MAP_NOTE),故clientMap作为参数传入。
选型说明:方案 A(MCP 依赖 CWebService 单例)依赖方向错误,且 WebSvrPort=0 时 m_pParentDlg 为空导致取不到数;方案 B(MCP 自持父对话框复制逻辑)违反 DRY、重复易错的编码处理。故取 C。
返回内容(全量,含实时信息)
保留 BuildDeviceListJson 的全部字段,不做精简,以支持「AI 协助监督客户端运行状态」的场景:
- 基础标识:
id/name/remark/ip/os/location/group/version/clientType/screen - 实时信息:
rtt(延迟)、activeWindow(当前活动窗口,即被控端正在做什么)
输出结构 {"hosts": [...]},每台主机一个对象,字段与 §3.3.2 的 outputSchema 一致。
3.5 安全设计
- 绑定地址:默认
127.0.0.1(仅本机回环,其他机器无法访问);可经McpBind配置为0.0.0.0(所有网卡)或内网 IP(如192.168.0.92)以支持远程调用。- 非回环绑定时 token 经明文 HTTP 传输,需强 token,并建议配合防火墙限制源 IP 或启用 HTTPS(项目已有 WebHTTPS 实践)。
- 静态 token 校验:每个
POST /mcp请求校验Authorization: Bearer <token>header;不匹配返回 HTTP 401。 - token 来源(优先顺序):环境变量
YAMA_MCP_TOKEN→THIS_CFG的McpToken→ 两者皆空则随机生成。- 前两者任一非空即作为固定 token;仅当两者皆空时才随机生成(仅本次进程运行期间有效,进程重启后重新生成不同的 token)。
- 随机生成时必须将 token 输出到日志(
Mprintf),否则用户无从获知、无法在 Claude Code 侧配置。 - 环境变量名
YAMA_MCP_TOKEN建议同BRAND_WEB_ENV_VAR一样在UIBranding.h定义为宏(如BRAND_MCP_ENV_VAR),避免散落硬编码字符串。
- 只读边界:MVP 仅一个只读工具,不暴露任何写/操控能力。
- HTTP 方法限制:仅接受
POST /mcp,其余返回 404/405。
3.6 配置设计
沿用现有 THIS_CFG(settings 节):
| 配置键 | 默认值 | 说明 |
|---|---|---|
McpEnabled |
0 |
MCP 总开关:0 = 禁用(默认),1 = 启用。经「扩展 → MCP设置」对话框设置 |
McpPort |
6544 |
MCP 监听端口;仅当 McpEnabled=1 时生效;未配置用默认 6544 |
McpBind |
127.0.0.1 |
监听地址;默认仅本机;可设 0.0.0.0(所有网卡)或内网 IP(如 192.168.0.92)以支持远程 |
McpToken |
空(UI 默认随机值) | 静态 token;对话框内「token 必填、默认随机值」——首次打开若为空则预填随机并随保存持久化。运行时优先级:env YAMA_MCP_TOKEN → McpToken → 皆空则随机生成(见 §3.5) |
与旧版「
McpPort=0即禁用」不同:启用与否改由独立的McpEnabled开关控制,McpPort回归纯端口语义,二者解耦。
3.7 生命周期接入
在 2015RemoteDlg.cpp Web 服务启动块(约 2048-2081)之后,新增 MCP 启动逻辑。McpServer 与 CWebService 同为单例:提供 static McpServer& Instance() 与全局 inline McpServer& McpServer() 访问器(仿 WebService(),见 WebService.h 末尾的全局访问器写法)。
auto mcpEnabled = THIS_CFG.GetInt("settings", "McpEnabled", 0); // 默认禁用
auto mcpPort = THIS_CFG.GetInt("settings", "McpPort", 6544);
auto mcpBind = THIS_CFG.GetStr("settings", "McpBind", "127.0.0.1");
if (mcpEnabled) {
// token 优先顺序:env YAMA_MCP_TOKEN → THIS_CFG McpToken → 皆空则随机(仅本次进程有效)
const char* envTok = getenv("YAMA_MCP_TOKEN");
std::string mcpToken;
if (envTok && *envTok) {
mcpToken = envTok;
} else {
mcpToken = THIS_CFG.GetStr("settings", "McpToken", "");
}
if (mcpToken.empty()) {
mcpToken = GenerateRandomToken(); // 32 hex 随机串
Mprintf("[McpServer] YAMA_MCP_TOKEN / McpToken 均未设置,本次进程随机 token:%s\n", mcpToken.c_str());
}
McpServer().SetParentDlg(this); // 方案 C:MCP 需遍历 m_HostList,须持父对话框指针
McpServer().SetToken(mcpToken);
if (!McpServer().Start(mcpBind, mcpPort)) {
Mprintf("McpServer start failed on %s:%d\n", mcpBind.c_str(), mcpPort);
}
}
并在退出路径(OnDestroy / ExitInstance 对应位置)调用 McpServer().Stop()。
3.8 「MCP设置」配置对话框
MCP 默认不启用,通过主对话框「扩展 → MCP设置」菜单项打开配置对话框来开启。菜单项位置:2015Remote.rc 扩展菜单(POPUP "扩展(&X)")内、「地理信息(&L)」子菜单(纯真数据库 / IP2Region)的 END 之后、「插件设置」之前。
3.8.1 菜单与资源接线
resource.h:新增命令 ID(取当前空闲段,经查33077空闲):#define ID_MCP_SETTINGS 330772015Remote.rc:在「地理信息(&L)」子菜单END之后、插件设置之前插入:并新增对话框资源MENUITEM "MCP设置(&M)...", ID_MCP_SETTINGSIDD_DIALOG_MCP_SETTINGS(「启用 MCP」复选框 + 端口/绑定地址/token 三个编辑框 + 确定/取消按钮)。UIBranding.h:扩展菜单隐藏开关新增一行(默认0显示):#define HIDE_MENU_MCP_SETTINGS 0 // MCP设置FeatureFlags.h:新增运行时许可位,占用 MenuFlags 保留段[43-63]的首位(紧跟MF_REQUEST_AUTH之后):#define MF_MCP_SETTINGS (1ULL << 43) // HIDE_MENU_MCP_SETTINGS2015RemoteDlg.cpp:#include "McpSettingsDlg.h",然后消息映射 + 处理器 + 剪枝:并在扩展菜单剪枝块(ON_COMMAND(ID_MCP_SETTINGS, &CMy2015RemoteDlg::OnMcpSettings) // ... void CMy2015RemoteDlg::OnMcpSettings() { CMcpSettingsDlg dlg(this); dlg.DoModal(); }pExtMenu,约2015RemoteDlg.cpp:1225之后)追加:if (SHOULD_HIDE_MENU(HIDE_MENU_MCP_SETTINGS, MF_MCP_SETTINGS)) pExtMenu->DeleteMenu(ID_MCP_SETTINGS, MF_BYCOMMAND);
实现注意:
2015Remote.rc为 UTF-16 编码,菜单与对话框资源须由 VS 资源编辑器维护(手工改文本易破坏编码与资源 ID 引用)。IDD_DIALOG_MCP_SETTINGS需在resource.h分配独立空闲的IDD_数值(与ID_MCP_SETTINGS分开);对话框内控件 ID(如IDC_CHK_ENABLE_MCP/IDC_EDIT_MCP_PORT/IDC_EDIT_MCP_BIND/IDC_EDIT_MCP_TOKEN)同理。
3.8.2 对话框字段与默认值
| 控件 | 绑定配置键 | 默认值 | 说明 |
|---|---|---|---|
| 「启用 MCP」复选框 | McpEnabled |
未勾选(0) |
勾选后持久化 McpEnabled=1 |
| 端口 | McpPort |
6544 |
数字编辑框,仅当启用时有效 |
| 绑定地址 | McpBind |
127.0.0.1 |
默认仅本机;可改 0.0.0.0 / 内网 IP |
| Token | McpToken |
随机值 | 必填;为空时预填随机 token |
3.8.3 初始化与保存
打开时读 THIS_CFG 回填;token 为空则当场生成随机值预填(32 hex)。保存时落盘并弹重启提醒:
BOOL CMcpSettingsDlg::OnInitDialog()
{
CDialogLangEx::OnInitDialog();
int enabled = THIS_CFG.GetInt("settings", "McpEnabled", 0);
int port = THIS_CFG.GetInt("settings", "McpPort", 6544);
std::string bind = THIS_CFG.GetStr("settings", "McpBind", "127.0.0.1");
std::string tok = THIS_CFG.GetStr("settings", "McpToken", "");
if (tok.empty()) tok = GenerateRandomToken(); // 预填随机,随保存持久化
// 回填到控件:m_bEnabled / m_nPort / m_strBind / m_strToken
return TRUE;
}
void CMcpSettingsDlg::OnBnClickedBtnSave()
{
// 从控件收集:enabled / port / bind / token
if (enabled && token.empty()) {
MessageBoxL(_TR("Token 不能为空"), _TR("提示"), MB_ICONWARNING);
return;
}
THIS_CFG.SetInt("settings", "McpEnabled", enabled ? 1 : 0);
THIS_CFG.SetInt("settings", "McpPort", port);
THIS_CFG.SetStr("settings", "McpBind", bind);
THIS_CFG.SetStr("settings", "McpToken", token);
MessageBoxL(_TR("MCP 设置已保存。\n启用/端口/绑定地址/Token 的改动需重启程序生效。"),
_TR("提示"), MB_ICONINFORMATION);
CDialogLangEx::OnOK();
}
3.8.4 与运行时 token 逻辑的衔接
对话框的「默认随机 token」是把随机值写入 McpToken 并持久化,于是下次启动走 env → McpToken 的固定 token 分支;运行时「两者皆空则随机」分支仅在用户从未通过对话框设置过(或手动清空 token)时兜底,两者不冲突。GenerateRandomToken() 为 MCP 侧新增的小工具函数(32 hex 随机串,可用 rand_s / BCryptGenRandom 实现;如需可复用 WebServiceAuth.h 的 ComputeSHA256 派生)。
4. 实施步骤
| 步骤 | 内容 | 验收 |
|---|---|---|
| 1 | 新建 McpProtocol:JSON-RPC 分发 + initialize/tools/list/tools/call(含 jsoncpp 解析/序列化) |
单元自测:手写请求串,验证响应 |
| 2 | 新建 McpServer:httplib 起 127.0.0.1:6544,POST /mcp 路由 + token 校验(含随机生成) |
curl 请求返回 401/正常 |
| 3 | 抽公共函数 BuildHostJson,CWebService::BuildDeviceListJson 改调之 |
Web 输出不变,零回归 |
| 4 | 注册 list_online_hosts 工具:handler 持父对话框、m_cs 锁内遍历、调 BuildHostJson 组装 |
tools/call 返回主机列表 |
| 5 | 新增 McpSettingsDlg + 菜单项接线(ID_MCP_SETTINGS / OnMcpSettings / HIDE_MENU_MCP_SETTINGS / IDD_DIALOG_MCP_SETTINGS 资源) |
对话框可启用/禁用、配置端口/绑定/token,保存落盘并提示重启 |
| 6 | 接入 2015RemoteDlg 启动/停止(按 McpEnabled 门控)+ 配置 |
服务端启动后端口监听正常 |
| 7 | Claude Code 接入验证(见 §5) | 见验收标准 |
5. 验收标准
- 在「MCP设置」对话框启用并重启服务端后,
127.0.0.1:6544监听正常,外部地址无法访问;未启用时该端口不监听。 - 无 token 的请求返回 HTTP 401;错误 token 返回 401;正确 token 通过。
curl模拟initialize→tools/list→tools/call全流程,返回符合 JSON-RPC 2.0 与 MCP 规范。- Claude Code 侧:
claude mcp add yama --transport http http://127.0.0.1:6544/mcp -H "Authorization: Bearer <token>"claude mcp list能看到yama,在对话中问「列出在线主机」能正确触发工具并返回列表。 - 现有 Web 控制台、IOCP 主服务功能无回归。
6. 风险与约束
| 风险 | 说明 | 应对 |
|---|---|---|
| 无官方 C++ MCP SDK | 需手写 JSON-RPC 协议层 | 仅实现 3 个方法,量小可控;协议稳定后再考虑抽库 |
| MCP 规范版本演进 | protocolVersion 字符串需与客户端匹配 | 实现时对照最新规范;initialize 返回可协商版本 |
| 并发安全 | 遍历 m_HostList 需持 m_cs |
MCP 与 WebService 采用相同的「m_cs 锁内遍历」模式 |
| 字符编码 | GBK/UTF-8 分叉 | 复用公共函数 BuildHostJson 的编码处理,不自造 |
| token 存储 | THIS_CFG 的 token 会明文落盘;随机 token 会打印到日志 |
本地回环 + 只读,风险可控;敏感场景建议仅用 env 并妥善保管 |
7. 后续扩展规划(本期不做)
- 工具:
get_host_processes(进程列表)、execute_command(命令执行)、capture_screen(截图)等 - 写操作工具的安全边界评审(操作对象、权限、审计)
- 认证升级:复用
WebServiceAuth的签名 token / 过期机制 - 分组过滤:
list_online_hosts加group参数
8. 决策记录
决策记录(全部已定):
- ✅ 启用开关:新增
McpEnabled,默认0(禁用)。MCP 默认不启动,须用户在「扩展 → MCP设置」对话框手动开启。 - ✅ 端口:
McpPort可配置,未配置默认6544(纯端口语义,不再兼任启用开关)。 - ✅ token:优先顺序 env
YAMA_MCP_TOKEN→THIS_CFG.McpToken→ 皆空则随机生成(仅本次进程有效,打印到日志)。对话框内 token 必填、默认随机值(预填并随保存持久化到McpToken)。 - ✅ 绑定地址:默认
127.0.0.1(仅本机);可配置为0.0.0.0或内网 IP(如192.168.0.92)以支持多人协作跨机调用。 - ✅ 配置入口:主对话框「扩展」菜单,位于「地理信息(&L)」子菜单下方新增「MCP设置」菜单项,打开独立配置对话框。
- ✅ 生效方式:MCP 启用/端口/绑定/token 的改动均需重启服务端生效,对话框保存后弹窗提醒「重启程序生效」。
- ✅ 取数方案:C(抽公共函数
BuildHostJson,MCP 与 WebService 平级复用)。 - ✅ 返回字段:全量,含实时信息(
rtt/activeWindow),支持 AI 监督场景。 - ✅ 序列化:
structuredContent+outputSchema,content附带可读摘要。