Unravel Engine C++ Reference
Loading...
Searching...
No Matches
mcp_protocol.cpp
Go to the documentation of this file.
1#include "mcp_protocol.h"
2
3#include "mcp_tool_registry.h"
4
5#include <logging/logging.h>
6#include <ser20/external/simdjson/simdjson.h>
7
8namespace unravel::mcp
9{
10
11auto json_escape(const std::string& value) -> std::string
12{
13 std::string out;
14 out.reserve(value.size() + 8);
15 for(char c : value)
16 {
17 switch(c)
18 {
19 case '\\':
20 out += "\\\\";
21 break;
22 case '"':
23 out += "\\\"";
24 break;
25 case '\b':
26 out += "\\b";
27 break;
28 case '\f':
29 out += "\\f";
30 break;
31 case '\n':
32 out += "\\n";
33 break;
34 case '\r':
35 out += "\\r";
36 break;
37 case '\t':
38 out += "\\t";
39 break;
40 default:
41 if(static_cast<unsigned char>(c) < 0x20)
42 {
43 out += fmt::format("\\u{:04x}", static_cast<unsigned char>(c));
44 }
45 else
46 {
47 out.push_back(c);
48 }
49 break;
50 }
51 }
52 return out;
53}
54
55auto make_json_string(const std::string& value) -> std::string
56{
57 return "\"" + json_escape(value) + "\"";
58}
59
60auto make_json_rpc_result(const std::optional<std::string>& id_json, const std::string& result_json) -> std::string
61{
62 const std::string id = id_json ? *id_json : "null";
63 return fmt::format(R"({{"jsonrpc":"2.0","id":{},"result":{}}})", id, result_json);
64}
65
66auto make_json_rpc_error(const std::optional<std::string>& id_json, int code, const std::string& message) -> std::string
67{
68 const std::string id = id_json ? *id_json : "null";
69 return fmt::format(R"({{"jsonrpc":"2.0","id":{},"error":{{"code":{},"message":{}}}}})",
70 id,
71 code,
72 make_json_string(message));
73}
74
75auto make_tool_result(const std::string& text, bool is_error) -> std::string
76{
77 tool_result result;
78 result.text = text;
79 result.is_error = is_error;
80 return make_tool_result(result);
81}
82
83auto make_tool_result(const tool_result& result) -> std::string
84{
85 std::string content = "[";
86 content += fmt::format(R"({{"type":"text","text":{}}})", make_json_string(result.text));
87 if(!result.image_base64.empty())
88 {
89 content += fmt::format(R"(,{{"type":"image","data":{},"mimeType":{}}})",
90 make_json_string(result.image_base64),
91 make_json_string(result.image_mime.empty() ? "image/png" : result.image_mime));
92 }
93 content += "]";
94 return fmt::format(R"({{"content":{},"isError":{}}})", content, result.is_error ? "true" : "false");
95}
96
97auto parse_json_rpc_request(const std::string& body, json_rpc_request& out, std::string& error) -> bool
98{
99 simdjson::dom::parser parser;
100 simdjson::dom::element root;
101 auto parse_error = parser.parse(body).get(root);
102 if(parse_error)
103 {
104 error = "Invalid JSON body";
105 return false;
106 }
107
108 simdjson::dom::object obj;
109 if(root.get(obj))
110 {
111 error = "JSON-RPC request must be an object";
112 return false;
113 }
114
115 std::string_view method;
116 if(obj["method"].get(method))
117 {
118 error = "Missing JSON-RPC method";
119 return false;
120 }
121 out.method.assign(method);
122
123 simdjson::dom::element params_el;
124 if(!obj["params"].get(params_el))
125 {
126 out.params_json = std::string(simdjson::minify(params_el));
127 }
128 else
129 {
130 out.params_json = "{}";
131 }
132
133 simdjson::dom::element id_el;
134 if(!obj["id"].get(id_el))
135 {
136 out.has_id = true;
137 out.id_json = std::string(simdjson::minify(id_el));
138 }
139 else
140 {
141 out.has_id = false;
142 out.id_json.reset();
143 }
144
145 return true;
146}
147
148} // namespace unravel::mcp
std::string error
Definition mcp_async.cpp:33
auto parse_json_rpc_request(const std::string &body, json_rpc_request &out, std::string &error) -> bool
auto make_json_string(const std::string &value) -> std::string
auto make_json_rpc_error(const std::optional< std::string > &id_json, int code, const std::string &message) -> std::string
auto json_escape(const std::string &value) -> std::string
auto make_tool_result(const std::string &text, bool is_error) -> std::string
auto make_json_rpc_result(const std::optional< std::string > &id_json, const std::string &result_json) -> std::string