LCOV - code coverage report
Current view: top level - muse/framework/rcontrol/mcp - mcpcontroller.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 0.0 % 79 0
Test Date: 2026-11-05 04:07:02

            Line data    Source code
       1              : /*
       2              :  * SPDX-License-Identifier: GPL-3.0-only
       3              :  * MuseScore/Audacity CLA applies
       4              :  *
       5              :  * Copyright (C) 2026 MuseScore/Audacity and others
       6              :  *
       7              :  * This program is free software: you can redistribute it and/or modify
       8              :  * it under the terms of the GNU General Public License version 3 as
       9              :  * published by the Free Software Foundation.
      10              :  *
      11              :  * This program is distributed in the hope that it will be useful,
      12              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14              :  * GNU General Public License for more details.
      15              :  *
      16              :  * You should have received a copy of the GNU General Public License
      17              :  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
      18              :  */
      19              : 
      20              : #include "mcpcontroller.h"
      21              : 
      22              : #include "mcpserver.h"
      23              : 
      24              : #include "log.h"
      25              : 
      26              : using namespace muse::rcontrol::mcp;
      27              : using namespace muse::rcommand;
      28              : 
      29            0 : static TypeSchema toMcpTypeSchema(muse::rcommand::DataType type)
      30              : {
      31              :     using CT = muse::rcommand::DataType;
      32              :     using MT = muse::rcontrol::mcp::DataType;
      33              :     using MF = muse::rcontrol::mcp::Format;
      34              : 
      35            0 :     switch (type) {
      36            0 :     case CT::Undefined: return TypeSchema{ MT::Undefined, MF::Undefined };
      37            0 :     case CT::String: return TypeSchema{ MT::String, MF::Undefined };
      38            0 :     case CT::Int: return TypeSchema{ MT::Integer, MF::Undefined };
      39            0 :     case CT::Int64: return TypeSchema{ MT::String, MF::Int64 };
      40            0 :     case CT::Float: return TypeSchema{ MT::Number, MF::Float };
      41            0 :     case CT::Double: return TypeSchema{ MT::Number, MF::Double };
      42            0 :     case CT::Bool: return TypeSchema{ MT::Boolean, MF::Undefined };
      43            0 :     case CT::List: return TypeSchema{ MT::Array, MF::Undefined };
      44            0 :     case CT::Map: return TypeSchema{ MT::Object, MF::Undefined };
      45              :     }
      46            0 :     return TypeSchema{ MT::Undefined, MF::Undefined };
      47              : }
      48              : 
      49            0 : McpController::McpController(const modularity::ContextPtr& iocCtx)
      50            0 :     : Contextable(iocCtx)
      51              : {
      52            0 : }
      53              : 
      54            0 : McpController::~McpController()
      55              : {
      56            0 :     deinit();
      57            0 : }
      58              : 
      59              : //! NOTE The tool name must be in the format: group_name
      60            0 : static std::string commandToToolName(const Command& command)
      61              : {
      62            0 :     std::string path = command.path();
      63            0 :     std::replace(path.begin(), path.end(), '/', '.');
      64            0 :     return path;
      65              : }
      66              : 
      67            0 : static Command toolNameToCommand(const std::string& name)
      68              : {
      69            0 :     std::string path = name;
      70            0 :     std::replace(path.begin(), path.end(), '.', '/');
      71            0 :     return Command(std::string(COMMAND_SCHEME), path);
      72            0 : }
      73              : 
      74            0 : void McpController::init()
      75              : {
      76            0 :     m_mcpServer = std::make_unique<McpServer>(application()->version().toStdString());
      77              : 
      78            0 :     m_mcpServer->onToolsListRequest([this](const McpServer::ToolsListResultHandler& onResult) {
      79            0 :         std::vector<Tool> tools = makeToolsList();
      80            0 :         onResult(tools);
      81            0 :     });
      82              : 
      83            0 :     m_mcpServer->onToolsCallRequest([this](const std::string& name,
      84              :                                            const std::map<std::string, Val>& args,
      85              :                                            const McpServer::ToolsCallResultHandler& onResult)
      86              :     {
      87            0 :         LOGDA() << "Tools call: " << name;
      88              : 
      89            0 :         async::Promise<Response> promise = commandsDispatcher()->dispatch(toolNameToCommand(name), args);
      90            0 :         promise.onResolve(this, [onResult](const Response& response) {
      91            0 :             ToolResult result;
      92            0 :             result.ret = response.ret;
      93            0 :             result.result = response.result;
      94            0 :             onResult(result);
      95            0 :         });
      96            0 :     });
      97              : 
      98            0 :     m_mcpServer->init();
      99            0 : }
     100              : 
     101            0 : void McpController::deinit()
     102              : {
     103            0 :     if (m_mcpServer) {
     104            0 :         m_mcpServer->deinit();
     105            0 :         m_mcpServer = nullptr;
     106              :     }
     107            0 : }
     108              : 
     109            0 : std::vector<Tool> McpController::makeToolsList() const
     110              : {
     111            0 :     std::vector<Tool> tools;
     112            0 :     auto commandList = commandsRegister()->commandInfoList();
     113            0 :     tools.reserve(commandList.size());
     114            0 :     for (const auto& info : commandList) {
     115            0 :         if (!info.availabilities.testFlag(Availability::MCP)) {
     116            0 :             continue;
     117              :         }
     118            0 :         Tool tool;
     119            0 :         tool.name = commandToToolName(info.command);
     120            0 :         tool.title = info.title.raw().translated().toStdString();
     121            0 :         tool.description = info.description.translated().toStdString();
     122            0 :         for (const auto& [name, arg] : info.inputSchema.args) {
     123            0 :             Property property;
     124            0 :             property.type = toMcpTypeSchema(arg.type);
     125            0 :             property.description = arg.description.toStdString();
     126            0 :             property.minimum = arg.min;
     127            0 :             property.maximum = arg.max;
     128            0 :             tool.inputSchema.properties[name] = property;
     129            0 :         }
     130              : 
     131            0 :         for (const auto& [name, arg] : info.outputSchema.args) {
     132            0 :             Property property;
     133            0 :             property.type = toMcpTypeSchema(arg.type);
     134            0 :             property.description = arg.description.toStdString();
     135            0 :             tool.outputSchema.properties[name] = property;
     136            0 :         }
     137            0 :         tools.push_back(std::move(tool));
     138            0 :     }
     139            0 :     return tools;
     140            0 : }
        

Generated by: LCOV version 2.0-1