27namespace mcp::protocol {
36 std::optional<std::vector<std::string>>
audience;
55 std::optional<std::string>
title;
72 Json json = Json::object();
73 if (annotations.
title.has_value()) {
74 json[
"title"] = *annotations.
title;
91 if (annotations.
raw.is_object()) {
92 for (
const auto& item : annotations.
raw.items()) {
93 if (!json.contains(item.key())) {
94 json[item.key()] = item.value();
104 if (!json.is_object()) {
105 return mcp::core::unexpected(
106 core::Error{
static_cast<int>(ErrorCode::InvalidRequest),
107 "tool annotations must be an object",
113 if (json.contains(
"title")) {
114 if (!json.at(
"title").is_string()) {
115 return mcp::core::unexpected(
116 core::Error{
static_cast<int>(ErrorCode::InvalidRequest),
117 "tool annotations title must be a string",
120 annotations.
title = json.at(
"title").get<std::string>();
122 if (json.contains(
"descriptionHint")) {
123 if (!json.at(
"descriptionHint").is_string()) {
124 return mcp::core::unexpected(
125 core::Error{
static_cast<int>(ErrorCode::InvalidRequest),
126 "tool annotations descriptionHint must be a string",
130 json.at(
"descriptionHint").get<std::string>();
132 if (json.contains(
"destructiveHint")) {
133 if (!json.at(
"destructiveHint").is_boolean()) {
134 return mcp::core::unexpected(
135 core::Error{
static_cast<int>(ErrorCode::InvalidRequest),
136 "tool annotations destructiveHint must be a boolean",
141 if (json.contains(
"readOnlyHint")) {
142 if (!json.at(
"readOnlyHint").is_boolean()) {
143 return mcp::core::unexpected(
144 core::Error{
static_cast<int>(ErrorCode::InvalidRequest),
145 "tool annotations readOnlyHint must be a boolean",
150 if (json.contains(
"openWorldHint")) {
151 if (!json.at(
"openWorldHint").is_boolean()) {
152 return mcp::core::unexpected(
153 core::Error{
static_cast<int>(ErrorCode::InvalidRequest),
154 "tool annotations openWorldHint must be a boolean",
159 if (json.contains(
"idempotentHint")) {
160 if (!json.at(
"idempotentHint").is_boolean()) {
161 return mcp::core::unexpected(
162 core::Error{
static_cast<int>(ErrorCode::InvalidRequest),
163 "tool annotations idempotentHint must be a boolean",
170 json, {
"title",
"descriptionHint",
"destructiveHint",
"readOnlyHint",
171 "openWorldHint",
"idempotentHint"});
182 Json json = Json::object();
184 if (annotations.
audience.has_value()) {
185 json[
"audience"] = *annotations.
audience;
187 if (annotations.
priority.has_value()) {
188 json[
"priority"] = *annotations.
priority;
195 if (annotations.
raw.is_object()) {
196 for (
const auto& item : annotations.
raw.items()) {
197 if (!json.contains(item.key())) {
198 json[item.key()] = item.value();
214 if (!json.is_object()) {
215 return mcp::core::unexpected(
216 core::Error{
static_cast<int>(ErrorCode::InvalidRequest),
217 "annotations must be an object",
223 if (json.contains(
"audience")) {
224 const auto& audience_val = json.at(
"audience");
225 if (!audience_val.is_array()) {
226 return mcp::core::unexpected(
227 core::Error{
static_cast<int>(ErrorCode::InvalidRequest),
228 "annotations audience must be an array",
231 std::vector<std::string> audience;
232 audience.reserve(audience_val.size());
233 for (
const auto& item : audience_val) {
234 if (!item.is_string()) {
235 return mcp::core::unexpected(
236 core::Error{
static_cast<int>(ErrorCode::InvalidRequest),
237 "annotations audience entries must be strings",
240 audience.push_back(item.get<std::string>());
242 annotations.
audience = std::move(audience);
245 if (json.contains(
"priority")) {
246 const auto& priority_val = json.at(
"priority");
247 if (!priority_val.is_number()) {
248 return mcp::core::unexpected(
249 core::Error{
static_cast<int>(ErrorCode::InvalidRequest),
250 "annotations priority must be a number",
253 const float priority = priority_val.get<
float>();
254 if (!std::isfinite(priority) || priority < 0.0f || priority > 1.0f) {
255 return mcp::core::unexpected(
256 core::Error{
static_cast<int>(ErrorCode::InvalidRequest),
257 "annotations priority must be between 0.0 and 1.0",
263 if (json.contains(
"lastModified")) {
264 const auto& ts_val = json.at(
"lastModified");
265 if (!ts_val.is_string()) {
266 return mcp::core::unexpected(
267 core::Error{
static_cast<int>(ErrorCode::InvalidRequest),
268 "annotations lastModified must be a string",
Json tool_annotations_to_json(const ToolAnnotations &annotations)
Serializes a ToolAnnotations struct to JSON.
Definition annotations.hpp:71
core::Result< Annotations > annotations_from_json(const Json &json)
Parses an Annotations struct from JSON.
Definition annotations.hpp:213
core::Result< ToolAnnotations > tool_annotations_from_json(const Json &json)
Parses a ToolAnnotations struct from JSON.
Definition annotations.hpp:102
Json annotations_to_json(const Annotations &annotations)
Serializes an Annotations struct to JSON.
Definition annotations.hpp:181
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
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
Shared result and error primitives used by the public cxxmcp SDK.
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
Typed representation of MCP annotations.
Definition annotations.hpp:34
std::optional< std::vector< std::string > > audience
Target audience roles. Valid wire values are "user" and "assistant".
Definition annotations.hpp:36
std::optional< float > priority
Presentation priority in the closed interval [0.0, 1.0].
Definition annotations.hpp:39
std::optional< std::string > last_modified
ISO 8601 timestamp indicating when the annotated object was last modified.
Definition annotations.hpp:42
Json raw
Unknown JSON members preserved for forward-compatible round trips.
Definition annotations.hpp:45