cxxmcp 1.2.4
C++ MCP SDK
Loading...
Searching...
No Matches
schema.hpp
Go to the documentation of this file.
1// Copyright (c) 2025 [caomengxuan666]
2
3#pragma once
4
7
8#include <string>
9#include <type_traits>
10#include <utility>
11#include <vector>
12
15
16namespace mcp::protocol {
17
20 public:
21 static Json any() { return Json::object(); }
22
23 static Json object() { return Json{{"type", "object"}}; }
24
25 static Json string() { return Json{{"type", "string"}}; }
26
27 static Json integer() { return Json{{"type", "integer"}}; }
28
29 static Json number() { return Json{{"type", "number"}}; }
30
31 static Json boolean() { return Json{{"type", "boolean"}}; }
32
33 static Json array(Json items) {
34 return Json{{"type", "array"}, {"items", std::move(items)}};
35 }
36
37 static Json string_enum(std::vector<std::string> values) {
38 return Json{{"type", "string"}, {"enum", std::move(values)}};
39 }
40};
41
43template <class T, class Enable = void>
44struct SchemaTraits {};
45
46template <>
48 static Json schema() { return JsonSchema::any(); }
49};
50
51template <>
52struct SchemaTraits<std::string> {
53 static Json schema() { return JsonSchema::string(); }
54};
55
56template <>
57struct SchemaTraits<bool> {
58 static Json schema() { return JsonSchema::boolean(); }
59};
60
61template <class T>
63 T, std::enable_if_t<std::is_integral_v<T> && !std::is_same_v<T, bool>>> {
64 static Json schema() { return JsonSchema::integer(); }
65};
66
67template <class T>
68struct SchemaTraits<T, std::enable_if_t<std::is_floating_point_v<T>>> {
69 static Json schema() { return JsonSchema::number(); }
70};
71
72template <class T>
73struct SchemaTraits<T, std::enable_if_t<std::is_enum_v<T>>> {
74 static Json schema() { return JsonSchema::integer(); }
75};
76
78template <class T>
79inline Json schema_for();
80
81template <class T>
82struct SchemaTraits<std::vector<T>> {
83 static Json schema() { return JsonSchema::array(schema_for<T>()); }
84};
85
86template <class T>
87struct SchemaTraits<std::optional<T>> {
88 static Json schema() { return schema_for<T>(); }
89};
90
92namespace detail {
93
94template <typename Struct, typename Field>
95inline void add_reflected_field_schema(
96 Json& properties, Json& required,
98 if constexpr (is_optional_v<Field>) {
99 properties[fd.wire_name] = schema_for<typename Field::value_type>();
100 } else {
101 properties[fd.wire_name] = schema_for<Field>();
102 required.push_back(fd.wire_name);
103 }
104}
105
106template <typename Struct>
107inline void add_reflected_field_schema(Json&, Json&,
108 const ExtensionsField<Struct>&) {}
109
110template <typename Struct, typename Field>
111inline void add_reflected_field_schema(
112 Json&, Json&, const DeserializeOnlyField<Struct, Field>&) {}
113
114template <class T>
115inline Json reflect_schema() {
116 Json properties = Json::object();
117 Json required = Json::array();
118
119 std::apply(
120 [&](const auto&... fds) {
121 (add_reflected_field_schema(properties, required, fds), ...);
122 },
123 reflect_fields<T>());
124
125 Json result = {{"type", "object"}, {"properties", std::move(properties)}};
126 if (!required.empty()) {
127 result["required"] = std::move(required);
128 }
129 result["additionalProperties"] = false;
130 return result;
131}
132
133} // namespace detail
134
139template <class T>
140inline Json schema_for() {
141 using Decayed = std::decay_t<T>;
142 if constexpr (has_reflect_v<Decayed>) {
143 return detail::reflect_schema<Decayed>();
144 } else {
146 }
147}
148
149template <class T, class = void>
150struct has_schema_traits : std::false_type {};
151
152template <class T>
153struct has_schema_traits<T, std::void_t<decltype(SchemaTraits<T>::schema())>>
154 : std::true_type {};
155
156template <class T>
158 : std::bool_constant<has_reflect_v<std::decay_t<T>> ||
159 has_schema_traits<std::decay_t<T>>::value> {};
160
161template <class T>
162struct is_tool_schema_type<std::vector<T>> : is_tool_schema_type<T> {};
163
164template <class T>
165struct is_tool_schema_type<std::optional<T>> : is_tool_schema_type<T> {};
166
167template <class T>
168inline constexpr bool is_tool_schema_type_v = is_tool_schema_type<T>::value;
169
176template <class T>
178 using Decayed = std::decay_t<T>;
179 static_assert(
180 is_tool_schema_type_v<Decayed>,
181 "cxxmcp typed tool argument/result type is a class or struct but is "
182 "not reflectable. Add CXXMCP_REFLECT_SELF(Type, ...) inside the type, "
183 "CXXMCP_REFLECT(Type, ...) after it, or provide nlohmann JSON conversion "
184 "plus an explicit mcp::protocol::SchemaTraits<T> specialization.");
185 auto schema = schema_for<Decayed>();
186 if (schema.is_object() && schema.value("type", std::string{}) == "object") {
187 return schema;
188 }
189 if constexpr (std::is_same_v<Decayed, Json>) {
190 return JsonSchema::object();
191 } else {
192 return Json{{"type", "object"},
193 {"properties", Json{{"value", std::move(schema)}}},
194 {"required", Json::array({"value"})},
195 {"additionalProperties", false}};
196 }
197}
198
200template <class T>
202 return tool_input_schema_for<T>();
203}
204
207 public:
209 schema_["type"] = "object";
210 schema_["properties"] = Json::object();
211 }
212
213 ObjectSchemaBuilder& title(std::string value) {
214 schema_["title"] = std::move(value);
215 return *this;
216 }
217
218 ObjectSchemaBuilder& description(std::string value) {
219 schema_["description"] = std::move(value);
220 return *this;
221 }
222
223 ObjectSchemaBuilder& property(std::string name, Json schema) {
224 schema_["properties"][std::move(name)] = std::move(schema);
225 return *this;
226 }
227
228 ObjectSchemaBuilder& optional_property(std::string name, Json schema) {
229 return property(std::move(name), std::move(schema));
230 }
231
232 ObjectSchemaBuilder& required(std::string name) {
233 schema_["required"].push_back(std::move(name));
234 return *this;
235 }
236
237 ObjectSchemaBuilder& required_property(std::string name, Json schema) {
238 const auto required_name = name;
239 property(std::move(name), std::move(schema));
240 return required(required_name);
241 }
242
243 ObjectSchemaBuilder& additional_properties(bool value) {
244 schema_["additionalProperties"] = value;
245 return *this;
246 }
247
248 Json build() const& { return schema_; }
249
250 Json build() && { return std::move(schema_); }
251
252 private:
253 Json schema_ = Json::object();
254};
255
258
259} // namespace mcp::protocol
Primitive JSON Schema helpers used by public SDK builders.
Definition schema.hpp:19
Fluent object-schema builder for tool input and output schemas.
Definition schema.hpp:206
Shared JSON, JSON-RPC, error, cancellation, and progress model types.
nlohmann::json Json
JSON value type used by all protocol DTOs.
Definition types.hpp:28
C++17 tuple-reflection infrastructure for zero-boilerplate DTO serialization.
Json tool_input_schema_for()
Returns the root object schema required by MCP tool arguments.
Definition schema.hpp:177
Json schema_for()
Returns the JSON Schema advertised for a C++ type.
Definition schema.hpp:140
Json tool_output_schema_for()
Returns the root object schema required by MCP structuredContent.
Definition schema.hpp:201
ObjectSchemaBuilder object_schema()
Creates a fluent object-schema builder.
Definition schema.hpp:257
Describes a single DTO field: its JSON wire name, pointer-to-member, and optional post-deserializatio...
Definition reflect.hpp:41
Type-to-schema customization point for typed SDK helpers.
Definition schema.hpp:44
Definition schema.hpp:150
Definition schema.hpp:159