Entropic 2.14.3
Local-first agentic inference engine
Loading...
Searching...
No Matches
server_base.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
10
11#include <nlohmann/json.hpp>
12
13#include <exception>
14
15static auto logger = entropic::log::get("mcp.server_base");
16
17namespace entropic {
18
26 : name_(std::move(name)) {}
27
34const std::string& MCPServerBase::name() const {
35 return name_;
36}
37
54
68std::string MCPServerBase::list_tools() const {
70}
71
109std::string MCPServerBase::normalize_args(
110 const std::string& tool_name,
111 const std::string& raw) const {
112 const auto first = raw.find_first_not_of(" \t\r\n");
113 if (first == std::string::npos) {
114 return "{}";
115 }
116 // Non-throwing parse: a discarded value is unparseable and is left
117 // alone on purpose, as is any non-null non-object.
118 const auto parsed = nlohmann::json::parse(raw, nullptr, false);
119 if (!parsed.is_null()) {
120 return raw;
121 }
122 logger->info(
123 "[{}.{}] arguments arrived as JSON null — reading as \"no "
124 "arguments\" and dispatching with {{}}",
125 name_, tool_name);
126 return "{}";
127}
128
166 const std::string& tool_name,
167 const std::string& raw_args_json) {
168 logger->info("[EXECUTE] {}.{}", name_, tool_name);
169
170 const std::string args_json = normalize_args(tool_name, raw_args_json);
171
173 try {
174 response = registry_.dispatch(tool_name, args_json);
175
176 auto* tool = registry_.get_tool(tool_name);
177 if (tool != nullptr) {
178 inject_anchor_if_needed(*tool, args_json, response);
179 }
180 } catch (const std::exception& e) {
181 // Full args are logged, never truncated — for this failure class
182 // the arguments are the whole diagnosis.
183 logger->error("Tool '{}.{}' threw: {} — args: {}",
184 name_, tool_name, e.what(), args_json);
185 response.directives.clear();
186 response.result =
187 "Error: tool '" + name_ + "." + tool_name + "' failed: "
188 + e.what();
189 }
190
191 return serialize_response(response);
192}
193
210 const std::string& tool_name,
211 const std::string& /*args_json*/) const {
212 return tool_name;
213}
214
231 const std::string& /*tool_name*/) const {
232 return false;
233}
234
246bool MCPServerBase::configure(const std::string& /*config_json*/) {
247 return true;
248}
249
261bool MCPServerBase::set_working_dir(const std::string& /*path*/) {
262 return true;
263}
264
284static const char* const DIRECTIVE_NAMES[] = {
285 "stop_processing", // 0
286 "tier_change", // 1
287 "delegate", // 2
288 "pipeline", // 3
289 "complete", // 4
290 "clear_self_todos", // 5
291 "inject_context", // 6
292 "prune_messages", // 7
293 "context_anchor", // 8
294 "phase_change", // 9
295 "notify_presenter", // 10
296};
297
309static const char* directive_type_name(
311 auto idx = static_cast<int>(type);
312 constexpr int count = sizeof(DIRECTIVE_NAMES)
313 / sizeof(DIRECTIVE_NAMES[0]);
314 if (idx < 0 || idx >= count) {
315 return "unknown";
316 }
317 return DIRECTIVE_NAMES[idx];
318}
319
333std::string MCPServerBase::serialize_response(
334 const ServerResponse& response) {
335 nlohmann::json j;
336 j["result"] = response.result;
337
338 auto directives = nlohmann::json::array();
339 for (const auto& d : response.directives) {
340 nlohmann::json dj;
341 dj["type"] = directive_type_name(d.type);
342 directives.push_back(std::move(dj));
343 }
344 j["directives"] = std::move(directives);
345
346 return j.dump();
347}
348
362void MCPServerBase::inject_anchor_if_needed(
363 const ToolBase& tool,
364 const std::string& args_json,
365 ServerResponse& response) {
366 auto key = tool.anchor_key(args_json);
367 if (key.empty()) {
368 return;
369 }
370 Directive anchor;
372 response.directives.push_back(std::move(anchor));
373 logger->info("Auto-injected ContextAnchor: {}", key);
374}
375
376} // namespace entropic
std::string list_tools() const
List all registered tools as a JSON array string.
const std::string & name() const
Get the server name.
std::string name_
Server name.
virtual bool skip_duplicate_check(const std::string &tool_name) const
Check if a tool should skip duplicate detection.
void register_tool(ToolBase *tool)
Register a tool with this server.
MCPServerBase(std::string name)
Construct with server name.
virtual std::string get_permission_pattern(const std::string &tool_name, const std::string &args_json) const
Generate permission pattern for 'Always Allow/Deny'.
ToolRegistry registry_
Tool registry.
virtual bool set_working_dir(const std::string &path)
Set the working directory.
virtual bool configure(const std::string &config_json)
Configure the server after creation.
std::string execute(const std::string &tool_name, const std::string &raw_args_json)
Execute a tool and wrap result in ServerResponse JSON.
Abstract base class for individual MCP tools.
Definition tool_base.h:52
void register_tool(ToolBase *tool)
Register a tool instance.
ServerResponse dispatch(const std::string &name, const std::string &args_json)
Dispatch a tool call to the registered tool's execute().
std::string get_tools_json() const
Get all registered tool definitions as a JSON array string.
ToolBase * get_tool(const std::string &name) const
Get a registered tool by name.
entropic_directive_type_t
Directive types emitted by MCP tool results.
Definition enums.h:58
@ ENTROPIC_DIRECTIVE_CONTEXT_ANCHOR
Replace context anchor.
Definition enums.h:67
spdlog initialization and logger access.
ENTROPIC_EXPORT std::shared_ptr< spdlog::logger > get(const std::string &name)
Get or create a named logger.
Definition logging.cpp:211
Activate model on GPU (WARM → ACTIVE).
static const char * directive_type_name(entropic_directive_type_t type)
Map directive type enum to wire-format string.
@ optional
optional: every escape asks the host's path approver
@ count
Sentinel — MUST remain last.
static const char *const DIRECTIVE_NAMES[]
Serialize ServerResponse to JSON envelope.
MCPServerBase concrete base class + ServerResponse.
Structured result from tool execution.
Definition server_base.h:33