diff --git a/inc/mcp_plugin_api.h b/inc/mcp_plugin_api.h index 8b284bc..f82d769 100644 --- a/inc/mcp_plugin_api.h +++ b/inc/mcp_plugin_api.h @@ -5,9 +5,37 @@ class mcp_Tool_Utility { public: - // 1. 纯文本响应 - static nlohmann::json make_text_result(const std::string &text) + + static std::wstring utf8ToWString(const std::string &utf8Str) { + if (utf8Str.empty()) return std::wstring(); + + // 第一次调用获取需要的宽字符缓冲区大小 + int sizeNeeded = ::MultiByteToWideChar(CP_UTF8, 0, &utf8Str[0], (int)utf8Str.size(), NULL, 0); + std::wstring wstrTo(sizeNeeded, 0); + + // 第二次调用真正进行转换 + ::MultiByteToWideChar(CP_UTF8, 0, &utf8Str[0], (int)utf8Str.size(), &wstrTo[0], sizeNeeded); + return wstrTo; + } + + static std::string WStringToUtf8(const std::wstring &wstr) + { + if (wstr.empty()) return std::string(); + + // 第一次调用获取需要的 UTF-8 缓冲区大小 + int sizeNeeded = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL); + std::string strTo(sizeNeeded, 0); + + // 第二次调用真正进行转换 + WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0], sizeNeeded, NULL, NULL); + return strTo; + } + + // 1. 纯文本响应 + static nlohmann::json make_text_result(const std::wstring &_text) + { + std::string text = WStringToUtf8(_text); return { { "result", { { "content", { @@ -31,10 +59,11 @@ public: } // 3. 图文混合响应 (文字汇报结果 + 附带 CAD 视口截图) - static nlohmann::json make_mixed_result(const std::string &text + static nlohmann::json make_mixed_result(const std::wstring &_text , const std::string &base64Data , const std::string &mimeType = "image/png") { + std::string text = WStringToUtf8(_text); return { { "result", { { "content", { @@ -45,8 +74,9 @@ public: }; } - static nlohmann::json make_error(int code, const std::string &message) + static nlohmann::json make_error(int code, const std::wstring &_message) { + std::string message = WStringToUtf8(_message); return { { "error",{ { "code", code }, @@ -60,7 +90,7 @@ class mcp_Tool { protected: nlohmann::json m_config; - + std::string m_abiBuffer; // 存在于对象实例自己的堆内存中,确保指针生命周期安全 public: virtual ~mcp_Tool() = default; @@ -97,6 +127,29 @@ public: // 整个类唯一一个纯虚函数:全心全意干活! virtual nlohmann::json Execute(const nlohmann::json &args) = 0; + + // 安全配置注入 + virtual void SetConfigAbiSafe(const char* config_json_str) + { + // 在 DLL 内部的安全环境中完成字符串到 JSON 的反序列化 + m_config = nlohmann::json::parse(config_json_str); + } + + // 安全执行路由 + virtual const char* ExecuteAbiSafe(const char* args_json_str) + { + // 1. 在 DLL 的上下文中,将传入的 C 字符串转为 JSON + nlohmann::json args = nlohmann::json::parse(args_json_str); + + // 2. 调用真实的业务逻辑 + nlohmann::json result = Execute(args); + + // 3. 将结果序列化为字符串,存入属于该 DLL 的内存缓冲区 + m_abiBuffer = result.dump(); + + // 4. 返回安全的 C 指针 + return m_abiBuffer.c_str(); + } }; #define EXPORT_MCP_TOOL(ToolClass, FactoryName) \ diff --git a/src/cad_mcp_frame/mcp_ConfigParser.cpp b/src/cad_mcp_frame/mcp_ConfigParser.cpp index a3fa0e7..f85c822 100644 --- a/src/cad_mcp_frame/mcp_ConfigParser.cpp +++ b/src/cad_mcp_frame/mcp_ConfigParser.cpp @@ -122,7 +122,9 @@ void mcp_ConfigParser::LoadDllTool(const nlohmann::json &toolConfig, const std:: if (pRealTool) { // 给真正的 DLL 实例也注入配置,以防第三方需要在内部读取 - pRealTool->SetConfig(toolConfig); + std::string cfgStr = toolConfig.dump(); + pRealTool->SetConfigAbiSafe(cfgStr.c_str()); + //pRealTool->SetConfig(toolConfig); // 实例化代理类,接管生命周期 auto pProxy = std::make_shared(hMod, pRealTool, destroyFn); @@ -145,7 +147,6 @@ void mcp_ConfigParser::LoadDllTool(const nlohmann::json &toolConfig, const std:: #pragma endregion mcp_ConfigParser - #pragma region mcp_Tools // 注册工具 void mcp_Tools::Register(std::shared_ptr pTool) @@ -177,7 +178,7 @@ nlohmann::json mcp_Tools::Call(const std::string &name, const nlohmann::json &ar } // 找不到工具时,返回标准的 JSON-RPC 错误对象 - return mcp_Tool_Utility::make_error(-32601, "Specified tool not found: " + name); + return mcp_Tool_Utility::make_error(-32601, L"Specified tool not found: " + mcp_utils::utf8ToWString(name)); } void mcp_Tools::print() diff --git a/src/cad_mcp_frame/mcp_tool.cpp b/src/cad_mcp_frame/mcp_tool.cpp index 804ad9d..806a4b9 100644 --- a/src/cad_mcp_frame/mcp_tool.cpp +++ b/src/cad_mcp_frame/mcp_tool.cpp @@ -46,14 +46,14 @@ nlohmann::json mcp_Tool_LispInline::Execute(const nlohmann::json &args) std::wstring finalScript; if (!ReplaceTemplateArgs(tpl, args, finalScript)) - return mcp_Tool_Utility::make_error(-32603, "Script template replacement failed."); + return mcp_Tool_Utility::make_error(-32603, L"Script template replacement failed."); finalScript += _T(" "); // 尾部加空格,等同于在 CAD 命令行敲回车 // 异步推送到 AutoCAD 命令行执行 acDocManager->sendStringToExecute(acDocManager->curDocument(), finalScript.c_str()); - return mcp_Tool_Utility::make_text_result("LISP inline command issued for execution (asynchronous)"); + return mcp_Tool_Utility::make_text_result(L"LISP inline command issued for execution (asynchronous)"); } #pragma endregion LispInline @@ -66,7 +66,7 @@ nlohmann::json mcp_Tool_LispFile::Execute(const nlohmann::json &args) if (!fs::exists(filePath)) { - return mcp_Tool_Utility::make_error(-32603, "LISP file does not exist: " + filePath.string()); + return mcp_Tool_Utility::make_error(-32603, L"LISP file does not exist: " + mcp_utils::utf8ToWString(filePath.string())); } std::string callTpl = m_config["backend"].value("call_template", ""); @@ -76,7 +76,7 @@ nlohmann::json mcp_Tool_LispFile::Execute(const nlohmann::json &args) std::wstring executeCmd; if (!ReplaceTemplateArgs(callTpl, args, executeCmd)) { - return mcp_Tool_Utility::make_error(-32603, "Script template replacement failed."); + return mcp_Tool_Utility::make_error(-32603, L"Script template replacement failed."); } executeCmd += _T(" "); @@ -84,7 +84,7 @@ nlohmann::json mcp_Tool_LispFile::Execute(const nlohmann::json &args) acDocManager->sendStringToExecute(acDocManager->curDocument(), finalScript.c_str()); - return mcp_Tool_Utility::make_text_result("LISP external file loaded and issued for execution (asynchronous)"); + return mcp_Tool_Utility::make_text_result(L"LISP external file loaded and issued for execution (asynchronous)"); } #pragma endregion LispFile @@ -106,9 +106,12 @@ nlohmann::json mcp_Tool_DllProxy::Execute(const nlohmann::json &args) { if (m_pRealTool) { - return m_pRealTool->Execute(args); // 完美转发 + std::string argStr = args.dump(); + //return m_pRealTool->Execute(args); // 完美转发 + const char* retStr = m_pRealTool->ExecuteAbiSafe(argStr.c_str()); + return nlohmann::json::parse(retStr); } - return mcp_Tool_Utility::make_error(-32603, "Underlying DLL tool instance is invalid"); + return mcp_Tool_Utility::make_error(-32603, L"Underlying DLL tool instance is invalid"); } #pragma endregion DllProxy diff --git a/src/cad_mcp_frame/mcp_utils.cpp b/src/cad_mcp_frame/mcp_utils.cpp index 8395347..658776e 100644 --- a/src/cad_mcp_frame/mcp_utils.cpp +++ b/src/cad_mcp_frame/mcp_utils.cpp @@ -3,33 +3,18 @@ #include #include #include +#include "mcp_plugin_api.h" namespace mcp_utils { std::wstring utf8ToWString(const std::string &utf8Str) { - if (utf8Str.empty()) return std::wstring(); - - // 第一次调用获取需要的宽字符缓冲区大小 - int sizeNeeded = ::MultiByteToWideChar(CP_UTF8, 0, &utf8Str[0], (int)utf8Str.size(), NULL, 0); - std::wstring wstrTo(sizeNeeded, 0); - - // 第二次调用真正进行转换 - ::MultiByteToWideChar(CP_UTF8, 0, &utf8Str[0], (int)utf8Str.size(), &wstrTo[0], sizeNeeded); - return wstrTo; + return mcp_Tool_Utility::utf8ToWString(utf8Str); } std::string WStringToUtf8(const std::wstring &wstr) { - if (wstr.empty()) return std::string(); - - // 第一次调用获取需要的 UTF-8 缓冲区大小 - int sizeNeeded = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL); - std::string strTo(sizeNeeded, 0); - - // 第二次调用真正进行转换 - WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0], sizeNeeded, NULL, NULL); - return strTo; + return mcp_Tool_Utility::WStringToUtf8(wstr); } bool mcp_utils::hasFileExist(const std::wstring &filePath) { return _taccess(filePath.c_str(), 0) == 0; } diff --git a/src/cad_mcp_plugins/mcp_plugins.cpp b/src/cad_mcp_plugins/mcp_plugins.cpp index 4637b29..31f5b4c 100644 --- a/src/cad_mcp_plugins/mcp_plugins.cpp +++ b/src/cad_mcp_plugins/mcp_plugins.cpp @@ -61,11 +61,11 @@ public: // 5. 返回标准 MCP 结果,如果失败可以根据 es 的值返回 make_error if (es == Acad::eOk) { - return mcp_Tool_Utility::make_text_result("C++底层接口已成功在模型空间生成圆形!"); + return mcp_Tool_Utility::make_text_result(L"C++底层接口已成功在模型空间生成圆形!"); } else { - return mcp_Tool_Utility::make_error((int)es, "ObjectARX 内部错误"); + return mcp_Tool_Utility::make_error((int)es, L"ObjectARX 内部错误"); } } };