Entropic 2.14.3
Local-first agentic inference engine
Loading...
Searching...
No Matches
server_manager.h
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
13#pragma once
14
24
25#include <nlohmann/json_fwd.hpp>
26
27#include <chrono>
28#include <filesystem>
29#include <map>
30#include <shared_mutex>
31#include <memory>
32#include <string>
33#include <vector>
34
35namespace entropic {
36
41struct ServerInfo {
42 std::string name;
43 std::string transport;
44 std::string url;
45 std::string command;
46 std::string status;
47 std::vector<std::string> tools;
48 std::string source;
49 std::chrono::system_clock::time_point connected_at;
51};
52
63public:
70 ServerManager(const PermissionsConfig& permissions,
71 const std::filesystem::path& project_dir);
72
78 void register_server(std::unique_ptr<MCPServerBase> server);
79
96 const std::vector<std::string>& tier_names,
97 const std::string& data_dir,
98 const std::vector<std::string>&
100
121
126 void initialize();
127
133 std::string list_tools() const;
134
145 std::string execute(const std::string& tool_name,
146 const std::string& args_json);
147
154 MCPServerBase* get_server(const std::string& name) const;
155
168 bool set_outside_root_approver(OutsideRootApprover fn, void* user_data);
169
177 using DiscoveredServerApprover = bool (*)(const std::string& context_json,
178 void* user_data);
179
193 void* user_data);
194
205 void set_own_bridge_socket(const std::filesystem::path& socket);
206
223 std::size_t release_session(const std::string& key);
224
230 std::vector<std::string> server_names() const;
231
238 const std::filesystem::path& project_dir() const { return project_dir_; }
239
260 size_t set_working_dir_all(const std::filesystem::path& dir);
261
278 size_t enter_working_dir(const std::filesystem::path& dir);
279
290 size_t leave_working_dir(const std::filesystem::path& dir);
291
305 std::vector<std::string> external_tools_without_readonly_hint(
306 const std::vector<std::string>& allowed) const;
307
319 static std::vector<std::string> tools_without_readonly_hint(
320 const std::string& tools_json,
321 const std::vector<std::string>& allowed);
322
329 std::string get_tool_schema(const std::string& tool_name) const;
330
338 bool is_explicitly_allowed(const std::string& tool_name,
339 const std::string& args_json) const;
340
348 std::string get_permission_pattern(const std::string& tool_name,
349 const std::string& args_json) const;
350
357 bool skip_duplicate_check(const std::string& tool_name) const;
358
366 const std::string& tool_name) const;
367
374 void add_permission(const std::string& pattern, bool allow);
375
380 void shutdown();
381
382 /* ── v1.8.7: External server methods ───────────────── */
383
397 std::vector<std::string> connect_external_server(
398 const ExternalServerConfig& spec);
399
415 std::vector<std::string> connect_external_server(
416 const std::string& name,
417 const std::string& command = "",
418 const std::vector<std::string>& args = {},
419 const std::string& url = "");
420
426 void disconnect_external_server(const std::string& name);
427
433 std::map<std::string, ServerInfo> list_server_info() const;
434
440
446 void set_mcp_config(const MCPConfig& config);
447
459
466
467private:
474 static std::string extract_prefix(const std::string& tool_name);
475
482 static std::string extract_local_name(const std::string& tool_name);
483
490 static std::string args_to_pattern(const std::string& args_json);
491
492 PermissionManager permissions_;
493 std::filesystem::path project_dir_;
494 DiscoveredServerApprover discovered_approver_ = nullptr;
495 void* discovered_approver_ud_ = nullptr;
496 std::filesystem::path own_bridge_socket_;
497 std::map<std::string, std::unique_ptr<MCPServerBase>> servers_;
498
504 std::unique_ptr<ToolRootLock> root_lock_ =
505 std::make_unique<ToolRootLock>();
506
516 static std::string route_plugin_call(PluginServer& plugin,
517 const std::string& local_name,
518 const std::string& args_json);
519
528 std::string plugin_tool_schema(const std::string& prefix,
529 const std::string& local_name) const;
530
545 std::string route_external_or_unknown(const std::string& prefix,
546 const std::string& tool_name,
547 const std::string& local_name,
548 const std::string& args_json);
549
556 void append_plugin_tools(nlohmann::json& all) const;
557
564 void append_external_tools(nlohmann::json& all) const;
565
566 /* ── gh#133 (v2.10.1): dlopen plugin state ─────────── */
567 std::map<std::string, std::unique_ptr<PluginServer>> plugin_servers_;
568
569 /* ── v1.8.7: External server state ─────────────────── */
573 std::map<std::string, std::shared_ptr<ExternalMCPClient>> external_clients_;
574 std::map<std::string, ServerInfo> server_info_;
575
589 std::unique_ptr<std::shared_mutex> external_mutex_ =
590 std::make_unique<std::shared_mutex>();
591
598 std::vector<std::pair<std::string, std::shared_ptr<ExternalMCPClient>>>
599 external_snapshot() const;
600
608 std::shared_ptr<ExternalMCPClient> find_external(const std::string& name) const;
609 std::unique_ptr<HealthMonitor> health_monitor_;
610 std::unique_ptr<MCPJsonDiscovery> mcp_json_discovery_;
611 MCPConfig mcp_config_;
612
618 void initialize_external_servers();
619
625 void connect_declared_servers();
626
632 void connect_discovered_servers();
633
641 bool admit_discovered(const ExternalServerConfig& cfg) const;
642
655 std::string route_tool_call(const std::string& tool_name,
656 const std::string& args_json);
657
668 std::string route_external_call(
669 ExternalMCPClient* client,
670 const std::string& tool_name,
671 const std::string& local_name,
672 const std::string& args_json);
673
684 std::shared_ptr<ExternalMCPClient> connect_and_register_external(
685 const std::string& name,
686 std::unique_ptr<ExternalMCPClient> client,
687 const std::string& source,
688 const std::string& url,
689 const std::string& command);
690
699 std::unique_ptr<ExternalMCPClient> create_external_client(
700 const std::string& name,
701 const ExternalServerEntry& entry);
702
710 std::unique_ptr<ExternalMCPClient> create_external_client(
711 const ExternalServerConfig& config);
712
728 std::unique_ptr<Transport> make_transport(
729 const ExternalServerConfig& spec) const;
730
739 static std::string disconnected_error(
740 const std::string& tool_name,
741 const std::string& server_name);
742};
743
744} // namespace entropic
Concrete base class for MCP servers (80% logic).
Definition server_base.h:66
Manages MCP server instances and routes tool calls.
std::vector< std::string > connect_external_server(const ExternalServerConfig &spec)
Connect to an external MCP server at runtime (canonical spec-based API).
void init_builtins(const MCPConfig &mcp_config, const std::vector< std::string > &tier_names, const std::string &data_dir, const std::vector< std::string > &require_context_tiers={})
Register built-in servers based on config flags.
size_t enter_working_dir(const std::filesystem::path &dir)
Re-root every in-process and plugin server for a sandboxed delegation, and KEEP the root lock (gh#158...
bool(*)(const std::string &context_json, void *user_data) DiscoveredServerApprover
Approver consulted for a discovered .mcp.json server that config neither disabled nor pre-approved (v...
MCPAccessLevel get_required_access_level(const std::string &tool_name) const
Get the required access level for a tool.
bool is_explicitly_allowed(const std::string &tool_name, const std::string &args_json) const
Check if tool is explicitly allowed (skip prompting).
std::map< std::string, ServerInfo > list_server_info() const
Get snapshot of all servers with current status.
std::vector< std::string > server_names() const
List registered server names (in-process + external).
void process_health_events()
Process pending health events (call from engine loop).
MCPServerBase * get_server(const std::string &name) const
Get a registered in-process server by name.
const std::filesystem::path & project_dir() const
Get the project root directory.
std::string list_tools() const
List all tools from all connected servers.
std::vector< std::string > external_tools_without_readonly_hint(const std::vector< std::string > &allowed) const
External tools that do not declare readOnlyHint: true.
size_t leave_working_dir(const std::filesystem::path &dir)
Restore after enter_working_dir(), then release one level of the root lock (gh#158,...
void clear_external_tool_interrupts()
Release the interrupt on every external client (gh#150).
std::size_t release_session(const std::string &key)
Release every in-process server's state for one session (gh#158).
void register_server(std::unique_ptr< MCPServerBase > server)
Register a built-in server (in-process, ownership transferred).
void add_permission(const std::string &pattern, bool allow)
Add a runtime permission pattern.
entropic_error_t load_plugins(const MCPConfig &mcp_config)
Load the dlopen plugins listed in mcp.plugins (gh#133).
bool skip_duplicate_check(const std::string &tool_name) const
Check if tool should skip duplicate detection.
void set_discovered_server_approver(DiscoveredServerApprover fn, void *user_data)
Install the discovered-server approver (v2.14.0, gh#199).
std::string get_permission_pattern(const std::string &tool_name, const std::string &args_json) const
Generate permission pattern via server class delegation.
std::string get_tool_schema(const std::string &tool_name) const
Get the JSON Schema for a tool's input parameters.
void interrupt_external_tools()
Abort in-flight tool calls across every external MCP client.
std::string execute(const std::string &tool_name, const std::string &args_json)
Execute a tool call via the appropriate server.
void set_mcp_config(const MCPConfig &config)
Set MCP config for external server initialization.
size_t set_working_dir_all(const std::filesystem::path &dir)
Point every in-process and plugin server at dir (gh#160).
bool set_outside_root_approver(OutsideRootApprover fn, void *user_data)
Install the outside-root approver on this set's filesystem server (v2.13.0).
static std::vector< std::string > tools_without_readonly_hint(const std::string &tools_json, const std::vector< std::string > &allowed)
The readOnlyHint filter itself, over one descriptor list.
void shutdown()
Shutdown all servers (in-process + external).
void disconnect_external_server(const std::string &name)
Disconnect and remove an external server.
void initialize()
Initialize all registered servers.
void set_own_bridge_socket(const std::filesystem::path &socket)
The socket this handle's external bridge binds (v2.14.0, gh#200).
Configuration structs with defaults.
entropic_error_t
Error codes returned by all C API functions.
Definition error.h:37
Client for communicating with external MCP servers.
Filesystem MCP server — read/write/edit/glob/grep/list_directory.
Monitors external MCP server health and triggers reconnection.
Discovers external MCP servers from .mcp.json files.
Activate model on GPU (WARM → ACTIVE).
@ allow
true: every escape served, no prompt
@ optional
optional: every escape asks the host's path approver
OutsideRootVerdict(*)(const OutsideRootRequest &request, void *user_data) OutsideRootApprover
Approver the server consults under allow_outside_root: optional.
Definition filesystem.h:134
MCPAccessLevel
MCP tool access level for per-identity authorization.
Definition config.h:38
Permission manager for MCP tool access control.
dlopen-loaded in-process MCP server plugin (gh#133).
MCPServerBase concrete base class + ServerResponse.
Parsed server entry from .mcp.json.
MCP server configuration.
Definition config.h:953
Tool permission configuration.
Definition config.h:754
Runtime state of a connected MCP server.
std::string url
SSE URL (empty otherwise)
std::string transport
"stdio" | "sse" | "in_process"
std::string source
"builtin" | "config" | "mcp_json" | "runtime"
std::vector< std::string > tools
Registered tool names (prefixed)
std::string name
Server name (unique key)
std::string command
Stdio command (empty otherwise)
int reconnect_attempts
Current reconnect attempt count.
std::chrono::system_clock::time_point connected_at
Connection timestamp.
std::string status
"connected" | "disconnected" | "error" | "reconnecting"
The lock that guards the working directory one ServerManager's in-process and plugin servers resolve ...