metal-kompanion/src/main.cpp

135 lines
3.5 KiB
C++

// Minimal CLI runner that registers Kompanion MCP tools and dispatches requests.
#include <cstdlib>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <optional>
#include <sstream>
#include <string>
#ifdef HAVE_KCONFIG
#include <KConfigGroup>
#include <KSharedConfig>
#else
#include <QDir>
#include <QSettings>
#include <QStandardPaths>
#endif
#include "mcp/KomMcpServer.hpp"
#include "mcp/RegisterTools.hpp"
namespace {
std::string read_all(std::istream& in) {
std::ostringstream oss;
oss << in.rdbuf();
return oss.str();
}
std::string load_request(int argc, char** argv) {
if (argc < 3) {
return read_all(std::cin);
}
std::string arg = argv[2];
if (arg == "-") {
return read_all(std::cin);
}
std::filesystem::path p{arg};
if (std::filesystem::exists(p)) {
std::ifstream file(p);
if (!file) throw std::runtime_error("unable to open request file: " + p.string());
return read_all(file);
}
return arg;
}
void print_usage(const char* exe, KomMcpServer& server) {
std::cerr << "Usage: " << exe << " <tool-name> [request-json|-|path]\n";
std::cerr << "Available tools:\n";
for (const auto& name : server.listTools()) {
std::cerr << " - " << name << "\n";
}
}
} // namespace
#ifdef HAVE_KCONFIG
std::optional<std::string> read_dsn_from_config() {
auto config = KSharedConfig::openConfig(QStringLiteral("kompanionrc"));
if (!config) return std::nullopt;
KConfigGroup dbGroup(config, QStringLiteral("Database"));
const QString dsn = dbGroup.readEntry(QStringLiteral("PgDsn"), QString());
if (dsn.isEmpty()) {
return std::nullopt;
}
return dsn.toStdString();
}
#else
QString configFilePath() {
QString base = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation);
if (base.isEmpty()) {
base = QDir::homePath();
}
return QDir(base).filePath(QStringLiteral("kompanionrc"));
}
std::optional<std::string> read_dsn_from_config() {
QSettings settings(configFilePath(), QSettings::IniFormat);
const QString dsn = settings.value(QStringLiteral("Database/PgDsn")).toString();
if (dsn.isEmpty()) {
return std::nullopt;
}
return dsn.toStdString();
}
#endif
int main(int argc, char** argv) {
KomMcpServer server;
register_default_tools(server);
const char* envDsn = std::getenv("PG_DSN");
std::optional<std::string> effectiveDsn;
if (envDsn && *envDsn) {
effectiveDsn = std::string(envDsn);
} else {
effectiveDsn = read_dsn_from_config();
if (effectiveDsn) {
::setenv("PG_DSN", effectiveDsn->c_str(), 1);
}
}
if (!effectiveDsn) {
std::cerr << "[kom_mcp] PG_DSN not set; fallback DAL will be used if available (configure Database/PgDsn via KConfig).\n";
}
if (argc < 2) {
print_usage(argv[0], server);
return 1;
}
std::string tool = argv[1];
if (tool == "--list") {
for (const auto& name : server.listTools()) {
std::cout << name << "\n";
}
return 0;
}
if (!server.hasTool(tool)) {
std::cerr << "Unknown tool: " << tool << "\n";
print_usage(argv[0], server);
return 1;
}
try {
std::string request = load_request(argc, argv);
std::string response = server.dispatch(tool, request);
std::cout << response << std::endl;
return 0;
} catch (const std::exception& ex) {
std::cerr << "Error: " << ex.what() << "\n";
return 1;
}
}