Feature: Add get_audit_log MCP tool

Expose the server main-window audit log (host online/offline, operation
results, alerts) as a read-only, no-arg, in-memory MCP tool. The log lives
in m_CList_Message, a CListCtrl that is only safe to touch on the UI
thread, so add a thread-safe mirror m_MessageLog (guarded by m_cs) and keep
it in sync at the four item-mutation sites: ShowMessage, OnShowErrMessage,
OnMsglogDelete and OnMsglogClear. The tool reads the mirror directly under
m_cs and returns up to MAX_MESSAGE_COUNT (1000) entries, newest first.

Co-Authored-By: deepseek-v4-pro
This commit is contained in:
yuanyuanxiang
2026-08-21 20:33:59 +02:00
parent 8de5c00a39
commit 8815c4f896
3 changed files with 126 additions and 0 deletions

View File

@@ -639,6 +639,34 @@ Json::Value BuildClientLogOutputSchema() {
return schema;
}
// get_audit_log 的 outputSchema服务端消息/审计日志条目数组)
Json::Value BuildAuditLogOutputSchema() {
Json::Value props(Json::objectValue);
Json::Value entriesProp(Json::objectValue);
entriesProp["type"] = "array";
Json::Value items(Json::objectValue);
items["type"] = "object";
Json::Value itemProps(Json::objectValue);
const char* strFields[] = { "type", "time", "msg" };
for (const char* f : strFields) {
Json::Value s(Json::objectValue);
s["type"] = "string";
itemProps[f] = s;
}
items["properties"] = itemProps;
entriesProp["items"] = items;
props["entries"] = entriesProp;
Json::Value schema(Json::objectValue);
schema["type"] = "object";
schema["properties"] = props;
Json::Value required(Json::arrayValue);
required.append("entries");
schema["required"] = required;
return schema;
}
// get_screenshot 的 outputSchemaimage 元数据base64 数据在 content 的 image 块中)
Json::Value BuildScreenshotOutputSchema() {
Json::Value props(Json::objectValue);
@@ -897,6 +925,23 @@ std::string BuildToolsListResult(const Json::Value& id) {
tools.append(tool);
}
// 11) get_audit_log服务端本地主界面消息/审计日志,纯内存,无子链接)
{
Json::Value tool(Json::objectValue);
tool["name"] = "get_audit_log";
tool["description"] = u8"获取 YAMA 服务端主界面的消息/审计日志(主机上线/下线、操作结果、告警等)。返回列表内当前全部条目(最多 1000 条,新在前)。只读、纯内存。";
Json::Value inputSchema(Json::objectValue);
inputSchema["type"] = "object";
inputSchema["properties"] = Json::Value(Json::objectValue);
inputSchema["required"] = Json::Value(Json::arrayValue);
tool["inputSchema"] = inputSchema;
tool["outputSchema"] = BuildAuditLogOutputSchema();
tools.append(tool);
}
result["tools"] = tools;
return BuildResult(id, result);
}
@@ -1418,6 +1463,41 @@ std::string BuildGetClientLog(const Json::Value& id, const Json::Value& args, CM
return BuildResult(id, result);
}
// tools/callget_audit_log服务端本地消息日志读取 UI 日志列表的线程安全镜像)
std::string BuildGetAuditLog(const Json::Value& id, CMy2015RemoteDlg* parent) {
Json::Value entries(Json::arrayValue);
if (parent) {
EnterCriticalSection(&parent->m_cs);
// m_MessageLog 新在前、旧在后(与界面一致),直接顺序输出。
for (const auto& e : parent->m_MessageLog) {
Json::Value item(Json::objectValue);
item["type"] = ToUtf8(e.type.c_str(), 936);
item["time"] = ToUtf8(e.time.c_str(), 936);
item["msg"] = ToUtf8(e.msg.c_str(), 936);
entries.append(item);
}
LeaveCriticalSection(&parent->m_cs);
}
int count = (int)entries.size();
Json::Value result(Json::objectValue);
Json::Value structuredContent(Json::objectValue);
structuredContent["entries"] = entries;
result["structuredContent"] = structuredContent;
Json::Value content(Json::arrayValue);
Json::Value item(Json::objectValue);
item["type"] = "text";
item["text"] = count > 0 ? std::string(u8"") + std::to_string(count) + std::string(u8" 条日志。")
: std::string(u8"当前无日志。");
content.append(item);
result["content"] = content;
result["isError"] = false;
return BuildResult(id, result);
}
// tools/call 分派
std::string BuildToolsCall(const Json::Value& root, CMy2015RemoteDlg* parent) {
const Json::Value& id = root["id"];
@@ -1440,6 +1520,7 @@ std::string BuildToolsCall(const Json::Value& root, CMy2015RemoteDlg* parent) {
if (toolName == "list_files") return BuildListFiles(id, args, parent);
if (toolName == "list_services") return BuildListServices(id, args, parent);
if (toolName == "get_client_log") return BuildGetClientLog(id, args, parent);
if (toolName == "get_audit_log") return BuildGetAuditLog(id, parent);
return BuildError(id, -32602,
"Unknown tool: " + (toolName.empty() ? std::string("(empty)") : toolName));