fix(external-systems): 修复 MCP 接口数量显示
This commit is contained in:
parent
e53e91372d
commit
b96c6d021f
|
|
@ -5,6 +5,10 @@
|
||||||
> 所以不是每个版本号都有条目。条目格式 `## <版本> — <日期>`,新条目加在最上面。
|
> 所以不是每个版本号都有条目。条目格式 `## <版本> — <日期>`,新条目加在最上面。
|
||||||
> 工程口径的完整记录见 `PROGRESS.md` / git log。
|
> 工程口径的完整记录见 `PROGRESS.md` / git log。
|
||||||
|
|
||||||
|
## 0.63.9 — 2026-08-11
|
||||||
|
|
||||||
|
- 修复 MCP 外部系统测试连接成功后,可用接口数量错误显示为 0 的问题。
|
||||||
|
|
||||||
## 0.63.8 — 2026-08-11
|
## 0.63.8 — 2026-08-11
|
||||||
|
|
||||||
- 外部系统的新建与凭据更新改用独立弹框;点击已有连接即可编辑,新建时不再列出已连接系统,连接卡片同时用图标和文字区分 OpenAPI 与 MCP。
|
- 外部系统的新建与凭据更新改用独立弹框;点击已有连接即可编辑,新建时不再列出已连接系统,连接卡片同时用图标和文字区分 OpenAPI 与 MCP。
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
> 配合 `DESIGN.md`。本文件只记 phase 状态、决策偏差、文件量、下一步。每条 1-2 句:做了啥 + 关键判断;细节查 `git log` / `git diff` / `DESIGN §7.9`。
|
> 配合 `DESIGN.md`。本文件只记 phase 状态、决策偏差、文件量、下一步。每条 1-2 句:做了啥 + 关键判断;细节查 `git log` / `git diff` / `DESIGN §7.9`。
|
||||||
|
|
||||||
最后更新:2026-08-11(外部系统连接弹框与类型标识,bump 0.63.8)
|
最后更新:2026-08-11(MCP 测试连接接口计数修复,bump 0.63.9)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -23,6 +23,8 @@
|
||||||
|
|
||||||
### 2026-08-11
|
### 2026-08-11
|
||||||
|
|
||||||
|
- **08-11 / 0.63.9 / MCP 测试连接接口计数修复**:MCP 连接探测统一返回与 OpenAPI 相同的 `operation_count`,同时保留 `tool_count` 兼容字段;用户端测试连接兼容读取新旧响应,修复 Server 实际暴露工具时仍显示“可用接口 0 个”的问题。外部系统、无 DB 路由与静态页面共 57 项 unittest、JavaScript 语法及 diff 检查通过;无 schema、migration、依赖或运行方式变化,未连接生产 DB。
|
||||||
|
|
||||||
- **08-11 / 0.63.8 / 外部系统连接弹框 + connector 类型标识**:用户外部系统主页移除状态耦合的内联凭据表单,新建连接与更新凭据统一改为独立弹框;点击已有卡片直接进入编辑,新建弹框只列出尚未连接的 definition,避免重复创建。连接卡片读取既有 `connector` 字段,以不同 SVG、颜色和文字区分 OpenAPI 与 MCP。Web 无 DB 路由与静态资源共 36 项 unittest、JavaScript 语法及 diff 检查通过;本地无安全的 Web 实例可做真实点击,未启动会读取生产 `.env` 的应用,未连接生产 DB。无 schema、migration、HTTP API、依赖或运行方式变化。
|
- **08-11 / 0.63.8 / 外部系统连接弹框 + connector 类型标识**:用户外部系统主页移除状态耦合的内联凭据表单,新建连接与更新凭据统一改为独立弹框;点击已有卡片直接进入编辑,新建弹框只列出尚未连接的 definition,避免重复创建。连接卡片读取既有 `connector` 字段,以不同 SVG、颜色和文字区分 OpenAPI 与 MCP。Web 无 DB 路由与静态资源共 36 项 unittest、JavaScript 语法及 diff 检查通过;本地无安全的 Web 实例可做真实点击,未启动会读取生产 `.env` 的应用,未连接生产 DB。无 schema、migration、HTTP API、依赖或运行方式变化。
|
||||||
|
|
||||||
- **08-11 / 0.63.7 / 外部系统已有连接直接重连**:用户凭据表单按所选 definition 识别已有连接,自动切换为“重新连接并验证”并调用现有凭据更新接口,验证成功后保存新凭据和 active 状态,不再先按新连接提交后收到重复连接提示;卡片上的显式“更新凭据”入口保持不变。Web 无 DB 路由与静态资源共 35 项 unittest、JavaScript 语法及 diff 检查通过;无 schema、migration、HTTP API、依赖或运行方式变化,未连接生产 DB。
|
- **08-11 / 0.63.7 / 外部系统已有连接直接重连**:用户凭据表单按所选 definition 识别已有连接,自动切换为“重新连接并验证”并调用现有凭据更新接口,验证成功后保存新凭据和 active 状态,不再先按新连接提交后收到重复连接提示;卡片上的显式“更新凭据”入口保持不变。Web 无 DB 路由与静态资源共 35 项 unittest、JavaScript 语法及 diff 检查通过;无 schema、migration、HTTP API、依赖或运行方式变化,未连接生产 DB。
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
# zcbot 版本号单一事实源:web/app.py 的 FastAPI version、/healthz 返回、前端展示都引这里。
|
# zcbot 版本号单一事实源:web/app.py 的 FastAPI version、/healthz 返回、前端展示都引这里。
|
||||||
# 改版本只动这一行。
|
# 改版本只动这一行。
|
||||||
__version__ = "0.63.8"
|
__version__ = "0.63.9"
|
||||||
|
|
|
||||||
|
|
@ -439,9 +439,13 @@ class McpClient:
|
||||||
|
|
||||||
def test_connection(self) -> dict[str, Any]:
|
def test_connection(self) -> dict[str, Any]:
|
||||||
catalog = self._catalog(force=True)
|
catalog = self._catalog(force=True)
|
||||||
|
tool_count = len(catalog["tools"])
|
||||||
return {
|
return {
|
||||||
"server": catalog["server"],
|
"server": catalog["server"],
|
||||||
"tool_count": len(catalog["tools"]),
|
# 对外测试连接响应与 OpenAPI 统一使用 operation_count;保留
|
||||||
|
# tool_count,兼容已依赖 MCP 连接器原始响应的调用方。
|
||||||
|
"operation_count": tool_count,
|
||||||
|
"tool_count": tool_count,
|
||||||
}
|
}
|
||||||
|
|
||||||
def search(self, query: str, limit: int = 12) -> list[dict[str, Any]]:
|
def search(self, query: str, limit: int = 12) -> list[dict[str, Any]]:
|
||||||
|
|
|
||||||
|
|
@ -428,6 +428,7 @@ class GenericMcpConnectorTests(unittest.TestCase):
|
||||||
thread.join(timeout=5)
|
thread.join(timeout=5)
|
||||||
|
|
||||||
self.assertEqual(connection["server"]["name"], "test-mcp")
|
self.assertEqual(connection["server"]["name"], "test-mcp")
|
||||||
|
self.assertEqual(connection["operation_count"], 2)
|
||||||
self.assertEqual(connection["tool_count"], 2)
|
self.assertEqual(connection["tool_count"], 2)
|
||||||
self.assertEqual(found[0]["operation_id"], "mcp/echo_material")
|
self.assertEqual(found[0]["operation_id"], "mcp/echo_material")
|
||||||
self.assertEqual(result["data"], {"name": "低碳水泥"})
|
self.assertEqual(result["data"], {"name": "低碳水泥"})
|
||||||
|
|
|
||||||
|
|
@ -194,6 +194,10 @@ class StaticVendorTests(unittest.TestCase):
|
||||||
self.assertIn('$("ext-add").onclick = () => openConnectionModal();', external_js)
|
self.assertIn('$("ext-add").onclick = () => openConnectionModal();', external_js)
|
||||||
self.assertIn("openConnectionModal(systemsById.get(id));", external_js)
|
self.assertIn("openConnectionModal(systemsById.get(id));", external_js)
|
||||||
self.assertIn('await api("PUT", `/v1/external-systems/${editingId}/credentials`', external_js)
|
self.assertIn('await api("PUT", `/v1/external-systems/${editingId}/credentials`', external_js)
|
||||||
|
self.assertIn(
|
||||||
|
"result.operation_count ?? result.tool_count ?? 0",
|
||||||
|
external_js,
|
||||||
|
)
|
||||||
self.assertNotIn("function connectionForDefinition(", external_js)
|
self.assertNotIn("function connectionForDefinition(", external_js)
|
||||||
|
|
||||||
def test_static_js_is_served_with_revalidation_header(self) -> None:
|
def test_static_js_is_served_with_revalidation_header(self) -> None:
|
||||||
|
|
|
||||||
|
|
@ -209,7 +209,8 @@ $("ext-list").addEventListener("click", async event => {
|
||||||
button.disabled = true;
|
button.disabled = true;
|
||||||
try {
|
try {
|
||||||
const result = await api("POST", `/v1/external-systems/${id}/test`);
|
const result = await api("POST", `/v1/external-systems/${id}/test`);
|
||||||
message(result.ok ? `连接正常,可用接口 ${result.operation_count || 0} 个` : `连接失败:${result.error}`, result.ok ? "success" : "error");
|
const operationCount = result.operation_count ?? result.tool_count ?? 0;
|
||||||
|
message(result.ok ? `连接正常,可用接口 ${operationCount} 个` : `连接失败:${result.error}`, result.ok ? "success" : "error");
|
||||||
await loadExternalSystems();
|
await loadExternalSystems();
|
||||||
} catch (error) { message("测试失败:" + error.message, "error"); }
|
} catch (error) { message("测试失败:" + error.message, "error"); }
|
||||||
finally { button.disabled = false; }
|
finally { button.disabled = false; }
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue