refactor
重构 mcp-server 功能
This commit is contained in:
1 parent
5d6f1c74d1
commit
1435b864f8
12 files changed
+232
-95
No files matched your search
@@ -38,9 +38,12 @@ extern "C" AcRx::AppRetCode acrxEntryPoint(AcRx::AppMsgCode msg, void* pkt)
|
||||
case AcRx::kInitAppMsg:
|
||||
acrxDynamicLinker->unlockApplication(pkt);
|
||||
acrxDynamicLinker->registerAppMDIAware(pkt);
|
||||
if (!mcp::init_mcp_server())
|
||||
return AcRx::kRetError;
|
||||
InitApplication();
|
||||
break;
|
||||
case AcRx::kUnloadAppMsg:
|
||||
mcp::close_mcp_server();
|
||||
UnloadApplication();
|
||||
break;
|
||||
}
|
||||
@@ -50,8 +53,6 @@ extern "C" AcRx::AppRetCode acrxEntryPoint(AcRx::AppMsgCode msg, void* pkt)
|
||||
void CR_SCGXCmdFnc();
|
||||
void InitApplication()
|
||||
{
|
||||
mcp::init_mcp_server();
|
||||
|
||||
acrxBuildClassHierarchy();
|
||||
AddCommand(_T("SHCRACKTOOLS"), _T("CR_SCGX"), _T("CR_SCGX"), ACRX_CMD_TRANSPARENT | ACRX_CMD_USEPICKSET, CR_SCGXCmdFnc);
|
||||
|
||||
@@ -60,7 +61,6 @@ void InitApplication()
|
||||
void UnloadApplication()
|
||||
{
|
||||
acedRegCmds->removeGroup(_T("SHCRACKTOOLS"));
|
||||
mcp::close_mcp_server();
|
||||
}
|
||||
|
||||
void AddCommand(const TCHAR* cmdGroup, const TCHAR* cmdInt, const TCHAR* cmdLoc,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"version": "1.0.0",
|
||||
"global_settings": {
|
||||
"plugin_directory": "./mcp_plugins",
|
||||
"lisp_directory": "./mcp_lisp",
|
||||
"lisp_directory": "./mcp_plugins",
|
||||
"hot_reload": true
|
||||
},
|
||||
"tools": [
|
||||
|
||||
@@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 3.16)
|
||||
project(AutoAgent)
|
||||
|
||||
find_package(nlohmann_json CONFIG REQUIRED)
|
||||
find_package(ghc_filesystem CONFIG REQUIRED)
|
||||
|
||||
set(SOURCES
|
||||
"AutoAgent.cpp"
|
||||
@@ -12,6 +13,7 @@ set(SOURCES
|
||||
"mcp_server.cpp"
|
||||
"mcp_tool.cpp"
|
||||
"mcp_ConfigParser.cpp"
|
||||
"mcp_utils.cpp"
|
||||
)
|
||||
add_def_file_name(SOURCES "${PROJECT_NAME}")
|
||||
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
#include "mcp_ConfigParser.h"
|
||||
#include "mcp_ConfigParser.h"
|
||||
#include "cadsdk.h"
|
||||
#include <windows.h>
|
||||
#include "mcp_tool.h"
|
||||
#include "mcp_utils.h"
|
||||
#include "ghc/filesystem.hpp"
|
||||
|
||||
#pragma region mcp_ConfigParser
|
||||
bool mcp_ConfigParser::LoadAndRegister(const std::string &jsonFilePath, mcp_Tools ®istry)
|
||||
bool mcp_ConfigParser::LoadAndRegister(const std::wstring &jsonFilePath, mcp_Tools ®istry)
|
||||
{
|
||||
std::ifstream ifs(jsonFilePath);
|
||||
if (!ifs.is_open()) return false;
|
||||
@@ -12,8 +15,15 @@ bool mcp_ConfigParser::LoadAndRegister(const std::string &jsonFilePath, mcp_Tool
|
||||
try { ifs >> config; }
|
||||
catch (...) { return false; } // 防御非法 JSON
|
||||
|
||||
std::string pluginDir = config["global_settings"].value("plugin_directory", "./mcp_plugins");
|
||||
std::string lispDir = config["global_settings"].value("lisp_directory", "./mcp_lisp");
|
||||
fs::path pluginPath
|
||||
= mcp_utils::relative2absolute(config["global_settings"].value("plugin_directory", "./mcp_plugins"));
|
||||
fs::path lispPath
|
||||
= mcp_utils::relative2absolute(config["global_settings"].value("lisp_directory", "./mcp_lisp"));
|
||||
|
||||
if (!fs::exists(lispPath))
|
||||
AfxMessageBox(CString(_T("[MCP Server]Warning: The LISP script directory does not exist; the associated tools will not load!\n")) + pluginPath.c_str());
|
||||
if (!fs::exists(pluginPath))
|
||||
AfxMessageBox(CString(_T("[MCP Server]Warning: The plugin DLL directory does not exist; the associated tools will not load!\n")) + pluginPath.c_str());
|
||||
|
||||
for (const auto &toolConfig : config["tools"])
|
||||
{
|
||||
@@ -25,28 +35,35 @@ bool mcp_ConfigParser::LoadAndRegister(const std::string &jsonFilePath, mcp_Tool
|
||||
pTool->SetConfig(toolConfig);
|
||||
registry.Register(pTool);
|
||||
}
|
||||
else if (type == "lisp_file")
|
||||
else if (type == "lisp_file" && fs::exists(lispPath))
|
||||
{
|
||||
auto pTool = std::make_shared<mcp_Tool_LispFile>(lispDir);
|
||||
auto pTool = std::make_shared<mcp_Tool_LispFile>(lispPath);
|
||||
pTool->SetConfig(toolConfig);
|
||||
registry.Register(pTool);
|
||||
}
|
||||
else if (type == "c++_dll")
|
||||
else if (type == "c++_dll" && fs::exists(pluginPath))
|
||||
{
|
||||
LoadDllTool(toolConfig, pluginDir, registry);
|
||||
|
||||
LoadDllTool(toolConfig, pluginPath, registry);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void mcp_ConfigParser::LoadDllTool(const nlohmann::json &toolConfig, const std::string &pluginDir, mcp_Tools ®istry)
|
||||
void mcp_ConfigParser::LoadDllTool(const nlohmann::json &toolConfig, const std::wstring &pluginDir, mcp_Tools ®istry)
|
||||
{
|
||||
std::string dllName = toolConfig["backend"].value("dll_name", "");
|
||||
fs::path dllPath
|
||||
= mcp_utils::relative2absolute(toolConfig["backend"].value("dll_name", "")
|
||||
, fs::path(pluginDir));
|
||||
std::string factoryName = toolConfig["backend"].value("factory_function", "");
|
||||
|
||||
std::string fullPath = pluginDir + "\\" + dllName; // Windows 环境下拼接 DLL 路径
|
||||
if (!fs::exists(dllPath))
|
||||
{
|
||||
AfxMessageBox(CString(_T("[MCP Server]Warning: The DLL file does not exist; the associated tools will not load!\n")) + dllPath.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
HMODULE hMod = LoadLibraryA(fullPath.c_str());
|
||||
HMODULE hMod = LoadLibrary(dllPath.c_str());
|
||||
if (!hMod) return;
|
||||
|
||||
typedef mcp_Tool *(*CreateFunc)();
|
||||
@@ -117,7 +134,20 @@ nlohmann::json mcp_Tools::Call(const std::string &name, const nlohmann::json &ar
|
||||
}
|
||||
|
||||
// 找不到工具时,返回标准的 JSON-RPC 错误对象
|
||||
return mcp_Tool_Utility::make_error(-32601, "未找到指定的 Tool: " + name);
|
||||
return mcp_Tool_Utility::make_error(-32601, "Specified tool not found: " + name);
|
||||
}
|
||||
|
||||
void mcp_Tools::print()
|
||||
{
|
||||
for (const auto &pair : m_tools)
|
||||
{
|
||||
acutPrintf(_T("Tool: %s Already registered.\n"), mcp_utils::utf8ToWString(pair.first.c_str()).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void mcp_Tools::clear()
|
||||
{
|
||||
m_tools.clear();
|
||||
}
|
||||
#pragma endregion mcp_Tools
|
||||
|
||||
|
||||
@@ -17,13 +17,17 @@ public:
|
||||
|
||||
// 路由分发执行指令 (用于 tools/call)
|
||||
nlohmann::json Call(const std::string &name, const nlohmann::json &args);
|
||||
|
||||
void print();
|
||||
|
||||
void clear();
|
||||
};
|
||||
|
||||
class mcp_ConfigParser
|
||||
{
|
||||
public:
|
||||
static bool LoadAndRegister(const std::string &jsonFilePath, mcp_Tools ®istry);
|
||||
static bool LoadAndRegister(const std::wstring &jsonFilePath, mcp_Tools ®istry);
|
||||
|
||||
private:
|
||||
static void LoadDllTool(const nlohmann::json &toolConfig, const std::string &pluginDir, mcp_Tools ®istry);
|
||||
static void LoadDllTool(const nlohmann::json &toolConfig, const std::wstring &pluginDir, mcp_Tools ®istry);
|
||||
};
|
||||
@@ -6,11 +6,15 @@
|
||||
#include <atomic>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include "mcp_ConfigParser.h"
|
||||
#include "mcp_utils.h"
|
||||
|
||||
#pragma comment(lib, "ws2_32.lib")
|
||||
#define WM_MCP_EXECUTE_TASK (WM_USER + 2048)
|
||||
extern HINSTANCE _hdllInstance;
|
||||
|
||||
#define MCP_SERVER_PORT 8080
|
||||
#define MCP_SERVER_CONFIG _T("mcp_config.json")
|
||||
|
||||
namespace
|
||||
{
|
||||
std::thread g_serverThread;
|
||||
@@ -142,7 +146,7 @@ namespace
|
||||
sockaddr_in serverAddr = { 0 };
|
||||
serverAddr.sin_family = AF_INET;
|
||||
inet_pton(AF_INET, "127.0.0.1", &serverAddr.sin_addr);
|
||||
serverAddr.sin_port = htons(8080);
|
||||
serverAddr.sin_port = htons(MCP_SERVER_PORT);
|
||||
|
||||
bind(g_listenSocket, (sockaddr *)&serverAddr, sizeof(serverAddr));
|
||||
listen(g_listenSocket, SOMAXCONN);
|
||||
@@ -197,6 +201,27 @@ namespace
|
||||
|
||||
namespace mcp
|
||||
{
|
||||
bool close_mcp_server()
|
||||
{
|
||||
g_bRunning = false;
|
||||
if (g_serverThread.joinable())
|
||||
{
|
||||
g_serverThread.join();
|
||||
}
|
||||
|
||||
if (g_hMsgWnd != NULL)
|
||||
{
|
||||
DestroyWindow(g_hMsgWnd);
|
||||
UnregisterClass(g_szMsgClassName, _hdllInstance);
|
||||
g_hMsgWnd = NULL;
|
||||
}
|
||||
|
||||
g_mcpTools.clear();
|
||||
|
||||
acutPrintf(_T("\n[MCP Server] The plugin has been uninstalled, and the thread has been closed.\n"));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool init_mcp_server()
|
||||
{
|
||||
// 1. 在主线程注册并创建 Message-Only 窗口
|
||||
@@ -214,48 +239,35 @@ namespace mcp
|
||||
0, 0, 0, 0, 0,
|
||||
HWND_MESSAGE, // 纯消息窗口,无界面、无感知
|
||||
NULL,
|
||||
GetModuleHandle(NULL),
|
||||
_hdllInstance,
|
||||
NULL
|
||||
);
|
||||
g_bRunning = true;
|
||||
try
|
||||
{
|
||||
g_serverThread = std::thread(TcpServerLoop);
|
||||
acutPrintf(_T("\n[MCP Server] 后台 TCP 监听线程已启动 (端口: 8080)...\n"));
|
||||
acutPrintf(_T("\n[MCP Server] Background TCP listening thread started (Port: 8080)...\n"));
|
||||
}
|
||||
catch (const std::system_error &e)
|
||||
{
|
||||
// 线程创建失败,重置状态标志并输出错误
|
||||
g_bRunning = false;
|
||||
// e.what() 返回的是 const char*,所以在 acutPrintf 中要用 %hs 而不是 %s 或 %ls
|
||||
acutPrintf(_T("\n[MCP Server] 致命错误:无法创建后台监听线程!原因: %hs\n"), e.what());
|
||||
acutPrintf(_T("\n[MCP Server] Fatal error: Unable to create background listening thread! Reason: %hs\n"), e.what());
|
||||
}
|
||||
|
||||
// 如果监听跑起来了,则注册tools
|
||||
if (g_bRunning)
|
||||
{
|
||||
mcp_ConfigParser::LoadAndRegister("mcp_config.json", g_mcpTools);
|
||||
if (!mcp_ConfigParser::LoadAndRegister(mcp_utils::getModelDirPath() / MCP_SERVER_CONFIG, g_mcpTools))
|
||||
{
|
||||
acutPrintf(_T("\n[MCP Server] Warning: Failed to load tool configuration!\n[MCP Server] Automatic Shutdown.\n"));
|
||||
g_bRunning = false;
|
||||
}
|
||||
|
||||
g_mcpTools.print();
|
||||
}
|
||||
|
||||
return g_bRunning;
|
||||
}
|
||||
|
||||
bool close_mcp_server()
|
||||
{
|
||||
g_bRunning = false;
|
||||
if (g_serverThread.joinable())
|
||||
{
|
||||
g_serverThread.join();
|
||||
}
|
||||
|
||||
if (g_hMsgWnd != NULL)
|
||||
{
|
||||
DestroyWindow(g_hMsgWnd);
|
||||
UnregisterClass(g_szMsgClassName, _hdllInstance);
|
||||
g_hMsgWnd = NULL;
|
||||
}
|
||||
|
||||
acutPrintf(_T("\n[MCP Server] 插件已卸载,线程已关闭。\n"));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+36
-33
@@ -1,24 +1,14 @@
|
||||
#include "mcp_tool.h"
|
||||
#include "cadsdk.h"
|
||||
#include "cadsdk.h"
|
||||
#include "mcp_tool.h"
|
||||
#include "mcp_utils.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
// UTF-8 转 宽字符 (std::wstring)
|
||||
std::wstring Utf8ToWString(const std::string &utf8Str)
|
||||
bool ReplaceTemplateArgs(const std::string &_tpl, const nlohmann::json &args, std::wstring &outScript)
|
||||
{
|
||||
if (utf8Str.empty()) return std::wstring();
|
||||
if (_tpl.empty()) return false;
|
||||
|
||||
// 第一次调用获取需要的宽字符缓冲区大小
|
||||
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;
|
||||
}
|
||||
|
||||
std::string ReplaceTemplateArgs(std::string tpl, const nlohmann::json &args)
|
||||
{
|
||||
std::string tpl(_tpl);
|
||||
for (auto it = args.begin(); it != args.end(); ++it)
|
||||
{
|
||||
std::string placeholder = "{" + it.key() + "}";
|
||||
@@ -44,7 +34,8 @@ namespace
|
||||
pos += valueStr.length();
|
||||
}
|
||||
}
|
||||
return tpl;
|
||||
outScript = mcp_utils::utf8ToWString(tpl);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,36 +43,48 @@ namespace
|
||||
nlohmann::json mcp_Tool_LispInline::Execute(const nlohmann::json &args)
|
||||
{
|
||||
std::string tpl = m_config["backend"].value("script_template", "");
|
||||
std::string finalScript = ReplaceTemplateArgs(tpl, args) + " "; // 尾部加空格,等同于在 CAD 命令行敲回车
|
||||
std::wstring wScript = Utf8ToWString(finalScript);
|
||||
std::wstring finalScript;
|
||||
|
||||
if (!ReplaceTemplateArgs(tpl, args, finalScript))
|
||||
return mcp_Tool_Utility::make_error(-32603, "Script template replacement failed.");
|
||||
|
||||
finalScript += _T(" "); // 尾部加空格,等同于在 CAD 命令行敲回车
|
||||
|
||||
// 异步推送到 AutoCAD 命令行执行
|
||||
acDocManager->sendStringToExecute(acDocManager->curDocument(), wScript.c_str());
|
||||
acDocManager->sendStringToExecute(acDocManager->curDocument(), finalScript.c_str());
|
||||
|
||||
return mcp_Tool_Utility::make_text_result("LISP内联指令已下发执行 (异步)");
|
||||
return mcp_Tool_Utility::make_text_result("LISP inline command issued for execution (asynchronous)");
|
||||
}
|
||||
#pragma endregion mcp_Tool_LispInline
|
||||
|
||||
#pragma region mcp_Tool_LispFile
|
||||
nlohmann::json mcp_Tool_LispFile::Execute(const nlohmann::json &args)
|
||||
{
|
||||
std::string fileName = m_config["backend"].value("file_name", "");
|
||||
fs::path filePath
|
||||
= mcp_utils::relative2absolute(m_config["backend"].value("file_name", "")
|
||||
, fs::path(m_lispDir));
|
||||
|
||||
if (!fs::exists(filePath))
|
||||
{
|
||||
return mcp_Tool_Utility::make_error(-32603, "LISP file does not exist: " + filePath.string());
|
||||
}
|
||||
|
||||
std::string callTpl = m_config["backend"].value("call_template", "");
|
||||
|
||||
// 组装文件完整路径,并将反斜杠 \ 转换为 LISP 安全的正斜杠 /
|
||||
std::string fullPath = m_lispDir + "/" + fileName;
|
||||
std::replace(fullPath.begin(), fullPath.end(), '\\', '/');
|
||||
|
||||
// 组装前置加载命令,末尾的 nil 是为了防止文件不存在时 LISP 引擎报错弹窗
|
||||
std::string loadCmd = "(load \"" + fullPath + "\" nil) ";
|
||||
std::string executeCmd = ReplaceTemplateArgs(callTpl, args) + " ";
|
||||
std::wstring loadCmd = std::wstring(_T("(load \"")) + filePath.generic_wstring() + _T("\" nil) ");
|
||||
std::wstring executeCmd;
|
||||
if (!ReplaceTemplateArgs(callTpl, args, executeCmd))
|
||||
{
|
||||
return mcp_Tool_Utility::make_error(-32603, "Script template replacement failed.");
|
||||
}
|
||||
executeCmd += _T(" ");
|
||||
|
||||
std::string finalScript = loadCmd + executeCmd;
|
||||
std::wstring wScript = Utf8ToWString(finalScript);
|
||||
std::wstring finalScript = loadCmd + executeCmd;
|
||||
|
||||
acDocManager->sendStringToExecute(acDocManager->curDocument(), wScript.c_str());
|
||||
acDocManager->sendStringToExecute(acDocManager->curDocument(), finalScript.c_str());
|
||||
|
||||
return mcp_Tool_Utility::make_text_result("LISP外部文件已加载并下发执行 (异步)");
|
||||
return mcp_Tool_Utility::make_text_result("LISP external file loaded and issued for execution (asynchronous)");
|
||||
}
|
||||
#pragma endregion mcp_Tool_LispFile
|
||||
|
||||
@@ -105,7 +108,7 @@ nlohmann::json mcp_Tool_DllProxy::Execute(const nlohmann::json &args)
|
||||
{
|
||||
return m_pRealTool->Execute(args); // 完美转发
|
||||
}
|
||||
return mcp_Tool_Utility::make_error(-32603, "底层 DLL 工具实例已失效");
|
||||
return mcp_Tool_Utility::make_error(-32603, "Underlying DLL tool instance is invalid");
|
||||
}
|
||||
#pragma endregion mcp_Tool_DllProxy
|
||||
|
||||
@@ -13,10 +13,10 @@ public:
|
||||
class mcp_Tool_LispFile : public mcp_Tool
|
||||
{
|
||||
private:
|
||||
std::string m_lispDir;
|
||||
std::wstring m_lispDir;
|
||||
|
||||
public:
|
||||
mcp_Tool_LispFile(const std::string& lispDir) : m_lispDir(lispDir) {}
|
||||
mcp_Tool_LispFile(const std::wstring& lispDir) : m_lispDir(lispDir) {}
|
||||
|
||||
virtual nlohmann::json Execute(const nlohmann::json &args) override;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
#include "mcp_utils.h"
|
||||
#include <Windows.h>
|
||||
#include <tchar.h>
|
||||
#include <ghc/filesystem.hpp>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool mcp_utils::hasFileExist(const std::wstring &filePath) { return _taccess(filePath.c_str(), 0) == 0; }
|
||||
|
||||
bool mcp_utils::hasDirExist(const std::wstring &filePath) { return _taccess(filePath.c_str(), 0) == 0; }
|
||||
|
||||
std::wstring getModelDir()
|
||||
{
|
||||
TCHAR szPath[MAX_PATH];
|
||||
::GetModuleFileName(_hdllInstance, szPath, MAX_PATH);
|
||||
ghc::filesystem::path path(szPath);
|
||||
return path.parent_path().wstring();
|
||||
}
|
||||
|
||||
fs::path getModelDirPath()
|
||||
{
|
||||
return fs::path(getModelDir());
|
||||
}
|
||||
|
||||
fs::path relative2absolute(const std::string &relativePath, const fs::path &rootPath)
|
||||
{
|
||||
return relative2absolute(fs::path(utf8ToWString(relativePath)), rootPath);
|
||||
}
|
||||
|
||||
fs::path relative2absolute(const fs::path &relativePath, const fs::path &rootPath)
|
||||
{
|
||||
fs::path absolutePath = rootPath / relativePath;
|
||||
return absolutePath.lexically_normal().wstring();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
#include "ghc/filesystem.hpp"
|
||||
|
||||
namespace fs = ghc::filesystem;
|
||||
|
||||
namespace mcp_utils
|
||||
{
|
||||
std::wstring utf8ToWString(const std::string &utf8Str);
|
||||
|
||||
bool hasFileExist(const std::wstring &filePath);
|
||||
bool hasDirExist(const std::wstring &filePath);
|
||||
|
||||
std::wstring getModelDir();
|
||||
|
||||
ghc::filesystem::path getModelDirPath();
|
||||
|
||||
fs::path relative2absolute(const std::string &relativePath
|
||||
, const fs::path &rootPath = getModelDirPath());
|
||||
|
||||
fs::path relative2absolute(const fs::path &relativePath
|
||||
, const fs::path &rootPath = getModelDirPath());
|
||||
}
|
||||
+30
-16
@@ -1,20 +1,34 @@
|
||||
import socket
|
||||
import json
|
||||
|
||||
# 模拟大模型生成的 JSON 指令
|
||||
command = {
|
||||
"cmd": "draw_circle",
|
||||
"x": 500.0,
|
||||
"y": 500.0,
|
||||
"r": 250.0
|
||||
}
|
||||
def send_request(req_data):
|
||||
try:
|
||||
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
client.connect(("127.0.0.1", 8080))
|
||||
client.sendall(json.dumps(req_data).encode('utf-8'))
|
||||
response = client.recv(4096)
|
||||
print(">>> 收到回复:")
|
||||
print(json.dumps(json.loads(response.decode('utf-8')), indent=2, ensure_ascii=False))
|
||||
client.close()
|
||||
except Exception as e:
|
||||
print(f"连接失败: {e}")
|
||||
|
||||
try:
|
||||
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
client.connect(("127.0.0.1", 8080))
|
||||
# 发送序列化后的 JSON 字符串
|
||||
client.sendall(json.dumps(command).encode('utf-8'))
|
||||
client.close()
|
||||
print("指令发送成功,请查看 AutoCAD 屏幕。")
|
||||
except Exception as e:
|
||||
print(f"连接失败: {e}")
|
||||
if __name__ == "__main__":
|
||||
print("=== 测试 LISP 外部文件挂载 ===")
|
||||
request_call = {
|
||||
"jsonrpc": "2.0",
|
||||
"id": 3,
|
||||
"method": "tools/call",
|
||||
"params": {
|
||||
"name": "draw_conference_table",
|
||||
"arguments": {
|
||||
"cx": 1000.0,
|
||||
"cy": 1000.0,
|
||||
"length": 1500.0,
|
||||
"width": 600.0,
|
||||
"chair_count": 4,
|
||||
"layer": "MCP_CONF_ROOM"
|
||||
}
|
||||
}
|
||||
}
|
||||
send_request(request_call)
|
||||
+2
-1
@@ -3,7 +3,8 @@
|
||||
"version": "1.0.0",
|
||||
"dependencies": [
|
||||
"nlohmann-json",
|
||||
"curl"
|
||||
"curl",
|
||||
"ghc-filesystem"
|
||||
],
|
||||
"builtin-baseline": "127402f1c75bb3d5ff6bce04b285faa4930a5aca"
|
||||
}
|
||||
Reference in new issue
Block a user