Server Overview
The McpServer class exposes capabilities (tools, resources, prompts) to connected MCP clients.
Creating a Server
auto transport = std::make_shared<StdioServerTransport>();
ServerOptions opts;
opts.server_info = Implementation{"MyServer", "1.0.0"};
auto server = McpServer::Create(transport, opts);
server->Run();For Streamable HTTP mode:
StreamableHttpServerOptions http_opts;
http_opts.port = 3001;
http_opts.stateless = true; // or false for session mode
auto transport = std::make_shared<StreamableHttpServerTransport>(http_opts);
ServerOptions opts;
opts.server_info = Implementation{"MyServer", "1.0.0"};
auto server = McpServer::Create(transport, opts);
server->Run();ServerOptions
| Field | Type | Description |
|---|---|---|
server_info | optional<Implementation> | Server identity (name, version) |
protocol_version | optional<string> | Pin to a specific version |
server_instructions | optional<string> | Instructions sent to client |
initialization_timeout | chrono::seconds | Handshake timeout (default 60s) |
declare_logging | bool | Explicitly declare the logging capability (merged into derived capabilities; default false) |
declare_completions | bool | Explicitly declare the completions capability (default false) |
task_store | shared_ptr<IMcpTaskStore> | Task persistence backend |
request_state_verifier | function<bool(string_view)> | HMAC/AEAD verifier for MRTR |
request_state_key | optional<string> | Server-side requestState signing key (HMAC); when set without an explicit request_state_verifier, a built-in verifier is wired to reject tampered/expired states before handlers (-32602 with data.reason="invalid_request_state") |
request_state_ttl | chrono::seconds | Max age of minted requestState payloads (default 0 = no expiry check) |
cache_hints | optional<map<string, CacheHint, less<>>> | Per-method cache hints (ttlMs, cacheScope) |
cache_hint_resolver | function<optional<CacheHint>(string_view)> | Escape hook resolving cache hints per method (takes precedence over the static cache_hints table; replaceable at runtime via SetCacheable) |
supported_protocol_versions | optional<vector<string>> | Narrows the server's supported-version table (applies to the discover response, the initialize candidate set, and the _meta gate plus error data.supported together; empty means the full table) |
subscriptions_enabled | bool | Subscription master switch (default true; when off, subscriptions/listen returns MethodNotFound) |
max_tool_input_elements | optional<size_t> | Tool-argument element cap (object key count / array length; over-budget calls return an is_error tool result, not a protocol error) |
input_required_config | optional<InputRequiredConfig> | Configuration for MRTR/elicitation behavior |
input_required_config.max_rounds | int | Maximum elicitation rounds (default 10) |
input_required_config.round_timeout | chrono::seconds | Per-round timeout (default 600s) |
input_required_config.legacy_shim | bool | Enable legacy compatibility shim (default true) |
on_request | function | Called on each incoming JSON-RPC request with method name + full request body |
on_response | function | Called on each outgoing JSON-RPC response |
on_error | function | Called on each outgoing JSON-RPC error response |
on_notification | function | Called on each incoming JSON-RPC notification |
on_method_called | function(string_view) | Shorthand — method name only (fires alongside on_request) |
on_protocol_error | function(string_view) | Shorthand — error message only (fires alongside on_error) |
on_client_connected | function(const Implementation&) | Called when a client completes initialize |
on_initialized | function() | Called when client sends notifications/initialized |
on_transport_close | function() | Called when the transport connection closes |
on_transport_error | function(string_view) | Called on transport-level errors |
incoming_filters | shared_ptr<FilterPipeline> | Pipeline to intercept/modify/block inbound messages |
outgoing_filters | shared_ptr<FilterPipeline> | Pipeline to intercept/modify/block outbound messages |
Shorthand callbacks (on_method_called, on_protocol_error) and full-message callbacks (on_request, on_error) are chained — both fire when set simultaneously.
RequestContext<TParams>
Every tool handler receives a RequestContext<CallToolRequestParams> providing request context:
| Member | Return Type | Description |
|---|---|---|
Params() | const TParams& | The deserialized request parameters |
Server() | McpServer& | Reference to the owning server instance |
GetRequest() | const JsonRpcRequest& | The raw JSON-RPC request |
LogLevel() | optional<LoggingLevel> | Per-request log level from _meta (2026-era) |
Log(level, data) | void | Sends a logging notification, filtered by LogLevel() |
IsCancellationRequested() | bool | Whether notifications/cancelled has arrived for this request; handlers poll it for cooperative cancellation |
The Log() method respects per-request log levels: messages below the request's LogLevel() are silently dropped.
McpServerTool
For reusable tool definitions, subclass McpServerTool or use McpServerTool::Create:
auto tool = McpServerTool::Create("get_weather",
[](const RequestContext<CallToolRequestParams>& ctx) -> CallToolResult {
// ...
},
ToolOptions{}.Description("Get weather"));
server->RegisterTool(tool);The McpServerTool abstract class exposes:
ProtocolTool()— returns the protocol-levelToolstructInvokeAsync(ctx, promise)— override for custom async execution
The lambda-based RegisterTool overload works identically — it creates an McpServerTool internally.
Properties
| Method | Return Type | Description |
|---|---|---|
GetClientCapabilities() | std::shared_ptr<const ClientCapabilities> | Only populated during a 2025-era client initialize handshake; always nullptr in the 2026 era (no initialize) |
GetClientInfo() | std::shared_ptr<const Implementation> | Client identity (nullptr before connect) |
GetNegotiatedProtocolVersion() | std::string | The negotiated protocol version string |
GetCapabilities() | const ServerCapabilities& | Server capabilities auto-derived from registered primitives |
IsMrtrSupported() | bool | Whether MRTR (Multi-Round Tool Retrieval) is supported |
Notifications
| Method | Description |
|---|---|
SendToolListChanged() | Notifies clients of tool list changes |
SendResourceListChanged() | Notifies clients of resource list changes |
SendResourceUpdated(uri) | Notifies clients that a specific resource changed (delivered only to subscribers of that uri) |
SendPromptListChanged() | Notifies clients of prompt list changes |
SendLoggingMessage(level, data) | Sends a logging message (respects client's logging/setLevel) |
SendLoggingMessage(level, data, min_level) | Overload with explicit minimum level override |
Completion Handler
Register an optional handler for completion/complete requests (e.g., argument auto-complete):
server->SetCompletionHandler(
[](const CompleteRequestParams& params) -> CompleteResult {
CompleteResult result;
result.completion = JsonValue::Parse(R"({"values":["value1","value2"]})");
return result;
});Lifecycle
- Construction:
McpServer::Create— creates the session handler, wires handlers, starts message loop - Registration: Register tools, resources, prompts via
RegisterTool,RegisterResource,RegisterResourceTemplate,RegisterPrompt - Run:
server->Run()— blocks untilClose()is called; the session handler processes messages asynchronously - Shutdown:
server->Close()— waits for pending async calls, closes handler and transport
Capability Derivation
Capabilities are automatically derived from registered primitives. For example, registering a tool sets capabilities.tools.list_changed = true. There is no ServerOptions.capabilities field — capabilities are always auto-derived from registered tools, resources, prompts, and task store. The only explicit overrides are declare_logging and declare_completions, which merge the logging / completions capabilities into the derived set (useful when handlers are wired outside the registration APIs, e.g. SetCompletionHandler).