Download Source/McpServer.cpp from RAM2118/pluginbridge: direct link, hf CLI and curl.
- Browser
- Download file 8.17 kB
-
https://huggingface.co/RAM2118/pluginbridge/resolve/e99e9f97e97304dfd53cbc1ec4634ede3563ffb9/Source/McpServer.cpp
- Command line
-
hf download hf://RAM2118/pluginbridge@e99e9f97e97304dfd53cbc1ec4634ede3563ffb9/Source/McpServer.cpp
-
curl -L -o McpServer.cpp https://huggingface.co/RAM2118/pluginbridge/resolve/e99e9f97e97304dfd53cbc1ec4634ede3563ffb9/Source/McpServer.cpp
8.17 kB
| // httplib must be included in exactly ONE .cpp file | |
| using json = nlohmann::json; | |
| McpServer::McpServer(int port) | |
| : server(std::make_unique<httplib::Server>()), port(port) | |
| { | |
| setupRoutes(); | |
| } | |
| McpServer::~McpServer() | |
| { | |
| stop(); | |
| } | |
| void McpServer::setupRoutes() | |
| { | |
| // Single MCP endpoint — all JSON-RPC goes through here | |
| server->Post("/mcp", [this](const httplib::Request& req, httplib::Response& res) { | |
| res.set_header("Access-Control-Allow-Origin", "http://localhost"); | |
| try { | |
| auto body = json::parse(req.body); | |
| std::string method = body.value("method", ""); | |
| std::string responseStr; | |
| if (method == "initialize") { | |
| responseStr = handleInitialize(req.body); | |
| } | |
| else if (method == "notifications/initialized") { | |
| // Notification — no response needed | |
| initialized = true; | |
| res.status = 204; | |
| return; | |
| } | |
| else if (method == "tools/list") { | |
| responseStr = handleToolsList(); | |
| } | |
| else if (method == "tools/call") { | |
| responseStr = handleToolsCall(req.body); | |
| } | |
| else { | |
| json errResponse = { | |
| {"jsonrpc", "2.0"}, | |
| {"id", body.value("id", json(nullptr))}, | |
| {"error", {{"code", -32601}, {"message", "Method not found"}}} | |
| }; | |
| responseStr = errResponse.dump(); | |
| } | |
| if (!responseStr.empty()) { | |
| res.set_content(responseStr, "application/json"); | |
| } | |
| } | |
| catch (const json::exception& e) { | |
| json errResponse = { | |
| {"jsonrpc", "2.0"}, | |
| {"id", nullptr}, | |
| {"error", {{"code", -32700}, {"message", "Parse error"}}} | |
| }; | |
| res.set_content(errResponse.dump(), "application/json"); | |
| } | |
| }); | |
| // Health check — quick way to verify server is alive | |
| server->Get("/health", [this](const httplib::Request&, httplib::Response& res) { | |
| json health = {{"status", "ok"}, {"port", port}, {"initialized", initialized}}; | |
| res.set_content(health.dump(), "application/json"); | |
| }); | |
| // CORS preflight | |
| server->Options("/mcp", [](const httplib::Request&, httplib::Response& res) { | |
| res.set_header("Access-Control-Allow-Origin", "http://localhost"); | |
| res.set_header("Access-Control-Allow-Methods", "POST, OPTIONS"); | |
| res.set_header("Access-Control-Allow-Headers", "Content-Type, Mcp-Session-Id"); | |
| res.status = 204; | |
| }); | |
| } | |
| void McpServer::start() | |
| { | |
| if (running.load()) return; | |
| serverThread = std::thread([this]() { | |
| running.store(true); | |
| server->listen("127.0.0.1", port); | |
| running.store(false); | |
| }); | |
| // Wait until server is actually ready | |
| server->wait_until_ready(); | |
| } | |
| void McpServer::stop() | |
| { | |
| if (server && server->is_running()) { | |
| server->stop(); | |
| } | |
| if (serverThread.joinable()) { | |
| serverThread.join(); | |
| } | |
| running.store(false); | |
| } | |
| bool McpServer::isRunning() const | |
| { | |
| return running.load(); | |
| } | |
| void McpServer::serverThreadFunc() | |
| { | |
| server->listen("127.0.0.1", port); | |
| } | |
| // --- MCP Protocol Handlers --- | |
| std::string McpServer::handleInitialize(const std::string& requestBody) | |
| { | |
| auto body = json::parse(requestBody); | |
| // Generate session ID | |
| sessionId = "pb-" + std::to_string(std::chrono::steady_clock::now().time_since_epoch().count()); | |
| json response = { | |
| {"jsonrpc", "2.0"}, | |
| {"id", body.value("id", json(nullptr))}, | |
| {"result", { | |
| {"protocolVersion", "2025-06-18"}, | |
| {"capabilities", { | |
| {"tools", {{"listChanged", false}}} | |
| }}, | |
| {"serverInfo", { | |
| {"name", "PluginBridge"}, | |
| {"version", "0.1.0"} | |
| }} | |
| }} | |
| }; | |
| return response.dump(); | |
| } | |
| std::string McpServer::handleToolsList() | |
| { | |
| json response = { | |
| {"jsonrpc", "2.0"}, | |
| {"id", 1}, | |
| {"result", { | |
| {"tools", json::array({ | |
| { | |
| {"name", "list_plugins"}, | |
| {"description", "List all loaded plugin instances"}, | |
| {"inputSchema", {{"type", "object"}, {"properties", json::object()}}} | |
| }, | |
| { | |
| {"name", "search_param"}, | |
| {"description", "Search plugin parameters by keyword"}, | |
| {"inputSchema", { | |
| {"type", "object"}, | |
| {"properties", { | |
| {"plugin", {{"type", "string"}, {"description", "Plugin name"}}}, | |
| {"keyword", {{"type", "string"}, {"description", "Search term"}}} | |
| }}, | |
| {"required", json::array({"plugin", "keyword"})} | |
| }} | |
| }, | |
| { | |
| {"name", "get_params"}, | |
| {"description", "Get current values for parameter IDs"}, | |
| {"inputSchema", { | |
| {"type", "object"}, | |
| {"properties", { | |
| {"plugin", {{"type", "string"}}}, | |
| {"ids", {{"type", "array"}, {"items", {{"type", "integer"}}}}} | |
| }}, | |
| {"required", json::array({"plugin", "ids"})} | |
| }} | |
| }, | |
| { | |
| {"name", "set_params"}, | |
| {"description", "Set parameter values by ID (batch)"}, | |
| {"inputSchema", { | |
| {"type", "object"}, | |
| {"properties", { | |
| {"plugin", {{"type", "string"}}}, | |
| {"values", {{"type", "object"}, {"description", "param_id → value (0.0-1.0)"}}} | |
| }}, | |
| {"required", json::array({"plugin", "values"})} | |
| }} | |
| }, | |
| { | |
| {"name", "get_analysis"}, | |
| {"description", "Get real-time audio analysis (LUFS, bands, stereo)"}, | |
| {"inputSchema", {{"type", "object"}, {"properties", json::object()}}} | |
| } | |
| })} | |
| }} | |
| }; | |
| return response.dump(); | |
| } | |
| std::string McpServer::handleToolsCall(const std::string& requestBody) | |
| { | |
| auto body = json::parse(requestBody); | |
| std::string toolName = body["params"]["name"]; | |
| json result; | |
| if (toolName == "list_plugins") { | |
| // Sprint 1: no plugins loaded yet | |
| result = { | |
| {"content", json::array({{{"type", "text"}, {"text", "[]"}}})}, | |
| {"isError", false} | |
| }; | |
| } | |
| else if (toolName == "search_param") { | |
| result = { | |
| {"content", json::array({{{"type", "text"}, {"text", "no plugin loaded"}}})}, | |
| {"isError", true} | |
| }; | |
| } | |
| else if (toolName == "get_params") { | |
| result = { | |
| {"content", json::array({{{"type", "text"}, {"text", "no plugin loaded"}}})}, | |
| {"isError", true} | |
| }; | |
| } | |
| else if (toolName == "set_params") { | |
| result = { | |
| {"content", json::array({{{"type", "text"}, {"text", "no plugin loaded"}}})}, | |
| {"isError", true} | |
| }; | |
| } | |
| else if (toolName == "get_analysis") { | |
| // Sprint 1: stub response | |
| result = { | |
| {"content", json::array({{{"type", "text"}, {"text", "silent"}}})}, | |
| {"isError", false} | |
| }; | |
| } | |
| else { | |
| result = { | |
| {"content", json::array({{{"type", "text"}, {"text", "unknown tool: " + toolName}}})}, | |
| {"isError", true} | |
| }; | |
| } | |
| json response = { | |
| {"jsonrpc", "2.0"}, | |
| {"id", body.value("id", json(nullptr))}, | |
| {"result", result} | |
| }; | |
| return response.dump(); | |
| } | |