20namespace mcp::server {
24template <
class T,
class =
void>
28struct has_tool_title<T, std::void_t<decltype(T::title)>> : std::true_type {};
30template <
class T,
class =
void>
37template <
class T,
class =
void>
42 T, std::void_t<decltype(std::declval<const T&>().definition())>>
45template <
class Tool,
class Text>
46inline std::string static_tool_text(Text value) {
47 if constexpr (std::is_convertible_v<Text, std::string_view>) {
48 return std::string(std::string_view(value));
50 return std::string(value);
57template <
class Args,
class Result,
class Handler>
64template <
class Args,
class Result>
68 definition_ = protocol::tool_definition(std::move(name))
71 detail::apply_default_output_schema<Result>(definition_);
75 : definition_(std::move(definition)) {}
78 definition_.
title = std::move(value);
94 return input_schema(protocol::tool_input_schema_for<T>());
105 return output_schema(protocol::tool_output_schema_for<T>());
114 definition_.
icons.push_back(std::move(value));
119 if (!definition_.
execution.has_value()) {
122 definition_.
execution->task_support = value;
127 definition_.
execution = std::move(value);
137 definition_.
meta = std::move(value);
141 template <
class Handler>
143 detail::require_callable(value,
"tool");
144 detail::require_unambiguous_tool_handler<Handler, Args>();
154template <
class Args,
class Result>
167 using Args =
typename Tool::Args;
168 using Result =
typename Tool::Result;
169 auto definition = [&]() {
171 return value.definition();
174 protocol::tool_definition(detail::static_tool_text<Tool>(Tool::name))
177 built.title = detail::static_tool_text<Tool>(Tool::title);
180 built.description = detail::static_tool_text<Tool>(Tool::description);
185 if (definition.input_schema.empty()) {
186 definition.input_schema = protocol::tool_input_schema_for<Args>();
188 detail::apply_default_output_schema<Result>(definition);
190 return builder.handler(std::move(value));
201template <
class Args,
class Handler>
212 : prompt_(std::move(prompt)) {}
215 prompt_ = protocol::prompt_definition(std::move(name)).build();
219 prompt_.
title = std::move(value);
229 std::string description = {}) {
231 argument.
name = std::move(name);
235 prompt_.
arguments.push_back(std::move(argument));
240 prompt_.
icons.push_back(std::move(value));
250 prompt_.
meta = std::move(value);
254 template <
class Handler>
256 detail::require_callable(value,
"prompt");
257 detail::require_unambiguous_typed_context_handler<Handler, Args,
274 return TypedPromptBuilder<Args>(std::move(prompt));
278template <
class Args,
class Handler>
289 : resource_(std::move(resource)) {}
293 protocol::resource_definition(std::move(uri), std::move(name)).build();
297 resource_.
title = std::move(value);
312 resource_.
size = value;
317 resource_.
icons.push_back(std::move(value));
327 resource_.
meta = std::move(value);
331 template <
class Handler>
333 detail::require_callable(value,
"resource");
334 detail::require_unambiguous_typed_context_handler<Handler, Args,
352 return TypedResourceBuilder<Args>(std::move(resource));
356 std::string uri_template, std::string name) {
357 return protocol::resource_template_definition(std::move(uri_template),
365class CXXMCP_DEPRECATED(
366 "App is a compatibility entry point; use ServerPeer::builder() with "
367 "cxxmcp/run.hpp instead") App {
373 Builder& name(std::string value);
376 Builder& version(std::string value);
379 Builder& instructions(std::string value);
384#if defined(CXXMCP_ENABLE_HTTP)
389 Builder& streamable_http(std::string host, std::uint16_t port,
390 std::string path =
"/mcp");
396 Builder& legacy_sse(std::string host, std::uint16_t port,
397 std::string path =
"/mcp");
402 Builder& transport(std::unique_ptr<Transport> value);
405 Builder& tasks(TaskOperationProcessorOptions options = {});
408 Builder& schema_validator(
409 std::shared_ptr<const JsonSchemaValidator> validator);
420 template <
class Args,
class Result,
class Handler>
421 Builder& tool(std::string name, Handler handler);
424 template <
class Args,
class Result,
class Handler>
425 Builder& tool(protocol::ToolDefinition definition, Handler handler);
428 template <
class Args,
class Result,
class Handler>
429 Builder& tool(TypedToolRegistration<Args, Result, Handler> registration);
432 Builder& tool(protocol::ToolDefinition definition, ToolHandler handler);
441 template <
class Args,
class Handler>
442 Builder& prompt(std::string name, Handler handler);
444 template <
class Handler>
445 Builder& prompt(std::string name, Handler handler);
448 Builder& prompt(protocol::Prompt prompt, PromptHandler handler);
458 template <
class Args,
class Handler>
459 Builder& resource(std::string name, Handler handler);
461 template <
class Handler>
462 Builder& resource(std::string name, Handler handler);
465 Builder& resource(protocol::Resource resource, ResourceReadHandler handler);
474 template <
class Handler>
475 Builder& resource_template(std::string name, Handler handler);
478 Builder& resource_template(protocol::ResourceTemplate resource_template);
481 template <
class Handler>
482 Builder& completion(Handler handler);
485 template <
class Handler>
486 Builder& sampling(Handler handler);
489 template <
class Handler>
490 Builder& logging(Handler handler);
496 template <
class Handler>
497 Builder& raw_request(Handler handler);
500 core::Result<std::unique_ptr<Server>> build();
506 ServerBuilder builder_;
510 CXXMCP_DEPRECATED(
"use ServerPeer::builder() instead")
511 static Builder builder();
514template <class Args, class Result, class Handler>
515App::Builder& App::Builder::tool(std::
string name, Handler handler) {
516 detail::require_callable(handler,
"tool");
517 detail::require_unambiguous_tool_handler<Handler, Args>();
518 auto definition = protocol::tool_definition(std::move(name))
519 .input_schema(protocol::tool_input_schema_for<Args>())
521 detail::apply_default_output_schema<Result>(definition);
522 return tool<Args, Result>(std::move(definition), std::move(handler));
525template <
class Args,
class Result,
class Handler>
526App::Builder& App::Builder::tool(protocol::ToolDefinition definition,
528 detail::require_callable(handler,
"tool");
529 detail::require_unambiguous_tool_handler<Handler, Args>();
530 if (definition.input_schema.empty()) {
531 definition.input_schema = protocol::tool_input_schema_for<Args>();
533 detail::apply_default_output_schema<Result>(definition);
535 std::move(definition),
536 [handler = std::move(handler)](
537 const ToolContext& context) -> core::Result<protocol::ToolResult> {
539 auto args = detail::argument_from_json<Args>(context.arguments);
541 detail::invoke_tool_handler(handler, std::move(args), context);
542 if constexpr (detail::is_result<
decltype(handled)>::value) {
546 return detail::value_to_tool_result(*handled);
548 return detail::value_to_tool_result(std::move(handled));
550 }
catch (
const std::exception& exception) {
552 static_cast<int>(protocol::ErrorCode::InvalidParams),
553 "failed to decode tool arguments",
560template <
class Args,
class Result,
class Handler>
561App::Builder& App::Builder::tool(
562 TypedToolRegistration<Args, Result, Handler> registration) {
563 return tool<Args, Result>(std::move(registration.definition),
564 std::move(registration.handler));
567template <
class Args,
class Handler>
568App::Builder& App::Builder::prompt(std::string name, Handler handler) {
569 detail::require_callable(handler,
"prompt");
570 detail::require_unambiguous_typed_context_handler<Handler, Args,
571 PromptContext>(
"prompt");
572 protocol::Prompt prompt;
573 prompt.name = std::move(name);
576 [handler = std::move(handler)](
const PromptContext& context)
577 -> core::Result<protocol::PromptsGetResult> {
579 auto args = context.arguments.get<Args>();
580 auto handled = detail::invoke_typed_context_handler(
581 handler, std::move(args), context);
582 if constexpr (detail::is_result<
decltype(handled)>::value) {
586 return detail::value_to_prompt_result(*handled);
588 return detail::value_to_prompt_result(std::move(handled));
590 }
catch (
const std::exception& exception) {
592 static_cast<int>(protocol::ErrorCode::InvalidParams),
593 "failed to decode prompt arguments",
600template <
class Handler>
601App::Builder& App::Builder::prompt(std::string name, Handler handler) {
602 detail::require_callable(handler,
"prompt");
603 detail::require_unambiguous_prompt_handler<Handler>();
604 protocol::Prompt prompt;
605 prompt.name = std::move(name);
608 [handler = std::move(handler)](
const PromptContext& context)
609 -> core::Result<protocol::PromptsGetResult> {
611 auto handled = detail::invoke_prompt_handler(handler, context);
612 if constexpr (detail::is_result<
decltype(handled)>::value) {
616 return detail::value_to_prompt_result(*handled);
618 return detail::value_to_prompt_result(std::move(handled));
620 }
catch (
const std::exception& exception) {
622 static_cast<int>(protocol::ErrorCode::InvalidParams),
623 "failed to run prompt handler",
630template <
class Args,
class Handler>
631App::Builder& App::Builder::resource(std::string name, Handler handler) {
632 detail::require_callable(handler,
"resource");
633 detail::require_unambiguous_typed_context_handler<Handler, Args,
636 protocol::Resource resource;
637 resource.uri = std::move(name);
638 resource.name = resource.uri;
639 return this->resource(
641 [handler = std::move(handler)](
const ResourceContext& context)
642 -> core::Result<protocol::ResourcesReadResult> {
644 auto args = context.params.get<Args>();
645 auto handled = detail::invoke_typed_context_handler(
646 handler, std::move(args), context);
647 if constexpr (detail::is_result<
decltype(handled)>::value) {
651 return detail::value_to_resource_read_result(*handled, context.uri);
653 return detail::value_to_resource_read_result(std::move(handled),
656 }
catch (
const std::exception& exception) {
658 static_cast<int>(protocol::ErrorCode::InvalidParams),
659 "failed to decode resource parameters",
666template <
class Handler>
667App::Builder& App::Builder::resource(std::string name, Handler handler) {
668 detail::require_callable(handler,
"resource");
669 detail::require_unambiguous_resource_handler<Handler>();
670 protocol::Resource resource;
671 resource.uri = std::move(name);
672 resource.name = resource.uri;
673 if constexpr (std::is_invocable_v<Handler>) {
674 using Handled =
decltype(handler());
675 if constexpr (std::is_same_v<std::decay_t<Handled>, protocol::Resource>) {
676 resource = handler();
679 return this->resource(
681 [handler = std::move(handler)](
const ResourceContext& context)
682 -> core::Result<protocol::ResourcesReadResult> {
684 auto handled = detail::invoke_resource_handler(handler, context);
685 if constexpr (std::is_same_v<std::decay_t<
decltype(handled)>,
686 protocol::Resource>) {
687 return protocol::ResourcesReadResult{};
688 }
else if constexpr (detail::is_result<
decltype(handled)>::value) {
692 return detail::value_to_resource_read_result(*handled, context.uri);
694 return detail::value_to_resource_read_result(std::move(handled),
697 }
catch (
const std::exception& exception) {
699 static_cast<int>(protocol::ErrorCode::InvalidParams),
700 "failed to run resource handler",
707template <
class Handler>
708App::Builder& App::Builder::resource_template(std::string name,
710 detail::require_callable(handler,
"resource_template");
711 protocol::ResourceTemplate resource_template;
712 if constexpr (std::is_invocable_v<Handler>) {
713 auto handled = handler();
714 if constexpr (detail::is_result<
decltype(handled)>::value) {
716 throw std::runtime_error(handled.error().message);
718 resource_template = *handled;
720 resource_template = std::move(handled);
722 }
else if constexpr (std::is_invocable_v<Handler, std::string>) {
723 resource_template = handler({});
726 std::is_invocable_v<Handler>,
727 "resource_template handler must accept no arguments or string");
729 if (resource_template.name.empty()) {
730 resource_template.name = name;
732 if (resource_template.uri_template.empty()) {
733 resource_template.uri_template = std::move(name);
735 return this->resource_template(std::move(resource_template));
738template <
class Handler>
739App::Builder& App::Builder::completion(Handler handler) {
740 detail::require_callable(handler,
"completion");
741 if constexpr (detail::is_typed_completion_handler_v<Handler>) {
742 detail::require_unambiguous_completion_handler<Handler>();
744 detail::require_unambiguous_json_extension_handler<Handler>();
746 builder_.on_completion(
747 [handler = std::move(handler)](
const protocol::Json& request,
748 const SessionContext& context,
749 CancellationToken cancellation)
mutable
750 -> core::Result<protocol::Json> {
751 if constexpr (detail::is_typed_completion_handler_v<Handler>) {
752 const auto params = protocol::complete_params_from_json(request);
755 static_cast<int>(protocol::ErrorCode::InvalidParams),
756 params.error().message, params.error().detail,
"protocol"});
758 CompletionContext completion_context;
759 static_cast<SessionContext&
>(completion_context) = context;
760 completion_context.params = *params;
761 completion_context.cancellation = cancellation;
763 detail::invoke_completion_handler(handler, completion_context);
764 return detail::completion_response_to_json(std::move(handled));
766 auto handled = detail::invoke_json_extension_handler(
767 handler, request, context, cancellation);
768 if constexpr (detail::is_result<
decltype(handled)>::value) {
771 return detail::value_to_json(std::move(handled));
778template <
class Handler>
779App::Builder& App::Builder::sampling(Handler handler) {
780 detail::require_callable(handler,
"sampling");
781 detail::require_unambiguous_json_extension_handler<Handler>();
782 builder_.on_sampling(
783 [handler = std::move(handler)](
const protocol::Json& request,
784 const SessionContext& context,
785 CancellationToken cancellation)
mutable
786 -> core::Result<protocol::Json> {
787 auto handled = detail::invoke_json_extension_handler(
788 handler, request, context, cancellation);
789 if constexpr (detail::is_result<
decltype(handled)>::value) {
792 return detail::value_to_json(std::move(handled));
798template <
class Handler>
799App::Builder& App::Builder::logging(Handler handler) {
800 detail::require_callable(handler,
"logging");
801 builder_.on_logging([handler = std::move(handler)](std::string_view level,
802 std::string_view message) {
803 handler(level, message);
808template <
class Handler>
809App::Builder& App::Builder::raw_request(Handler handler) {
810 detail::require_callable(handler,
"raw_request");
811 builder_.on_raw_request([handler = std::move(handler)](
812 const protocol::JsonRpcRequest& request,
813 const SessionContext& context)
814 -> std::optional<protocol::JsonRpcResponse> {
816 if constexpr (std::is_same_v<std::decay_t<
decltype(handler(request))>,
817 std::optional<protocol::JsonRpcResponse>>) {
818 return handler(request);
819 }
else if constexpr (std::is_same_v<
820 std::decay_t<
decltype(handler(request))>,
821 protocol::JsonRpcResponse>) {
822 return handler(request);
TypedToolBuilder< Args, Result > tool(std::string name)
Starts a typed tool registration builder.
Definition authoring.hpp:155
Fluent builder for resource-template descriptors.
Definition resource.hpp:151
Fluent typed prompt builder for low-boilerplate server authoring.
Definition authoring.hpp:209
Fluent typed resource builder for low-boilerplate server authoring.
Definition authoring.hpp:286
Public SDK configuration and compatibility markers.
Internal handler dispatch helpers for cxxmcp server authoring APIs.
nlohmann::json Json
JSON value type used by all protocol DTOs.
Definition types.hpp:28
constexpr auto unexpected(E &&value)
Creates an unexpected result value for the active expected backend.
Definition result.hpp:24
High-level server compatibility API, builder, and convenience app API.
Icon descriptor used by tools, resources, resource templates, and prompts.
Definition types.hpp:160
Argument accepted by a prompt template.
Definition prompt.hpp:63
std::string name
Stable argument name used as a key in prompts/get arguments.
Definition prompt.hpp:67
bool required
Whether the caller must provide this argument.
Definition prompt.hpp:71
bool required_present
Whether required was explicitly present on the wire or configured.
Definition prompt.hpp:73
std::string description
Optional human-readable description.
Definition prompt.hpp:69
Prompt descriptor returned by prompts/list.
Definition prompt.hpp:83
std::optional< Json > meta
Optional _meta extension object preserved on the wire.
Definition prompt.hpp:97
std::string description
Optional human-readable description.
Definition prompt.hpp:89
std::vector< Icon > icons
Optional icon descriptors for client presentation.
Definition prompt.hpp:93
std::vector< PromptArgument > arguments
Prompt arguments accepted by this prompt.
Definition prompt.hpp:91
std::string title
Optional human-readable display title.
Definition prompt.hpp:85
Json annotations
Optional annotations for model or client presentation.
Definition prompt.hpp:95
Concrete resource advertised by resources/list.
Definition resource.hpp:28
std::string title
Optional human-readable display title.
Definition resource.hpp:30
std::string mime_type
Optional MIME type for the resource contents.
Definition resource.hpp:38
std::string description
Optional human-readable description.
Definition resource.hpp:36
Json annotations
Optional annotations for model or client presentation.
Definition resource.hpp:44
std::optional< Json > meta
Optional _meta extension object preserved on the wire.
Definition resource.hpp:46
std::optional< std::int64_t > size
Optional size hint in bytes when known.
Definition resource.hpp:40
std::vector< Icon > icons
Optional icon descriptors for client presentation.
Definition resource.hpp:42
Invocation context passed to prompt handlers.
Definition context.hpp:56
Invocation context passed to resource read handlers.
Definition context.hpp:70
Typed prompt registration produced by mcp::server::prompt().
Definition authoring.hpp:202
Typed resource registration produced by mcp::server::resource().
Definition authoring.hpp:279