cxxmcp 1.2.4
C++ MCP SDK
Loading...
Searching...
No Matches
handler_dispatch.hpp
Go to the documentation of this file.
1// Copyright (c) 2025 [caomengxuan666]
2
3#pragma once
4
7
8#include <optional>
9#include <string>
10#include <tuple>
11#include <type_traits>
12#include <utility>
13
16
17namespace mcp::server {
18
19namespace detail {
20
21template <class T>
22struct is_result : std::false_type {};
23
24template <class T>
25struct is_result<core::Result<T>> : std::true_type {};
26
27template <class>
28inline constexpr bool always_false_v = false;
29
30template <class T, class = void>
32 using type = void;
33};
34
35template <class Class, class Return, class... Args>
36struct callable_argument_types<Return (Class::*)(Args...) const, void> {
37 using type = std::tuple<std::decay_t<Args>...>;
38};
39
40template <class Class, class Return, class... Args>
41struct callable_argument_types<Return (Class::*)(Args...), void> {
42 using type = std::tuple<std::decay_t<Args>...>;
43};
44
45template <class Return, class... Args>
46struct callable_argument_types<Return (*)(Args...), void> {
47 using type = std::tuple<std::decay_t<Args>...>;
48};
49
50template <class T>
51struct callable_argument_types<T, std::void_t<decltype(&T::operator())>>
52 : callable_argument_types<decltype(&T::operator())> {};
53
54template <class Handler, class Tuple, class = void>
55struct callable_arguments_match : std::false_type {};
56
57template <class Handler, class... Args>
59 Handler, std::tuple<Args...>,
60 std::void_t<typename callable_argument_types<std::decay_t<Handler>>::type>>
61 : std::is_same<
62 typename callable_argument_types<std::decay_t<Handler>>::type,
63 std::tuple<std::decay_t<Args>...>> {};
64
65template <class Handler, class... Args>
66inline constexpr bool callable_arguments_match_v =
67 callable_arguments_match<Handler, std::tuple<Args...>>::value;
68
69template <class Handler, class = void>
70struct has_callable_arguments : std::false_type {};
71
72template <class Handler>
74 Handler,
75 std::void_t<typename callable_argument_types<std::decay_t<Handler>>::type>>
76 : std::true_type {};
77
78template <class Handler>
79inline constexpr bool has_callable_arguments_v =
81
82template <bool... Values>
83inline constexpr int bool_count_v = (0 + ... + (Values ? 1 : 0));
84
85template <class Handler, class... Args>
86inline constexpr bool handler_accepts_v =
87 callable_arguments_match_v<Handler, Args...> ||
88 (!callable_arguments_match_v<Handler, Args...> &&
89 std::is_invocable_v<Handler&, Args...>);
90
91template <class Handler, class... Args>
92inline constexpr bool handler_shape_accepts_v =
93 has_callable_arguments_v<Handler>
94 ? callable_arguments_match_v<Handler, Args...>
95 : std::is_invocable_v<Handler&, Args...>;
96
97template <class Handler, class Args>
98inline constexpr int tool_handler_match_count_v =
99 bool_count_v<handler_accepts_v<Handler, Args, const ToolContext&>,
100 handler_accepts_v<Handler, const ToolContext&, Args>,
101 handler_accepts_v<Handler, Args, CancellationToken>,
102 handler_accepts_v<Handler, CancellationToken, Args>,
103 handler_accepts_v<Handler, Args>,
104 handler_accepts_v<Handler, const ToolContext&>,
105 handler_accepts_v<Handler>>;
106
107template <class Handler, class Args, class Context>
108inline constexpr int typed_context_handler_match_count_v =
109 bool_count_v<handler_accepts_v<Handler, Args, const Context&>,
110 handler_accepts_v<Handler, const Context&, Args>,
111 handler_accepts_v<Handler, Args, CancellationToken>,
112 handler_accepts_v<Handler, CancellationToken, Args>,
113 handler_accepts_v<Handler, Args>,
114 handler_accepts_v<Handler, const Context&>,
115 handler_accepts_v<Handler, CancellationToken>,
116 handler_accepts_v<Handler>>;
117
118template <class Handler>
119inline constexpr int prompt_handler_exact_match_count_v = bool_count_v<
120 callable_arguments_match_v<Handler, protocol::Json, PromptContext>,
121 callable_arguments_match_v<Handler, PromptContext, protocol::Json>,
122 callable_arguments_match_v<Handler, std::string, PromptContext>,
123 callable_arguments_match_v<Handler, PromptContext, std::string>,
124 callable_arguments_match_v<Handler, protocol::Json>,
125 callable_arguments_match_v<Handler, std::string>,
126 callable_arguments_match_v<Handler, PromptContext>,
127 callable_arguments_match_v<Handler, protocol::Json, CancellationToken>,
128 callable_arguments_match_v<Handler, CancellationToken, protocol::Json>,
129 callable_arguments_match_v<Handler, std::string, CancellationToken>,
130 callable_arguments_match_v<Handler, CancellationToken, std::string>,
131 callable_arguments_match_v<Handler, CancellationToken>,
132 callable_arguments_match_v<Handler>>;
133
134template <class Handler>
135inline constexpr int prompt_handler_invocable_match_count_v = bool_count_v<
136 std::is_invocable_v<Handler&, protocol::Json, PromptContext>,
137 std::is_invocable_v<Handler&, PromptContext, protocol::Json>,
138 std::is_invocable_v<Handler&, std::string, PromptContext>,
139 std::is_invocable_v<Handler&, PromptContext, std::string>,
140 std::is_invocable_v<Handler&, protocol::Json>,
141 std::is_invocable_v<Handler&, std::string>,
142 std::is_invocable_v<Handler&, PromptContext>,
143 std::is_invocable_v<Handler&, protocol::Json, CancellationToken>,
144 std::is_invocable_v<Handler&, CancellationToken, protocol::Json>,
145 std::is_invocable_v<Handler&, std::string, CancellationToken>,
146 std::is_invocable_v<Handler&, CancellationToken, std::string>,
147 std::is_invocable_v<Handler&, CancellationToken>,
148 std::is_invocable_v<Handler&>>;
149
150template <class Handler>
151inline constexpr int prompt_handler_match_count_v =
152 prompt_handler_exact_match_count_v<Handler> > 0
153 ? prompt_handler_exact_match_count_v<Handler>
154 : prompt_handler_invocable_match_count_v<Handler>;
155
156template <class Handler>
157inline constexpr int resource_handler_exact_match_count_v = bool_count_v<
158 callable_arguments_match_v<Handler, protocol::Json, ResourceContext>,
159 callable_arguments_match_v<Handler, ResourceContext, protocol::Json>,
160 callable_arguments_match_v<Handler, std::string, ResourceContext>,
161 callable_arguments_match_v<Handler, ResourceContext, std::string>,
162 callable_arguments_match_v<Handler, protocol::Json>,
163 callable_arguments_match_v<Handler, std::string>,
164 callable_arguments_match_v<Handler, ResourceContext>,
165 callable_arguments_match_v<Handler, protocol::Json, CancellationToken>,
166 callable_arguments_match_v<Handler, CancellationToken, protocol::Json>,
167 callable_arguments_match_v<Handler, std::string, CancellationToken>,
168 callable_arguments_match_v<Handler, CancellationToken, std::string>,
169 callable_arguments_match_v<Handler, CancellationToken>,
170 callable_arguments_match_v<Handler>>;
171
172template <class Handler>
173inline constexpr int resource_handler_invocable_match_count_v = bool_count_v<
174 std::is_invocable_v<Handler&, protocol::Json, ResourceContext>,
175 std::is_invocable_v<Handler&, ResourceContext, protocol::Json>,
176 std::is_invocable_v<Handler&, std::string, ResourceContext>,
177 std::is_invocable_v<Handler&, ResourceContext, std::string>,
178 std::is_invocable_v<Handler&, protocol::Json>,
179 std::is_invocable_v<Handler&, std::string>,
180 std::is_invocable_v<Handler&, ResourceContext>,
181 std::is_invocable_v<Handler&, protocol::Json, CancellationToken>,
182 std::is_invocable_v<Handler&, CancellationToken, protocol::Json>,
183 std::is_invocable_v<Handler&, std::string, CancellationToken>,
184 std::is_invocable_v<Handler&, CancellationToken, std::string>,
185 std::is_invocable_v<Handler&, CancellationToken>,
186 std::is_invocable_v<Handler&>>;
187
188template <class Handler>
189inline constexpr int resource_handler_match_count_v =
190 resource_handler_exact_match_count_v<Handler> > 0
191 ? resource_handler_exact_match_count_v<Handler>
192 : resource_handler_invocable_match_count_v<Handler>;
193
194template <class Handler>
195inline constexpr int json_extension_handler_match_count_v = bool_count_v<
196 handler_accepts_v<Handler, const protocol::Json&, const SessionContext&,
198 handler_accepts_v<Handler, const protocol::Json&, const SessionContext&>,
199 handler_accepts_v<Handler, const SessionContext&, const protocol::Json&,
201 handler_accepts_v<Handler, const SessionContext&, const protocol::Json&>,
202 handler_accepts_v<Handler, const protocol::Json&, CancellationToken>,
203 handler_accepts_v<Handler, CancellationToken, const protocol::Json&>,
204 handler_accepts_v<Handler, const protocol::Json&>,
205 handler_accepts_v<Handler, const SessionContext&, CancellationToken>,
206 handler_accepts_v<Handler, CancellationToken, const SessionContext&>,
207 handler_accepts_v<Handler, const SessionContext&>,
208 handler_accepts_v<Handler, CancellationToken>, handler_accepts_v<Handler>>;
209
210template <class Handler>
211inline constexpr int completion_handler_match_count_v = bool_count_v<
212 handler_accepts_v<Handler, const protocol::CompleteParams&,
213 const CompletionContext&>,
214 handler_accepts_v<Handler, const CompletionContext&,
216 handler_accepts_v<Handler, const protocol::CompletionArgument&,
217 const CompletionContext&>,
218 handler_accepts_v<Handler, const CompletionContext&,
220 handler_accepts_v<Handler, std::string, const CompletionContext&>,
221 handler_accepts_v<Handler, const CompletionContext&, std::string>,
222 handler_accepts_v<Handler, const protocol::CompleteParams&,
224 handler_accepts_v<Handler, CancellationToken,
226 handler_accepts_v<Handler, const protocol::CompletionArgument&,
228 handler_accepts_v<Handler, CancellationToken,
230 handler_accepts_v<Handler, std::string, CancellationToken>,
231 handler_accepts_v<Handler, CancellationToken, std::string>,
232 handler_accepts_v<Handler, const protocol::CompleteParams&>,
233 handler_accepts_v<Handler, const protocol::CompletionArgument&>,
234 handler_accepts_v<Handler, std::string>,
235 handler_accepts_v<Handler, CancellationToken>>;
236
237template <class Handler, class Args>
238constexpr void require_unambiguous_tool_handler() {
239 static_assert(tool_handler_match_count_v<Handler, Args> <= 1,
240 "ambiguous tool handler signature: use one explicit callable "
241 "shape instead of a generic/default-argument handler");
242}
243
244template <class Handler, class Args, class Context>
245constexpr void require_unambiguous_typed_context_handler(
246 std::string_view label) {
247 (void)label;
248 static_assert(
249 typed_context_handler_match_count_v<Handler, Args, Context> <= 1,
250 "ambiguous typed handler signature: use one explicit callable "
251 "shape instead of a generic/default-argument handler");
252}
253
254template <class Handler>
255constexpr void require_unambiguous_prompt_handler() {
256 static_assert(prompt_handler_match_count_v<Handler> <= 1,
257 "ambiguous prompt handler signature: use one explicit callable "
258 "shape instead of a generic/default-argument handler");
259}
260
261template <class Handler>
262constexpr void require_unambiguous_resource_handler() {
263 static_assert(
264 resource_handler_match_count_v<Handler> <= 1,
265 "ambiguous resource handler signature: use one explicit callable shape "
266 "instead of a generic/default-argument handler");
267}
268
269template <class Handler>
270constexpr void require_unambiguous_json_extension_handler() {
271 static_assert(json_extension_handler_match_count_v<Handler> <= 1,
272 "ambiguous JSON extension handler signature: use one explicit "
273 "callable shape instead of a generic/default-argument handler");
274}
275
276template <class Handler>
277constexpr void require_unambiguous_completion_handler() {
278 static_assert(
279 completion_handler_match_count_v<Handler> <= 1,
280 "ambiguous completion handler signature: use one explicit callable shape "
281 "instead of a generic/default-argument handler");
282}
283
284template <class T>
285inline protocol::Json value_to_json(T&& value) {
286 using Value = std::decay_t<T>;
287 if constexpr (std::is_same_v<Value, protocol::Json>) {
288 return std::forward<T>(value);
289 } else if constexpr (protocol::has_reflect_v<Value>) {
290 return protocol::reflect_to_json(value);
291 } else {
292 return protocol::Json(std::forward<T>(value));
293 }
294}
295
296template <class T>
297inline protocol::Json value_to_tool_structured_content(T&& value) {
298 auto json = value_to_json(std::forward<T>(value));
299 if (json.is_object()) {
300 return json;
301 }
302 return protocol::Json{{"value", std::move(json)}};
303}
304
305template <class Handler>
306inline bool callable_is_empty(const Handler&) noexcept {
307 return false;
308}
309
310template <class Return, class... Args>
311inline bool callable_is_empty(
312 const std::function<Return(Args...)>& handler) noexcept {
313 return !handler;
314}
315
316template <class Return, class... Args>
317inline bool callable_is_empty(Return (*handler)(Args...)) noexcept {
318 return handler == nullptr;
319}
320
321template <class Handler>
322inline void require_callable(const Handler& handler, std::string_view label) {
323 if (callable_is_empty(handler)) {
324 throw std::invalid_argument(std::string(label) +
325 " handler must not be empty");
326 }
327}
328
329inline protocol::ToolResult value_to_tool_result(protocol::ToolResult result) {
330 return result;
331}
332
333inline protocol::ToolResult value_to_tool_result(std::string text) {
334 protocol::ToolResult result;
335 protocol::ContentBlock block;
336 block.type = "text";
337 block.text = std::move(text);
338 result.content.push_back(std::move(block));
339 return result;
340}
341
342inline protocol::ToolResult value_to_tool_result(const char* text) {
343 return value_to_tool_result(std::string(text == nullptr ? "" : text));
344}
345
346template <class T>
347inline protocol::ToolResult value_to_tool_result(T&& value) {
348 protocol::ToolResult result;
349 result.structured_content =
350 value_to_tool_structured_content(std::forward<T>(value));
351 protocol::ContentBlock block;
352 block.type = "text";
353 block.text = result.structured_content->dump();
354 result.content.push_back(std::move(block));
355 return result;
356}
357
358inline protocol::PromptsGetResult value_to_prompt_result(
359 protocol::PromptsGetResult result) {
360 return result;
361}
362
363inline protocol::PromptsGetResult value_to_prompt_result(std::string text) {
364 protocol::PromptsGetResult result;
365 protocol::ContentBlock block;
366 block.type = "text";
367 block.text = std::move(text);
368 protocol::PromptMessage message;
369 message.role = "assistant";
370 message.content = std::move(block);
371 result.messages.push_back(std::move(message));
372 return result;
373}
374
375inline protocol::PromptsGetResult value_to_prompt_result(
376 protocol::PromptMessage message) {
377 protocol::PromptsGetResult result;
378 result.messages.push_back(std::move(message));
379 return result;
380}
381
382inline protocol::PromptsGetResult value_to_prompt_result(
383 std::vector<protocol::PromptMessage> messages) {
384 protocol::PromptsGetResult result;
385 result.messages = std::move(messages);
386 return result;
387}
388
389inline protocol::ResourcesReadResult value_to_resource_read_result(
390 protocol::ResourcesReadResult result, std::string_view) {
391 return result;
392}
393
394inline protocol::ResourcesReadResult value_to_resource_read_result(
395 protocol::ResourceContents contents, std::string_view) {
396 protocol::ResourcesReadResult result;
397 result.contents.push_back(std::move(contents));
398 return result;
399}
400
401inline protocol::ResourcesReadResult value_to_resource_read_result(
402 std::vector<protocol::ResourceContents> contents, std::string_view) {
403 protocol::ResourcesReadResult result;
404 result.contents = std::move(contents);
405 return result;
406}
407
408inline protocol::ResourcesReadResult value_to_resource_read_result(
409 std::string text, std::string_view uri) {
410 protocol::ResourcesReadResult result;
411 protocol::ResourceContents contents;
412 contents.uri = std::string(uri);
413 contents.mime_type = "text/plain";
414 contents.text = std::move(text);
415 result.contents.push_back(std::move(contents));
416 return result;
417}
418
419inline protocol::Json value_to_complete_result_json(protocol::Json json) {
420 return json;
421}
422
423inline protocol::Json value_to_complete_result_json(
424 protocol::CompleteResult result) {
425 return protocol::complete_result_to_json(result);
426}
427
428inline protocol::Json value_to_complete_result_json(
429 protocol::CompletionResult result) {
430 protocol::CompleteResult envelope;
431 envelope.completion = std::move(result);
432 return protocol::complete_result_to_json(envelope);
433}
434
435inline protocol::Json value_to_complete_result_json(
436 std::vector<std::string> values) {
437 protocol::CompletionResult completion;
438 completion.values = std::move(values);
439 return value_to_complete_result_json(std::move(completion));
440}
441
442inline protocol::Json value_to_complete_result_json(std::string value) {
443 return value_to_complete_result_json(
444 std::vector<std::string>{std::move(value)});
445}
446
447inline protocol::Json value_to_complete_result_json(const char* value) {
448 return value_to_complete_result_json(
449 std::string(value == nullptr ? "" : value));
450}
451
452template <class T>
453inline core::Result<protocol::Json> completion_response_to_json(T&& value) {
454 using Value = std::decay_t<T>;
455 if constexpr (is_result<Value>::value) {
456 if (!value) {
457 return mcp::core::unexpected(value.error());
458 }
459 return completion_response_to_json(std::move(*value));
460 } else {
461 return value_to_complete_result_json(std::forward<T>(value));
462 }
463}
464
465template <class Arg>
466inline Arg argument_from_json(const protocol::Json& arguments,
467 std::string_view fallback_name = {}) {
468 using Decayed = std::decay_t<Arg>;
469 if constexpr (std::is_same_v<Decayed, protocol::Json>) {
470 return arguments;
471 } else if constexpr (protocol::has_reflect_v<Decayed>) {
472 protocol::Json effective = arguments;
473 if (!fallback_name.empty() && arguments.is_object() &&
474 arguments.contains(std::string(fallback_name))) {
475 effective = arguments.at(std::string(fallback_name));
476 }
477 auto result = protocol::reflect_from_json<Decayed>(effective);
478 if (!result) {
479 throw std::invalid_argument(result.error().message);
480 }
481 return std::move(*result);
482 } else {
483 if (!fallback_name.empty() && arguments.is_object() &&
484 arguments.contains(std::string(fallback_name))) {
485 return arguments.at(std::string(fallback_name)).template get<Arg>();
486 }
487 if (arguments.is_object() && arguments.size() == 1) {
488 return arguments.begin().value().template get<Arg>();
489 }
490 return arguments.template get<Arg>();
491 }
492}
493
494template <class Result>
495inline void apply_default_output_schema(protocol::ToolDefinition& definition) {
496 if constexpr (!std::is_same_v<std::decay_t<Result>, protocol::ToolResult> &&
497 !std::is_same_v<std::decay_t<Result>, std::string> &&
498 !std::is_same_v<std::decay_t<Result>, const char*> &&
499 !std::is_same_v<std::decay_t<Result>, char*>) {
500 if (definition.output_schema.empty()) {
501 definition.output_schema = protocol::tool_output_schema_for<Result>();
502 definition.output_schema_present = true;
503 }
504 }
505}
506
507template <class Handler, class Args>
508decltype(auto) invoke_tool_handler(Handler& handler, Args&& args,
509 const ToolContext& context) {
510 using Arg = std::decay_t<Args>;
511 if constexpr (std::is_invocable_v<Handler&, Arg, const ToolContext&>) {
512 return handler(std::forward<Args>(args), context);
513 } else if constexpr (std::is_invocable_v<Handler&, const ToolContext&, Arg>) {
514 return handler(context, std::forward<Args>(args));
515 } else if constexpr (std::is_invocable_v<Handler&, Arg, CancellationToken>) {
516 return handler(std::forward<Args>(args), context.cancellation);
517 } else if constexpr (std::is_invocable_v<Handler&, CancellationToken, Arg>) {
518 return handler(context.cancellation, std::forward<Args>(args));
519 } else if constexpr (std::is_invocable_v<Handler&, Arg>) {
520 return handler(std::forward<Args>(args));
521 } else if constexpr (std::is_invocable_v<Handler&, const ToolContext&>) {
522 return handler(context);
523 } else if constexpr (std::is_invocable_v<Handler&>) {
524 return handler();
525 } else {
526 static_assert(always_false_v<Handler>,
527 "tool handler must accept Args, Args+ToolContext, "
528 "ToolContext+Args, Args+CancellationToken, "
529 "CancellationToken+Args, ToolContext, or no arguments");
530 }
531}
532
533template <class Handler, class Args, class Context>
534decltype(auto) invoke_typed_context_handler(Handler& handler, Args&& args,
535 const Context& context) {
536 using Arg = std::decay_t<Args>;
537 if constexpr (std::is_invocable_v<Handler&, Arg, const Context&>) {
538 return handler(std::forward<Args>(args), context);
539 } else if constexpr (std::is_invocable_v<Handler&, const Context&, Arg>) {
540 return handler(context, std::forward<Args>(args));
541 } else if constexpr (std::is_invocable_v<Handler&, Arg, CancellationToken>) {
542 return handler(std::forward<Args>(args), context.cancellation);
543 } else if constexpr (std::is_invocable_v<Handler&, CancellationToken, Arg>) {
544 return handler(context.cancellation, std::forward<Args>(args));
545 } else if constexpr (std::is_invocable_v<Handler&, Arg>) {
546 return handler(std::forward<Args>(args));
547 } else if constexpr (std::is_invocable_v<Handler&, const Context&>) {
548 return handler(context);
549 } else if constexpr (std::is_invocable_v<Handler&, CancellationToken>) {
550 return handler(context.cancellation);
551 } else if constexpr (std::is_invocable_v<Handler&>) {
552 return handler();
553 } else {
554 static_assert(always_false_v<Handler>,
555 "typed handler must accept Args, Args+Context, "
556 "Context+Args, Args+CancellationToken, "
557 "CancellationToken+Args, Context, CancellationToken, "
558 "or no arguments");
559 }
560}
561
562template <class Handler>
563decltype(auto) invoke_prompt_handler(Handler& handler,
564 const PromptContext& context) {
565 using Json = protocol::Json;
566 if constexpr (callable_arguments_match_v<Handler, Json, PromptContext>) {
567 return handler(context.arguments, context);
568 } else if constexpr (callable_arguments_match_v<Handler, PromptContext,
569 Json>) {
570 return handler(context, context.arguments);
571 } else if constexpr (callable_arguments_match_v<Handler, std::string,
572 PromptContext>) {
573 auto text = argument_from_json<std::string>(context.arguments,
574 std::string_view("text"));
575 return handler(std::move(text), context);
576 } else if constexpr (callable_arguments_match_v<Handler, PromptContext,
577 std::string>) {
578 auto text = argument_from_json<std::string>(context.arguments,
579 std::string_view("text"));
580 return handler(context, std::move(text));
581 } else if constexpr (callable_arguments_match_v<Handler, Json>) {
582 return handler(context.arguments);
583 } else if constexpr (callable_arguments_match_v<Handler, std::string>) {
584 auto text = argument_from_json<std::string>(context.arguments,
585 std::string_view("text"));
586 return handler(std::move(text));
587 } else if constexpr (callable_arguments_match_v<Handler, PromptContext>) {
588 return handler(context);
589 } else if constexpr (callable_arguments_match_v<Handler, Json,
591 return handler(context.arguments, context.cancellation);
592 } else if constexpr (callable_arguments_match_v<Handler, CancellationToken,
593 Json>) {
594 return handler(context.cancellation, context.arguments);
595 } else if constexpr (callable_arguments_match_v<Handler, std::string,
597 auto text = argument_from_json<std::string>(context.arguments,
598 std::string_view("text"));
599 return handler(std::move(text), context.cancellation);
600 } else if constexpr (callable_arguments_match_v<Handler, CancellationToken,
601 std::string>) {
602 auto text = argument_from_json<std::string>(context.arguments,
603 std::string_view("text"));
604 return handler(context.cancellation, std::move(text));
605 } else if constexpr (callable_arguments_match_v<Handler, CancellationToken>) {
606 return handler(context.cancellation);
607 } else if constexpr (std::is_invocable_v<Handler&, const Json&,
608 const PromptContext&>) {
609 return handler(context.arguments, context);
610 } else if constexpr (std::is_invocable_v<Handler&, const PromptContext&,
611 const Json&>) {
612 return handler(context, context.arguments);
613 } else if constexpr (std::is_invocable_v<Handler&, std::string,
614 const PromptContext&>) {
615 auto text = argument_from_json<std::string>(context.arguments,
616 std::string_view("text"));
617 return handler(std::move(text), context);
618 } else if constexpr (std::is_invocable_v<Handler&, const PromptContext&,
619 std::string>) {
620 auto text = argument_from_json<std::string>(context.arguments,
621 std::string_view("text"));
622 return handler(context, std::move(text));
623 } else if constexpr (std::is_invocable_v<Handler&, const Json&>) {
624 return handler(context.arguments);
625 } else if constexpr (std::is_invocable_v<Handler&, std::string>) {
626 auto text = argument_from_json<std::string>(context.arguments,
627 std::string_view("text"));
628 return handler(std::move(text));
629 } else if constexpr (std::is_invocable_v<Handler&, const PromptContext&>) {
630 return handler(context);
631 } else if constexpr (std::is_invocable_v<Handler&>) {
632 return handler();
633 } else {
634 static_assert(always_false_v<Handler>,
635 "prompt handler must accept Json, Json+PromptContext, "
636 "PromptContext+Json, string, string+PromptContext, "
637 "PromptContext+string, PromptContext, Json/string plus "
638 "CancellationToken, CancellationToken, or no arguments");
639 }
640}
641
642template <class Handler>
643decltype(auto) invoke_resource_handler(Handler& handler,
644 const ResourceContext& context) {
645 using Json = protocol::Json;
646 if constexpr (callable_arguments_match_v<Handler, Json, ResourceContext>) {
647 return handler(context.params, context);
648 } else if constexpr (callable_arguments_match_v<Handler, ResourceContext,
649 Json>) {
650 return handler(context, context.params);
651 } else if constexpr (callable_arguments_match_v<Handler, std::string,
652 ResourceContext>) {
653 return handler(context.uri, context);
654 } else if constexpr (callable_arguments_match_v<Handler, ResourceContext,
655 std::string>) {
656 return handler(context, context.uri);
657 } else if constexpr (callable_arguments_match_v<Handler, Json>) {
658 return handler(context.params);
659 } else if constexpr (callable_arguments_match_v<Handler, std::string>) {
660 return handler(context.uri);
661 } else if constexpr (callable_arguments_match_v<Handler, ResourceContext>) {
662 return handler(context);
663 } else if constexpr (callable_arguments_match_v<Handler, Json,
665 return handler(context.params, context.cancellation);
666 } else if constexpr (callable_arguments_match_v<Handler, CancellationToken,
667 Json>) {
668 return handler(context.cancellation, context.params);
669 } else if constexpr (callable_arguments_match_v<Handler, std::string,
671 return handler(context.uri, context.cancellation);
672 } else if constexpr (callable_arguments_match_v<Handler, CancellationToken,
673 std::string>) {
674 return handler(context.cancellation, context.uri);
675 } else if constexpr (callable_arguments_match_v<Handler, CancellationToken>) {
676 return handler(context.cancellation);
677 } else if constexpr (std::is_invocable_v<Handler&, const Json&,
678 const ResourceContext&>) {
679 return handler(context.params, context);
680 } else if constexpr (std::is_invocable_v<Handler&, const ResourceContext&,
681 const Json&>) {
682 return handler(context, context.params);
683 } else if constexpr (std::is_invocable_v<Handler&, std::string,
684 const ResourceContext&>) {
685 return handler(context.uri, context);
686 } else if constexpr (std::is_invocable_v<Handler&, const ResourceContext&,
687 std::string>) {
688 return handler(context, context.uri);
689 } else if constexpr (std::is_invocable_v<Handler&, const Json&>) {
690 return handler(context.params);
691 } else if constexpr (std::is_invocable_v<Handler&, std::string>) {
692 return handler(context.uri);
693 } else if constexpr (std::is_invocable_v<Handler&, const ResourceContext&>) {
694 return handler(context);
695 } else if constexpr (std::is_invocable_v<Handler&>) {
696 return handler();
697 } else {
698 static_assert(always_false_v<Handler>,
699 "resource handler must accept Json, Json+ResourceContext, "
700 "ResourceContext+Json, string, string+ResourceContext, "
701 "ResourceContext+string, ResourceContext, Json/string plus "
702 "CancellationToken, CancellationToken, or no arguments");
703 }
704}
705
706template <class Handler>
707decltype(auto) invoke_json_extension_handler(Handler& handler,
708 const protocol::Json& request,
709 const SessionContext& context,
710 CancellationToken cancellation) {
711 using Json = protocol::Json;
712 if constexpr (std::is_invocable_v<Handler&, const Json&,
713 const SessionContext&, CancellationToken>) {
714 return handler(request, context, cancellation);
715 } else if constexpr (std::is_invocable_v<Handler&, const Json&,
716 const SessionContext&>) {
717 return handler(request, context);
718 } else if constexpr (std::is_invocable_v<Handler&, const SessionContext&,
719 const Json&, CancellationToken>) {
720 return handler(context, request, cancellation);
721 } else if constexpr (std::is_invocable_v<Handler&, const SessionContext&,
722 const Json&>) {
723 return handler(context, request);
724 } else if constexpr (std::is_invocable_v<Handler&, const Json&,
726 return handler(request, cancellation);
727 } else if constexpr (std::is_invocable_v<Handler&, CancellationToken,
728 const Json&>) {
729 return handler(cancellation, request);
730 } else if constexpr (std::is_invocable_v<Handler&, const Json&>) {
731 return handler(request);
732 } else if constexpr (std::is_invocable_v<Handler&, const SessionContext&,
734 return handler(context, cancellation);
735 } else if constexpr (std::is_invocable_v<Handler&, CancellationToken,
736 const SessionContext&>) {
737 return handler(cancellation, context);
738 } else if constexpr (std::is_invocable_v<Handler&, const SessionContext&>) {
739 return handler(context);
740 } else if constexpr (std::is_invocable_v<Handler&, CancellationToken>) {
741 return handler(cancellation);
742 } else if constexpr (std::is_invocable_v<Handler&>) {
743 return handler();
744 } else {
745 static_assert(always_false_v<Handler>,
746 "JSON extension handler must accept Json, "
747 "Json+SessionContext, SessionContext+Json, "
748 "Json/SessionContext plus CancellationToken, "
749 "CancellationToken, or no arguments");
750 }
751}
752
753template <class Handler>
754inline constexpr bool is_typed_completion_handler_v =
755 !callable_arguments_match_v<Handler, protocol::Json, SessionContext> &&
756 !callable_arguments_match_v<Handler, SessionContext, protocol::Json> &&
757 !callable_arguments_match_v<Handler, protocol::Json> &&
758 (callable_arguments_match_v<Handler, protocol::CompleteParams,
759 CompletionContext> ||
760 callable_arguments_match_v<Handler, CompletionContext,
761 protocol::CompleteParams> ||
762 callable_arguments_match_v<Handler, protocol::CompletionArgument,
763 CompletionContext> ||
764 callable_arguments_match_v<Handler, CompletionContext,
765 protocol::CompletionArgument> ||
766 callable_arguments_match_v<Handler, std::string, CompletionContext> ||
767 callable_arguments_match_v<Handler, CompletionContext, std::string> ||
768 callable_arguments_match_v<Handler, protocol::CompleteParams,
770 callable_arguments_match_v<Handler, CancellationToken,
771 protocol::CompleteParams> ||
772 callable_arguments_match_v<Handler, protocol::CompletionArgument,
774 callable_arguments_match_v<Handler, CancellationToken,
775 protocol::CompletionArgument> ||
776 callable_arguments_match_v<Handler, std::string, CancellationToken> ||
777 callable_arguments_match_v<Handler, CancellationToken, std::string> ||
778 callable_arguments_match_v<Handler, protocol::CompleteParams> ||
779 callable_arguments_match_v<Handler, protocol::CompletionArgument> ||
780 callable_arguments_match_v<Handler, std::string> ||
781 callable_arguments_match_v<Handler, CancellationToken>);
782
783template <class Handler>
784decltype(auto) invoke_completion_handler(Handler& handler,
785 const CompletionContext& context) {
786 if constexpr (std::is_invocable_v<Handler&, const protocol::CompleteParams&,
787 const CompletionContext&>) {
788 return handler(context.params, context);
789 } else if constexpr (std::is_invocable_v<Handler&, const CompletionContext&,
790 const protocol::CompleteParams&>) {
791 return handler(context, context.params);
792 } else if constexpr (std::is_invocable_v<Handler&,
793 const protocol::CompletionArgument&,
794 const CompletionContext&>) {
795 return handler(context.params.argument, context);
796 } else if constexpr (std::is_invocable_v<
797 Handler&, const CompletionContext&,
798 const protocol::CompletionArgument&>) {
799 return handler(context, context.params.argument);
800 } else if constexpr (std::is_invocable_v<Handler&, std::string,
801 const CompletionContext&>) {
802 return handler(context.params.argument.value, context);
803 } else if constexpr (std::is_invocable_v<Handler&, const CompletionContext&,
804 std::string>) {
805 return handler(context, context.params.argument.value);
806 } else if constexpr (std::is_invocable_v<Handler&,
807 const protocol::CompleteParams&,
809 return handler(context.params, context.cancellation);
810 } else if constexpr (std::is_invocable_v<Handler&, CancellationToken,
811 const protocol::CompleteParams&>) {
812 return handler(context.cancellation, context.params);
813 } else if constexpr (std::is_invocable_v<Handler&,
814 const protocol::CompletionArgument&,
816 return handler(context.params.argument, context.cancellation);
817 } else if constexpr (std::is_invocable_v<
818 Handler&, CancellationToken,
819 const protocol::CompletionArgument&>) {
820 return handler(context.cancellation, context.params.argument);
821 } else if constexpr (std::is_invocable_v<Handler&, std::string,
823 return handler(context.params.argument.value, context.cancellation);
824 } else if constexpr (std::is_invocable_v<Handler&, CancellationToken,
825 std::string>) {
826 return handler(context.cancellation, context.params.argument.value);
827 } else if constexpr (std::is_invocable_v<Handler&,
828 const protocol::CompleteParams&>) {
829 return handler(context.params);
830 } else if constexpr (std::is_invocable_v<
831 Handler&, const protocol::CompletionArgument&>) {
832 return handler(context.params.argument);
833 } else if constexpr (std::is_invocable_v<Handler&, std::string>) {
834 return handler(context.params.argument.value);
835 } else if constexpr (std::is_invocable_v<Handler&, CancellationToken>) {
836 return handler(context.cancellation);
837 } else {
838 static_assert(always_false_v<Handler>,
839 "completion handler must accept CompleteParams, "
840 "CompletionArgument, string, or those plus "
841 "CompletionContext or CancellationToken");
842 }
843}
844
845} // namespace detail
846
847} // namespace mcp::server
Copyable token observed by cancellation-aware SDK operations.
Definition cancellation.hpp:104
Server-side handler invocation contexts.
mcp::CancellationToken CancellationToken
Copyable cooperative cancellation token for server handlers.
Definition context.hpp:22
nlohmann::json Json
JSON value type used by all protocol DTOs.
Definition types.hpp:28
Shared result and error primitives used by the public cxxmcp SDK.
constexpr auto unexpected(E &&value)
Creates an unexpected result value for the active expected backend.
Definition result.hpp:24
Parameters for completion/complete.
Definition completion.hpp:98
Argument value being completed.
Definition completion.hpp:57
std::vector< PromptMessage > messages
Ordered messages produced by the prompt.
Definition prompt.hpp:217
std::vector< ResourceContents > contents
One or more content parts for the requested URI.
Definition resource.hpp:287
static ToolResult text(std::string value)
Creates a successful text-only tool result.
Definition tool.hpp:413
std::optional< Json > structured_content
Optional machine-readable result matching the tool output schema.
Definition tool.hpp:393
Completion request context passed to typed completion handlers.
Definition context.hpp:86
Per-message connection metadata supplied to server handlers.
Definition transport.hpp:42
Definition handler_dispatch.hpp:31
Definition handler_dispatch.hpp:55
Definition handler_dispatch.hpp:70
Definition handler_dispatch.hpp:22