yams/tests/unit/mcp/mcp_apps/ui_resource_handling_test.cpp

114 lines
4.4 KiB
C++

// ============================================================================
// MCP Apps Extension - UI Resource Handling Tests
// PBI-083: MCP Apps Support - Phase 1
//
// Test IDs: mcp-apps-res-01 through mcp-apps-res-09
// ============================================================================
#include <nlohmann/json.hpp>
#include <catch2/catch_test_macros.hpp>
#include <yams/mcp/mcp_server.h>
using namespace yams::mcp;
using json = nlohmann::json;
namespace {
class NullTransport : public yams::mcp::ITransport {
public:
void send(const json&) override {}
yams::mcp::MessageResult receive() override {
return yams::Error{yams::ErrorCode::NotImplemented, "Null transport"};
}
bool isConnected() const override { return false; }
void close() override {}
yams::mcp::TransportState getState() const override {
return yams::mcp::TransportState::Disconnected;
}
};
} // namespace
TEST_CASE("MCP Apps Resource - Declaration With UI Support",
"[mcp][apps][resource][mcp-apps-res-01][phase1]") {
auto transport = std::make_unique<NullTransport>();
auto server = std::make_shared<yams::mcp::MCPServer>(std::move(transport));
json initRequest = {{"jsonrpc", "2.0"},
{"id", 1},
{"method", "initialize"},
{"params",
{{"protocolVersion", "2025-11-25"},
{"clientInfo", {{"name", "test"}, {"version", "1.0"}}},
{"capabilities",
{{"extensions",
{{"io.modelcontextprotocol/ui",
{{"mimeTypes", json::array({"text/html;profile=mcp-app"})}}}}}}}}}};
auto initResponse = server->handleRequestPublic(initRequest);
REQUIRE(initResponse.has_value());
json listRequest = {
{"jsonrpc", "2.0"}, {"id", 2}, {"method", "resources/list"}, {"params", json::object()}};
auto listResponse = server->handleRequestPublic(listRequest);
REQUIRE(listResponse.has_value());
json result = listResponse.value();
REQUIRE(result.contains("result"));
REQUIRE(result["result"].contains("resources"));
bool foundUIResource = false;
for (const auto& resource : result["result"]["resources"]) {
if (resource.contains("uri") && resource["uri"].get<std::string>().find("ui://") == 0) {
foundUIResource = true;
CHECK(resource.contains("name"));
CHECK(resource.contains("mimeType"));
CHECK(resource["mimeType"] == "text/html;profile=mcp-app");
}
}
CHECK(foundUIResource);
}
TEST_CASE("MCP Apps Resource - Content Retrieval Text",
"[mcp][apps][resource][mcp-apps-res-03][phase1]") {
auto transport = std::make_unique<NullTransport>();
auto server = std::make_shared<yams::mcp::MCPServer>(std::move(transport));
json initRequest = {{"jsonrpc", "2.0"},
{"id", 1},
{"method", "initialize"},
{"params",
{{"protocolVersion", "2025-11-25"},
{"clientInfo", {{"name", "test"}, {"version", "1.0"}}},
{"capabilities",
{{"extensions",
{{"io.modelcontextprotocol/ui",
{{"mimeTypes", json::array({"text/html;profile=mcp-app"})}}}}}}}}}};
auto initResponse = server->handleRequestPublic(initRequest);
REQUIRE(initResponse.has_value());
json readRequest = {{"jsonrpc", "2.0"},
{"id", 2},
{"method", "resources/read"},
{"params", {{"uri", "ui://yams/dashboard"}}}};
auto readResponse = server->handleRequestPublic(readRequest);
REQUIRE(readResponse.has_value());
json result = readResponse.value();
REQUIRE(result.contains("result"));
REQUIRE(result["result"].contains("contents"));
REQUIRE(result["result"]["contents"].is_array());
REQUIRE(result["result"]["contents"].size() > 0);
auto content = result["result"]["contents"][0];
CHECK(content.contains("uri"));
CHECK(content["uri"] == "ui://yams/dashboard");
CHECK(content.contains("mimeType"));
CHECK(content["mimeType"] == "text/html;profile=mcp-app");
CHECK(content.contains("text"));
CHECK(content["text"].is_string());
}