324 TaskHandle() =
default;
327 : peer_(&peer), task_(std::move(task)) {}
329 const std::string& id()
const noexcept {
return task_.task_id; }
336 if (peer_ ==
nullptr) {
337 return mcp::core::unexpected(detached_error());
339 auto task = peer_->get_task(task_.task_id);
341 return mcp::core::unexpected(task.error());
348 if (peer_ ==
nullptr) {
349 return mcp::core::unexpected(detached_error());
351 auto task = peer_->cancel_task(task_.task_id);
353 return mcp::core::unexpected(task.error());
360 if (peer_ ==
nullptr) {
361 return mcp::core::unexpected(detached_error());
363 return peer_->task_result(task_.task_id);
368 auto payload = result();
370 return mcp::core::unexpected(payload.error());
373 if (payload->is_object() && payload->contains(
"value")) {
374 return payload->at(
"value").template get<T>();
376 return payload->template get<T>();
377 }
catch (
const std::exception& exception) {
378 return mcp::core::unexpected(errors::make(
379 protocol::ErrorCode::InvalidRequest,
"failed to decode task result",
380 exception.what(),
"protocol"));
382 return mcp::core::unexpected(
383 errors::make(protocol::ErrorCode::InvalidRequest,
384 "failed to decode task result", {},
"protocol"));
389 std::chrono::milliseconds poll_interval =
390 std::chrono::milliseconds(100)) {
391 if (peer_ ==
nullptr) {
392 return mcp::core::unexpected(detached_error());
394 if (poll_interval <= std::chrono::milliseconds::zero()) {
395 poll_interval = std::chrono::milliseconds(1);
398 const auto started_at = std::chrono::steady_clock::now();
400 if (is_terminal(task_.status)) {
403 if (std::chrono::steady_clock::now() - started_at >= timeout) {
404 return mcp::core::unexpected(errors::request_timed_out(timeout));
409 return mcp::core::unexpected(task.error());
411 if (is_terminal(task->
status)) {
415 const auto elapsed = std::chrono::steady_clock::now() - started_at;
416 if (elapsed >= timeout) {
417 return mcp::core::unexpected(errors::request_timed_out(timeout));
419 auto sleep_for = poll_interval;
420 const auto remaining =
421 std::chrono::duration_cast<std::chrono::milliseconds>(timeout -
423 if (remaining > std::chrono::milliseconds::zero() &&
424 remaining < sleep_for) {
425 sleep_for = remaining;
427 std::this_thread::sleep_for(sleep_for);
433 return status == protocol::TaskStatus::Completed ||
434 status == protocol::TaskStatus::Failed ||
435 status == protocol::TaskStatus::Cancelled;
439 return errors::make(protocol::ErrorCode::InvalidRequest,
440 "task handle is not attached to a client peer", {},
444 Peer* peer_ =
nullptr;
449 explicit Peer(std::unique_ptr<client::Transport> transport)
450 : client_(std::move(transport)) {}
453 explicit Peer(std::unique_ptr<transport::ClientTransport> transport)
454 : native_transport_(std::move(transport)),
455 client_(detail::make_peer_client_transport_adapter(native_transport_)) {
461#if defined(CXXMCP_ENABLE_HTTP)
462 static Peer connect_streamable_http(
463 client::Client::StreamableHttpEndpoint endpoint) {
464 return Peer(client::Client::connect_streamable_http(std::move(endpoint)));
467 static Peer connect_legacy_sse(
468 client::Client::StreamableHttpEndpoint endpoint) {
469 return Peer(client::Client::connect_legacy_sse(std::move(endpoint)));
473 static Peer connect_stdio(client::Client::StdioEndpoint endpoint) {
474 return Peer(client::Client::connect_stdio(std::move(endpoint)));
478 static Builder builder();
481 "client() is a compatibility escape hatch; prefer ClientPeer methods")
482 client::Client& client() noexcept {
return client_; }
485 "client() is a compatibility escape hatch; prefer ClientPeer methods")
486 const client::Client& client() const noexcept {
return client_; }
488 bool uses_native_transport() const noexcept {
489 return native_transport_ !=
nullptr;
492 core::Result<core::Unit> start(
493 CancellationToken cancellation = CancellationToken::none()) {
494 if (native_transport_) {
495 return start_native_receive_loop(cancellation);
497 return client_.start();
500 void stop() noexcept {
501 if (native_transport_) {
502 (void)native_transport_->close();
508 core::Result<protocol::Json> initialize(std::string client_name =
"cxxmcp",
509 std::string client_version =
"0") {
510 if (native_transport_) {
512 request_json(std::string(protocol::InitializeMethod),
513 detail::make_peer_initialize_params(
514 std::move(client_name), std::move(client_version),
515 client_capabilities_));
519 auto checked = detail::require_peer_initialize_payload(*payload);
523 auto recorded = record_server_capabilities(*checked);
529 return client_.initialize(std::move(client_name),
530 std::move(client_version));
533 core::Result<protocol::Json> initialize(std::string client_name,
534 std::string client_version,
535 RequestOptions options) {
536 if (native_transport_) {
537 auto params = detail::make_peer_initialize_params(
538 std::move(client_name), std::move(client_version),
539 client_capabilities_);
540 if (options.protocol_version.has_value()) {
541 params[
"protocolVersion"] = *options.protocol_version;
543 if (options.meta.has_value()) {
544 params[
"_meta"] = *options.meta;
548 [&](
const protocol::Json& p) -> core::Result<protocol::Json> {
549 protocol::JsonRpcRequest request = protocol::make_request(
550 std::string(protocol::InitializeMethod), next_peer_request_id(), p);
551 request.transport_headers = options.headers;
552 request.protocol_version_override = options.protocol_version;
553 auto payload = raw_request(request);
560 auto payload = do_init(params);
563 auto& err = payload.error();
564 if (!err.detail.empty()) {
565 auto detail_json = protocol::Json::parse(err.detail,
nullptr,
false);
566 std::string retry_version;
567 if (detail_json.is_object() &&
568 detail_json.contains(
"supportedVersion")) {
569 retry_version = detail_json[
"supportedVersion"].get<std::string>();
570 }
else if (detail_json.is_object() &&
571 detail_json.contains(
"supported") &&
572 detail_json[
"supported"].is_array() &&
573 !detail_json[
"supported"].empty()) {
576 retry_version = detail_json[
"supported"][0].get<std::string>();
577 }
else if (detail_json.is_string()) {
580 retry_version = std::string(protocol::McpProtocolVersion);
582 if (!retry_version.empty()) {
583 params[
"protocolVersion"] = retry_version;
584 if (options.meta.has_value()) {
585 params[
"_meta"] = *options.meta;
587 payload = do_init(params);
598 auto checked = detail::require_peer_initialize_payload(*payload);
602 auto recorded = record_server_capabilities(*checked);
608 return client_.initialize(std::move(client_name), std::move(client_version),
613 return native_transport_ ? server_capabilities_
614 : client_.server_capabilities();
617 core::Result<core::Unit> notify_initialized() {
618 return raw_notification(protocol::make_notification(
619 std::string(protocol::InitializedMethod), protocol::Json::object()));
622 core::Result<core::Unit> notify_initialized(RequestOptions options) {
623 protocol::Json params = protocol::Json::object();
624 if (options.meta.has_value()) {
625 params[
"_meta"] = *options.meta;
627 protocol::JsonRpcNotification notification;
628 notification.method = std::string(protocol::InitializedMethod);
629 notification.params = std::move(params);
630 return raw_notification(std::move(notification));
633 core::Result<core::Unit> notify_cancelled(protocol::RequestId request_id,
634 std::string reason = {}) {
635 protocol::CancelledNotificationParams params;
636 params.request_id = std::move(request_id);
637 if (!reason.empty()) {
638 params.reason = std::move(reason);
640 return raw_notification(protocol::make_notification(
641 std::string(protocol::CancelledNotificationMethod),
642 protocol::cancelled_notification_params_to_json(params)));
645 core::Result<core::Unit> notify_progress(
646 protocol::ProgressToken progress_token,
double progress,
647 std::optional<double> total = std::nullopt, std::string message = {}) {
648 protocol::ProgressNotificationParams params;
649 params.progress_token = std::move(progress_token);
650 params.progress = progress;
651 params.total = total;
652 if (!message.empty()) {
653 params.message = std::move(message);
655 return raw_notification(protocol::make_notification(
656 std::string(protocol::ProgressNotificationMethod),
657 protocol::progress_notification_params_to_json(params)));
660 core::Result<core::Unit> notify_roots_list_changed() {
661 return raw_notification(protocol::make_notification(
662 std::string(protocol::RootsListChangedNotificationMethod),
663 protocol::Json::object()));
666 core::Result<core::Unit> ping() {
667 return request_unit(std::string(protocol::PingMethod),
668 protocol::Json::object());
671 std::vector<protocol::Root> list_roots()
const {
672 if (native_transport_) {
675 return client_.list_roots();
678 Peer& set_roots(std::vector<protocol::Root> roots) {
680 client_.set_roots(std::move(roots));
684 Peer& set_capabilities(protocol::ClientCapabilities capabilities) {
685 client_capabilities_ = capabilities;
686 client_.set_capabilities(std::move(capabilities));
690 Peer& on_initialized(client::Client::InitializedHandler handler) {
691 initialized_handler_ = handler;
692 client_.on_initialized(std::move(handler));
696 Peer& on_cancelled(client::Client::CancelledHandler handler) {
697 cancelled_handler_ = handler;
698 client_.on_cancelled(std::move(handler));
702 Peer& on_logging_message(client::Client::LoggingMessageHandler handler) {
703 logging_message_handler_ = handler;
704 client_.on_logging_message(std::move(handler));
708 Peer& on_tool_list_changed(client::Client::ListChangedHandler handler) {
709 tool_list_changed_handler_ = handler;
710 client_.on_tool_list_changed(std::move(handler));
714 Peer& on_prompt_list_changed(client::Client::ListChangedHandler handler) {
715 prompt_list_changed_handler_ = handler;
716 client_.on_prompt_list_changed(std::move(handler));
720 Peer& on_resource_list_changed(client::Client::ListChangedHandler handler) {
721 resource_list_changed_handler_ = handler;
722 client_.on_resource_list_changed(std::move(handler));
726 Peer& on_resource_updated(client::Client::ResourceUpdatedHandler handler) {
727 resource_updated_handler_ = handler;
728 client_.on_resource_updated(std::move(handler));
732 Peer& on_progress(client::Client::ProgressHandler handler) {
733 progress_handler_ = handler;
734 client_.on_progress(std::move(handler));
738 Peer& on_elicitation_complete(
739 client::Client::ElicitationCompleteHandler handler) {
740 elicitation_complete_handler_ = handler;
741 client_.on_elicitation_complete(std::move(handler));
745 Peer& on_task_status(client::Client::TaskStatusHandler handler) {
746 task_status_handler_ = handler;
747 client_.on_task_status(std::move(handler));
751 Peer& on_roots_list_changed(client::Client::ListChangedHandler handler) {
752 roots_list_changed_handler_ = handler;
753 client_.on_roots_list_changed(std::move(handler));
757 Peer& on_list_roots_request(client::Client::ListRootsRequestHandler handler) {
758 roots_list_request_handler_ = handler;
759 client_.on_list_roots_request(std::move(handler));
763 Peer& on_list_roots_request(
764 client::Client::RootsListRequestCancellationHandler handler) {
765 roots_list_request_cancellation_handler_ = handler;
766 client_.on_list_roots_request(std::move(handler));
770 Peer& on_create_message_request(
771 client::Client::CreateMessageRequestHandler handler) {
772 sampling_request_handler_ = handler;
773 client_.on_create_message_request(std::move(handler));
777 Peer& on_create_message_request(
778 client::Client::SamplingRequestCancellationHandler handler) {
779 sampling_request_cancellation_handler_ = handler;
780 client_.on_create_message_request(std::move(handler));
784 Peer& on_create_elicitation_request(
785 client::Client::CreateElicitationRequestHandler handler) {
786 elicitation_request_handler_ = handler;
787 client_.on_create_elicitation_request(std::move(handler));
791 Peer& on_create_elicitation_request(
792 client::Client::ElicitationRequestCancellationHandler handler) {
793 elicitation_request_cancellation_handler_ = handler;
794 client_.on_create_elicitation_request(std::move(handler));
798 Peer& on_custom_request(client::Client::CustomRequestHandler handler) {
799 custom_request_handler_ = handler;
800 client_.on_custom_request(std::move(handler));
804 Peer& on_custom_request(
805 client::Client::CustomRequestCancellationHandler handler) {
806 custom_request_cancellation_handler_ = handler;
807 client_.on_custom_request(std::move(handler));
811 Peer& on_raw_notification(client::Client::RawNotificationHandler handler) {
812 raw_notification_handler_ = handler;
813 client_.on_raw_notification(std::move(handler));
817 Peer& set_handler(
const client::ClientHandler& handler) {
818 if (handler.on_initialized) {
819 on_initialized(handler.on_initialized);
821 if (handler.on_cancelled) {
822 on_cancelled(handler.on_cancelled);
824 if (handler.on_logging_message) {
825 on_logging_message(handler.on_logging_message);
827 if (handler.on_tool_list_changed) {
828 on_tool_list_changed(handler.on_tool_list_changed);
830 if (handler.on_prompt_list_changed) {
831 on_prompt_list_changed(handler.on_prompt_list_changed);
833 if (handler.on_resource_list_changed) {
834 on_resource_list_changed(handler.on_resource_list_changed);
836 if (handler.on_resource_updated) {
837 on_resource_updated(handler.on_resource_updated);
839 if (handler.on_progress) {
840 on_progress(handler.on_progress);
842 if (handler.on_elicitation_complete) {
843 on_elicitation_complete(handler.on_elicitation_complete);
845 if (handler.on_task_status) {
846 on_task_status(handler.on_task_status);
848 if (handler.on_roots_list_changed) {
849 on_roots_list_changed(handler.on_roots_list_changed);
851 if (handler.on_list_roots_request) {
852 on_list_roots_request(handler.on_list_roots_request);
854 if (handler.on_list_roots_request_with_cancellation) {
855 on_list_roots_request(handler.on_list_roots_request_with_cancellation);
857 if (handler.on_create_message_request) {
858 on_create_message_request(handler.on_create_message_request);
860 if (handler.on_create_message_request_with_cancellation) {
861 on_create_message_request(
862 handler.on_create_message_request_with_cancellation);
864 if (handler.on_create_elicitation_request) {
865 on_create_elicitation_request(handler.on_create_elicitation_request);
867 if (handler.on_create_elicitation_request_with_cancellation) {
868 on_create_elicitation_request(
869 handler.on_create_elicitation_request_with_cancellation);
871 if (handler.on_custom_request) {
872 on_custom_request(handler.on_custom_request);
874 if (handler.on_custom_request_with_cancellation) {
875 on_custom_request(handler.on_custom_request_with_cancellation);
877 if (handler.on_roots_list_request) {
878 on_list_roots_request(handler.on_roots_list_request);
880 if (handler.on_roots_list_request_with_cancellation) {
881 on_list_roots_request(handler.on_roots_list_request_with_cancellation);
883 if (handler.on_sampling_request) {
884 on_create_message_request(handler.on_sampling_request);
886 if (handler.on_sampling_request_with_cancellation) {
887 on_create_message_request(handler.on_sampling_request_with_cancellation);
889 if (handler.on_elicitation_request) {
890 on_create_elicitation_request(handler.on_elicitation_request);
892 if (handler.on_elicitation_request_with_cancellation) {
893 on_create_elicitation_request(
894 handler.on_elicitation_request_with_cancellation);
896 if (handler.on_raw_notification) {
897 on_raw_notification(handler.on_raw_notification);
899 if (handler.on_custom_notification) {
900 on_raw_notification(handler.on_custom_notification);
905 Peer& set_handler(
const client::ClientHandlerInterface& handler) {
906 on_initialized([&handler]() { handler.on_initialized(); });
907 on_cancelled([&handler](
const protocol::RequestId& request_id,
908 std::string_view reason) {
909 handler.on_cancelled(request_id, reason);
912 [&handler](std::string_view level, std::string_view message) {
913 handler.on_logging_message(level, message);
915 on_tool_list_changed([&handler]() { handler.on_tool_list_changed(); });
916 on_prompt_list_changed([&handler]() { handler.on_prompt_list_changed(); });
917 on_resource_list_changed(
918 [&handler]() { handler.on_resource_list_changed(); });
919 on_resource_updated([&handler](
const std::string& uri) {
920 handler.on_resource_updated(uri);
922 on_progress([&handler](
const protocol::ProgressNotificationParams& params) {
923 handler.on_progress(params);
925 on_elicitation_complete([&handler](std::string_view elicitation_id) {
926 handler.on_elicitation_complete(elicitation_id);
928 on_task_status([&handler](
const protocol::Task& task) {
929 handler.on_task_status(task);
931 on_roots_list_changed([&handler]() { handler.on_roots_list_changed(); });
932 on_list_roots_request([&handler](CancellationToken cancellation)
933 -> core::Result<protocol::RootsListResult> {
934 const auto response = handler.on_list_roots_request(cancellation);
935 if (response.has_value()) {
936 return std::move(*response);
938 return mcp::core::unexpected(client::handler_method_not_found(
939 "client handler does not handle list_roots"));
941 on_create_message_request(
942 [&handler](
const protocol::CreateMessageParams& params,
943 CancellationToken cancellation)
944 -> core::Result<protocol::CreateMessageResult> {
945 const auto response =
946 handler.on_create_message_request(params, cancellation);
947 if (response.has_value()) {
948 return std::move(*response);
950 return mcp::core::unexpected(client::handler_method_not_found(
951 "client handler does not handle create_message"));
953 on_create_elicitation_request(
954 [&handler](
const protocol::CreateElicitationRequestParam& params,
955 CancellationToken cancellation)
956 -> core::Result<protocol::CreateElicitationResult> {
957 const auto response =
958 handler.on_create_elicitation_request(params, cancellation);
959 if (response.has_value()) {
960 return std::move(*response);
962 return mcp::core::unexpected(client::handler_method_not_found(
963 "client handler does not handle elicitation"));
965 on_custom_request([&handler](
const protocol::JsonRpcRequest& request,
966 CancellationToken cancellation)
967 -> core::Result<protocol::Json> {
968 const auto response = handler.on_custom_request(request, cancellation);
969 if (response.has_value()) {
970 return std::move(*response);
972 return mcp::core::unexpected(client::handler_method_not_found(
973 "client handler does not handle custom request"));
976 [&handler](
const protocol::JsonRpcNotification& notification) {
977 handler.on_raw_notification(notification);
982 core::Result<std::vector<protocol::ToolDefinition>> list_tools() {
983 const auto page = list_tools_page();
987 cache_tool_schemas(page->tools);
991 core::Result<protocol::ToolsListResult> list_tools_page(
992 const protocol::PaginatedRequestParams& params = {}) {
993 if (!native_transport_) {
994 return client_.list_tools_page(params);
997 request_json(std::string(protocol::ToolsListMethod),
998 protocol::paginated_request_params_to_json(params));
1002 const auto result = protocol::tools_list_result_from_json(*payload);
1009 core::Result<std::vector<protocol::ToolDefinition>> list_all_tools() {
1010 auto result = list_all_pages<protocol::ToolDefinition>(
1011 std::string(protocol::ToolsListMethod),
1012 [](
const protocol::Json& payload) {
1013 return protocol::tools_list_result_from_json(payload);
1015 [](
const protocol::ToolsListResult& page,
1016 std::vector<protocol::ToolDefinition>& all) {
1017 all.insert(all.end(), page.tools.begin(), page.tools.end());
1020 cache_tool_schemas(*result);
1025 core::Result<protocol::ToolResult> call_tool(
const protocol::ToolCall& call) {
1026 auto request = protocol::make_request(
1027 std::string(protocol::ToolsCallMethod), next_peer_request_id(),
1028 protocol::tool_call_to_json(call));
1029 apply_x_mcp_headers(request, call);
1030 auto payload = raw_request(request);
1034 return protocol::tool_result_from_json(*payload);
1037 core::Result<protocol::CreateTaskResult> call_tool_task(
1038 const protocol::ToolCall& call) {
1039 if (!call.task.has_value()) {
1041 protocol::ErrorCode::InvalidRequest,
1042 "task-aware tool call requires task parameters", {},
"protocol"));
1044 if (!supports_server_task_tool_call()) {
1046 "server does not support task-aware tool calls"));
1048 auto payload = request_json(std::string(protocol::ToolsCallMethod),
1049 protocol::tool_call_to_json(call));
1053 return protocol::create_task_result_from_json(*payload);
1056 core::Result<TaskHandle> call_tool_task_handle(
1057 const protocol::ToolCall& call) {
1058 auto task = call_tool_task(call);
1062 return TaskHandle(*
this, task->task);
1065 core::Result<protocol::ToolResult> call_tool(
1066 std::string_view name,
1067 const protocol::Json& arguments = protocol::Json::object()) {
1068 protocol::ToolCall call;
1069 call.name = std::string(name);
1070 call.arguments = arguments;
1071 return call_tool(call);
1074 core::Result<std::vector<protocol::Prompt>> list_prompts() {
1075 const auto page = list_prompts_page();
1079 return page->prompts;
1082 core::Result<protocol::PromptsListResult> list_prompts_page(
1083 const protocol::PaginatedRequestParams& params = {}) {
1084 if (!native_transport_) {
1085 return client_.list_prompts_page(params);
1088 request_json(std::string(protocol::PromptsListMethod),
1089 protocol::paginated_request_params_to_json(params));
1093 const auto result = protocol::prompts_list_result_from_json(*payload);
1100 core::Result<std::vector<protocol::Prompt>> list_all_prompts() {
1101 return list_all_pages<protocol::Prompt>(
1102 std::string(protocol::PromptsListMethod),
1103 [](
const protocol::Json& payload) {
1104 return protocol::prompts_list_result_from_json(payload);
1106 [](
const protocol::PromptsListResult& page,
1107 std::vector<protocol::Prompt>& all) {
1108 all.insert(all.end(), page.prompts.begin(), page.prompts.end());
1112 core::Result<protocol::PromptsGetResult> get_prompt(
1113 const protocol::PromptsGetParams& params) {
1114 auto payload = request_json(std::string(protocol::PromptsGetMethod),
1115 protocol::prompts_get_params_to_json(params));
1119 return protocol::prompts_get_result_from_json(*payload);
1122 core::Result<protocol::PromptsGetResult> get_prompt(
1123 std::string_view name,
1124 const protocol::Json& arguments = protocol::Json::object()) {
1125 protocol::PromptsGetParams params;
1126 params.name = std::string(name);
1127 params.arguments = arguments;
1128 return get_prompt(params);
1131 core::Result<std::vector<protocol::Resource>> list_resources() {
1132 const auto page = list_resources_page();
1136 return page->resources;
1139 core::Result<protocol::ResourcesListResult> list_resources_page(
1140 const protocol::PaginatedRequestParams& params = {}) {
1141 if (!native_transport_) {
1142 return client_.list_resources_page(params);
1145 request_json(std::string(protocol::ResourcesListMethod),
1146 protocol::paginated_request_params_to_json(params));
1150 const auto result = protocol::resources_list_result_from_json(*payload);
1157 core::Result<std::vector<protocol::Resource>> list_all_resources() {
1158 return list_all_pages<protocol::Resource>(
1159 std::string(protocol::ResourcesListMethod),
1160 [](
const protocol::Json& payload) {
1161 return protocol::resources_list_result_from_json(payload);
1163 [](
const protocol::ResourcesListResult& page,
1164 std::vector<protocol::Resource>& all) {
1165 all.insert(all.end(), page.resources.begin(), page.resources.end());
1169 core::Result<std::vector<protocol::ResourceTemplate>>
1170 list_resource_templates() {
1171 const auto page = list_resource_templates_page();
1175 return page->resource_templates;
1178 core::Result<protocol::ResourceTemplatesListResult>
1179 list_resource_templates_page(
1180 const protocol::PaginatedRequestParams& params = {}) {
1181 if (!native_transport_) {
1182 return client_.list_resource_templates_page(params);
1185 request_json(std::string(protocol::ResourcesTemplatesListMethod),
1186 protocol::paginated_request_params_to_json(params));
1191 protocol::resource_templates_list_result_from_json(*payload);
1198 core::Result<std::vector<protocol::ResourceTemplate>>
1199 list_all_resource_templates() {
1200 return list_all_pages<protocol::ResourceTemplate>(
1201 std::string(protocol::ResourcesTemplatesListMethod),
1202 [](
const protocol::Json& payload) {
1203 return protocol::resource_templates_list_result_from_json(payload);
1205 [](
const protocol::ResourceTemplatesListResult& page,
1206 std::vector<protocol::ResourceTemplate>& all) {
1207 all.insert(all.end(), page.resource_templates.begin(),
1208 page.resource_templates.end());
1212 core::Result<protocol::ResourcesReadResult> read_resource(
1213 const protocol::ResourcesReadParams& params) {
1215 request_json(std::string(protocol::ResourcesReadMethod),
1216 protocol::resources_read_params_to_json(params));
1220 return protocol::resources_read_result_from_json(*payload);
1223 core::Result<protocol::ResourcesReadResult> read_resource(
1224 std::string_view uri) {
1225 return read_resource(protocol::ResourcesReadParams{std::string(uri)});
1228 core::Result<protocol::CompleteResult> complete(
1229 const protocol::CompleteParams& request) {
1230 if (!supports_server_completion()) {
1232 unsupported_server_capability(
"server does not support completion"));
1234 auto payload = request_json(std::string(protocol::CompletionCompleteMethod),
1235 protocol::complete_params_to_json(request));
1239 return protocol::complete_result_from_json(*payload);
1242 core::Result<protocol::Json> complete(
const protocol::Json& request) {
1243 if (!supports_server_completion()) {
1245 unsupported_server_capability(
"server does not support completion"));
1247 return request_json(std::string(protocol::CompletionCompleteMethod),
1251 core::Result<protocol::CompletionResult> complete_prompt_argument(
1252 std::string_view prompt_name, std::string_view argument_name,
1253 std::string current_value,
1254 protocol::Json context = protocol::Json::object()) {
1255 protocol::CompletionArgument argument;
1256 argument.name = std::string(argument_name);
1257 argument.value = std::move(current_value);
1258 protocol::CompleteParams params;
1260 protocol::prompt_completion_reference(std::string(prompt_name));
1261 params.argument = std::move(argument);
1262 params.context = std::move(context);
1263 const auto result = complete(params);
1267 return result->completion;
1270 core::Result<protocol::CompletionResult> complete_resource_argument(
1271 std::string_view uri_template, std::string_view argument_name,
1272 std::string current_value,
1273 protocol::Json context = protocol::Json::object()) {
1274 protocol::CompletionArgument argument;
1275 argument.name = std::string(argument_name);
1276 argument.value = std::move(current_value);
1277 protocol::CompleteParams params;
1279 protocol::resource_completion_reference(std::string(uri_template));
1280 params.argument = std::move(argument);
1281 params.context = std::move(context);
1282 const auto result = complete(params);
1286 return result->completion;
1289 core::Result<std::vector<std::string>> complete_prompt_simple(
1290 std::string_view prompt_name, std::string_view argument_name,
1291 std::string current_value,
1292 protocol::Json context = protocol::Json::object()) {
1293 const auto completion =
1294 complete_prompt_argument(prompt_name, argument_name,
1295 std::move(current_value), std::move(context));
1299 return completion->values;
1302 core::Result<std::vector<std::string>> complete_resource_simple(
1303 std::string_view uri_template, std::string_view argument_name,
1304 std::string current_value,
1305 protocol::Json context = protocol::Json::object()) {
1306 const auto completion = complete_resource_argument(
1307 uri_template, argument_name, std::move(current_value),
1308 std::move(context));
1312 return completion->values;
1315 core::Result<protocol::CreateMessageResult> create_message(
1316 const protocol::CreateMessageParams& request) {
1318 request_json(std::string(protocol::SamplingCreateMessageMethod),
1319 protocol::create_message_params_to_json(request));
1323 return protocol::create_message_result_from_json(*payload);
1326 core::Result<protocol::Json> create_message(
const protocol::Json& request) {
1327 return request_json(std::string(protocol::SamplingCreateMessageMethod),
1331 core::Result<protocol::CreateElicitationResult> create_elicitation(
1332 const protocol::CreateElicitationRequestParam& request) {
1333 auto payload = request_json(
1334 std::string(protocol::ElicitationCreateMethod),
1335 protocol::create_elicitation_request_param_to_json(request));
1339 return protocol::create_elicitation_result_from_json(*payload);
1342 core::Result<protocol::Json> create_elicitation(
1343 const protocol::Json& request) {
1344 return request_json(std::string(protocol::ElicitationCreateMethod),
1348 core::Result<std::vector<protocol::Task>> list_tasks() {
1349 const auto page = list_tasks_page();
1356 core::Result<protocol::TaskListResult> list_tasks_page(
1357 const protocol::TaskListParams& params = {}) {
1358 if (!supports_server_task_list()) {
1360 "server does not support task listing"));
1362 if (!native_transport_) {
1363 return client_.list_tasks_page(params);
1365 auto payload = request_json(std::string(protocol::TasksListMethod),
1366 protocol::task_list_params_to_json(params));
1370 const auto result = protocol::task_list_result_from_json(*payload);
1377 core::Result<std::vector<protocol::Task>> list_all_tasks() {
1378 if (!supports_server_task_list()) {
1380 "server does not support task listing"));
1382 return list_all_pages<protocol::Task>(
1383 std::string(protocol::TasksListMethod),
1384 [](
const protocol::Json& payload) {
1385 return protocol::task_list_result_from_json(payload);
1387 [](
const protocol::TaskListResult& page,
1388 std::vector<protocol::Task>& all) {
1389 all.insert(all.end(), page.tasks.begin(), page.tasks.end());
1393 core::Result<protocol::Task> get_task(std::string_view task_id) {
1394 if (!supports_server_tasks()) {
1396 unsupported_server_capability(
"server does not support tasks"));
1398 protocol::TaskGetParams params;
1399 params.task_id = std::string(task_id);
1400 auto payload = request_json(std::string(protocol::TasksGetMethod),
1401 protocol::task_get_params_to_json(params));
1405 return protocol::task_from_json(*payload);
1408 core::Result<protocol::Task> cancel_task(std::string_view task_id) {
1409 if (!supports_server_task_cancel()) {
1411 "server does not support task cancellation"));
1413 protocol::TaskCancelParams params;
1414 params.task_id = std::string(task_id);
1415 auto payload = request_json(std::string(protocol::TasksCancelMethod),
1416 protocol::task_cancel_params_to_json(params));
1420 return protocol::task_from_json(*payload);
1423 core::Result<protocol::Json> task_result(std::string_view task_id) {
1424 if (!supports_server_tasks()) {
1426 unsupported_server_capability(
"server does not support tasks"));
1428 protocol::TaskResultParams params;
1429 params.task_id = std::string(task_id);
1430 return request_json(std::string(protocol::TasksResultMethod),
1431 protocol::task_result_params_to_json(params));
1434 core::Result<core::Unit> set_level(std::string_view level) {
1435 const auto parsed = protocol::logging_level_from_string(std::string(level));
1436 if (!parsed.has_value()) {
1438 errors::make(protocol::ErrorCode::InvalidRequest,
1439 "logging/setLevel level is invalid", {},
"protocol"));
1441 if (!supports_server_logging()) {
1443 unsupported_server_capability(
"server does not support logging"));
1445 protocol::LoggingSetLevelParams params;
1446 params.level = *parsed;
1447 return request_unit(std::string(protocol::LoggingSetLevelMethod),
1448 protocol::logging_set_level_params_to_json(params));
1451 core::Result<core::Unit> subscribe(std::string_view uri) {
1452 if (!supports_server_resource_subscribe()) {
1454 "server does not support resource subscriptions"));
1456 protocol::ResourcesSubscribeParams params;
1457 params.uri = std::string(uri);
1458 return request_unit(std::string(protocol::ResourcesSubscribeMethod),
1459 protocol::resources_subscribe_params_to_json(params));
1462 core::Result<core::Unit> unsubscribe(std::string_view uri) {
1463 if (!supports_server_resource_subscribe()) {
1465 "server does not support resource subscriptions"));
1467 protocol::ResourcesUnsubscribeParams params;
1468 params.uri = std::string(uri);
1469 return request_unit(std::string(protocol::ResourcesUnsubscribeMethod),
1470 protocol::resources_unsubscribe_params_to_json(params));
1473 core::Result<protocol::Json> raw_request(
1474 const protocol::JsonRpcRequest& request) {
1475 if (native_transport_) {
1476 const auto response = send_native_request(request);
1480 return detail::peer_require_result_payload(*response);
1482 return client_.raw_request(request);
1485 RequestHandle<protocol::Json> request_async(
1486 std::string method, protocol::Json params = protocol::Json::object(),
1487 RequestOptions options = {}) {
1488 if (native_transport_) {
1489 protocol::JsonRpcRequest request = protocol::make_request(
1490 std::move(method), next_peer_request_id(), std::move(params));
1491 if (options.meta.has_value()) {
1492 request.meta = std::move(options.meta);
1494 request.transport_headers = std::move(options.headers);
1495 request.protocol_version_override = std::move(options.protocol_version);
1497 const auto request_id = request.id;
1498 return RequestHandle<protocol::Json>::spawn(
1499 request_id, options.timeout, options.cancellation_token,
1500 [
this, request_id](std::string reason)
mutable {
1501 return notify_cancelled(std::move(request_id), std::move(reason));
1503 [
this, request = std::move(request)]()
mutable {
1504 return raw_request(request);
1507 return client_.request_async(std::move(method), std::move(params),
1508 std::move(options));
1511 template <
class T,
class Parser>
1512 RequestHandle<T> request_async(std::string method, protocol::Json params,
1513 Parser parser, RequestOptions options = {}) {
1514 if (native_transport_) {
1515 protocol::JsonRpcRequest request = protocol::make_request(
1516 std::move(method), next_peer_request_id(), std::move(params));
1517 if (options.meta.has_value()) {
1518 request.meta = std::move(options.meta);
1520 request.transport_headers = std::move(options.headers);
1521 request.protocol_version_override = std::move(options.protocol_version);
1523 const auto request_id = request.id;
1524 return RequestHandle<T>::spawn(
1525 request_id, options.timeout, options.cancellation_token,
1526 [
this, request_id](std::string reason)
mutable {
1527 return notify_cancelled(std::move(request_id), std::move(reason));
1529 [
this, request = std::move(request),
1530 parser = std::move(parser)]() mutable -> core::Result<T> {
1531 auto payload = raw_request(request);
1533 return mcp::core::unexpected(payload.error());
1535 return parser(*payload);
1538 return client_.request_async<T>(std::move(method), std::move(params),
1539 std::move(parser), std::move(options));
1542 RequestHandle<std::vector<protocol::ToolDefinition>> list_tools_async(
1543 RequestOptions options = {}) {
1544 return request_async<std::vector<protocol::ToolDefinition>>(
1545 std::string(protocol::ToolsListMethod), protocol::Json::object(),
1546 [](
const protocol::Json& payload)
1547 -> core::Result<std::vector<protocol::ToolDefinition>> {
1548 const auto result = protocol::tools_list_result_from_json(payload);
1552 return result->tools;
1554 std::move(options));
1557 RequestHandle<std::vector<protocol::Prompt>> list_prompts_async(
1558 RequestOptions options = {}) {
1559 return request_async<std::vector<protocol::Prompt>>(
1560 std::string(protocol::PromptsListMethod), protocol::Json::object(),
1561 [](
const protocol::Json& payload)
1562 -> core::Result<std::vector<protocol::Prompt>> {
1563 const auto result = protocol::prompts_list_result_from_json(payload);
1567 return result->prompts;
1569 std::move(options));
1572 RequestHandle<std::vector<protocol::Resource>> list_resources_async(
1573 RequestOptions options = {}) {
1574 return request_async<std::vector<protocol::Resource>>(
1575 std::string(protocol::ResourcesListMethod), protocol::Json::object(),
1576 [](
const protocol::Json& payload)
1577 -> core::Result<std::vector<protocol::Resource>> {
1579 protocol::resources_list_result_from_json(payload);
1583 return result->resources;
1585 std::move(options));
1588 RequestHandle<std::vector<protocol::ResourceTemplate>>
1589 list_resource_templates_async(RequestOptions options = {}) {
1590 return request_async<std::vector<protocol::ResourceTemplate>>(
1591 std::string(protocol::ResourcesTemplatesListMethod),
1592 protocol::Json::object(),
1593 [](
const protocol::Json& payload)
1594 -> core::Result<std::vector<protocol::ResourceTemplate>> {
1596 protocol::resource_templates_list_result_from_json(payload);
1600 return result->resource_templates;
1602 std::move(options));
1605 RequestHandle<protocol::ToolResult> call_tool_async(
1606 const protocol::ToolCall& call, RequestOptions options = {}) {
1607 return request_async<protocol::ToolResult>(
1608 std::string(protocol::ToolsCallMethod),
1609 protocol::tool_call_to_json(call),
1610 [](
const protocol::Json& payload) {
1611 return protocol::tool_result_from_json(payload);
1613 std::move(options));
1616 RequestHandle<protocol::ToolResult> call_tool_async(
1617 std::string_view name,
1618 const protocol::Json& arguments = protocol::Json::object(),
1619 RequestOptions options = {}) {
1620 protocol::ToolCall call;
1621 call.name = std::string(name);
1622 call.arguments = arguments;
1623 return call_tool_async(call, std::move(options));
1626 RequestHandle<protocol::CreateTaskResult> call_tool_task_async(
1627 const protocol::ToolCall& call, RequestOptions options = {}) {
1628 if (!call.task.has_value()) {
1630 next_peer_request_id(),
1631 mcp::core::unexpected(
1632 errors::make(protocol::ErrorCode::InvalidRequest,
1633 "task-aware tool call requires task parameters", {},
1636 if (!supports_server_task_tool_call()) {
1638 next_peer_request_id(),
1639 mcp::core::unexpected(unsupported_server_capability(
1640 "server does not support task-aware tool calls")));
1643 return request_async<protocol::CreateTaskResult>(
1644 std::string(protocol::ToolsCallMethod),
1645 protocol::tool_call_to_json(call),
1646 [](
const protocol::Json& payload) {
1647 return protocol::create_task_result_from_json(payload);
1649 std::move(options));
1652 RequestHandle<protocol::PromptsGetResult> get_prompt_async(
1653 const protocol::PromptsGetParams& params, RequestOptions options = {}) {
1654 return request_async<protocol::PromptsGetResult>(
1655 std::string(protocol::PromptsGetMethod),
1656 protocol::prompts_get_params_to_json(params),
1657 [](
const protocol::Json& payload) {
1658 return protocol::prompts_get_result_from_json(payload);
1660 std::move(options));
1663 RequestHandle<protocol::PromptsGetResult> get_prompt_async(
1664 std::string_view name,
1665 const protocol::Json& arguments = protocol::Json::object(),
1666 RequestOptions options = {}) {
1667 protocol::PromptsGetParams params;
1668 params.name = std::string(name);
1669 params.arguments = arguments;
1670 return get_prompt_async(params, std::move(options));
1673 RequestHandle<protocol::ResourcesReadResult> read_resource_async(
1674 const protocol::ResourcesReadParams& params,
1675 RequestOptions options = {}) {
1676 return request_async<protocol::ResourcesReadResult>(
1677 std::string(protocol::ResourcesReadMethod),
1678 protocol::resources_read_params_to_json(params),
1679 [](
const protocol::Json& payload) {
1680 return protocol::resources_read_result_from_json(payload);
1682 std::move(options));
1685 RequestHandle<protocol::ResourcesReadResult> read_resource_async(
1686 std::string_view uri, RequestOptions options = {}) {
1687 return read_resource_async(protocol::ResourcesReadParams{std::string(uri)},
1688 std::move(options));
1691 RequestHandle<protocol::CompleteResult> complete_async(
1692 const protocol::CompleteParams& request, RequestOptions options = {}) {
1693 if (!supports_server_completion()) {
1695 next_peer_request_id(),
1696 mcp::core::unexpected(unsupported_server_capability(
1697 "server does not support completion")));
1699 return request_async<protocol::CompleteResult>(
1700 std::string(protocol::CompletionCompleteMethod),
1701 protocol::complete_params_to_json(request),
1702 [](
const protocol::Json& payload) {
1703 return protocol::complete_result_from_json(payload);
1705 std::move(options));
1708 RequestHandle<protocol::Json> complete_async(
const protocol::Json& request,
1709 RequestOptions options = {}) {
1710 if (!supports_server_completion()) {
1712 next_peer_request_id(),
1713 mcp::core::unexpected(unsupported_server_capability(
1714 "server does not support completion")));
1716 return request_async(std::string(protocol::CompletionCompleteMethod),
1717 request, std::move(options));
1720 RequestHandle<protocol::CreateMessageResult> create_message_async(
1721 const protocol::CreateMessageParams& request,
1722 RequestOptions options = {}) {
1723 return request_async<protocol::CreateMessageResult>(
1724 std::string(protocol::SamplingCreateMessageMethod),
1725 protocol::create_message_params_to_json(request),
1726 [](
const protocol::Json& payload) {
1727 return protocol::create_message_result_from_json(payload);
1729 std::move(options));
1732 RequestHandle<protocol::Json> create_message_async(
1733 const protocol::Json& request, RequestOptions options = {}) {
1734 return request_async(std::string(protocol::SamplingCreateMessageMethod),
1735 request, std::move(options));
1738 RequestHandle<protocol::CreateElicitationResult> create_elicitation_async(
1739 const protocol::CreateElicitationRequestParam& request,
1740 RequestOptions options = {}) {
1741 return request_async<protocol::CreateElicitationResult>(
1742 std::string(protocol::ElicitationCreateMethod),
1743 protocol::create_elicitation_request_param_to_json(request),
1744 [](
const protocol::Json& payload) {
1745 return protocol::create_elicitation_result_from_json(payload);
1747 std::move(options));
1750 RequestHandle<protocol::Json> create_elicitation_async(
1751 const protocol::Json& request, RequestOptions options = {}) {
1752 return request_async(std::string(protocol::ElicitationCreateMethod),
1753 request, std::move(options));
1756 RequestHandle<std::vector<protocol::Task>> list_tasks_async(
1757 RequestOptions options = {}) {
1758 if (!supports_server_task_list()) {
1759 return RequestHandle<std::vector<protocol::Task>>::ready(
1760 next_peer_request_id(),
1761 mcp::core::unexpected(unsupported_server_capability(
1762 "server does not support task listing")));
1764 return request_async<std::vector<protocol::Task>>(
1765 std::string(protocol::TasksListMethod), protocol::Json::object(),
1766 [](
const protocol::Json& payload)
1767 -> core::Result<std::vector<protocol::Task>> {
1768 const auto result = protocol::task_list_result_from_json(payload);
1772 return result->tasks;
1774 std::move(options));
1777 RequestHandle<protocol::Task> get_task_async(
1778 const protocol::TaskGetParams& request, RequestOptions options = {}) {
1779 if (!supports_server_tasks()) {
1781 next_peer_request_id(),
1782 mcp::core::unexpected(
1783 unsupported_server_capability(
"server does not support tasks")));
1785 return request_async<protocol::Task>(
1786 std::string(protocol::TasksGetMethod),
1787 protocol::task_get_params_to_json(request),
1788 [](
const protocol::Json& payload) {
1789 return protocol::task_from_json(payload);
1791 std::move(options));
1794 RequestHandle<protocol::Task> get_task_async(std::string_view task_id,
1795 RequestOptions options = {}) {
1796 protocol::TaskGetParams params;
1797 params.task_id = std::string(task_id);
1798 return get_task_async(params, std::move(options));
1801 RequestHandle<protocol::Task> cancel_task_async(
1802 const protocol::TaskCancelParams& request, RequestOptions options = {}) {
1803 if (!supports_server_task_cancel()) {
1805 next_peer_request_id(),
1806 mcp::core::unexpected(unsupported_server_capability(
1807 "server does not support task cancellation")));
1809 return request_async<protocol::Task>(
1810 std::string(protocol::TasksCancelMethod),
1811 protocol::task_cancel_params_to_json(request),
1812 [](
const protocol::Json& payload) {
1813 return protocol::task_from_json(payload);
1815 std::move(options));
1818 RequestHandle<protocol::Task> cancel_task_async(std::string_view task_id,
1819 RequestOptions options = {}) {
1820 protocol::TaskCancelParams params;
1821 params.task_id = std::string(task_id);
1822 return cancel_task_async(params, std::move(options));
1825 RequestHandle<protocol::Json> task_result_async(
1826 const protocol::TaskResultParams& request, RequestOptions options = {}) {
1827 if (!supports_server_tasks()) {
1829 next_peer_request_id(),
1830 mcp::core::unexpected(
1831 unsupported_server_capability(
"server does not support tasks")));
1833 return request_async(std::string(protocol::TasksResultMethod),
1834 protocol::task_result_params_to_json(request),
1835 std::move(options));
1838 RequestHandle<protocol::Json> task_result_async(std::string_view task_id,
1839 RequestOptions options = {}) {
1840 protocol::TaskResultParams params;
1841 params.task_id = std::string(task_id);
1842 return task_result_async(params, std::move(options));
1845 core::Result<core::Unit> raw_notification(
1846 const protocol::JsonRpcNotification& notification) {
1847 if (native_transport_) {
1848 return native_transport_->send(protocol::JsonRpcMessage{notification});
1850 return client_.raw_notification(notification);
1860 if (
const auto* request = std::get_if<protocol::JsonRpcRequest>(&message)) {
1861 auto handled = native_transport_ ? handle_native_request(*request)
1862 : client_.handle_request(*request);
1866 detail::peer_error_object_from_core_error(handled.error()))};
1871 if (
const auto* notification =
1872 std::get_if<protocol::JsonRpcNotification>(&message)) {
1873 const auto handled = native_transport_
1874 ? handle_native_notification(*notification)
1875 : client_.handle_notification(*notification);
1877 return mcp::core::unexpected(handled.error());
1879 return std::nullopt;
1882 if (
const auto* response =
1883 std::get_if<protocol::JsonRpcResponse>(&message)) {
1884 if (native_transport_) {
1885 auto stored = store_native_response(*response);
1887 return mcp::core::unexpected(stored.error());
1889 return std::nullopt;
1893 return mcp::core::unexpected(detail::peer_dispatch_error(
1894 "client peer cannot dispatch an uncorrelated response"));
1902 return detail::serve_transport_loop(
1903 transport, cancellation,
1905 return dispatch_message(message);
1910 std::int64_t next_peer_request_id() noexcept {
1911 return next_request_id_->fetch_add(1, std::memory_order_relaxed);
1914 void cache_tool_schemas(
const std::vector<protocol::ToolDefinition>& tools) {
1915 for (
const auto& tool : tools) {
1916 tool_schema_cache_[tool.name] = tool.input_schema;
1920 void apply_x_mcp_headers(protocol::JsonRpcRequest& request,
1921 const protocol::ToolCall& call) {
1922 auto it = tool_schema_cache_.find(call.name);
1923 if (it == tool_schema_cache_.end())
return;
1924 auto entries = protocol::extract_x_mcp_headers(it->second);
1925 if (entries.empty())
return;
1926 auto param_headers =
1927 protocol::build_tool_param_headers(call.arguments, entries);
1928 for (
auto& [key, value] : param_headers) {
1929 request.transport_headers.emplace(std::move(key), std::move(value));
1933 bool native_receive_loop_active()
const {
1934 std::lock_guard<std::mutex> lock(native_receive_state_->mutex);
1935 return native_receive_state_->loop_active;
1938 core::Result<core::Unit> start_native_receive_loop(
1939 CancellationToken cancellation) {
1941 std::lock_guard<std::mutex> lock(native_receive_state_->mutex);
1942 if (native_receive_state_->loop_active) {
1944 "client peer receive loop is already running"));
1946 native_receive_state_->loop_active =
true;
1947 native_receive_state_->closed =
false;
1948 native_receive_state_->failure.reset();
1949 native_receive_state_->responses.clear();
1952 auto finished = detail::serve_transport_loop(
1953 *native_transport_, cancellation,
1954 [
this](
const protocol::JsonRpcMessage& message) {
1955 return dispatch_message(message);
1959 std::lock_guard<std::mutex> lock(native_receive_state_->mutex);
1960 native_receive_state_->loop_active =
false;
1961 native_receive_state_->closed =
true;
1963 native_receive_state_->failure = finished.error();
1966 native_receive_state_->cv.notify_all();
1970 core::Result<core::Unit> store_native_response(
1971 const protocol::JsonRpcResponse& response) {
1972 if (!response.id.has_value()) {
1974 "client peer received a response without an id"));
1976 std::lock_guard<std::mutex> lock(native_receive_state_->mutex);
1977 native_receive_state_
1978 ->responses[detail::peer_request_cancellation_key(*response.id)] =
1980 native_receive_state_->cv.notify_all();
1981 return core::Unit{};
1984 core::Result<protocol::JsonRpcResponse> wait_native_response(
1985 const protocol::RequestId& request_id) {
1986 const auto key = detail::peer_request_cancellation_key(request_id);
1987 std::unique_lock<std::mutex> lock(native_receive_state_->mutex);
1988 native_receive_state_->cv.wait(lock, [&] {
1989 return native_receive_state_->responses.find(key) !=
1990 native_receive_state_->responses.end() ||
1991 native_receive_state_->failure.has_value() ||
1992 native_receive_state_->closed;
1995 const auto found = native_receive_state_->responses.find(key);
1996 if (found != native_receive_state_->responses.end()) {
1997 auto response = std::move(found->second);
1998 native_receive_state_->responses.erase(found);
2001 if (native_receive_state_->failure.has_value()) {
2005 "client peer transport closed before response"));
2008 std::optional<protocol::JsonRpcResponse> take_native_response(
2009 const protocol::RequestId& request_id) {
2010 const auto key = detail::peer_request_cancellation_key(request_id);
2011 std::lock_guard<std::mutex> lock(native_receive_state_->mutex);
2012 const auto found = native_receive_state_->responses.find(key);
2013 if (found == native_receive_state_->responses.end()) {
2014 return std::nullopt;
2016 auto response = std::move(found->second);
2017 native_receive_state_->responses.erase(found);
2021 static protocol::JsonRpcResponse native_error_response(
2022 const protocol::JsonRpcRequest& request,
const core::Error& error) {
2023 return protocol::make_error_response(
2024 std::optional<protocol::RequestId>{request.id},
2025 protocol::make_error(
2026 error.code, error.message,
2027 error.detail.empty()
2029 : std::optional<protocol::Json>{error.detail}));
2032 static protocol::JsonRpcResponse native_error_response(
2033 const protocol::JsonRpcRequest& request, protocol::ErrorCode code,
2034 std::string message, std::string detail = {}) {
2035 return protocol::make_error_response(
2036 std::optional<protocol::RequestId>{request.id},
2037 protocol::make_error(
2038 code, std::move(message),
2039 detail.empty() ? std::nullopt
2040 : std::optional<protocol::Json>{std::move(detail)}));
2044 const protocol::RequestId& request_id) {
2045 CancellationSource source;
2046 auto token = source.token();
2047 std::lock_guard lock(*client_request_cancellations_mutex_);
2048 (*client_request_cancellations_)[detail::peer_request_cancellation_key(
2049 request_id)] = std::move(source);
2053 void end_client_request_cancellation(
2054 const protocol::RequestId& request_id)
noexcept {
2055 std::lock_guard lock(*client_request_cancellations_mutex_);
2056 client_request_cancellations_->erase(
2057 detail::peer_request_cancellation_key(request_id));
2060 void cancel_client_request(
const protocol::RequestId& request_id)
noexcept {
2061 std::lock_guard lock(*client_request_cancellations_mutex_);
2062 const auto it = client_request_cancellations_->find(
2063 detail::peer_request_cancellation_key(request_id));
2064 if (it != client_request_cancellations_->end()) {
2065 it->second.cancel();
2069 core::Result<core::Unit> handle_native_notification(
2070 const protocol::JsonRpcNotification& notification)
try {
2071 if (notification.method == std::string(protocol::InitializedMethod) &&
2072 initialized_handler_) {
2073 initialized_handler_();
2074 }
else if (notification.method ==
2075 std::string(protocol::CancelledNotificationMethod)) {
2076 const auto params = protocol::cancelled_notification_params_from_json(
2077 notification.params);
2080 errors::make(protocol::ErrorCode::InvalidParams,
2081 "cancelled notification requires a requestId"));
2083 cancel_client_request(params->request_id);
2084 if (cancelled_handler_) {
2085 cancelled_handler_(params->request_id,
2086 params->reason.value_or(std::string{}));
2088 }
else if (notification.method ==
2089 std::string(protocol::LoggingMessageNotificationMethod) &&
2090 logging_message_handler_) {
2092 std::string message;
2093 if (notification.params.is_object()) {
2094 if (notification.params.contains(
"level") &&
2095 notification.params.at(
"level").is_string()) {
2096 level = notification.params.at(
"level").get<std::string>();
2098 if (notification.params.contains(
"data")) {
2099 if (notification.params.at(
"data").is_string()) {
2100 message = notification.params.at(
"data").get<std::string>();
2102 message = notification.params.at(
"data").dump();
2106 logging_message_handler_(level, message);
2107 }
else if (notification.method ==
2108 std::string(protocol::ToolsListChangedNotificationMethod) &&
2109 tool_list_changed_handler_) {
2110 tool_list_changed_handler_();
2111 }
else if (notification.method ==
2113 protocol::PromptsListChangedNotificationMethod) &&
2114 prompt_list_changed_handler_) {
2115 prompt_list_changed_handler_();
2116 }
else if (notification.method ==
2118 protocol::ResourcesListChangedNotificationMethod) &&
2119 resource_list_changed_handler_) {
2120 resource_list_changed_handler_();
2121 }
else if (notification.method ==
2122 std::string(protocol::ResourcesUpdatedNotificationMethod) &&
2123 resource_updated_handler_) {
2124 if (!notification.params.is_object() ||
2125 !notification.params.contains(
"uri") ||
2126 !notification.params.at(
"uri").is_string()) {
2128 protocol::ErrorCode::InvalidParams,
2129 "resource updated notification requires a string uri"));
2131 resource_updated_handler_(
2132 notification.params.at(
"uri").get<std::string>());
2133 }
else if (notification.method ==
2134 std::string(protocol::ProgressNotificationMethod) &&
2135 progress_handler_) {
2137 protocol::progress_notification_params_from_json(notification.params);
2140 errors::make(protocol::ErrorCode::InvalidParams,
2141 "progress notification requires valid params"));
2143 progress_handler_(*params);
2144 }
else if (notification.method ==
2146 protocol::ElicitationCompleteNotificationMethod) &&
2147 elicitation_complete_handler_) {
2149 protocol::elicitation_complete_notification_params_from_json(
2150 notification.params);
2153 protocol::ErrorCode::InvalidParams,
2154 "elicitation completion notification requires valid params"));
2156 elicitation_complete_handler_(params->elicitation_id);
2157 }
else if (notification.method ==
2158 std::string(protocol::TasksStatusNotificationMethod) &&
2159 task_status_handler_) {
2160 const auto task = protocol::task_from_json(notification.params);
2163 errors::make(protocol::ErrorCode::InvalidParams,
2164 "task status notification requires valid task data"));
2166 task_status_handler_(*task);
2167 }
else if (notification.method ==
2168 std::string(protocol::RootsListChangedNotificationMethod) &&
2169 roots_list_changed_handler_) {
2170 roots_list_changed_handler_();
2173 if (raw_notification_handler_) {
2174 raw_notification_handler_(notification);
2176 return core::Unit{};
2177 }
catch (
const std::exception& ex) {
2183 core::Result<protocol::JsonRpcResponse> handle_native_request(
2184 const protocol::JsonRpcRequest& request)
try {
2185 if (request.method == std::string(protocol::PingMethod)) {
2186 return protocol::make_response(request.id, protocol::Json::object());
2189 const auto request_cancellation =
2190 begin_client_request_cancellation(request.id);
2191 const std::shared_ptr<void> request_cancellation_cleanup(
2192 nullptr, [
this, request_id = request.id](
void*)
noexcept {
2193 end_client_request_cancellation(request_id);
2196 if (request.method == std::string(protocol::RootsListMethod)) {
2197 if (roots_list_request_cancellation_handler_) {
2199 roots_list_request_cancellation_handler_(request_cancellation);
2201 return native_error_response(request, roots.error());
2203 return protocol::make_response(
2204 request.id, protocol::roots_list_result_to_json(*roots));
2206 if (roots_list_request_handler_) {
2207 const auto roots = roots_list_request_handler_();
2209 return native_error_response(request, roots.error());
2211 return protocol::make_response(
2212 request.id, protocol::roots_list_result_to_json(*roots));
2215 protocol::RootsListResult result;
2216 result.roots = roots_;
2217 return protocol::make_response(
2218 request.id, protocol::roots_list_result_to_json(result));
2221 if (request.method == std::string(protocol::SamplingCreateMessageMethod)) {
2222 if (!sampling_request_handler_ &&
2223 !sampling_request_cancellation_handler_) {
2224 return native_error_response(
2225 request, protocol::ErrorCode::MethodNotFound,
2226 "sampling request handler is not configured");
2229 protocol::create_message_params_from_json(request.params);
2231 return detail::peer_params_error_response(request, params.error());
2233 const auto result = sampling_request_cancellation_handler_
2234 ? sampling_request_cancellation_handler_(
2235 *params, request_cancellation)
2236 : sampling_request_handler_(*params);
2238 return native_error_response(request, result.error());
2240 return protocol::make_response(
2241 request.id, protocol::create_message_result_to_json(*result));
2244 if (request.method == std::string(protocol::ElicitationCreateMethod)) {
2246 protocol::create_elicitation_request_param_from_json(request.params);
2248 return detail::peer_params_error_response(request, params.error());
2250 if (!elicitation_request_handler_ &&
2251 !elicitation_request_cancellation_handler_) {
2252 protocol::CreateElicitationResult decline_result;
2253 decline_result.action = protocol::ElicitationAction::Decline;
2254 return protocol::make_response(
2256 protocol::create_elicitation_result_to_json(decline_result));
2258 const auto result = elicitation_request_cancellation_handler_
2259 ? elicitation_request_cancellation_handler_(
2260 *params, request_cancellation)
2261 : elicitation_request_handler_(*params);
2263 return native_error_response(request, result.error());
2265 const auto capabilities =
2266 detail::default_peer_client_capabilities(client_capabilities_);
2267 if (params->mode == protocol::ElicitationMode::Form &&
2268 capabilities.elicitation.form_schema_validation) {
2269 const auto valid = protocol::validate_elicitation_result_content(
2270 params->requested_schema, *result);
2272 return native_error_response(
2274 errors::make(protocol::ErrorCode::InternalError,
2275 "elicitation result failed schema validation",
2276 valid.error().message));
2279 return protocol::make_response(
2280 request.id, protocol::create_elicitation_result_to_json(*result));
2283 if (custom_request_cancellation_handler_ || custom_request_handler_) {
2284 const auto result = custom_request_cancellation_handler_
2285 ? custom_request_cancellation_handler_(
2286 request, request_cancellation)
2287 : custom_request_handler_(request);
2289 return native_error_response(request, result.error());
2291 return protocol::make_response(request.id, std::move(*result));
2294 return native_error_response(request, protocol::ErrorCode::MethodNotFound,
2295 "method not found", request.method);
2296 }
catch (
const std::exception& ex) {
2297 return native_error_response(request, errors::handler_failed(ex.what()));
2299 return native_error_response(request, errors::handler_unknown_exception());
2302 static core::Error unsupported_server_capability(std::string message) {
2303 return errors::make(protocol::ErrorCode::MethodNotFound, std::move(message),
2307 core::Result<core::Unit> record_server_capabilities(
2308 const protocol::Json& initialize_payload) {
2312 if (initialize_payload.is_object() &&
2313 !initialize_payload.contains(
"protocolVersion")) {
2314 return core::Unit{};
2318 protocol::initialize_result_from_json(initialize_payload);
2319 if (!parsed.has_value()) {
2321 protocol::ErrorCode::InvalidRequest, parsed.error().message,
2322 parsed.error().detail,
"protocol"));
2324 server_capabilities_ = parsed->capabilities;
2325 return core::Unit{};
2328 bool supports_server_completion() const noexcept {
2330 return !capabilities.has_value() || capabilities->completions.enabled;
2333 bool supports_server_logging() const noexcept {
2335 return !capabilities.has_value() || capabilities->logging.enabled;
2338 bool supports_server_resource_subscribe() const noexcept {
2340 return !capabilities.has_value() || capabilities->resources.subscribe;
2343 bool supports_server_task_list() const noexcept {
2345 return !capabilities.has_value() ||
2346 (capabilities->tasks.has_value() && capabilities->tasks->list);
2349 bool supports_server_task_cancel() const noexcept {
2351 return !capabilities.has_value() ||
2352 (capabilities->tasks.has_value() && capabilities->tasks->cancel);
2355 bool supports_server_tasks() const noexcept {
2357 return !capabilities.has_value() || capabilities->tasks.has_value();
2360 bool supports_server_task_tool_call() const noexcept {
2362 return !capabilities.has_value() ||
2363 (capabilities->tasks.has_value() && capabilities->tasks->tools_call);
2366 core::Result<protocol::Json> request_json(std::string method,
2367 protocol::Json params) {
2368 return raw_request(protocol::make_request(
2369 std::move(method), next_peer_request_id(), std::move(params)));
2372 core::Result<core::Unit> request_unit(std::string method,
2373 protocol::Json params) {
2374 auto payload = request_json(std::move(method), std::move(params));
2378 return core::Unit{};
2381 static protocol::Json cursor_params(
2382 const std::optional<std::string>& cursor) {
2383 protocol::Json params = protocol::Json::object();
2384 if (cursor.has_value()) {
2385 params[
"cursor"] = *cursor;
2390 template <
class Item,
class Parser,
class Append>
2391 core::Result<std::vector<Item>> list_all_pages(std::string method,
2392 Parser parser, Append append) {
2393 std::vector<Item> all;
2394 std::optional<std::string> cursor;
2396 auto payload = request_json(method, cursor_params(cursor));
2400 auto page = parser(*payload);
2405 cursor = page->next_cursor;
2406 }
while (cursor.has_value() && !cursor->empty());
2410 core::Result<protocol::JsonRpcResponse> send_native_request(
2411 const protocol::JsonRpcRequest& request) {
2412 std::lock_guard<std::mutex> request_lock(*native_request_mutex_);
2414 auto sent = native_transport_->send(protocol::JsonRpcMessage{request});
2419 if (native_receive_loop_active()) {
2420 return wait_native_response(request.id);
2423 if (
auto buffered = take_native_response(request.id)) {
2428 auto received = native_transport_->receive();
2432 if (!received->has_value()) {
2434 "client peer transport closed before response"));
2437 if (
auto* response =
2438 std::get_if<protocol::JsonRpcResponse>(&received->value())) {
2439 if (response->id.has_value() && *response->id == request.id) {
2442 auto stored = store_native_response(*response);
2449 auto dispatched = dispatch_message(received->value());
2453 if (dispatched->has_value()) {
2454 sent = native_transport_->send(std::move(dispatched->value()));
2462 std::unique_ptr<transport::ClientTransport> native_transport_;
2463 std::shared_ptr<std::mutex> native_request_mutex_ =
2464 std::make_shared<std::mutex>();
2465 std::shared_ptr<detail::ClientNativeReceiveState> native_receive_state_ =
2466 std::make_shared<detail::ClientNativeReceiveState>();
2467 std::shared_ptr<std::atomic<std::int64_t>> next_request_id_ =
2468 std::make_shared<std::atomic<std::int64_t>>(1);
2469 std::optional<protocol::ClientCapabilities> client_capabilities_;
2470 std::optional<protocol::ServerCapabilities> server_capabilities_;
2471 std::vector<protocol::Root> roots_;
2484 client::Client::RootsListRequestCancellationHandler
2485 roots_list_request_cancellation_handler_;
2487 client::Client::SamplingRequestCancellationHandler
2488 sampling_request_cancellation_handler_;
2490 client::Client::ElicitationRequestCancellationHandler
2491 elicitation_request_cancellation_handler_;
2493 client::Client::CustomRequestCancellationHandler
2494 custom_request_cancellation_handler_;
2496 std::shared_ptr<std::mutex> client_request_cancellations_mutex_ =
2497 std::make_shared<std::mutex>();
2498 std::shared_ptr<std::unordered_map<std::string, CancellationSource>>
2499 client_request_cancellations_ = std::make_shared<
2500 std::unordered_map<std::string, CancellationSource>>();
2501 client::Client client_;
2502 std::unordered_map<std::string, protocol::Json> tool_schema_cache_;
3001 : server_(std::make_unique<server::Server>(std::move(options))) {}
3004 explicit Peer(std::unique_ptr<server::Server> server)
3005 : server_(std::move(server)) {}
3008 auto built = builder.
build();
3010 return mcp::core::unexpected(built.error());
3012 return Peer(std::move(*built));
3016 static Builder builder();
3019 "server() is a compatibility escape hatch; prefer ServerPeer methods")
3020 server::Server& server() noexcept {
return *server_; }
3023 "server() is a compatibility escape hatch; prefer ServerPeer methods")
3024 const server::Server& server() const noexcept {
return *server_; }
3026 server::ServerInfo get_info()
const {
return server_->get_info(); }
3028 const protocol::ServerCapabilities& capabilities() const noexcept {
3029 return server_->capabilities();
3034 completion_handler_ = [handler](
const protocol::Json& params,
3035 const server::SessionContext&)
mutable {
3036 return handler(params);
3039 completion_handler_ = {};
3041 server_->set_completion_handler(std::move(handler));
3045 Peer& set_completion_handler(server::Server::JsonContextHandler handler) {
3046 completion_handler_ = handler;
3047 server_->set_completion_handler(std::move(handler));
3053 sampling_handler_ = [handler](
const protocol::Json& params,
3054 const server::SessionContext&)
mutable {
3055 return handler(params);
3058 sampling_handler_ = {};
3060 server_->set_sampling_handler(std::move(handler));
3064 Peer& set_sampling_handler(server::Server::JsonContextHandler handler) {
3065 sampling_handler_ = handler;
3066 server_->set_sampling_handler(std::move(handler));
3071 logging_handler_ = handler;
3072 server_->set_logging_handler(std::move(handler));
3077 raw_request_handler_ = handler;
3078 server_->set_raw_request_handler(std::move(handler));
3082 Peer& set_raw_request_handler(
3083 server::Server::RawRequestContextHandler handler) {
3084 raw_request_context_handler_ = handler;
3085 server_->set_raw_request_handler(std::move(handler));
3089 Peer& set_raw_notification_handler(
3091 native_notification_state_ =
true;
3092 raw_notification_handler_ = handler;
3093 server_->set_raw_notification_handler(std::move(handler));
3098 raw_request_handler_ = handler;
3099 server_->set_custom_request_handler(std::move(handler));
3103 Peer& set_custom_request_handler(
3104 server::Server::RawRequestContextHandler handler) {
3105 raw_request_context_handler_ = handler;
3106 server_->set_custom_request_handler(std::move(handler));
3110 Peer& set_custom_notification_handler(
3112 native_notification_state_ =
true;
3113 raw_notification_handler_ = handler;
3114 server_->set_custom_notification_handler(std::move(handler));
3119 server_->set_tools_list_handler(std::move(handler));
3124 server_->set_prompts_list_handler(std::move(handler));
3128 Peer& set_resources_list_handler(
3130 server_->set_resources_list_handler(std::move(handler));
3134 Peer& set_resource_templates_list_handler(
3136 server_->set_resource_templates_list_handler(std::move(handler));
3141 task_list_handler_ = handler;
3142 server_->set_task_list_handler(std::move(handler));
3147 task_get_handler_ = handler;
3148 server_->set_task_get_handler(std::move(handler));
3153 task_cancel_handler_ = handler;
3154 server_->set_task_cancel_handler(std::move(handler));
3159 task_result_handler_ = handler;
3160 server_->set_task_result_handler(std::move(handler));
3165 native_notification_state_ =
true;
3166 progress_handler_ = handler;
3167 server_->set_progress_handler(std::move(handler));
3171 Peer& set_roots_list_changed_handler(
3173 native_notification_state_ =
true;
3174 roots_list_changed_handler_ = handler;
3175 server_->set_roots_list_changed_handler(std::move(handler));
3179 Peer& set_tool_list_changed_handler(
3181 native_notification_state_ =
true;
3182 tool_list_changed_handler_ = handler;
3183 server_->set_tool_list_changed_handler(std::move(handler));
3187 Peer& set_prompt_list_changed_handler(
3189 native_notification_state_ =
true;
3190 prompt_list_changed_handler_ = handler;
3191 server_->set_prompt_list_changed_handler(std::move(handler));
3195 Peer& set_resource_list_changed_handler(
3197 native_notification_state_ =
true;
3198 resource_list_changed_handler_ = handler;
3199 server_->set_resource_list_changed_handler(std::move(handler));
3203 Peer& set_resource_updated_handler(
3205 native_notification_state_ =
true;
3206 resource_updated_handler_ = handler;
3207 server_->set_resource_updated_handler(std::move(handler));
3211 Peer& set_handler(
const server::ServerHandler& handler) {
3212 if (handler.on_completion) {
3213 set_completion_handler(handler.on_completion);
3215 if (handler.on_sampling) {
3216 set_sampling_handler(handler.on_sampling);
3218 if (handler.on_logging) {
3219 set_logging_handler(handler.on_logging);
3221 if (handler.on_raw_request) {
3222 set_raw_request_handler(handler.on_raw_request);
3224 if (handler.on_raw_notification) {
3225 set_raw_notification_handler(handler.on_raw_notification);
3227 if (handler.on_custom_request) {
3228 set_custom_request_handler(handler.on_custom_request);
3230 if (handler.on_custom_notification) {
3231 set_custom_notification_handler(handler.on_custom_notification);
3233 if (handler.on_tools_list) {
3234 set_tools_list_handler(handler.on_tools_list);
3236 if (handler.on_prompts_list) {
3237 set_prompts_list_handler(handler.on_prompts_list);
3239 if (handler.on_resources_list) {
3240 set_resources_list_handler(handler.on_resources_list);
3242 if (handler.on_resource_templates_list) {
3243 set_resource_templates_list_handler(handler.on_resource_templates_list);
3245 if (handler.on_task_list) {
3246 set_task_list_handler(handler.on_task_list);
3248 if (handler.on_task_get) {
3249 set_task_get_handler(handler.on_task_get);
3251 if (handler.on_task_cancel) {
3252 set_task_cancel_handler(handler.on_task_cancel);
3254 if (handler.on_task_result) {
3255 set_task_result_handler(handler.on_task_result);
3257 if (handler.on_progress) {
3258 set_progress_handler(handler.on_progress);
3260 if (handler.on_roots_list_changed) {
3261 set_roots_list_changed_handler(handler.on_roots_list_changed);
3263 if (handler.on_tool_list_changed) {
3264 set_tool_list_changed_handler(handler.on_tool_list_changed);
3266 if (handler.on_prompt_list_changed) {
3267 set_prompt_list_changed_handler(handler.on_prompt_list_changed);
3269 if (handler.on_resource_list_changed) {
3270 set_resource_list_changed_handler(handler.on_resource_list_changed);
3272 if (handler.on_resource_updated) {
3273 set_resource_updated_handler(handler.on_resource_updated);
3275 if (handler.on_completion_with_context) {
3276 set_completion_handler(handler.on_completion_with_context);
3278 if (handler.on_sampling_with_context) {
3279 set_sampling_handler(handler.on_sampling_with_context);
3284 Peer& set_handler(
const server::ServerHandlerInterface& handler) {
3285 server_->set_handler(handler);
3286 set_raw_request_handler([&handler](
const protocol::JsonRpcRequest& request,
3287 const server::SessionContext& context,
3288 CancellationToken cancellation)
3289 -> std::optional<protocol::JsonRpcResponse> {
3290 const auto handler_response = server::dispatch_server_handler_request(
3291 handler, request, context, cancellation);
3292 if (handler_response.has_value()) {
3293 return handler_response;
3295 return handler.on_custom_request(request, context);
3300 std::vector<protocol::ToolDefinition> list_tools()
const {
3301 return server_->list_tools();
3304 core::Result<protocol::ToolDefinition> get_tool(std::string_view name)
const {
3305 return server_->get_tool(name);
3308 core::Result<protocol::ToolResult> call_tool(
3309 std::string_view name,
3310 protocol::Json arguments = protocol::Json::object(),
3311 const std::string& session_id = {})
const {
3312 return server_->call_tool(name, std::move(arguments), session_id);
3315 core::Result<protocol::ToolResult> call_tool(
3316 std::string_view name, protocol::Json arguments,
3317 const server::SessionContext& context,
3319 return server_->call_tool(name, std::move(arguments), context,
3323 std::vector<protocol::Prompt> list_prompts()
const {
3324 return server_->list_prompts();
3327 core::Result<protocol::PromptsGetResult> get_prompt(
3328 std::string_view name,
3329 protocol::Json arguments = protocol::Json::object(),
3330 const std::string& session_id = {})
const {
3331 return server_->get_prompt(name, std::move(arguments), session_id);
3334 core::Result<protocol::PromptsGetResult> get_prompt(
3335 std::string_view name, protocol::Json arguments,
3336 const server::SessionContext& context,
3338 return server_->get_prompt(name, std::move(arguments), context,
3342 std::vector<protocol::Resource> list_resources()
const {
3343 return server_->list_resources();
3346 core::Result<protocol::ResourcesReadResult> read_resource(
3347 std::string_view uri, protocol::Json params = protocol::Json::object(),
3348 const std::string& session_id = {})
const {
3349 return server_->read_resource(uri, std::move(params), session_id);
3352 core::Result<protocol::ResourcesReadResult> read_resource(
3353 std::string_view uri, protocol::Json params,
3354 const server::SessionContext& context,
3356 return server_->read_resource(uri, std::move(params), context,
3360 std::vector<protocol::ResourceTemplate> list_resource_templates()
const {
3361 return server_->list_resource_templates();
3364 core::Result<protocol::Json> initialize() {
return server_->initialize(); }
3366 core::Result<protocol::Json> ping(
3367 const server::SessionContext& context = {}) {
3368 return server_->ping(context);
3371 core::Result<protocol::JsonRpcResponse> handle_request(
3372 const protocol::JsonRpcRequest& request,
3373 const server::SessionContext& input_context = {},
3374 transport::ServerTransport* native_transport =
nullptr)
try {
3375 auto authenticated_context = server_->authenticate_context(input_context);
3376 if (!authenticated_context) {
3377 return detail::peer_auth_error_response(request,
3378 authenticated_context.error());
3380 server::SessionContext context = std::move(*authenticated_context);
3382 if (request.method == protocol::InitializeMethod) {
3384 detail::validate_peer_server_initialize_params(request.params);
3386 return detail::peer_error_response(request, valid.error());
3388 const auto requested_version =
3389 request.params.at(
"protocolVersion").get<std::string>();
3390 const auto negotiated_version =
3391 protocol::negotiate_protocol_version(requested_version);
3392 if (!negotiated_version.has_value()) {
3393 return detail::peer_error_response(
3394 request, core::Error{
3395 static_cast<int>(protocol::ErrorCode::InvalidParams),
3396 "unsupported MCP protocol version(\"" +
3397 requested_version +
"\")",
3402 return protocol::make_response(
3403 request.id, detail::make_peer_server_initialize_result(
3404 get_info(), capabilities(), *negotiated_version));
3406 if (request.method == protocol::PingMethod) {
3407 return protocol::make_response(request.id, protocol::Json::object());
3410 if (raw_request_context_handler_) {
3411 const auto request_cancellation =
3412 begin_peer_request_cancellation(request.id);
3413 const std::shared_ptr<void> request_cancellation_cleanup(
3414 nullptr, [
this, request_id = request.id](
void*)
noexcept {
3415 end_peer_request_cancellation(request_id);
3417 const auto raw_response =
3418 raw_request_context_handler_(request, context, request_cancellation);
3419 if (raw_response.has_value()) {
3420 return *raw_response;
3424 if (raw_request_handler_) {
3425 const auto raw_response = raw_request_handler_(request, context);
3426 if (raw_response.has_value()) {
3427 return *raw_response;
3431 if (request.method == protocol::ToolsListMethod) {
3433 protocol::paginated_request_params_from_json(request.params);
3435 return detail::peer_error_response(
3436 request, errors::make(protocol::ErrorCode::InvalidParams,
3437 "tools/list params must be an object with an "
3438 "optional string cursor"));
3440 const auto result = server_->list_tools(*params, context);
3442 return detail::peer_error_response(request, result.error());
3444 return protocol::make_response(
3445 request.id, protocol::tools_list_result_to_json(*result));
3448 if (request.method == protocol::ToolsGetMethod) {
3449 if (!request.params.is_object() || !request.params.contains(
"name") ||
3450 !request.params.at(
"name").is_string()) {
3451 return detail::peer_error_response(
3452 request, errors::make(protocol::ErrorCode::InvalidParams,
3453 "tools/get requires a string name"));
3456 const auto tool = get_tool(request.params.at(
"name").get<std::string>());
3458 return detail::peer_error_response(request,
tool.error());
3460 return protocol::make_response(request.id,
3461 protocol::tool_definition_to_json(*tool));
3464 if (request.method == protocol::ToolsCallMethod) {
3465 const auto call = protocol::tool_call_from_json(request.params);
3467 return detail::peer_params_error_response(request, call.error());
3469 if (call->task.has_value()) {
3470 const auto valid = server_->tools().validate(*call);
3472 return detail::peer_params_error_response(request, valid.error());
3474 const auto task_manager = server_->task_manager();
3475 if (!task_manager) {
3476 return detail::peer_error_response(
3477 request, errors::make(protocol::ErrorCode::MethodNotFound,
3478 "task processor is not configured"));
3481 task_manager->submit_tool_call(server_->tools(), *call, context,
3482 server_->schema_validator().get());
3484 return detail::peer_params_error_response(request, task.error());
3486 return protocol::make_response(
3487 request.id, protocol::create_task_result_to_json(*task));
3490 const auto request_cancellation =
3491 begin_peer_request_cancellation(request.id);
3492 const std::shared_ptr<void> request_cancellation_cleanup(
3493 nullptr, [
this, request_id = request.id](
void*)
noexcept {
3494 end_peer_request_cancellation(request_id);
3497 server_->tools().call(*call, context, request_cancellation,
3498 server_->schema_validator().get());
3500 return detail::peer_error_response(request, result.error());
3503 return protocol::make_response(request.id,
3504 protocol::tool_result_to_json(*result));
3507 if (request.method == protocol::PromptsListMethod) {
3509 protocol::paginated_request_params_from_json(request.params);
3511 return detail::peer_error_response(
3513 errors::make(protocol::ErrorCode::InvalidParams,
3514 "prompts/list params must be an object with an "
3515 "optional string cursor"));
3517 const auto result = server_->list_prompts(*params, context);
3519 return detail::peer_error_response(request, result.error());
3521 return protocol::make_response(
3522 request.id, protocol::prompts_list_result_to_json(*result));
3525 if (request.method == protocol::PromptsGetMethod) {
3527 protocol::prompts_get_params_from_json(request.params);
3529 return detail::peer_params_error_response(request, params.error());
3532 const auto request_cancellation =
3533 begin_peer_request_cancellation(request.id);
3534 const std::shared_ptr<void> request_cancellation_cleanup(
3535 nullptr, [
this, request_id = request.id](
void*)
noexcept {
3536 end_peer_request_cancellation(request_id);
3538 const auto result = server_->prompts().get(
3539 params->name, params->arguments, context, request_cancellation);
3541 return detail::peer_error_response(request, result.error());
3544 return protocol::make_response(
3545 request.id, protocol::prompts_get_result_to_json(*result));
3548 if (request.method == protocol::ResourcesListMethod) {
3550 protocol::paginated_request_params_from_json(request.params);
3552 return detail::peer_error_response(
3554 errors::make(protocol::ErrorCode::InvalidParams,
3555 "resources/list params must be an object with an "
3556 "optional string cursor"));
3558 const auto result = server_->list_resources(*params, context);
3560 return detail::peer_error_response(request, result.error());
3562 return protocol::make_response(
3563 request.id, protocol::resources_list_result_to_json(*result));
3566 if (request.method == protocol::ResourcesReadMethod) {
3568 protocol::resources_read_params_from_json(request.params);
3570 return detail::peer_params_error_response(request, params.error());
3573 const auto request_cancellation =
3574 begin_peer_request_cancellation(request.id);
3575 const std::shared_ptr<void> request_cancellation_cleanup(
3576 nullptr, [
this, request_id = request.id](
void*)
noexcept {
3577 end_peer_request_cancellation(request_id);
3579 auto result = server_->resources().read(params->uri, request.params,
3580 context, request_cancellation);
3582 return detail::peer_error_response(request, result.error());
3584 result->ttl_ms = 300000;
3585 result->cache_scope =
"public";
3587 return protocol::make_response(
3588 request.id, protocol::resources_read_result_to_json(*result));
3591 if (request.method == protocol::ResourcesTemplatesListMethod) {
3593 protocol::paginated_request_params_from_json(request.params);
3595 return detail::peer_error_response(
3597 errors::make(protocol::ErrorCode::InvalidParams,
3598 "resources/templates/list params must be an object "
3599 "with an optional string cursor"));
3601 const auto result = server_->list_resource_templates(*params, context);
3603 return detail::peer_error_response(request, result.error());
3605 return protocol::make_response(
3607 protocol::resource_templates_list_result_to_json(*result));
3610 if (request.method == protocol::ResourcesSubscribeMethod ||
3611 request.method == protocol::ResourcesUnsubscribeMethod) {
3612 if (!capabilities().resources.subscribe) {
3613 return detail::peer_error_response(
3614 request, errors::make(protocol::ErrorCode::MethodNotFound,
3615 "resource subscriptions are not enabled"));
3617 if (!request.params.is_object() || !request.params.contains(
"uri") ||
3618 !request.params.at(
"uri").is_string()) {
3619 return detail::peer_error_response(
3621 errors::make(protocol::ErrorCode::InvalidParams,
3622 "resource subscription requires a string uri"));
3624 const auto subscription = server_->set_resource_subscription(
3625 subscription_context_for(context, native_transport),
3626 request.params.at(
"uri").get<std::string>(),
3627 request.method == protocol::ResourcesSubscribeMethod);
3628 if (!subscription) {
3629 return detail::peer_error_response(request, subscription.error());
3631 return protocol::make_response(request.id, protocol::Json::object());
3634 if (request.method == protocol::CompletionCompleteMethod &&
3635 completion_handler_) {
3636 const auto result = completion_handler_(request.params, context);
3638 return detail::peer_error_response(request, result.error());
3640 return protocol::make_response(request.id, *result);
3643 if (request.method == protocol::SamplingCreateMessageMethod &&
3644 sampling_handler_) {
3645 const auto result = sampling_handler_(request.params, context);
3647 return detail::peer_error_response(request, result.error());
3649 return protocol::make_response(request.id, *result);
3652 if (request.method == protocol::LoggingSetLevelMethod && logging_handler_) {
3653 if (!request.params.is_object() || !request.params.contains(
"level") ||
3654 !request.params.at(
"level").is_string()) {
3655 return detail::peer_error_response(
3656 request, errors::make(protocol::ErrorCode::InvalidParams,
3657 "logging/setLevel requires a string level"));
3659 logging_handler_(request.params.at(
"level").get<std::string>(),
3660 "logging level changed");
3661 return protocol::make_response(request.id, protocol::Json::object());
3664 if (request.method == protocol::TasksListMethod && task_list_handler_) {
3665 const auto params = protocol::task_list_params_from_json(request.params);
3667 return detail::peer_params_error_response(request, params.error());
3669 const auto result = task_list_handler_(*params, context);
3671 return detail::peer_error_response(request, result.error());
3673 return protocol::make_response(
3674 request.id, protocol::task_list_result_to_json(*result));
3677 if (request.method == protocol::TasksGetMethod && task_get_handler_) {
3678 const auto params = protocol::task_get_params_from_json(request.params);
3680 return detail::peer_params_error_response(request, params.error());
3682 const auto result = task_get_handler_(*params, context);
3684 return detail::peer_error_response(request, result.error());
3686 protocol::TaskGetResult response_result;
3687 response_result.task = *result;
3688 return protocol::make_response(
3689 request.id, protocol::task_get_result_to_json(response_result));
3692 if (request.method == protocol::TasksCancelMethod && task_cancel_handler_) {
3694 protocol::task_cancel_params_from_json(request.params);
3696 return detail::peer_params_error_response(request, params.error());
3698 const auto result = task_cancel_handler_(*params, context);
3700 return detail::peer_error_response(request, result.error());
3702 protocol::TaskCancelResult response_result;
3703 response_result.task = *result;
3704 return protocol::make_response(
3705 request.id, protocol::task_cancel_result_to_json(response_result));
3708 if (request.method == protocol::TasksResultMethod && task_result_handler_) {
3710 protocol::task_result_params_from_json(request.params);
3712 return detail::peer_params_error_response(request, params.error());
3714 const auto result = task_result_handler_(*params, context);
3716 return detail::peer_error_response(request, result.error());
3718 return protocol::make_response(request.id, *result);
3721 return server_->handle_request(request, context);
3722 }
catch (
const std::exception& ex) {
3723 return detail::peer_error_response(request,
3724 errors::handler_failed(ex.what()));
3726 return detail::peer_error_response(request,
3727 errors::handler_unknown_exception());
3730 core::Result<core::Unit> handle_notification(
3731 const protocol::JsonRpcNotification& notification,
3732 const server::SessionContext& context = {}) {
3733 if (notification.method == protocol::CancelledNotificationMethod ||
3734 native_notification_state_) {
3735 return handle_native_notification(notification, context);
3737 return server_->handle_notification(notification, context);
3740 core::Result<core::Unit> add_transport(
3741 std::unique_ptr<server::Transport> transport) {
3742 return server_->add_transport(std::move(transport));
3747 std::unique_ptr<transport::ServerTransport> transport) {
3749 return mcp::core::unexpected(detail::peer_dispatch_error(
3750 "server peer transport must not be null"));
3752 native_transports_.push_back(std::move(transport));
3753 native_context_transports_.push_back(
3754 server::make_contract_transport_adapter(*native_transports_.back()));
3755 const auto attached =
3756 server_->add_session_transport(*native_context_transports_.back());
3758 native_context_transports_.pop_back();
3759 native_transports_.pop_back();
3760 return mcp::core::unexpected(attached.error());
3767 if (native_transports_.empty()) {
3768 return server_->start();
3771 std::vector<std::thread> workers;
3772 workers.reserve(native_transports_.size());
3773 std::mutex error_mutex;
3774 std::optional<core::Error> first_error;
3776 for (std::size_t index = 0; index < native_transports_.size(); ++index) {
3777 auto* transport_ptr = native_transports_[index].get();
3778 auto* context_transport_ptr = native_context_transports_[index].get();
3779 workers.emplace_back([
this, transport_ptr, context_transport_ptr,
3780 cancellation, &error_mutex,
3781 &first_error]()
noexcept {
3782 server::SessionContext context;
3783 context.remote_address = std::string(transport_ptr->name());
3784 context.transport = context_transport_ptr;
3785 if (context_transport_ptr !=
nullptr) {
3786 context.transport_lifetime = context_transport_ptr->lifetime_token();
3789 serve_transport(*transport_ptr, context, cancellation);
3791 detail::keep_first_service_error(first_error, error_mutex,
3797 for (
auto& worker : workers) {
3798 if (worker.joinable()) {
3803 if (first_error.has_value()) {
3806 return core::Unit{};
3809 void stop() noexcept {
3810 for (
auto& transport : native_transports_) {
3812 (void)transport->close();
3820 for (
auto& transport : native_transports_) {
3821 transport->wait_until_ready();
3826 return server_->notify_roots_list_changed();
3829 core::Result<core::Unit> notify_tool_list_changed() {
3830 return server_->notify_tool_list_changed();
3833 core::Result<core::Unit> notify_prompt_list_changed() {
3834 return server_->notify_prompt_list_changed();
3837 core::Result<core::Unit> notify_resource_list_changed() {
3838 return server_->notify_resource_list_changed();
3841 core::Result<core::Unit> notify_resource_updated(std::string_view uri) {
3842 return server_->notify_resource_updated(uri);
3845 core::Result<core::Unit> notify_progress(
3846 const protocol::ProgressNotificationParams& params) {
3847 return server_->notify_progress(params);
3850 core::Result<core::Unit> notify_logging_message(
3851 const protocol::LoggingMessageNotificationParams& params) {
3852 return server_->notify_logging_message(params);
3855 core::Result<core::Unit> notify_elicitation_complete(
3856 std::string elicitation_id) {
3857 return server_->notify_elicitation_complete(std::move(elicitation_id));
3860 core::Result<core::Unit> notify_task_status(
const protocol::Task& task) {
3861 return server_->notify_task_status(task);
3873 if (
const auto* request = std::get_if<protocol::JsonRpcRequest>(&message)) {
3874 auto handled = handle_request(*request, context, native_transport);
3878 detail::peer_error_object_from_core_error(handled.error()))};
3880 return protocol::JsonRpcMessage{std::move(*handled)};
3883 if (
const auto* notification =
3884 std::get_if<protocol::JsonRpcNotification>(&message)) {
3885 const auto handled = handle_notification(*notification, context);
3889 return std::nullopt;
3893 "server peer cannot dispatch an uncorrelated response"));
3902 bool initialized =
false;
3903 return detail::serve_transport_loop(
3904 transport, cancellation,
3905 [
this, &context, &transport,
3907 ->
core::Result<std::optional<protocol::JsonRpcMessage>> {
3909 auto is_stateless_request = [](
const protocol::Json& params) ->
bool {
3910 return params.is_object() && params.contains(
"_meta") &&
3911 params.at(
"_meta").is_object() &&
3912 params.at(
"_meta").contains(
3913 "io.modelcontextprotocol/protocolVersion");
3915 if (
const auto* request =
3916 std::get_if<protocol::JsonRpcRequest>(&message)) {
3917 const bool stateless = is_stateless_request(request->params);
3918 const bool allowed_before_initialized =
3919 stateless || request->method == protocol::InitializeMethod ||
3920 request->method == protocol::PingMethod;
3921 if (!initialized && !allowed_before_initialized) {
3922 return core::Result<std::optional<protocol::JsonRpcMessage>>{
3923 protocol::JsonRpcMessage{protocol::make_error_response(
3925 protocol::make_error(protocol::ErrorCode::InvalidRequest,
3926 "server peer transport session is "
3927 "not initialized"))}};
3930 if (
const auto* notification =
3931 std::get_if<protocol::JsonRpcNotification>(&message)) {
3932 const bool stateless = is_stateless_request(notification->params);
3933 if (!initialized && !stateless &&
3934 notification->method != protocol::InitializedMethod) {
3936 "server peer transport session is not initialized"));
3938 auto message_context =
3939 detail::context_for_received_server_message(transport, context);
3941 dispatch_message(message, message_context, &transport);
3945 if (notification->method == protocol::InitializedMethod) {
3950 auto message_context =
3951 detail::context_for_received_server_message(transport, context);
3952 return dispatch_message(message, message_context, &transport);
3957 server::SessionContext subscription_context_for(
3958 const server::SessionContext& context,
3959 const transport::ServerTransport* native_transport)
const {
3960 server::SessionContext subscription_context = context;
3961 if (subscription_context.transport || native_transport ==
nullptr) {
3962 return subscription_context;
3965 for (std::size_t index = 0; index < native_transports_.size(); ++index) {
3966 if (native_transports_[index].get() == native_transport &&
3967 index < native_context_transports_.size()) {
3968 subscription_context.transport =
3969 native_context_transports_[index].get();
3970 subscription_context.transport_lifetime =
3971 native_context_transports_[index]->lifetime_token();
3975 return subscription_context;
3979 const protocol::RequestId& request_id) {
3980 CancellationSource source;
3981 auto token = source.token();
3982 std::lock_guard lock(*peer_request_cancellations_mutex_);
3983 (*peer_request_cancellations_)[detail::peer_request_cancellation_key(
3984 request_id)] = std::move(source);
3988 void end_peer_request_cancellation(
3989 const protocol::RequestId& request_id)
noexcept {
3990 std::lock_guard lock(*peer_request_cancellations_mutex_);
3991 peer_request_cancellations_->erase(
3992 detail::peer_request_cancellation_key(request_id));
3995 void cancel_peer_request(
const protocol::RequestId& request_id)
noexcept {
3996 std::lock_guard lock(*peer_request_cancellations_mutex_);
3997 const auto it = peer_request_cancellations_->find(
3998 detail::peer_request_cancellation_key(request_id));
3999 if (it != peer_request_cancellations_->end()) {
4000 it->second.cancel();
4004 core::Result<core::Unit> handle_native_notification(
4005 const protocol::JsonRpcNotification& notification,
4006 const server::SessionContext& context)
try {
4007 if (notification.method == protocol::CancelledNotificationMethod) {
4008 const auto cancelled = protocol::cancelled_notification_params_from_json(
4009 notification.params);
4012 errors::make(protocol::ErrorCode::InvalidParams,
4013 "cancelled notification requires valid params"));
4015 cancel_peer_request(cancelled->request_id);
4016 return server_->handle_notification(notification, context);
4019 if (raw_notification_handler_) {
4020 const auto raw_result = raw_notification_handler_(notification, context);
4026 if (notification.method == protocol::RootsListChangedNotificationMethod &&
4027 roots_list_changed_handler_) {
4028 const auto result = roots_list_changed_handler_(context);
4032 }
else if (notification.method == protocol::ProgressNotificationMethod &&
4033 progress_handler_) {
4035 protocol::progress_notification_params_from_json(notification.params);
4038 errors::make(protocol::ErrorCode::InvalidParams,
4039 "progress notification requires valid params"));
4041 const auto result = progress_handler_(*params, context);
4045 }
else if (notification.method ==
4046 protocol::ToolsListChangedNotificationMethod &&
4047 tool_list_changed_handler_) {
4048 const auto result = tool_list_changed_handler_(context);
4052 }
else if (notification.method ==
4053 protocol::PromptsListChangedNotificationMethod &&
4054 prompt_list_changed_handler_) {
4055 const auto result = prompt_list_changed_handler_(context);
4059 }
else if (notification.method ==
4060 protocol::ResourcesListChangedNotificationMethod &&
4061 resource_list_changed_handler_) {
4062 const auto result = resource_list_changed_handler_(context);
4066 }
else if (notification.method ==
4067 protocol::ResourcesUpdatedNotificationMethod &&
4068 resource_updated_handler_) {
4069 if (!notification.params.is_object() ||
4070 !notification.params.contains(
"uri") ||
4071 !notification.params.at(
"uri").is_string()) {
4073 protocol::ErrorCode::InvalidParams,
4074 "resource updated notification requires a string uri"));
4076 const auto result = resource_updated_handler_(
4077 notification.params.at(
"uri").get<std::string>(), context);
4083 return core::Unit{};
4084 }
catch (
const std::exception& ex) {
4090 std::unique_ptr<server::Server> server_;
4091 std::vector<std::unique_ptr<transport::ServerTransport>> native_transports_;
4092 std::vector<std::unique_ptr<server::Transport>> native_context_transports_;
4093 std::shared_ptr<std::mutex> peer_request_cancellations_mutex_ =
4094 std::make_shared<std::mutex>();
4095 std::shared_ptr<std::unordered_map<std::string, CancellationSource>>
4096 peer_request_cancellations_ = std::make_shared<
4097 std::unordered_map<std::string, CancellationSource>>();
4098 bool native_notification_state_ =
false;
4100 server::Server::RawRequestContextHandler raw_request_context_handler_;
4101 server::Server::JsonContextHandler completion_handler_;
4102 server::Server::JsonContextHandler sampling_handler_;