cxxmcp 1.1.6
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 Handler>
297inline bool callable_is_empty(const Handler&) noexcept {
298 return false;
299}
300
301template <class Return, class... Args>
302inline bool callable_is_empty(
303 const std::function<Return(Args...)>& handler) noexcept {
304 return !handler;
305}
306
307template <class Return, class... Args>
308inline bool callable_is_empty(Return (*handler)(Args...)) noexcept {
309 return handler == nullptr;
310}
311
312template <class Handler>
313inline void require_callable(const Handler& handler, std::string_view label) {
314 if (callable_is_empty(handler)) {
315 throw std::invalid_argument(std::string(label) +
316 " handler must not be empty");
317 }
318}
319
320inline protocol::ToolResult value_to_tool_result(protocol::ToolResult result) {
321 return result;
322}
323
324inline protocol::ToolResult value_to_tool_result(std::string text) {
325 protocol::ToolResult result;
326 protocol::ContentBlock block;
327 block.type = "text";
328 block.text = std::move(text);
329 result.content.push_back(std::move(block));
330 return result;
331}
332
333inline protocol::ToolResult value_to_tool_result(const char* text) {
334 return value_to_tool_result(std::string(text == nullptr ? "" : text));
335}
336
337template <class T>
338inline protocol::ToolResult value_to_tool_result(T&& value) {
339 protocol::ToolResult result;
340 result.structured_content = value_to_json(std::forward<T>(value));
341 protocol::ContentBlock block;
342 block.type = "text";
343 block.text = result.structured_content->dump();
344 result.content.push_back(std::move(block));
345 return result;
346}
347
348inline protocol::PromptsGetResult value_to_prompt_result(
349 protocol::PromptsGetResult result) {
350 return result;
351}
352
353inline protocol::PromptsGetResult value_to_prompt_result(std::string text) {
354 protocol::PromptsGetResult result;
355 protocol::ContentBlock block;
356 block.type = "text";
357 block.text = std::move(text);
358 protocol::PromptMessage message;
359 message.role = "assistant";
360 message.content = std::move(block);
361 result.messages.push_back(std::move(message));
362 return result;
363}
364
365inline protocol::PromptsGetResult value_to_prompt_result(
366 protocol::PromptMessage message) {
367 protocol::PromptsGetResult result;
368 result.messages.push_back(std::move(message));
369 return result;
370}
371
372inline protocol::PromptsGetResult value_to_prompt_result(
373 std::vector<protocol::PromptMessage> messages) {
374 protocol::PromptsGetResult result;
375 result.messages = std::move(messages);
376 return result;
377}
378
379inline protocol::ResourcesReadResult value_to_resource_read_result(
380 protocol::ResourcesReadResult result, std::string_view) {
381 return result;
382}
383
384inline protocol::ResourcesReadResult value_to_resource_read_result(
385 protocol::ResourceContents contents, std::string_view) {
386 protocol::ResourcesReadResult result;
387 result.contents.push_back(std::move(contents));
388 return result;
389}
390
391inline protocol::ResourcesReadResult value_to_resource_read_result(
392 std::vector<protocol::ResourceContents> contents, std::string_view) {
393 protocol::ResourcesReadResult result;
394 result.contents = std::move(contents);
395 return result;
396}
397
398inline protocol::ResourcesReadResult value_to_resource_read_result(
399 std::string text, std::string_view uri) {
400 protocol::ResourcesReadResult result;
401 protocol::ResourceContents contents;
402 contents.uri = std::string(uri);
403 contents.mime_type = "text/plain";
404 contents.text = std::move(text);
405 result.contents.push_back(std::move(contents));
406 return result;
407}
408
409inline protocol::Json value_to_complete_result_json(protocol::Json json) {
410 return json;
411}
412
413inline protocol::Json value_to_complete_result_json(
414 protocol::CompleteResult result) {
415 return protocol::complete_result_to_json(result);
416}
417
418inline protocol::Json value_to_complete_result_json(
419 protocol::CompletionResult result) {
420 protocol::CompleteResult envelope;
421 envelope.completion = std::move(result);
422 return protocol::complete_result_to_json(envelope);
423}
424
425inline protocol::Json value_to_complete_result_json(
426 std::vector<std::string> values) {
427 protocol::CompletionResult completion;
428 completion.values = std::move(values);
429 return value_to_complete_result_json(std::move(completion));
430}
431
432inline protocol::Json value_to_complete_result_json(std::string value) {
433 return value_to_complete_result_json(
434 std::vector<std::string>{std::move(value)});
435}
436
437inline protocol::Json value_to_complete_result_json(const char* value) {
438 return value_to_complete_result_json(
439 std::string(value == nullptr ? "" : value));
440}
441
442template <class T>
443inline core::Result<protocol::Json> completion_response_to_json(T&& value) {
444 using Value = std::decay_t<T>;
445 if constexpr (is_result<Value>::value) {
446 if (!value) {
447 return mcp::core::unexpected(value.error());
448 }
449 return completion_response_to_json(std::move(*value));
450 } else {
451 return value_to_complete_result_json(std::forward<T>(value));
452 }
453}
454
455template <class Arg>
456inline Arg argument_from_json(const protocol::Json& arguments,
457 std::string_view fallback_name = {}) {
458 using Decayed = std::decay_t<Arg>;
459 if constexpr (std::is_same_v<Decayed, protocol::Json>) {
460 return arguments;
461 } else if constexpr (protocol::has_reflect_v<Decayed>) {
462 protocol::Json effective = arguments;
463 if (!fallback_name.empty() && arguments.is_object() &&
464 arguments.contains(std::string(fallback_name))) {
465 effective = arguments.at(std::string(fallback_name));
466 }
467 auto result = protocol::reflect_from_json<Decayed>(effective);
468 if (!result) {
469 throw std::invalid_argument(result.error().message);
470 }
471 return std::move(*result);
472 } else {
473 if (!fallback_name.empty() && arguments.is_object() &&
474 arguments.contains(std::string(fallback_name))) {
475 return arguments.at(std::string(fallback_name)).template get<Arg>();
476 }
477 if (arguments.is_object() && arguments.size() == 1) {
478 return arguments.begin().value().template get<Arg>();
479 }
480 return arguments.template get<Arg>();
481 }
482}
483
484template <class Result>
485inline void apply_default_output_schema(protocol::ToolDefinition& definition) {
486 if constexpr (!std::is_same_v<std::decay_t<Result>, protocol::ToolResult> &&
487 !std::is_same_v<std::decay_t<Result>, std::string> &&
488 !std::is_same_v<std::decay_t<Result>, const char*> &&
489 !std::is_same_v<std::decay_t<Result>, char*>) {
490 if (definition.output_schema.empty()) {
491 definition.output_schema = protocol::schema_for<Result>();
492 definition.output_schema_present = true;
493 }
494 }
495}
496
497template <class Handler, class Args>
498decltype(auto) invoke_tool_handler(Handler& handler, Args&& args,
499 const ToolContext& context) {
500 using Arg = std::decay_t<Args>;
501 if constexpr (std::is_invocable_v<Handler&, Arg, const ToolContext&>) {
502 return handler(std::forward<Args>(args), context);
503 } else if constexpr (std::is_invocable_v<Handler&, const ToolContext&, Arg>) {
504 return handler(context, std::forward<Args>(args));
505 } else if constexpr (std::is_invocable_v<Handler&, Arg, CancellationToken>) {
506 return handler(std::forward<Args>(args), context.cancellation);
507 } else if constexpr (std::is_invocable_v<Handler&, CancellationToken, Arg>) {
508 return handler(context.cancellation, std::forward<Args>(args));
509 } else if constexpr (std::is_invocable_v<Handler&, Arg>) {
510 return handler(std::forward<Args>(args));
511 } else if constexpr (std::is_invocable_v<Handler&, const ToolContext&>) {
512 return handler(context);
513 } else if constexpr (std::is_invocable_v<Handler&>) {
514 return handler();
515 } else {
516 static_assert(always_false_v<Handler>,
517 "tool handler must accept Args, Args+ToolContext, "
518 "ToolContext+Args, Args+CancellationToken, "
519 "CancellationToken+Args, ToolContext, or no arguments");
520 }
521}
522
523template <class Handler, class Args, class Context>
524decltype(auto) invoke_typed_context_handler(Handler& handler, Args&& args,
525 const Context& context) {
526 using Arg = std::decay_t<Args>;
527 if constexpr (std::is_invocable_v<Handler&, Arg, const Context&>) {
528 return handler(std::forward<Args>(args), context);
529 } else if constexpr (std::is_invocable_v<Handler&, const Context&, Arg>) {
530 return handler(context, std::forward<Args>(args));
531 } else if constexpr (std::is_invocable_v<Handler&, Arg, CancellationToken>) {
532 return handler(std::forward<Args>(args), context.cancellation);
533 } else if constexpr (std::is_invocable_v<Handler&, CancellationToken, Arg>) {
534 return handler(context.cancellation, std::forward<Args>(args));
535 } else if constexpr (std::is_invocable_v<Handler&, Arg>) {
536 return handler(std::forward<Args>(args));
537 } else if constexpr (std::is_invocable_v<Handler&, const Context&>) {
538 return handler(context);
539 } else if constexpr (std::is_invocable_v<Handler&, CancellationToken>) {
540 return handler(context.cancellation);
541 } else if constexpr (std::is_invocable_v<Handler&>) {
542 return handler();
543 } else {
544 static_assert(always_false_v<Handler>,
545 "typed handler must accept Args, Args+Context, "
546 "Context+Args, Args+CancellationToken, "
547 "CancellationToken+Args, Context, CancellationToken, "
548 "or no arguments");
549 }
550}
551
552template <class Handler>
553decltype(auto) invoke_prompt_handler(Handler& handler,
554 const PromptContext& context) {
555 using Json = protocol::Json;
556 if constexpr (callable_arguments_match_v<Handler, Json, PromptContext>) {
557 return handler(context.arguments, context);
558 } else if constexpr (callable_arguments_match_v<Handler, PromptContext,
559 Json>) {
560 return handler(context, context.arguments);
561 } else if constexpr (callable_arguments_match_v<Handler, std::string,
562 PromptContext>) {
563 auto text = argument_from_json<std::string>(context.arguments,
564 std::string_view("text"));
565 return handler(std::move(text), context);
566 } else if constexpr (callable_arguments_match_v<Handler, PromptContext,
567 std::string>) {
568 auto text = argument_from_json<std::string>(context.arguments,
569 std::string_view("text"));
570 return handler(context, std::move(text));
571 } else if constexpr (callable_arguments_match_v<Handler, Json>) {
572 return handler(context.arguments);
573 } else if constexpr (callable_arguments_match_v<Handler, std::string>) {
574 auto text = argument_from_json<std::string>(context.arguments,
575 std::string_view("text"));
576 return handler(std::move(text));
577 } else if constexpr (callable_arguments_match_v<Handler, PromptContext>) {
578 return handler(context);
579 } else if constexpr (callable_arguments_match_v<Handler, Json,
581 return handler(context.arguments, context.cancellation);
582 } else if constexpr (callable_arguments_match_v<Handler, CancellationToken,
583 Json>) {
584 return handler(context.cancellation, context.arguments);
585 } else if constexpr (callable_arguments_match_v<Handler, std::string,
587 auto text = argument_from_json<std::string>(context.arguments,
588 std::string_view("text"));
589 return handler(std::move(text), context.cancellation);
590 } else if constexpr (callable_arguments_match_v<Handler, CancellationToken,
591 std::string>) {
592 auto text = argument_from_json<std::string>(context.arguments,
593 std::string_view("text"));
594 return handler(context.cancellation, std::move(text));
595 } else if constexpr (callable_arguments_match_v<Handler, CancellationToken>) {
596 return handler(context.cancellation);
597 } else if constexpr (std::is_invocable_v<Handler&, const Json&,
598 const PromptContext&>) {
599 return handler(context.arguments, context);
600 } else if constexpr (std::is_invocable_v<Handler&, const PromptContext&,
601 const Json&>) {
602 return handler(context, context.arguments);
603 } else if constexpr (std::is_invocable_v<Handler&, std::string,
604 const PromptContext&>) {
605 auto text = argument_from_json<std::string>(context.arguments,
606 std::string_view("text"));
607 return handler(std::move(text), context);
608 } else if constexpr (std::is_invocable_v<Handler&, const PromptContext&,
609 std::string>) {
610 auto text = argument_from_json<std::string>(context.arguments,
611 std::string_view("text"));
612 return handler(context, std::move(text));
613 } else if constexpr (std::is_invocable_v<Handler&, const Json&>) {
614 return handler(context.arguments);
615 } else if constexpr (std::is_invocable_v<Handler&, std::string>) {
616 auto text = argument_from_json<std::string>(context.arguments,
617 std::string_view("text"));
618 return handler(std::move(text));
619 } else if constexpr (std::is_invocable_v<Handler&, const PromptContext&>) {
620 return handler(context);
621 } else if constexpr (std::is_invocable_v<Handler&>) {
622 return handler();
623 } else {
624 static_assert(always_false_v<Handler>,
625 "prompt handler must accept Json, Json+PromptContext, "
626 "PromptContext+Json, string, string+PromptContext, "
627 "PromptContext+string, PromptContext, Json/string plus "
628 "CancellationToken, CancellationToken, or no arguments");
629 }
630}
631
632template <class Handler>
633decltype(auto) invoke_resource_handler(Handler& handler,
634 const ResourceContext& context) {
635 using Json = protocol::Json;
636 if constexpr (callable_arguments_match_v<Handler, Json, ResourceContext>) {
637 return handler(context.params, context);
638 } else if constexpr (callable_arguments_match_v<Handler, ResourceContext,
639 Json>) {
640 return handler(context, context.params);
641 } else if constexpr (callable_arguments_match_v<Handler, std::string,
642 ResourceContext>) {
643 return handler(context.uri, context);
644 } else if constexpr (callable_arguments_match_v<Handler, ResourceContext,
645 std::string>) {
646 return handler(context, context.uri);
647 } else if constexpr (callable_arguments_match_v<Handler, Json>) {
648 return handler(context.params);
649 } else if constexpr (callable_arguments_match_v<Handler, std::string>) {
650 return handler(context.uri);
651 } else if constexpr (callable_arguments_match_v<Handler, ResourceContext>) {
652 return handler(context);
653 } else if constexpr (callable_arguments_match_v<Handler, Json,
655 return handler(context.params, context.cancellation);
656 } else if constexpr (callable_arguments_match_v<Handler, CancellationToken,
657 Json>) {
658 return handler(context.cancellation, context.params);
659 } else if constexpr (callable_arguments_match_v<Handler, std::string,
661 return handler(context.uri, context.cancellation);
662 } else if constexpr (callable_arguments_match_v<Handler, CancellationToken,
663 std::string>) {
664 return handler(context.cancellation, context.uri);
665 } else if constexpr (callable_arguments_match_v<Handler, CancellationToken>) {
666 return handler(context.cancellation);
667 } else if constexpr (std::is_invocable_v<Handler&, const Json&,
668 const ResourceContext&>) {
669 return handler(context.params, context);
670 } else if constexpr (std::is_invocable_v<Handler&, const ResourceContext&,
671 const Json&>) {
672 return handler(context, context.params);
673 } else if constexpr (std::is_invocable_v<Handler&, std::string,
674 const ResourceContext&>) {
675 return handler(context.uri, context);
676 } else if constexpr (std::is_invocable_v<Handler&, const ResourceContext&,
677 std::string>) {
678 return handler(context, context.uri);
679 } else if constexpr (std::is_invocable_v<Handler&, const Json&>) {
680 return handler(context.params);
681 } else if constexpr (std::is_invocable_v<Handler&, std::string>) {
682 return handler(context.uri);
683 } else if constexpr (std::is_invocable_v<Handler&, const ResourceContext&>) {
684 return handler(context);
685 } else if constexpr (std::is_invocable_v<Handler&>) {
686 return handler();
687 } else {
688 static_assert(always_false_v<Handler>,
689 "resource handler must accept Json, Json+ResourceContext, "
690 "ResourceContext+Json, string, string+ResourceContext, "
691 "ResourceContext+string, ResourceContext, Json/string plus "
692 "CancellationToken, CancellationToken, or no arguments");
693 }
694}
695
696template <class Handler>
697decltype(auto) invoke_json_extension_handler(Handler& handler,
698 const protocol::Json& request,
699 const SessionContext& context,
700 CancellationToken cancellation) {
701 using Json = protocol::Json;
702 if constexpr (std::is_invocable_v<Handler&, const Json&,
703 const SessionContext&, CancellationToken>) {
704 return handler(request, context, cancellation);
705 } else if constexpr (std::is_invocable_v<Handler&, const Json&,
706 const SessionContext&>) {
707 return handler(request, context);
708 } else if constexpr (std::is_invocable_v<Handler&, const SessionContext&,
709 const Json&, CancellationToken>) {
710 return handler(context, request, cancellation);
711 } else if constexpr (std::is_invocable_v<Handler&, const SessionContext&,
712 const Json&>) {
713 return handler(context, request);
714 } else if constexpr (std::is_invocable_v<Handler&, const Json&,
716 return handler(request, cancellation);
717 } else if constexpr (std::is_invocable_v<Handler&, CancellationToken,
718 const Json&>) {
719 return handler(cancellation, request);
720 } else if constexpr (std::is_invocable_v<Handler&, const Json&>) {
721 return handler(request);
722 } else if constexpr (std::is_invocable_v<Handler&, const SessionContext&,
724 return handler(context, cancellation);
725 } else if constexpr (std::is_invocable_v<Handler&, CancellationToken,
726 const SessionContext&>) {
727 return handler(cancellation, context);
728 } else if constexpr (std::is_invocable_v<Handler&, const SessionContext&>) {
729 return handler(context);
730 } else if constexpr (std::is_invocable_v<Handler&, CancellationToken>) {
731 return handler(cancellation);
732 } else if constexpr (std::is_invocable_v<Handler&>) {
733 return handler();
734 } else {
735 static_assert(always_false_v<Handler>,
736 "JSON extension handler must accept Json, "
737 "Json+SessionContext, SessionContext+Json, "
738 "Json/SessionContext plus CancellationToken, "
739 "CancellationToken, or no arguments");
740 }
741}
742
743template <class Handler>
744inline constexpr bool is_typed_completion_handler_v =
745 !callable_arguments_match_v<Handler, protocol::Json, SessionContext> &&
746 !callable_arguments_match_v<Handler, SessionContext, protocol::Json> &&
747 !callable_arguments_match_v<Handler, protocol::Json> &&
748 (callable_arguments_match_v<Handler, protocol::CompleteParams,
749 CompletionContext> ||
750 callable_arguments_match_v<Handler, CompletionContext,
751 protocol::CompleteParams> ||
752 callable_arguments_match_v<Handler, protocol::CompletionArgument,
753 CompletionContext> ||
754 callable_arguments_match_v<Handler, CompletionContext,
755 protocol::CompletionArgument> ||
756 callable_arguments_match_v<Handler, std::string, CompletionContext> ||
757 callable_arguments_match_v<Handler, CompletionContext, std::string> ||
758 callable_arguments_match_v<Handler, protocol::CompleteParams,
760 callable_arguments_match_v<Handler, CancellationToken,
761 protocol::CompleteParams> ||
762 callable_arguments_match_v<Handler, protocol::CompletionArgument,
764 callable_arguments_match_v<Handler, CancellationToken,
765 protocol::CompletionArgument> ||
766 callable_arguments_match_v<Handler, std::string, CancellationToken> ||
767 callable_arguments_match_v<Handler, CancellationToken, std::string> ||
768 callable_arguments_match_v<Handler, protocol::CompleteParams> ||
769 callable_arguments_match_v<Handler, protocol::CompletionArgument> ||
770 callable_arguments_match_v<Handler, std::string> ||
771 callable_arguments_match_v<Handler, CancellationToken>);
772
773template <class Handler>
774decltype(auto) invoke_completion_handler(Handler& handler,
775 const CompletionContext& context) {
776 if constexpr (std::is_invocable_v<Handler&, const protocol::CompleteParams&,
777 const CompletionContext&>) {
778 return handler(context.params, context);
779 } else if constexpr (std::is_invocable_v<Handler&, const CompletionContext&,
780 const protocol::CompleteParams&>) {
781 return handler(context, context.params);
782 } else if constexpr (std::is_invocable_v<Handler&,
783 const protocol::CompletionArgument&,
784 const CompletionContext&>) {
785 return handler(context.params.argument, context);
786 } else if constexpr (std::is_invocable_v<
787 Handler&, const CompletionContext&,
788 const protocol::CompletionArgument&>) {
789 return handler(context, context.params.argument);
790 } else if constexpr (std::is_invocable_v<Handler&, std::string,
791 const CompletionContext&>) {
792 return handler(context.params.argument.value, context);
793 } else if constexpr (std::is_invocable_v<Handler&, const CompletionContext&,
794 std::string>) {
795 return handler(context, context.params.argument.value);
796 } else if constexpr (std::is_invocable_v<Handler&,
797 const protocol::CompleteParams&,
799 return handler(context.params, context.cancellation);
800 } else if constexpr (std::is_invocable_v<Handler&, CancellationToken,
801 const protocol::CompleteParams&>) {
802 return handler(context.cancellation, context.params);
803 } else if constexpr (std::is_invocable_v<Handler&,
804 const protocol::CompletionArgument&,
806 return handler(context.params.argument, context.cancellation);
807 } else if constexpr (std::is_invocable_v<
808 Handler&, CancellationToken,
809 const protocol::CompletionArgument&>) {
810 return handler(context.cancellation, context.params.argument);
811 } else if constexpr (std::is_invocable_v<Handler&, std::string,
813 return handler(context.params.argument.value, context.cancellation);
814 } else if constexpr (std::is_invocable_v<Handler&, CancellationToken,
815 std::string>) {
816 return handler(context.cancellation, context.params.argument.value);
817 } else if constexpr (std::is_invocable_v<Handler&,
818 const protocol::CompleteParams&>) {
819 return handler(context.params);
820 } else if constexpr (std::is_invocable_v<
821 Handler&, const protocol::CompletionArgument&>) {
822 return handler(context.params.argument);
823 } else if constexpr (std::is_invocable_v<Handler&, std::string>) {
824 return handler(context.params.argument.value);
825 } else if constexpr (std::is_invocable_v<Handler&, CancellationToken>) {
826 return handler(context.cancellation);
827 } else {
828 static_assert(always_false_v<Handler>,
829 "completion handler must accept CompleteParams, "
830 "CompletionArgument, string, or those plus "
831 "CompletionContext or CancellationToken");
832 }
833}
834
835} // namespace detail
836
837} // 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:76
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