feat: Add initial MCP Server support

This commit is contained in:
WerWolv
2025-12-16 20:25:46 +01:00
parent 932c281223
commit e696d384c2
15 changed files with 421 additions and 3 deletions

View File

@@ -30,6 +30,7 @@ namespace hex::plugin::builtin {
void handleValidatePluginCommand(const std::vector<std::string> &args);
void handleSaveEditorCommand(const std::vector<std::string> &args);
void handleFileInfoCommand(const std::vector<std::string> &args);
void handleMCPCommand(const std::vector<std::string> &args);
void registerCommandForwarders();

View File

@@ -54,6 +54,7 @@
"hex.builtin.achievement.misc.download_from_store.name": "There's an app for that",
"hex.builtin.achievement.misc.download_from_store.desc": "Download any item from the Content Store",
"hex.builtin.background_service.network_interface": "Network Interface",
"hex.builtin.setting.general.mcp_server": "MCP Server support",
"hex.builtin.background_service.auto_backup": "Auto Backup",
"hex.builtin.command.calc.desc": "Calculator",
"hex.builtin.command.convert.desc": "Unit conversion",

View File

@@ -17,6 +17,8 @@
#include <fmt/chrono.h>
#include <nlohmann/json.hpp>
#include <romfs/romfs.hpp>
#include <toasts/toast_notification.hpp>
namespace hex::plugin::builtin {
@@ -103,6 +105,16 @@ namespace hex::plugin::builtin {
std::this_thread::sleep_for(std::chrono::seconds(1));
}
void handleMCPServer() {
if (!ContentRegistry::MCP::isEnabled()) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
ContentRegistry::MCP::impl::getMcpServerInstance().disconnect();
return;
}
ContentRegistry::MCP::impl::getMcpServerInstance().listen();
}
}
void registerBackgroundServices() {
@@ -110,12 +122,17 @@ namespace hex::plugin::builtin {
s_networkInterfaceServiceEnabled = value.get<bool>(false);
});
ContentRegistry::Settings::onChange("hex.builtin.setting.general", "hex.builtin.setting.general.mcp_server", [](const ContentRegistry::Settings::SettingsValue &value) {
ContentRegistry::MCP::impl::setEnabled(value.get<bool>(false));
});
ContentRegistry::Settings::onChange("hex.builtin.setting.general", "hex.builtin.setting.general.backups.auto_backup_time", [](const ContentRegistry::Settings::SettingsValue &value) {
s_autoBackupTime = value.get<int>(0) * 30;
});
ContentRegistry::BackgroundServices::registerService("hex.builtin.background_service.network_interface", handleNetworkInterfaceService);
ContentRegistry::BackgroundServices::registerService("hex.builtin.background_service.auto_backup", handleAutoBackup);
ContentRegistry::BackgroundServices::registerService("hex.builtin.background_service.mcp", handleMCPServer);
EventProviderDirtied::subscribe([](prv::Provider *) {
s_dataDirty = true;

View File

@@ -1,4 +1,6 @@
#include <iostream>
#include <content/command_line_interface.hpp>
#include <hex/mcp/client.hpp>
#include <hex/api/imhex_api/system.hpp>
#include <hex/api/imhex_api/hex_editor.hpp>
@@ -530,6 +532,14 @@ namespace hex::plugin::builtin {
ContentRegistry::Views::setFullScreenView<ViewFullScreenFileInfo>(path);
}
void handleMCPCommand(const std::vector<std::string> &) {
mcp::Client client;
auto result = client.run(std::cin, std::cout);
std::fprintf(stderr, "MCP Client disconnected!\n");
std::exit(result);
}
void registerCommandForwarders() {
hex::subcommands::registerSubCommand("open", [](const std::vector<std::string> &args){

View File

@@ -768,6 +768,8 @@ namespace hex::plugin::builtin {
ContentRegistry::Settings::add<Widgets::Checkbox>("hex.builtin.setting.general", "hex.builtin.setting.general.network", "hex.builtin.setting.general.network_interface", false);
ContentRegistry::Settings::add<Widgets::Checkbox>("hex.builtin.setting.general", "hex.builtin.setting.general.network", "hex.builtin.setting.general.mcp_server", false);
#if !defined(OS_WEB)
ContentRegistry::Settings::add<ServerContactWidget>("hex.builtin.setting.general", "hex.builtin.setting.general.network", "hex.builtin.setting.general.server_contact");
ContentRegistry::Settings::add<Widgets::Checkbox>("hex.builtin.setting.general", "hex.builtin.setting.general.network", "hex.builtin.setting.general.upload_crash_logs", true);

View File

@@ -29,6 +29,7 @@
#include <csignal>
#include <fonts/tabler_icons.hpp>
#include <hex/api/content_registry/communication_interface.hpp>
namespace hex::plugin::builtin {
@@ -239,6 +240,20 @@ namespace hex::plugin::builtin {
});
}
ContentRegistry::UserInterface::addFooterItem([] {
if (ContentRegistry::MCP::isConnected()) {
ImGui::PushStyleColor(ImGuiCol_Text, ImGuiExt::GetCustomColorU32(ImGuiCustomCol_Highlight));
} else {
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetColorU32(ImGuiCol_TextDisabled));
}
if (ContentRegistry::MCP::isEnabled()) {
ImGui::TextUnformatted(ICON_VS_MCP);
}
ImGui::PopStyleColor();
});
if (dbg::debugModeEnabled()) {
ContentRegistry::UserInterface::addFooterItem([] {
static float framerate = 0;

View File

@@ -73,8 +73,8 @@ IMHEX_PLUGIN_SUBCOMMANDS() {
{ "open", "o", "Open files passed as argument. [default]", hex::plugin::builtin::handleOpenCommand },
{ "new", "n", "Create a new empty file", hex::plugin::builtin::handleNewCommand },
{ "select", "s", "Select a range of bytes in the Hex Editor", hex::plugin::builtin::handleSelectCommand },
{ "pattern", "p", "Sets the loaded pattern", hex::plugin::builtin::handlePatternCommand },
{ "select", "s", "Select a range of bytes in the Hex Editor", hex::plugin::builtin::handleSelectCommand },
{ "pattern", "p", "Sets the loaded pattern", hex::plugin::builtin::handlePatternCommand },
{ "calc", "", "Evaluate a mathematical expression", hex::plugin::builtin::handleCalcCommand },
{ "hash", "", "Calculate the hash of a file", hex::plugin::builtin::handleHashCommand },
{ "encode", "", "Encode a string", hex::plugin::builtin::handleEncodeCommand },
@@ -88,6 +88,7 @@ IMHEX_PLUGIN_SUBCOMMANDS() {
{ "validate-plugin", "", "Validates that a plugin can be loaded", hex::plugin::builtin::handleValidatePluginCommand },
{ "save-editor", "", "Opens a pattern file for save file editing", hex::plugin::builtin::handleSaveEditorCommand },
{ "file-info", "i", "Displays information about a file", hex::plugin::builtin::handleFileInfoCommand },
{ "mcp", "", "Starts a MCP Server for AI to interact with", hex::plugin::builtin::handleMCPCommand },
};
IMHEX_PLUGIN_SETUP_BUILTIN("Built-in", "WerWolv", "Default ImHex functionality") {