* Copyright (C) 2026 Xiaomi Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "tools/mcp_bridge.h"
#include "agent_compat.h"
#include "cJSON.h"
#include "tools/mcp_builtin_tools.h"
#include "tools/mcp_tool_registry.h"
#include <stdlib.h>
#include <string.h>
static const char* TAG = "mcp_bridge";
static bool s_initialized = false;
int mcp_bridge_init(void)
{
if (s_initialized) {
return OK;
}
int ret = mcp_tool_registry_init();
if (ret < 0) {
syslog(LOG_ERR, "[%s] mcp_tool_registry_init failed: %d\n", TAG, ret);
return ERROR;
}
ret = mcp_register_builtin_tools();
if (ret < 0) {
syslog(LOG_ERR, "[%s] mcp_register_builtin_tools failed: %d\n", TAG, ret);
mcp_tool_registry_cleanup();
return ERROR;
}
s_initialized = true;
syslog(LOG_INFO, "[%s] MCP bridge initialized\n", TAG);
return OK;
}
int mcp_bridge_execute(const char* name, const char* input_json, char* output,
size_t output_size)
{
if (!s_initialized || !name || !output || output_size == 0) {
return ERROR;
}
* We need to extract the actual result content from it. */
char* rpc_response = mcp_tool_registry_execute_tool(name, input_json ? input_json : "{}");
if (!rpc_response) {
return ERROR;
}
cJSON* root = cJSON_Parse(rpc_response);
free(rpc_response);
if (!root) {
snprintf(output, output_size, "{\"error\":\"MCP parse error\"}");
return ERROR;
}
cJSON* error = cJSON_GetObjectItem(root, "error");
if (error) {
cJSON* msg = cJSON_GetObjectItem(error, "message");
snprintf(output, output_size, "{\"error\":\"%s\"}",
(msg && cJSON_IsString(msg)) ? msg->valuestring : "MCP error");
cJSON_Delete(root);
return ERROR;
}
cJSON* result = cJSON_GetObjectItem(root, "result");
if (result) {
cJSON* content = cJSON_GetObjectItem(result, "content");
if (content && cJSON_IsArray(content)) {
cJSON* first = cJSON_GetArrayItem(content, 0);
if (first) {
cJSON* text = cJSON_GetObjectItem(first, "text");
if (text && cJSON_IsString(text)) {
strncpy(output, text->valuestring, output_size - 1);
output[output_size - 1] = '\0';
cJSON_Delete(root);
return OK;
}
}
}
char* result_str = cJSON_PrintUnformatted(result);
if (result_str) {
strncpy(output, result_str, output_size - 1);
output[output_size - 1] = '\0';
free(result_str);
}
}
cJSON_Delete(root);
return OK;
}
char* mcp_bridge_get_tools_json(void)
{
if (!s_initialized) {
return NULL;
}
char* rpc_response = mcp_tool_registry_get_tools_json();
if (!rpc_response) {
return NULL;
}
cJSON* root = cJSON_Parse(rpc_response);
free(rpc_response);
if (!root) {
return NULL;
}
cJSON* result = cJSON_GetObjectItem(root, "result");
cJSON* tools = result ? cJSON_GetObjectItem(result, "tools") : NULL;
if (!tools || !cJSON_IsArray(tools)) {
cJSON_Delete(root);
return NULL;
}
* MCP: {"name":"...", "description":"...", "inputSchema":{...}}
* Vela: {"name":"...", "description":"...", "input_schema":{...}}
*/
cJSON* vela_arr = cJSON_CreateArray();
cJSON* mcp_tool = NULL;
cJSON_ArrayForEach(mcp_tool, tools)
{
cJSON* name = cJSON_GetObjectItem(mcp_tool, "name");
cJSON* desc = cJSON_GetObjectItem(mcp_tool, "description");
cJSON* schema = cJSON_GetObjectItem(mcp_tool, "inputSchema");
if (!name || !cJSON_IsString(name))
continue;
cJSON* vt = cJSON_CreateObject();
cJSON_AddStringToObject(vt, "name", name->valuestring);
cJSON_AddStringToObject(vt, "description",
(desc && cJSON_IsString(desc)) ? desc->valuestring
: "");
if (schema) {
cJSON_AddItemToObject(vt, "input_schema", cJSON_Duplicate(schema, 1));
} else {
cJSON* empty = cJSON_CreateObject();
cJSON_AddStringToObject(empty, "type", "object");
cJSON_AddItemToObject(empty, "properties", cJSON_CreateObject());
cJSON_AddItemToObject(vt, "input_schema", empty);
}
cJSON_AddItemToArray(vela_arr, vt);
}
char* json = cJSON_PrintUnformatted(vela_arr);
cJSON_Delete(vela_arr);
cJSON_Delete(root);
return json;
}
void mcp_bridge_cleanup(void)
{
if (s_initialized) {
mcp_tool_registry_cleanup();
s_initialized = false;
syslog(LOG_INFO, "[%s] MCP bridge cleaned up\n", TAG);
}
}