|
| 1 | +#pragma once |
| 2 | + |
| 3 | +#include "fastmcpp/client/types.hpp" |
| 4 | +#include "fastmcpp/prompts/manager.hpp" |
| 5 | +#include "fastmcpp/proxy.hpp" |
| 6 | +#include "fastmcpp/resources/manager.hpp" |
| 7 | +#include "fastmcpp/server/server.hpp" |
| 8 | +#include "fastmcpp/tools/manager.hpp" |
| 9 | + |
| 10 | +#include <memory> |
| 11 | +#include <optional> |
| 12 | +#include <string> |
| 13 | +#include <vector> |
| 14 | + |
| 15 | +namespace fastmcpp |
| 16 | +{ |
| 17 | + |
| 18 | +/// Mounted app reference with prefix (direct mode) |
| 19 | +struct MountedApp |
| 20 | +{ |
| 21 | + std::string prefix; // Prefix for tools/prompts (e.g., "weather") |
| 22 | + class McpApp* app; // Non-owning pointer to mounted app |
| 23 | +}; |
| 24 | + |
| 25 | +/// Proxy-mounted app with prefix (proxy mode) |
| 26 | +struct ProxyMountedApp |
| 27 | +{ |
| 28 | + std::string prefix; // Prefix for tools/prompts |
| 29 | + std::unique_ptr<ProxyApp> proxy; // Owning pointer to proxy wrapper |
| 30 | +}; |
| 31 | + |
| 32 | +/// MCP Application - bundles server metadata with managers |
| 33 | +/// |
| 34 | +/// Similar to Python's FastMCP class. Provides: |
| 35 | +/// - Server metadata (name, version, icons, etc.) |
| 36 | +/// - Tool, Resource, and Prompt managers |
| 37 | +/// - App mounting support with prefixes |
| 38 | +/// |
| 39 | +/// Usage: |
| 40 | +/// ```cpp |
| 41 | +/// McpApp main_app("MainApp", "1.0"); |
| 42 | +/// McpApp weather_app("WeatherApp", "1.0"); |
| 43 | +/// |
| 44 | +/// // Register tools on sub-app |
| 45 | +/// weather_app.tools().register_tool(get_forecast_tool); |
| 46 | +/// |
| 47 | +/// // Mount sub-app with prefix |
| 48 | +/// main_app.mount(weather_app, "weather"); |
| 49 | +/// |
| 50 | +/// // Tools accessible as "weather_get_forecast" |
| 51 | +/// ``` |
| 52 | +class McpApp |
| 53 | +{ |
| 54 | + public: |
| 55 | + /// Construct app with metadata |
| 56 | + explicit McpApp(std::string name = "fastmcpp_app", std::string version = "1.0.0", |
| 57 | + std::optional<std::string> website_url = std::nullopt, |
| 58 | + std::optional<std::vector<Icon>> icons = std::nullopt); |
| 59 | + |
| 60 | + // Metadata accessors |
| 61 | + const std::string& name() const |
| 62 | + { |
| 63 | + return server_.name(); |
| 64 | + } |
| 65 | + const std::string& version() const |
| 66 | + { |
| 67 | + return server_.version(); |
| 68 | + } |
| 69 | + const std::optional<std::string>& website_url() const |
| 70 | + { |
| 71 | + return server_.website_url(); |
| 72 | + } |
| 73 | + const std::optional<std::vector<Icon>>& icons() const |
| 74 | + { |
| 75 | + return server_.icons(); |
| 76 | + } |
| 77 | + |
| 78 | + // Manager accessors |
| 79 | + tools::ToolManager& tools() |
| 80 | + { |
| 81 | + return tools_; |
| 82 | + } |
| 83 | + const tools::ToolManager& tools() const |
| 84 | + { |
| 85 | + return tools_; |
| 86 | + } |
| 87 | + |
| 88 | + resources::ResourceManager& resources() |
| 89 | + { |
| 90 | + return resources_; |
| 91 | + } |
| 92 | + const resources::ResourceManager& resources() const |
| 93 | + { |
| 94 | + return resources_; |
| 95 | + } |
| 96 | + |
| 97 | + prompts::PromptManager& prompts() |
| 98 | + { |
| 99 | + return prompts_; |
| 100 | + } |
| 101 | + const prompts::PromptManager& prompts() const |
| 102 | + { |
| 103 | + return prompts_; |
| 104 | + } |
| 105 | + |
| 106 | + server::Server& server() |
| 107 | + { |
| 108 | + return server_; |
| 109 | + } |
| 110 | + const server::Server& server() const |
| 111 | + { |
| 112 | + return server_; |
| 113 | + } |
| 114 | + |
| 115 | + // ========================================================================= |
| 116 | + // App Mounting |
| 117 | + // ========================================================================= |
| 118 | + |
| 119 | + /// Mount another app with an optional prefix |
| 120 | + /// |
| 121 | + /// Tools are prefixed with underscore: "prefix_toolname" |
| 122 | + /// Resources are prefixed in URI: "prefix+resource://..." or "resource://prefix/..." |
| 123 | + /// Prompts are prefixed with underscore: "prefix_promptname" |
| 124 | + /// |
| 125 | + /// @param app The app to mount (must outlive this app in direct mode) |
| 126 | + /// @param prefix Optional prefix (empty string = no prefix) |
| 127 | + /// @param as_proxy If true, mount in proxy mode (uses MCP handler for communication) |
| 128 | + void mount(McpApp& app, const std::string& prefix = "", bool as_proxy = false); |
| 129 | + |
| 130 | + /// Get list of directly mounted apps |
| 131 | + const std::vector<MountedApp>& mounted() const |
| 132 | + { |
| 133 | + return mounted_; |
| 134 | + } |
| 135 | + |
| 136 | + /// Get list of proxy-mounted apps |
| 137 | + const std::vector<ProxyMountedApp>& proxy_mounted() const |
| 138 | + { |
| 139 | + return proxy_mounted_; |
| 140 | + } |
| 141 | + |
| 142 | + // ========================================================================= |
| 143 | + // Aggregated Lists (includes mounted apps) |
| 144 | + // ========================================================================= |
| 145 | + |
| 146 | + /// List all tools including from mounted apps |
| 147 | + /// Tools from mounted apps have prefix: "prefix_toolname" |
| 148 | + std::vector<std::pair<std::string, const tools::Tool*>> list_all_tools() const; |
| 149 | + |
| 150 | + /// List all tools as ToolInfo (works for both direct and proxy mounts) |
| 151 | + std::vector<client::ToolInfo> list_all_tools_info() const; |
| 152 | + |
| 153 | + /// List all resources including from mounted apps |
| 154 | + std::vector<resources::Resource> list_all_resources() const; |
| 155 | + |
| 156 | + /// List all resource templates including from mounted apps |
| 157 | + std::vector<resources::ResourceTemplate> list_all_templates() const; |
| 158 | + |
| 159 | + /// List all prompts including from mounted apps |
| 160 | + std::vector<std::pair<std::string, const prompts::Prompt*>> list_all_prompts() const; |
| 161 | + |
| 162 | + // ========================================================================= |
| 163 | + // Routing (dispatches to correct app based on prefix) |
| 164 | + // ========================================================================= |
| 165 | + |
| 166 | + /// Invoke a tool by name (handles prefixed routing) |
| 167 | + Json invoke_tool(const std::string& name, const Json& args) const; |
| 168 | + |
| 169 | + /// Read a resource by URI (handles prefixed routing) |
| 170 | + resources::ResourceContent read_resource(const std::string& uri, |
| 171 | + const Json& params = Json::object()) const; |
| 172 | + |
| 173 | + /// Get prompt messages by name (handles prefixed routing) |
| 174 | + std::vector<prompts::PromptMessage> get_prompt(const std::string& name, const Json& args) const; |
| 175 | + |
| 176 | + private: |
| 177 | + server::Server server_; |
| 178 | + tools::ToolManager tools_; |
| 179 | + resources::ResourceManager resources_; |
| 180 | + prompts::PromptManager prompts_; |
| 181 | + std::vector<MountedApp> mounted_; |
| 182 | + std::vector<ProxyMountedApp> proxy_mounted_; |
| 183 | + |
| 184 | + // Prefix utilities |
| 185 | + static std::string add_prefix(const std::string& name, const std::string& prefix); |
| 186 | + static std::pair<std::string, std::string> strip_prefix(const std::string& name); |
| 187 | + static std::string add_resource_prefix(const std::string& uri, const std::string& prefix); |
| 188 | + static std::string strip_resource_prefix(const std::string& uri, const std::string& prefix); |
| 189 | + static bool has_resource_prefix(const std::string& uri, const std::string& prefix); |
| 190 | +}; |
| 191 | + |
| 192 | +} // namespace fastmcpp |
0 commit comments