Capabilities
MCP uses a capability negotiation mechanism during connection setup. Clients and servers exchange their supported capabilities so each side can adapt its behavior accordingly. Both sides should check the other's capabilities before using optional features.
Client capabilities
ClientCapabilities declares what features the client supports:
| Capability | Type | Description |
|---|---|---|
Roots |
RootsCapability | Client can provide filesystem root URIs |
Sampling |
SamplingCapability | Client can handle LLM sampling requests |
Elicitation |
ElicitationCapability | Client can present forms or URLs to the user |
Experimental |
IDictionary<string, object> |
Experimental capabilities |
Configure client capabilities when creating an MCP client:
var options = new McpClientOptions
{
Capabilities = new ClientCapabilities
{
Roots = new RootsCapability { ListChanged = true },
Sampling = new SamplingCapability(),
Elicitation = new ElicitationCapability
{
Form = new FormElicitationCapability(),
Url = new UrlElicitationCapability()
}
}
};
await using var client = await McpClient.CreateAsync(transport, options);
Handlers for each capability (roots, sampling, and elicitation) are covered in their respective documentation pages.
Server capabilities
ServerCapabilities declares what features the server supports:
| Capability | Type | Description |
|---|---|---|
Tools |
ToolsCapability | Server exposes callable tools |
Prompts |
PromptsCapability | Server exposes prompt templates |
Resources |
ResourcesCapability | Server exposes readable resources |
Logging |
LoggingCapability | Server can send log messages |
Completions |
CompletionsCapability | Server supports argument completions |
Experimental |
IDictionary<string, object> |
Experimental capabilities |
Server capabilities are automatically inferred from the configured features. For example, registering tools with .WithTools<T>() automatically declares the tools capability.
Checking capabilities
Before using an optional feature, check whether the other side declared the corresponding capability.
Within a server request handler, ClientCapabilities can reflect the current request's declarations, including on stateless servers using 2026-07-28. These declarations describe client features, not transport support for direct server-to-client requests. A stateless transport still cannot deliver direct sampling, roots, or elicitation requests without an appropriate outgoing-request interceptor; use MRTR for request-bound input instead.
Check server capabilities from the client
await using var client = await McpClient.CreateAsync(transport);
// Check if the server supports tools
if (client.ServerCapabilities.Tools is not null)
{
var tools = await client.ListToolsAsync();
}
// Check if the server supports resources with subscriptions
if (client.ServerCapabilities.Resources is { Subscribe: true })
{
await client.SubscribeToResourceAsync("config://app/settings");
}
// Check if the server supports prompts with list-changed notifications
if (client.ServerCapabilities.Prompts is { ListChanged: true })
{
client.RegisterNotificationHandler(
NotificationMethods.PromptListChangedNotification,
async (notification, ct) =>
{
var prompts = await client.ListPromptsAsync(cancellationToken: ct);
});
}
// Check if the server supports logging
if (client.ServerCapabilities.Logging is not null)
{
await client.SetLoggingLevelAsync(LoggingLevel.Info);
}
// Check if the server supports completions
if (client.ServerCapabilities.Completions is not null)
{
var completions = await client.CompleteAsync(
new PromptReference { Name = "my_prompt" },
argumentName: "language",
argumentValue: "py");
}
Optional server identity
ServerInfo is nullable because 2026-07-28 servers may omit identity metadata. After connecting, handle missing metadata explicitly, for example with client.ServerInfo?.Name ?? "Unknown server". Existing non-nullable assignments and dereferences may produce nullable warnings when upgrading to SDK 2.3.0. Accessing the property before the client connects still throws InvalidOperationException.
Server identity metadata is self-reported; do not use it to make authentication or authorization decisions.
Protocol version negotiation
During connection setup, the client and server negotiate a mutually supported MCP protocol version. After initialization, the negotiated version is available on both sides:
// On the client
string? version = client.NegotiatedProtocolVersion;
// On the server (within a tool or handler)
string? version = server.NegotiatedProtocolVersion;
Version negotiation is handled automatically. If the client and server cannot agree on a compatible protocol version, the initialization fails with an error.