mcp w.i.p.

This commit is contained in:
Syoyo Fujita
2025-07-12 11:51:18 +09:00
parent 792d1e3751
commit 651e9d5b03
10 changed files with 147 additions and 26 deletions

View File

@@ -448,6 +448,9 @@ if (TINYUSDZ_WITH_TYDRA)
${PROJECT_SOURCE_DIR}/src/tydra/texture-util.hh
${PROJECT_SOURCE_DIR}/src/tydra/mcp.cc
${PROJECT_SOURCE_DIR}/src/tydra/mcp-tools.cc
${PROJECT_SOURCE_DIR}/src/tydra/mcp-tools.hh
${PROJECT_SOURCE_DIR}/src/tydra/mcp-resources.cc
${PROJECT_SOURCE_DIR}/src/tydra/mcp-resources.hh
${PROJECT_SOURCE_DIR}/src/tydra/mcp-server.cc
${PROJECT_SOURCE_DIR}/src/tydra/mcp-server.hh
${PROJECT_SOURCE_DIR}/src/tydra/diff-and-compare.cc

View File

@@ -49,7 +49,7 @@ int main(int argc, char **argv) {
std::cout << "http://" + hostname << ":" << port << "/mcp" << "\n";
tydra::MCPServer server;
tydra::mcp::MCPServer server;
if (!server.init(port, hostname)) {
std::cerr << "Failed to init MCP server.\n";
return -1;

View File

@@ -16,3 +16,11 @@ curl -X POST \
"id": 1
}' \
http://localhost:8085/mcp
curl -X POST \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "notifications/initialized"
}' \
http://localhost:8085/mcp

View File

@@ -3,9 +3,7 @@ curl -X POST \
-d '{
"jsonrpc": "2.0",
"method": "tools/list",
"params": {
},
},
"params": {},
"id": 2
}' \
http://localhost:8085/mcp

View File

@@ -0,0 +1,22 @@
#include "mcp-tools.hh"
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Weverything"
#endif
#include "external/jsonhpp/nlohmann/json.hpp"
#ifdef __clang__
#pragma clang diagnostic pop
#endif
namespace tinyusdz {
namespace tydra {
namespace mcp {
} // namespace mcp
} // namespace tydra
} // namespace tinyusdz

View File

@@ -0,0 +1,28 @@
#pragma once
#include <vector>
#include <string>
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Weverything"
#endif
#include "external/jsonhpp/nlohmann/json_fwd.hpp"
#ifdef __clang__
#pragma clang diagnostic pop
#endif
namespace tinyusdz {
namespace tydra {
namespace mcp {
// for 'tools/list'
bool GetResourcesList(
std::vector<std::string> &toolslist);
} // namespace mcp
} // namespace tydra
} // namespace tinyusdz

View File

@@ -1,4 +1,5 @@
#include "mcp-server.hh"
#include "mcp-tools.hh"
#if defined(TINYUSDZ_WITH_MCP_SERVER)
@@ -21,6 +22,7 @@
namespace tinyusdz {
namespace tydra {
namespace mcp {
// JSON-RPC request structure
struct JsonRpcRequest {
@@ -127,18 +129,23 @@ int MCPServer::Impl::mcp_handler(struct mg_connection *conn, void *user_data) {
// Parse and process JSON-RPC request
JsonRpcRequest rpc_request = server->parse_request(body);
JsonRpcResponse rpc_response = server->process_request(rpc_request);
if (rpc_request.is_notification()) {
// Just acknowledge. No response.
} else {
// Send JSON-RPC response
std::string response_json = rpc_response.to_json().dump();
mg_printf(conn,
"HTTP/1.1 200 OK\r\n"
"Content-Type: application/json\r\n"
"Content-Length: %d\r\n"
"\r\n"
"%s",
static_cast<int>(response_json.length()),
response_json.c_str());
// Send JSON-RPC response
std::string response_json = rpc_response.to_json().dump();
mg_printf(conn,
"HTTP/1.1 200 OK\r\n"
"Content-Type: application/json\r\n"
"Content-Length: %d\r\n"
"\r\n"
"%s",
static_cast<int>(response_json.length()),
response_json.c_str());
}
return 200; // Request handled
}
@@ -257,6 +264,17 @@ bool MCPServer::Impl::init(int port, const std::string &host) {
};
});
register_method("tools/list",[](const nlohmann::json &params) -> nlohmann::json {
(void)params;
nlohmann::json j;
mcp::GetToolsList(j);
return j;
});
register_method("notifications/initialized", [](const nlohmann::json& params) -> nlohmann::json {
// no response required
(void)params;
@@ -297,7 +315,7 @@ bool MCPServer::Impl::run() {
return true;
}
MCPServer::MCPServer() : impl_(new tydra::MCPServer::Impl()) {}
MCPServer::MCPServer() : impl_(new tydra::mcp::MCPServer::Impl()) {}
bool MCPServer::init(int port, const std::string &host) {
return impl_->init(port, host);
}
@@ -310,6 +328,7 @@ bool MCPServer::stop() {
return impl_->stop();
}
} // namespace mcp
} // namespace tydra
} // namespace tinyusdz
@@ -318,6 +337,7 @@ bool MCPServer::stop() {
namespace tinyusdz {
namespace tydra {
namespace mcp {
MCPServer::MCPServer() {}
@@ -336,6 +356,7 @@ bool MCPServer::stop() {
}
} // namespace mcp
} // namespace tydra
} // namespace tinyusdz

View File

@@ -5,6 +5,7 @@
namespace tinyusdz {
namespace tydra {
namespace mcp {
class MCPServer
{
@@ -20,6 +21,7 @@ class MCPServer
};
} // namespace mcp
} // namespace tydra
} // namespace tinyusdz

View File

@@ -1,9 +1,42 @@
#include "mcp-tools.hh"
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Weverything"
#endif
#include "external/jsonhpp/nlohmann/json.hpp"
#ifdef __clang__
#pragma clang diagnostic pop
#endif
namespace tinyusdz {
namespace tydra {
namespace mcp {
bool GetToolsList(nlohmann::json &result) {
result["tools"] = nlohmann::json::array();
{
nlohmann::json j;
j["name"] = "get_version";
j["description"] = "Get TinyUSDZ MCP server version";
nlohmann::json schema;
schema["type"] = "object";
schema["properties"] = nlohmann::json::object();
//schena["required"] = nlohmann::json::array();
j["inputSchema"] = schema;
result["tools"].push_back(j);
}
return true;
}
} // namespace mcp
} // namespace tydra

View File

@@ -3,23 +3,29 @@
#include <vector>
#include <string>
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Weverything"
#endif
#include "external/jsonhpp/nlohmann/json_fwd.hpp"
#ifdef __clang__
#pragma clang diagnostic pop
#endif
namespace tinyusdz {
namespace tydra {
namespace mcp {
struct MCPTool
{
bool GetVersion();
bool ReadUSDFromFile(const std::string &filepath);
};
// for 'tools/list'
bool GetMCPToolsList(
std::vector<std::string> &toolslist);
bool GetToolsList(
nlohmann::json &result);
// TODO: Batch call tools
bool CallTool(const std::string &tool_name, const nlohmann::json &param);
} // namespace mcp
} // namespace tydra
} // namespace tinyusdz