This document describes the C++14-compatible alternatives we've implemented to replace C++17's class template argument deduction for the MCP C++ SDK.
Since C++17's CTAD is not available in C++14, we've implemented factory functions and helper utilities that provide similar ergonomics while maintaining type safety.
opt(value)- Creates an optional with automatic type deductionnone<T>()- Creates an empty optional of type Tmake_optional(value)- Standard factory function
make_request_id(value)- Creates RequestId variant from string or intmake_progress_token(value)- Creates ProgressToken variantmake_content_block()family - Creates ContentBlock variants
using ContentDiscriminator = TypeDiscriminator<TextContent, ImageContent, ResourceContent>;
auto content = ContentDiscriminator::create(TextContent("Hello"));
if (ContentDiscriminator::is_type<TextContent>(content)) {
auto* text = ContentDiscriminator::get_if<TextContent>(content);
}auto notification = make_method_notification("initialize", InitializeParams{1});
if (notification.has_method("initialize")) {
auto* params = notification.get_if<InitializeParams>();
}String literal enums with conversion functions:
enums::Role::to_string(enums::Role::USER) // "user"
enums::Role::from_string("user") // optional<Role::Value>Extensible key-value storage for unknown fields:
auto meta = make_metadata();
add_metadata(meta, "key", "value");
add_metadata(meta, "number", 42);For complex type construction:
auto tool = build_tool("calculator")
.description("Math calculator")
.parameter("expression", "string", true)
.build();
auto resource = build_resource("file:///doc.pdf", "document.pdf")
.description("Important document")
.mimeType("application/pdf")
.build();Type-safe error handling:
Result<int> result = make_result(42);
if (is_success<int>(result)) {
auto* value = get_value<int>(result);
}
Result<int> error = make_error_result<int>(Error(404, "Not found"));For all MCP types:
make_text_content(text)make_image_content(data, mimeType)make_resource_content(resource)make_user_message(text)make_assistant_message(text)make_request(id, method, params)make_response(id, result)make_error_response(id, error)
Generic builder for structs:
auto person = make_object<Person>()
.set(&Person::name, "John")
.set(&Person::age, 30)
.set_optional(&Person::email, "john@example.com")
.build();Pattern matching for variants:
auto result = match(variant_value,
[](int i) { return i * 2; },
[](double d) { return int(d); },
[](const string& s) { return s.length(); }
);- Type Safety: All factory functions maintain full type safety
- Ergonomics: Similar ease of use to C++17's CTAD
- Performance: Zero-cost abstractions with inline functions
- Extensibility: Easy to add new types and factories
- Compatibility: Works with C++14 compilers
// Create an MCP request
auto request = make_request(
make_request_id("req-123"),
"tools/call",
make_tool_call("calculator", metadata)
);
// Create a response
auto response = make_response(
request.id,
std::vector<ContentBlock>{
make_text_content("Result: 42")
}
);
// Pattern match on content
match(response.content,
[](const TextContent& text) {
std::cout << "Text: " << text.text << std::endl;
},
[](const ImageContent& image) {
std::cout << "Image: " << image.mimeType << std::endl;
},
[](const ResourceContent& resource) {
std::cout << "Resource: " << resource.resource.uri << std::endl;
}
);- All factory functions use perfect forwarding to minimize copies
- Builder patterns use method chaining for fluent interfaces
- Discriminated unions use visitor pattern for type-safe access
- Metadata uses recursive variant for nested structures
- String literal helpers enable compile-time string processing
This approach provides a clean, type-safe API that closely matches the TypeScript MCP schema while working within C++14's constraints.