csharp-sdk/docs/concepts/capabilities/capabilities.md
Jeff Handley 314bdb2f49
Refine 2.0.0 concept documentation (#1742)
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 782b5bad-4046-49ec-93a6-72768b5b7521
Copilot-Session: 4b938335-418c-4ee7-8287-6c70d9148b89
2026-07-27 20:15:16 -07:00

122 lines
4.6 KiB
Markdown

---
title: Capabilities
author: jeffhandley
description: How capability and protocol version negotiation works in MCP.
uid: capabilities
---
## 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.
[capability negotiation]: https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle#initialization
### Client capabilities
<xref:ModelContextProtocol.Protocol.ClientCapabilities> declares what features the client supports:
| Capability | Type | Description |
|-----------|------|-------------|
| `Roots` | <xref:ModelContextProtocol.Protocol.RootsCapability> | Client can provide filesystem root URIs |
| `Sampling` | <xref:ModelContextProtocol.Protocol.SamplingCapability> | Client can handle LLM sampling requests |
| `Elicitation` | <xref:ModelContextProtocol.Protocol.ElicitationCapability> | Client can present forms or URLs to the user |
| `Experimental` | `IDictionary<string, object>` | Experimental capabilities |
Configure client capabilities when creating an MCP client:
```csharp
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
<xref:ModelContextProtocol.Protocol.ServerCapabilities> declares what features the server supports:
| Capability | Type | Description |
|-----------|------|-------------|
| `Tools` | <xref:ModelContextProtocol.Protocol.ToolsCapability> | Server exposes callable tools |
| `Prompts` | <xref:ModelContextProtocol.Protocol.PromptsCapability> | Server exposes prompt templates |
| `Resources` | <xref:ModelContextProtocol.Protocol.ResourcesCapability> | Server exposes readable resources |
| `Logging` | <xref:ModelContextProtocol.Protocol.LoggingCapability> | Server can send log messages |
| `Completions` | <xref:ModelContextProtocol.Protocol.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.
#### Check server capabilities from the client
```csharp
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");
}
```
### 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:
```csharp
// 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.