27PluginServer::PluginServer(
void* handle, std::filesystem::path path)
28 : handle_(handle), path_(std::move(path)) {}
40PluginServer::~PluginServer() {
41 if (instance_ !=
nullptr && destroy_fn_ !=
nullptr) {
42 destroy_fn_(instance_);
45 if (handle_ !=
nullptr) {
71 std::unique_ptr<PluginServer>& out) {
75 void* handle = dlopen(path.c_str(), RTLD_NOW | RTLD_LOCAL);
76 if (handle ==
nullptr) {
77 const char* err = dlerror();
78 logger->error(
"Plugin load failed: dlopen('{}'): {}", path.string(),
79 (err !=
nullptr) ? err :
"unknown error");
84 std::unique_ptr<PluginServer> plugin(
new PluginServer(handle, path));
85 auto rc = plugin->resolve_and_init();
90 logger->info(
"Loaded MCP plugin '{}' from {}", plugin->name_,
92 out = std::move(plugin);
105 auto rc = resolve_and_check_version();
109 return create_instance();
126 instance_ = create_fn_();
127 if (instance_ ==
nullptr) {
128 logger->error(
"Plugin load failed: entropic_create_server() returned "
129 "NULL for {}", path_.string());
133 const char* raw_name = name_fn_(instance_);
134 name_ = (raw_name !=
nullptr) ? raw_name :
"";
136 logger->error(
"Plugin load failed: entropic_mcp_server_name() gave an "
137 "empty name for {} — the name is the tool-routing "
138 "prefix and cannot be blank", path_.string());
160 if (!resolve_symbols()) {
164 const int reported = version_fn_();
166 logger->error(
"Plugin version mismatch for {}: plugin reports API "
167 "version {}, this engine implements {}. Rebuild the "
168 "plugin against matching entropic headers.",
169 path_.string(), reported,
192bool PluginServer::resolve_symbols() {
195 const bool factory_ok = resolve_factory_symbols();
196 const bool instance_ok = resolve_instance_symbols();
197 return factory_ok && instance_ok;
208void* PluginServer::resolve_one(
const char* symbol_name,
bool& ok)
const {
212 void* addr = dlsym(handle_, symbol_name);
213 if (addr ==
nullptr) {
214 logger->error(
"Plugin {}: missing required entry point '{}'",
215 path_.string(), symbol_name);
227bool PluginServer::resolve_factory_symbols() {
229 version_fn_ =
reinterpret_cast<version_fn_t
>(
230 resolve_one(
"entropic_plugin_api_version", ok));
231 create_fn_ =
reinterpret_cast<create_fn_t
>(
232 resolve_one(
"entropic_create_server", ok));
233 name_fn_ =
reinterpret_cast<name_fn_t
>(
234 resolve_one(
"entropic_mcp_server_name", ok));
235 free_fn_ =
reinterpret_cast<free_fn_t
>(
236 resolve_one(
"entropic_free", ok));
246bool PluginServer::resolve_instance_symbols() {
248 list_tools_fn_ =
reinterpret_cast<list_tools_fn_t
>(
249 resolve_one(
"entropic_mcp_server_list_tools", ok));
250 execute_fn_ =
reinterpret_cast<execute_fn_t
>(
251 resolve_one(
"entropic_mcp_server_execute", ok));
252 configure_fn_ =
reinterpret_cast<configure_fn_t
>(
253 resolve_one(
"entropic_mcp_server_configure", ok));
254 set_dir_fn_ =
reinterpret_cast<set_dir_fn_t
>(
255 resolve_one(
"entropic_mcp_server_set_working_dir", ok));
256 destroy_fn_ =
reinterpret_cast<destroy_fn_t
>(
257 resolve_one(
"entropic_mcp_server_destroy", ok));
274std::string PluginServer::take_string(
char* raw)
const {
275 if (raw ==
nullptr) {
303std::string PluginServer::list_tools()
const {
304 std::lock_guard<std::mutex> lock(call_mutex_);
305 auto tools = take_string(list_tools_fn_(instance_));
306 return tools.empty() ?
"[]" : tools;
328std::string PluginServer::execute(
const std::string& tool_name,
329 const std::string& args_json) {
330 std::lock_guard<std::mutex> lock(call_mutex_);
332 execute_fn_(instance_, tool_name.c_str(), args_json.c_str()));
346 std::lock_guard<std::mutex> lock(call_mutex_);
347 return configure_fn_(instance_, config_json.c_str());
361 std::lock_guard<std::mutex> lock(call_mutex_);
362 return set_dir_fn_(instance_, dir.c_str());
A loaded MCP server plugin and its C-ABI entry points.
entropic_error_t
Error codes returned by all C API functions.
@ ENTROPIC_ERROR_PLUGIN_LOAD_FAILED
dlopen/dlsym failed on plugin .so
@ ENTROPIC_ERROR_PLUGIN_VERSION_MISMATCH
Plugin API version != engine expected version.
#define ENTROPIC_MCP_PLUGIN_API_VERSION
Current MCP plugin API version.
spdlog initialization and logger access.
ENTROPIC_EXPORT std::shared_ptr< spdlog::logger > get(const std::string &name)
Get or create a named logger.
Activate model on GPU (WARM → ACTIVE).
@ ok
Tool dispatched, returned non-empty content.
dlopen-loaded in-process MCP server plugin (gh#133).