135 lines
3.5 KiB
C++
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;
|
|
}
|
|
}
|