32namespace mcp::protocol {
40template <
typename Struct,
typename Field>
42 const char* wire_name;
43 Field Struct::* pointer;
44 using field_type = Field;
45 using struct_type = Struct;
47 bool absent_as_monostate =
false;
48 bool absent_as_default =
false;
55template <
typename Struct>
57 Json Struct::* pointer;
58 std::vector<std::string> own_keys;
59 using field_type =
Json;
60 using struct_type = Struct;
65template <
typename Struct,
typename Field>
67 const char* wire_name;
68 Field Struct::* pointer;
69 using field_type = Field;
70 using struct_type = Struct;
74template <
typename Struct,
typename Field>
76 Field Struct::* pointer) {
77 return {wire_name, pointer,
nullptr};
81template <
typename Struct,
typename Field>
83 const char* wire_name, Field Struct::* pointer,
84 core::Result<core::Unit> (*validator)(const Field&)) {
85 return {wire_name, pointer, validator};
89template <
typename Struct>
91 std::vector<std::string> own_keys) {
92 return {pointer, std::move(own_keys)};
96template <
typename Struct,
typename Field>
98 const char* wire_name, Field Struct::* pointer) {
99 return {wire_name, pointer};
120template <
typename... Ts>
122 : std::disjunction<std::is_same<Ts, std::monostate>...> {};
133template <
typename Struct,
typename Field>
135 const char* wire_name, Field Struct::* pointer) {
136 static_assert(is_nullable_variant_v<Field>,
137 "nullable_field requires a std::variant containing "
139 return {wire_name, pointer,
nullptr,
true};
144template <
typename Struct,
typename Field>
146 const char* wire_name, Field Struct::* pointer) {
147 return {wire_name, pointer,
nullptr,
false,
true};
151template <
typename T,
typename =
void>
156 T, std::void_t<decltype(std::declval<T>().extensions)>>
157 : std::bool_constant<
158 std::is_same_v<decltype(std::declval<T>().extensions), Json>> {};
168template <
typename T,
typename =
void>
177template <
typename S,
typename F>
180 keys.push_back(fd.wire_name);
182template <
typename S,
typename F>
185 keys.push_back(fd.wire_name);
188void push_wire_name(std::vector<std::string>&,
const ExtensionsField<S>&) {}
200 static constexpr bool defined =
false;
208 std::vector<std::string> keys;
220template <
typename T,
typename =
void>
225 : std::bool_constant<Reflect<T>::defined> {};
245template <
typename T,
typename Enable =
void>
247 static void serialize(
Json& json,
const char* key,
const T& value) {
251 static bool deserialize(
const Json& json,
const char* key, T& target) {
252 if (!json.contains(key)) {
255 const auto& val = json.at(key);
256 if constexpr (std::is_same_v<T, bool>) {
257 if (!val.is_boolean()) {
260 }
else if constexpr (std::is_floating_point_v<T>) {
261 if (!val.is_number()) {
264 }
else if constexpr (std::is_integral_v<T>) {
265 if (!val.is_number_integer()) {
269 target = val.get<T>();
277 static void serialize(
Json& json,
const char* key,
const T& value) {
281 static bool deserialize(
const Json& json,
const char* key, T& target) {
282 if (!json.contains(key)) {
285 auto value = reflect_from_json<T>(json.at(key));
289 target = std::move(*value);
300 static void serialize(
Json& json,
const char* key,
const std::string& value) {
304 static bool deserialize(
const Json& json,
const char* key,
305 std::string& target) {
306 if (!json.contains(key)) {
309 if (!json.at(key).is_string()) {
312 target = json.at(key).get<std::string>();
323 static void serialize(
Json& json,
const char* key,
const Json& value) {
324 if (!value.is_null() && !value.empty()) {
329 static bool deserialize(
const Json& json,
const char* key,
Json& target) {
330 if (!json.contains(key)) {
333 target = json.at(key);
340 static void serialize(
Json& json,
const char* key,
IconTheme value) {
344 static bool deserialize(
const Json& json,
const char* key,
346 if (!json.contains(key) || !json.at(key).is_string()) {
350 if (!value.has_value()) {
370 static void serialize(
Json& json,
const char* key,
371 const std::optional<T>& value) {
372 if (value.has_value()) {
377 static bool deserialize(
const Json& json,
const char* key,
378 std::optional<T>& target) {
379 if (!json.contains(key)) {
386 target = std::move(inner);
397 static void serialize(
Json& json,
const char* key,
398 const std::optional<Json>& value) {
399 if (value.has_value() && !value->is_null()) {
404 static bool deserialize(
const Json& json,
const char* key,
405 std::optional<Json>& target) {
406 if (!json.contains(key)) {
409 target = json.at(key);
420 static void serialize(
Json& json,
const char* key,
421 const std::vector<T>& value) {
425 json[key] = Json::array();
426 for (
const auto& item : value) {
427 Json element = Json::object();
429 json[key].push_back(std::move(element[
"_item"]));
433 static bool deserialize(
const Json& json,
const char* key,
434 std::vector<T>& target) {
435 if (!json.contains(key)) {
438 if (!json.at(key).is_array()) {
442 target.reserve(json.at(key).size());
443 for (
const auto& item : json.at(key)) {
446 if constexpr (has_reflect_v<T>) {
447 auto result = reflect_from_json<T>(item);
451 target.push_back(std::move(*result));
454 element = item.get<T>();
455 target.push_back(std::move(element));
468 static void serialize(
Json& json,
const char* key,
469 const std::vector<std::string>& value) {
476 static bool deserialize(
const Json& json,
const char* key,
477 std::vector<std::string>& target) {
478 if (!json.contains(key)) {
481 if (!json.at(key).is_array()) {
484 target.reserve(json.at(key).size());
485 for (
const auto& item : json.at(key)) {
486 if (!item.is_string()) {
489 target.push_back(item.get<std::string>());
501 static void serialize(
Json& json,
const char* key,
502 const std::map<std::string, std::string>& value) {
506 json[key] = Json::object();
507 for (
const auto& [k, v] : value) {
512 static bool deserialize(
const Json& json,
const char* key,
513 std::map<std::string, std::string>& target) {
514 if (!json.contains(key)) {
517 if (!json.at(key).is_object()) {
521 for (
const auto& [k, v] : json.at(key).items()) {
522 if (!v.is_string()) {
525 target[k] = v.get<std::string>();
537 static void serialize(
Json& json,
const char* key,
538 const std::variant<std::monostate, std::int64_t>& val) {
539 if (std::holds_alternative<std::int64_t>(val)) {
540 json[key] = std::get<std::int64_t>(val);
546 static bool deserialize(
const Json& json,
const char* key,
547 std::variant<std::monostate, std::int64_t>& target) {
548 if (!json.contains(key)) {
549 target = std::monostate{};
552 if (json.at(key).is_null()) {
553 target = std::monostate{};
556 if (json.at(key).is_number_integer()) {
557 target = json.at(key).get<std::int64_t>();
570 static void serialize(
Json& json,
const char* key,
571 const std::variant<std::int64_t, std::string>& val) {
572 json[key] = std::visit([](
const auto& v) {
return Json(v); }, val);
575 static bool deserialize(
const Json& json,
const char* key,
576 std::variant<std::int64_t, std::string>& target) {
577 if (!json.contains(key)) {
580 const auto& val = json.at(key);
581 if (val.is_number_integer()) {
582 target = val.get<std::int64_t>();
585 if (val.is_string()) {
586 target = val.get<std::string>();
598template <
typename Struct,
typename Field>
605template <
typename Struct,
typename Field>
610template <
typename Struct>
620template <
typename Struct,
typename Field>
624 const bool present = json.contains(fd.wire_name);
626 if (fd.absent_as_default) {
627 obj.*(fd.pointer) = Field{};
633 if constexpr (is_optional_v<Field>) {
636 if constexpr (is_nullable_variant_v<Field>) {
637 if (fd.absent_as_monostate) {
638 obj.*(fd.pointer) = Field{std::monostate{}};
644 static_cast<int>(ErrorCode::InvalidRequest),
645 "missing required field '" + std::string(fd.wire_name) +
"'",
651 status = mcp::core::unexpected(
652 core::Error{
static_cast<int>(ErrorCode::InvalidRequest),
653 "invalid field '" + std::string(fd.wire_name) +
"'",
657 if (fd.post_validate) {
658 auto validation = fd.post_validate(temp);
660 status = mcp::core::unexpected(validation.error());
664 obj.*(fd.pointer) = std::move(temp);
670template <
typename Struct>
677template <
typename Struct,
typename Field>
681 if constexpr (is_optional_v<Field>) {
702 static_assert(has_reflect_v<T>,
703 "Reflect<T> must be specialized for this type");
704 Json json = Json::object();
707 std::apply([&](
const auto&... fds) { (
serialize_one(json, obj, fds), ...); },
711 if constexpr (has_extensions_member_v<T>) {
723 static_assert(has_reflect_v<T>,
724 "Reflect<T> must be specialized for this type");
725 if (!json.is_object()) {
726 return mcp::core::unexpected(
727 core::Error{
static_cast<int>(ErrorCode::InvalidRequest),
728 "expected a JSON object",
737 [&](
const auto&... fds) {
738 auto one = [&](
const auto& fd) {
748 return mcp::core::unexpected(status.error());
752 if constexpr (has_extensions_member_v<T>) {
757 return extract_known_keys<T>();
770#define CXXMCP_REFL_IMPL_1(T, f1) \
772 struct mcp::protocol::Reflect<T> { \
773 static constexpr bool defined = true; \
774 static auto fields() { return std::make_tuple(field(#f1, &T::f1)); } \
777#define CXXMCP_REFL_IMPL_2(T, f1, f2) \
779 struct mcp::protocol::Reflect<T> { \
780 static constexpr bool defined = true; \
781 static auto fields() { \
782 return std::make_tuple(field(#f1, &T::f1), field(#f2, &T::f2)); \
786#define CXXMCP_REFL_IMPL_3(T, f1, f2, f3) \
788 struct mcp::protocol::Reflect<T> { \
789 static constexpr bool defined = true; \
790 static auto fields() { \
791 return std::make_tuple(field(#f1, &T::f1), field(#f2, &T::f2), \
792 field(#f3, &T::f3)); \
796#define CXXMCP_REFL_IMPL_4(T, f1, f2, f3, f4) \
798 struct mcp::protocol::Reflect<T> { \
799 static constexpr bool defined = true; \
800 static auto fields() { \
801 return std::make_tuple(field(#f1, &T::f1), field(#f2, &T::f2), \
802 field(#f3, &T::f3), field(#f4, &T::f4)); \
806#define CXXMCP_REFL_IMPL_5(T, f1, f2, f3, f4, f5) \
808 struct mcp::protocol::Reflect<T> { \
809 static constexpr bool defined = true; \
810 static auto fields() { \
811 return std::make_tuple(field(#f1, &T::f1), field(#f2, &T::f2), \
812 field(#f3, &T::f3), field(#f4, &T::f4), \
813 field(#f5, &T::f5)); \
817#define CXXMCP_REFL_IMPL_6(T, f1, f2, f3, f4, f5, f6) \
819 struct mcp::protocol::Reflect<T> { \
820 static constexpr bool defined = true; \
821 static auto fields() { \
822 return std::make_tuple(field(#f1, &T::f1), field(#f2, &T::f2), \
823 field(#f3, &T::f3), field(#f4, &T::f4), \
824 field(#f5, &T::f5), field(#f6, &T::f6)); \
828#define CXXMCP_REFL_IMPL_7(T, f1, f2, f3, f4, f5, f6, f7) \
830 struct mcp::protocol::Reflect<T> { \
831 static constexpr bool defined = true; \
832 static auto fields() { \
833 return std::make_tuple(field(#f1, &T::f1), field(#f2, &T::f2), \
834 field(#f3, &T::f3), field(#f4, &T::f4), \
835 field(#f5, &T::f5), field(#f6, &T::f6), \
836 field(#f7, &T::f7)); \
840#define CXXMCP_REFL_IMPL_8(T, f1, f2, f3, f4, f5, f6, f7, f8) \
842 struct mcp::protocol::Reflect<T> { \
843 static constexpr bool defined = true; \
844 static auto fields() { \
845 return std::make_tuple(field(#f1, &T::f1), field(#f2, &T::f2), \
846 field(#f3, &T::f3), field(#f4, &T::f4), \
847 field(#f5, &T::f5), field(#f6, &T::f6), \
848 field(#f7, &T::f7), field(#f8, &T::f8)); \
852#define CXXMCP_REFL_IMPL_9(T, f1, f2, f3, f4, f5, f6, f7, f8, f9) \
854 struct mcp::protocol::Reflect<T> { \
855 static constexpr bool defined = true; \
856 static auto fields() { \
857 return std::make_tuple( \
858 field(#f1, &T::f1), field(#f2, &T::f2), field(#f3, &T::f3), \
859 field(#f4, &T::f4), field(#f5, &T::f5), field(#f6, &T::f6), \
860 field(#f7, &T::f7), field(#f8, &T::f8), field(#f9, &T::f9)); \
864#define CXXMCP_REFL_IMPL_10(T, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10) \
866 struct mcp::protocol::Reflect<T> { \
867 static constexpr bool defined = true; \
868 static auto fields() { \
869 return std::make_tuple(field(#f1, &T::f1), field(#f2, &T::f2), \
870 field(#f3, &T::f3), field(#f4, &T::f4), \
871 field(#f5, &T::f5), field(#f6, &T::f6), \
872 field(#f7, &T::f7), field(#f8, &T::f8), \
873 field(#f9, &T::f9), field(#f10, &T::f10)); \
877#define CXXMCP_REFL_IMPL_11(T, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11) \
879 struct mcp::protocol::Reflect<T> { \
880 static constexpr bool defined = true; \
881 static auto fields() { \
882 return std::make_tuple( \
883 field(#f1, &T::f1), field(#f2, &T::f2), field(#f3, &T::f3), \
884 field(#f4, &T::f4), field(#f5, &T::f5), field(#f6, &T::f6), \
885 field(#f7, &T::f7), field(#f8, &T::f8), field(#f9, &T::f9), \
886 field(#f10, &T::f10), field(#f11, &T::f11)); \
890#define CXXMCP_REFL_IMPL_12(T, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, \
893 struct mcp::protocol::Reflect<T> { \
894 static constexpr bool defined = true; \
895 static auto fields() { \
896 return std::make_tuple( \
897 field(#f1, &T::f1), field(#f2, &T::f2), field(#f3, &T::f3), \
898 field(#f4, &T::f4), field(#f5, &T::f5), field(#f6, &T::f6), \
899 field(#f7, &T::f7), field(#f8, &T::f8), field(#f9, &T::f9), \
900 field(#f10, &T::f10), field(#f11, &T::f11), field(#f12, &T::f12)); \
904#define CXXMCP_REFL_IMPL_13(T, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, \
907 struct mcp::protocol::Reflect<T> { \
908 static constexpr bool defined = true; \
909 static auto fields() { \
910 return std::make_tuple( \
911 field(#f1, &T::f1), field(#f2, &T::f2), field(#f3, &T::f3), \
912 field(#f4, &T::f4), field(#f5, &T::f5), field(#f6, &T::f6), \
913 field(#f7, &T::f7), field(#f8, &T::f8), field(#f9, &T::f9), \
914 field(#f10, &T::f10), field(#f11, &T::f11), field(#f12, &T::f12), \
915 field(#f13, &T::f13)); \
919#define CXXMCP_REFL_IMPL_14(T, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, \
922 struct mcp::protocol::Reflect<T> { \
923 static constexpr bool defined = true; \
924 static auto fields() { \
925 return std::make_tuple( \
926 field(#f1, &T::f1), field(#f2, &T::f2), field(#f3, &T::f3), \
927 field(#f4, &T::f4), field(#f5, &T::f5), field(#f6, &T::f6), \
928 field(#f7, &T::f7), field(#f8, &T::f8), field(#f9, &T::f9), \
929 field(#f10, &T::f10), field(#f11, &T::f11), field(#f12, &T::f12), \
930 field(#f13, &T::f13), field(#f14, &T::f14)); \
934#define CXXMCP_REFL_IMPL_15(T, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, \
935 f12, f13, f14, f15) \
937 struct mcp::protocol::Reflect<T> { \
938 static constexpr bool defined = true; \
939 static auto fields() { \
940 return std::make_tuple( \
941 field(#f1, &T::f1), field(#f2, &T::f2), field(#f3, &T::f3), \
942 field(#f4, &T::f4), field(#f5, &T::f5), field(#f6, &T::f6), \
943 field(#f7, &T::f7), field(#f8, &T::f8), field(#f9, &T::f9), \
944 field(#f10, &T::f10), field(#f11, &T::f11), field(#f12, &T::f12), \
945 field(#f13, &T::f13), field(#f14, &T::f14), field(#f15, &T::f15)); \
949#define CXXMCP_REFL_IMPL_16(T, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, \
950 f12, f13, f14, f15, f16) \
952 struct mcp::protocol::Reflect<T> { \
953 static constexpr bool defined = true; \
954 static auto fields() { \
955 return std::make_tuple( \
956 field(#f1, &T::f1), field(#f2, &T::f2), field(#f3, &T::f3), \
957 field(#f4, &T::f4), field(#f5, &T::f5), field(#f6, &T::f6), \
958 field(#f7, &T::f7), field(#f8, &T::f8), field(#f9, &T::f9), \
959 field(#f10, &T::f10), field(#f11, &T::f11), field(#f12, &T::f12), \
960 field(#f13, &T::f13), field(#f14, &T::f14), field(#f15, &T::f15), \
961 field(#f16, &T::f16)); \
966#define CXXMCP_REFLECT_CHOOSER(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, \
967 _12, _13, _14, _15, _16, NAME, ...) \
969#define CXXMCP_REFLECT_EXPAND(expr) expr
979#define CXXMCP_REFLECT(Type, ...) \
980 using ::mcp::protocol::Reflect; \
981 using ::mcp::protocol::field; \
982 CXXMCP_REFLECT_EXPAND(CXXMCP_REFLECT_CHOOSER( \
983 __VA_ARGS__, CXXMCP_REFL_IMPL_16, CXXMCP_REFL_IMPL_15, \
984 CXXMCP_REFL_IMPL_14, CXXMCP_REFL_IMPL_13, CXXMCP_REFL_IMPL_12, \
985 CXXMCP_REFL_IMPL_11, CXXMCP_REFL_IMPL_10, CXXMCP_REFL_IMPL_9, \
986 CXXMCP_REFL_IMPL_8, CXXMCP_REFL_IMPL_7, CXXMCP_REFL_IMPL_6, \
987 CXXMCP_REFL_IMPL_5, CXXMCP_REFL_IMPL_4, CXXMCP_REFL_IMPL_3, \
988 CXXMCP_REFL_IMPL_2, CXXMCP_REFL_IMPL_1)(Type, __VA_ARGS__))
1008#define CXXMCP_REFLECT_CHECK(Struct, expected_count) \
1010 std::tuple_size_v< \
1011 decltype(::mcp::protocol::Reflect<Struct>::fields())> == \
1013 "Reflect<" #Struct \
1014 ">::fields() has " \
1015 "a different number of descriptors than expected (" #expected_count \
1016 "). Update the count or add/remove field descriptors.")
void push_wire_name(std::vector< std::string > &keys, const FieldDescriptor< S, F > &fd)
Overloads that extract wire_name from field descriptors.
Definition reflect.hpp:178
Shared JSON, JSON-RPC, error, cancellation, and progress model types.
std::string_view icon_theme_to_string(IconTheme theme) noexcept
Converts an icon theme enum to the lowercase wire value.
Definition types.hpp:259
void append_json_extensions(Json &json, const Json &extensions)
Flattens extension members into a JSON object without overwriting typed fields.
Definition types.hpp:358
IconTheme
Preferred icon variant for clients with light or dark surfaces.
Definition types.hpp:151
std::optional< IconTheme > icon_theme_from_string(std::string_view value) noexcept
Parses a lowercase icon theme wire value.
Definition types.hpp:270
nlohmann::json Json
JSON value type used by all protocol DTOs.
Definition types.hpp:28
Json collect_json_extensions(const Json &json, std::initializer_list< std::string_view > known_keys)
Collects unknown object members so typed DTOs can preserve future protocol fields and vendor extensio...
Definition types.hpp:320
constexpr FieldDescriptor< Struct, Field > field(const char *wire_name, Field Struct::*pointer)
Creates a FieldDescriptor with wire name and pointer-to-member.
Definition reflect.hpp:75
std::vector< std::string > extract_known_keys()
Extracts known wire names from the fields() tuple at runtime.
Definition reflect.hpp:207
constexpr FieldDescriptor< Struct, Field > defaulted_field(const char *wire_name, Field Struct::*pointer)
Creates a FieldDescriptor whose missing wire value keeps the C++ default value.
Definition reflect.hpp:145
constexpr FieldDescriptor< Struct, Field > nullable_field(const char *wire_name, Field Struct::*pointer)
Creates a FieldDescriptor whose missing wire value maps to std::monostate.
Definition reflect.hpp:134
ExtensionsField< Struct > extensions_field(Json Struct::*pointer, std::vector< std::string > own_keys)
Creates an ExtensionsField descriptor.
Definition reflect.hpp:90
void serialize_one(Json &json, const Struct &obj, const FieldDescriptor< Struct, Field > &fd)
Serializes a single field into the JSON object.
Definition reflect.hpp:599
constexpr DeserializeOnlyField< Struct, Field > deserialize_only(const char *wire_name, Field Struct::*pointer)
Creates a DeserializeOnlyField descriptor.
Definition reflect.hpp:97
Json reflect_to_json(const T &obj)
Serializes a DTO to JSON using its Reflect<T> trait.
Definition reflect.hpp:701
constexpr FieldDescriptor< Struct, Field > validated_field(const char *wire_name, Field Struct::*pointer, core::Result< core::Unit >(*validator)(const Field &))
Creates a FieldDescriptor with a post-deserialization validator.
Definition reflect.hpp:82
bool deserialize_one(const Json &json, Struct &obj, const FieldDescriptor< Struct, Field > &fd, core::Result< core::Unit > &status)
Deserializes a single field from the JSON object.
Definition reflect.hpp:621
core::Result< T > reflect_from_json(const Json &json)
Deserializes a DTO from JSON using its Reflect<T> trait.
Definition reflect.hpp:722
Shared result and error primitives used by the public cxxmcp SDK.
std::monostate Unit
Success value for operations that only need to report failure.
Definition result.hpp:55
tl::expected< T, Error > Result
Alias for the SDK result type.
Definition result.hpp:64
Structured error returned by fallible SDK operations.
Definition result.hpp:35
Tag-only field descriptor for fields that are populated during deserialization only (e....
Definition reflect.hpp:66
Tag-only field descriptor for the extensions member.
Definition reflect.hpp:56
Describes a single DTO field: its JSON wire name, pointer-to-member, and optional post-deserializatio...
Definition reflect.hpp:41
Type-specific serialization and deserialization logic.
Definition reflect.hpp:246
Primary template.
Definition reflect.hpp:199
Definition reflect.hpp:169
Detects whether a type has an extensions member of type Json.
Definition reflect.hpp:152
Detects whether Reflect<T> is specialized for a given type.
Definition reflect.hpp:221
Detects std::variant containing std::monostate (nullable on wire).
Definition reflect.hpp:118
Detects std::optional<T>.
Definition reflect.hpp:108