wiRedPanda
Logic Circuit Simulator
Loading...
Searching...
No Matches
ServerInfoHandler.cpp
Go to the documentation of this file.
1// Copyright 2015 - 2026, GIBIS-UNIFESP and the wiRedPanda contributors
2// SPDX-License-Identifier: GPL-3.0-or-later
3
5
6#include <QJsonArray>
7#include <QSet>
8
10
11namespace {
14struct CommandEntry
15{
16 const char *name;
17 const char *category;
18};
19
20constexpr CommandEntry kCommandTable[] = {
21 // Server / introspection
22 {"get_server_info", "server"},
23 {"list_commands", "introspection"},
24 {"describe_command", "introspection"},
25 // File
26 {"load_circuit", "file"},
27 {"save_circuit", "file"},
28 {"new_circuit", "file"},
29 {"close_circuit", "file"},
30 {"get_tab_count", "file"},
31 {"export_image", "file"},
32 {"export_arduino", "file"},
33 {"export_systemverilog", "file"},
34 // Element
35 {"create_element", "element"},
36 {"delete_element", "element"},
37 {"list_elements", "element"},
38 {"move_element", "element"},
39 {"set_element_properties", "element"},
40 {"set_input_value", "element"},
41 {"get_output_value", "element"},
42 {"rotate_element", "element"},
43 {"flip_element", "element"},
44 {"update_element", "element"},
45 {"change_input_size", "element"},
46 {"change_output_size", "element"},
47 {"toggle_truth_table_output", "element"},
48 {"morph_element", "element"},
49 // Connection
50 {"connect_elements", "connection"},
51 {"disconnect_elements", "connection"},
52 {"list_connections", "connection"},
53 {"split_connection", "connection"},
54 // Simulation
55 {"simulation_control", "simulation"},
56 {"create_waveform", "simulation"},
57 {"export_waveform", "simulation"},
58 // IC
59 {"create_ic", "ic"},
60 {"instantiate_ic", "ic"},
61 {"list_ics", "ic"},
62 {"embed_ic", "ic"},
63 {"extract_ic", "ic"},
64 // History
65 {"undo", "history"},
66 {"redo", "history"},
67 {"get_undo_stack", "history"},
68 // Theme
69 {"get_theme", "theme"},
70 {"set_theme", "theme"},
71 {"get_effective_theme", "theme"},
72};
73
74QString categoryFor(const QString &commandName)
75{
76 for (const auto &entry : kCommandTable) {
77 if (commandName == QLatin1String(entry.name)) {
78 return QString::fromLatin1(entry.category);
79 }
80 }
81 return {};
82}
83} // namespace
84
86 : BaseHandler(mainWindow, validator)
87{
88}
89
90QJsonObject ServerInfoHandler::handleCommand(const QString &command, const QJsonObject &params, const QJsonValue &requestId)
91{
92 if (command == "get_server_info") {
93 return handleGetServerInfo(params, requestId);
94 } else if (command == "list_commands") {
95 return handleListCommands(params, requestId);
96 } else if (command == "describe_command") {
97 return handleDescribeCommand(params, requestId);
98 } else {
99 return createErrorResponse(QString("Unknown server info command: %1").arg(command),
101 }
102}
103
104QJsonObject ServerInfoHandler::handleGetServerInfo(const QJsonObject &, const QJsonValue &requestId)
105{
106 QJsonObject result;
107 result["server_name"] = "wiRedPanda MCP Server";
108 result["version"] = APP_VERSION;
109 result["protocol_version"] = "1.0";
110 result["status"] = "ready";
111
112 QJsonArray capabilities;
113 capabilities.append("circuit_design");
114 capabilities.append("simulation");
115 capabilities.append("file_operations");
116 capabilities.append("image_export");
117 capabilities.append("waveform_generation");
118 capabilities.append("ic_management");
119 result["capabilities"] = capabilities;
120
121 return createSuccessResponse(result, requestId);
122}
123
124QJsonObject ServerInfoHandler::handleListCommands(const QJsonObject &, const QJsonValue &requestId)
125{
126 QJsonArray commands;
127 QSet<QString> categorySet;
128
129 for (const auto &entry : kCommandTable) {
130 QJsonObject cmd;
131 cmd["name"] = QString::fromLatin1(entry.name);
132 cmd["category"] = QString::fromLatin1(entry.category);
133 commands.append(cmd);
134 categorySet.insert(QString::fromLatin1(entry.category));
135 }
136
137 QStringList sortedCategories(categorySet.begin(), categorySet.end());
138 sortedCategories.sort();
139
140 QJsonArray categories;
141 for (const QString &c : sortedCategories) {
142 categories.append(c);
143 }
144
145 QJsonObject result;
146 result["commands"] = commands;
147 result["categories"] = categories;
148 return createSuccessResponse(result, requestId);
149}
150
151QJsonObject ServerInfoHandler::handleDescribeCommand(const QJsonObject &params, const QJsonValue &requestId)
152{
153 if (!validateParameters(params, {"name"})) {
154 return createErrorResponse("Missing required parameter: name", requestId, JsonRpcError::InvalidParams);
155 }
156
157 QString errorMsg;
158 if (!validateNonEmptyString(params.value("name"), "name", errorMsg)) {
159 return createErrorResponse(errorMsg, requestId, JsonRpcError::InvalidParams);
160 }
161
162 const QString name = params.value("name").toString();
163 const QString category = categoryFor(name);
164
165 if (category.isEmpty()) {
166 return createErrorResponse(QString("Unknown command: %1").arg(name),
168 }
169
170 if (!m_validator) {
171 return createErrorResponse("Schema validator not available",
172 requestId, JsonRpcError::InternalError);
173 }
174
175 // m_responseSchemas indexes by "<name>_response" key; m_commandSchemas by bare name.
176 const json inputSchema = m_validator->findCommandSchema(name);
177 const json responseSchema = m_validator->findResponseSchema(name + "_response");
178
179 QJsonObject result;
180 result["name"] = name;
181 result["category"] = category;
182 result["input_schema"] = inputSchema.is_null() ? QJsonObject{} : MCPValidator::nlohmannToQJson(inputSchema);
183 result["response_schema"] = responseSchema.is_null() ? QJsonObject{} : MCPValidator::nlohmannToQJson(responseSchema);
184 return createSuccessResponse(result, requestId);
185}
nlohmann::json json
const MCPValidator * m_validator
Definition BaseHandler.h:86
QJsonObject createSuccessResponse(const QJsonObject &result={}, const QJsonValue &requestId=QJsonValue()) const
BaseHandler(MainWindow *mainWindow, const MCPValidator *validator)
QJsonObject createErrorResponse(const QString &error, const QJsonValue &requestId=QJsonValue(), int code=JsonRpcError::InternalError) const
bool validateParameters(const QJsonObject &params, const QStringList &required) const
bool validateNonEmptyString(const QJsonValue &value, const QString &paramName, QString &errorMsg) const
JSON Schema validator for MCP commands and responses using native json-schema-validator.
static QJsonObject nlohmannToQJson(const json &nlohmannJson)
The top-level application window hosting the tab bar, menus, element palette, and editor.
Definition MainWindow.h:47
QJsonObject handleCommand(const QString &command, const QJsonObject &params, const QJsonValue &requestId) override
ServerInfoHandler(MainWindow *mainWindow, const MCPValidator *validator)
constexpr int MethodNotFound
The requested method does not exist or is unavailable.
constexpr int InternalError
Internal JSON-RPC error (last-resort).
constexpr int InvalidParams
Invalid method parameters (missing required, wrong type, etc.).