feat(bridge): 新增 stdio↔TCP 桥,让标准 MCP 客户端可直连 CAD 基座 #8
No files matched your search
@@ -24,7 +24,7 @@ type: project
|
|||||||
| 生命周期 | **没有** `initialize` / `initialized` / `ping` → **必须由桥合成** |
|
| 生命周期 | **没有** `initialize` / `initialized` / `ping` → **必须由桥合成** |
|
||||||
| 通知 | 无 `id` 即不回包 |
|
| 通知 | 无 `id` 即不回包 |
|
||||||
| `tools/list` | 26 个工具,`name`/`description`/`inputSchema(type=object)` 已是标准 MCP 形状 → **可原样转发** |
|
| `tools/list` | 26 个工具,`name`/`description`/`inputSchema(type=object)` 已是标准 MCP 形状 → **可原样转发** |
|
||||||
| 未知工具 | 回**顶层** `error:-32601`(不是 `result.isError`)→ 桥忠实透传 |
|
| 未知工具 | 回**顶层** `error:-32602`(`"Unknown tool: <name>"`)→ 桥忠实透传 |
|
||||||
|
|
||||||
## 关键设计决策
|
## 关键设计决策
|
||||||
|
|
||||||
@@ -37,9 +37,12 @@ type: project
|
|||||||
3. **stdout 纯净性**:只用 `sys.stdout.buffer.write(... + b"\n")` + `flush()`(加锁)。
|
3. **stdout 纯净性**:只用 `sys.stdout.buffer.write(... + b"\n")` + `flush()`(加锁)。
|
||||||
用 `buffer` 而非文本流,**规避 Windows 的 `\n`→`\r\n` 翻译**;所有日志只走 stderr。
|
用 `buffer` 而非文本流,**规避 Windows 的 `\n`→`\r\n` 翻译**;所有日志只走 stderr。
|
||||||
4. **CAD 未启动**:桥照常启动,`initialize`/`ping` 正常,`tools/list` 回 `-32603`(可重试)。
|
4. **CAD 未启动**:桥照常启动,`initialize`/`ping` 正常,`tools/list` 回 `-32603`(可重试)。
|
||||||
5. **不擅自改写语义**:基座对未知工具回顶层 `-32601`("Method not found")语义上偏 JSON-RPC
|
5. **不擅自改写语义**:桥只做忠实透传,错误码一律由基座决定。
|
||||||
方法层,严格说应是 `-32602` 或 `result.isError`。桥**不改写**;要修应改基座
|
(**2026-10-14 修正**:基座原先对未知工具回 `-32601`,语义偏 JSON-RPC 方法层;
|
||||||
`mcp_server.cpp: HandleToolsCall` 的码值分类。
|
按 MCP 规范「未知工具属于**协议错误**,示例码 `-32602`」已改为 `-32602` +
|
||||||
|
`"Unknown tool: <name>"`。改动点:`mcp_configParser.cpp: mcp_Tools::Call`
|
||||||
|
—— 只需改码值,`mcp_server.cpp: HandleToolsCall` 的协议错误白名单
|
||||||
|
`{-32700,-32600,-32601,-32602}` 已含 `-32602`,分类逻辑无需动。)
|
||||||
|
|
||||||
## 验证方法(重要,含踩坑)
|
## 验证方法(重要,含踩坑)
|
||||||
|
|
||||||
|
|||||||
@@ -255,8 +255,9 @@ nlohmann::json mcp_Tools::Call(const std::string &name, const nlohmann::json &ar
|
|||||||
return it->second->Execute(args);
|
return it->second->Execute(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 找不到工具时,返回标准的 JSON-RPC 错误对象
|
// 找不到工具时,返回标准的 JSON-RPC 协议错误。
|
||||||
return mcp_Tool_Utility::make_error(-32601, L"Specified tool not found: " + mcp_utils::utf8ToWString(name));
|
// 依 MCP 规范,未知工具属于「协议错误」,示例码为 -32602 (Invalid params)。
|
||||||
|
return mcp_Tool_Utility::make_error(-32602, L"Unknown tool: " + mcp_utils::utf8ToWString(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
void mcp_Tools::print()
|
void mcp_Tools::print()
|
||||||
|
|||||||
+3
-3
@@ -49,7 +49,7 @@ def test_string_id():
|
|||||||
|
|
||||||
|
|
||||||
def test_large_request():
|
def test_large_request():
|
||||||
"""构造 >2KB 的 arguments;旧基座会截断成 -32700,新基座应正常返回 -32601。"""
|
"""构造 >2KB 的 arguments;旧基座会截断成 -32700,新基座应正常返回 -32602。"""
|
||||||
big = {"blob": "x" * 5000}
|
big = {"blob": "x" * 5000}
|
||||||
resp = json.loads(
|
resp = json.loads(
|
||||||
_call(
|
_call(
|
||||||
@@ -62,8 +62,8 @@ def test_large_request():
|
|||||||
).decode()
|
).decode()
|
||||||
)
|
)
|
||||||
code = (resp.get("error") or {}).get("code")
|
code = (resp.get("error") or {}).get("code")
|
||||||
assert code == -32601, f"期望 -32601(工具不存在),实际 {resp}"
|
assert code == -32602, f"期望 -32602(未知工具,协议错误),实际 {resp}"
|
||||||
print("[PASS] >2KB 请求未被截断(返回 -32601 而非 -32700)")
|
print("[PASS] >2KB 请求未被截断(返回 -32602 而非 -32700)")
|
||||||
|
|
||||||
|
|
||||||
def test_notification_no_reply():
|
def test_notification_no_reply():
|
||||||
|
|||||||
@@ -193,7 +193,7 @@ def main():
|
|||||||
"params": {"name": "__no_such_tool__", "arguments": {}}})
|
"params": {"name": "__no_such_tool__", "arguments": {}}})
|
||||||
r = bridge.recv()
|
r = bridge.recv()
|
||||||
code = ((r or {}).get("error") or {}).get("code")
|
code = ((r or {}).get("error") or {}).get("code")
|
||||||
check("透传顶层 error.code == -32601", code == -32601, f"got {r!r}")
|
check("透传顶层 error.code == -32602(未知工具)", code == -32602, f"got {r!r}")
|
||||||
check("error 响应的 id 正确", (r or {}).get("id") == 7, f"got {(r or {}).get('id')!r}")
|
check("error 响应的 id 正确", (r or {}).get("id") == 7, f"got {(r or {}).get('id')!r}")
|
||||||
|
|
||||||
# ---- 8. 未知方法 ----
|
# ---- 8. 未知方法 ----
|
||||||
|
|||||||
Reference in new issue
Block a user