|
| 1 | +--- |
| 2 | +title: Capabilities |
| 3 | +author: jeffhandley |
| 4 | +description: How capability and protocol version negotiation works in MCP. |
| 5 | +uid: capabilities |
| 6 | +--- |
| 7 | + |
| 8 | +## Capabilities |
| 9 | + |
| 10 | +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. |
| 11 | + |
| 12 | +[capability negotiation]: https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle#initialization |
| 13 | + |
| 14 | +### Client capabilities |
| 15 | + |
| 16 | +<xref:ModelContextProtocol.Protocol.ClientCapabilities> declares what features the client supports: |
| 17 | + |
| 18 | +| Capability | Type | Description | |
| 19 | +|-----------|------|-------------| |
| 20 | +| `Roots` | <xref:ModelContextProtocol.Protocol.RootsCapability> | Client can provide filesystem root URIs | |
| 21 | +| `Sampling` | <xref:ModelContextProtocol.Protocol.SamplingCapability> | Client can handle LLM sampling requests | |
| 22 | +| `Elicitation` | <xref:ModelContextProtocol.Protocol.ElicitationCapability> | Client can present forms or URLs to the user | |
| 23 | +| `Experimental` | `IDictionary<string, object>` | Experimental capabilities | |
| 24 | + |
| 25 | +Configure client capabilities when creating an MCP client: |
| 26 | + |
| 27 | +```csharp |
| 28 | +var options = new McpClientOptions |
| 29 | +{ |
| 30 | + Capabilities = new ClientCapabilities |
| 31 | + { |
| 32 | + Roots = new RootsCapability { ListChanged = true }, |
| 33 | + Sampling = new SamplingCapability(), |
| 34 | + Elicitation = new ElicitationCapability |
| 35 | + { |
| 36 | + Form = new FormElicitationCapability(), |
| 37 | + Url = new UrlElicitationCapability() |
| 38 | + } |
| 39 | + } |
| 40 | +}; |
| 41 | + |
| 42 | +await using var client = await McpClient.CreateAsync(transport, options); |
| 43 | +``` |
| 44 | + |
| 45 | +Handlers for each capability (roots, sampling, elicitation) are covered in their respective documentation pages. |
| 46 | + |
| 47 | +### Server capabilities |
| 48 | + |
| 49 | +<xref:ModelContextProtocol.Protocol.ServerCapabilities> declares what features the server supports: |
| 50 | + |
| 51 | +| Capability | Type | Description | |
| 52 | +|-----------|------|-------------| |
| 53 | +| `Tools` | <xref:ModelContextProtocol.Protocol.ToolsCapability> | Server exposes callable tools | |
| 54 | +| `Prompts` | <xref:ModelContextProtocol.Protocol.PromptsCapability> | Server exposes prompt templates | |
| 55 | +| `Resources` | <xref:ModelContextProtocol.Protocol.ResourcesCapability> | Server exposes readable resources | |
| 56 | +| `Logging` | <xref:ModelContextProtocol.Protocol.LoggingCapability> | Server can send log messages | |
| 57 | +| `Completions` | <xref:ModelContextProtocol.Protocol.CompletionsCapability> | Server supports argument completions | |
| 58 | +| `Experimental` | `IDictionary<string, object>` | Experimental capabilities | |
| 59 | + |
| 60 | +Server capabilities are automatically inferred from the configured features. For example, registering tools with `.WithTools<T>()` automatically declares the tools capability. |
| 61 | + |
| 62 | +### Checking capabilities |
| 63 | + |
| 64 | +Before using an optional feature, check whether the other side declared the corresponding capability. |
| 65 | + |
| 66 | +#### Checking server capabilities from the client |
| 67 | + |
| 68 | +```csharp |
| 69 | +await using var client = await McpClient.CreateAsync(transport); |
| 70 | + |
| 71 | +// Check if the server supports tools |
| 72 | +if (client.ServerCapabilities.Tools is not null) |
| 73 | +{ |
| 74 | + var tools = await client.ListToolsAsync(); |
| 75 | +} |
| 76 | + |
| 77 | +// Check if the server supports resources with subscriptions |
| 78 | +if (client.ServerCapabilities.Resources is { Subscribe: true }) |
| 79 | +{ |
| 80 | + await client.SubscribeToResourceAsync("config://app/settings"); |
| 81 | +} |
| 82 | + |
| 83 | +// Check if the server supports prompts with list-changed notifications |
| 84 | +if (client.ServerCapabilities.Prompts is { ListChanged: true }) |
| 85 | +{ |
| 86 | + mcpClient.RegisterNotificationHandler( |
| 87 | + NotificationMethods.PromptListChangedNotification, |
| 88 | + async (notification, ct) => |
| 89 | + { |
| 90 | + var prompts = await mcpClient.ListPromptsAsync(cancellationToken: ct); |
| 91 | + }); |
| 92 | +} |
| 93 | + |
| 94 | +// Check if the server supports logging |
| 95 | +if (client.ServerCapabilities.Logging is not null) |
| 96 | +{ |
| 97 | + await client.SetLoggingLevelAsync(LoggingLevel.Info); |
| 98 | +} |
| 99 | + |
| 100 | +// Check if the server supports completions |
| 101 | +if (client.ServerCapabilities.Completions is not null) |
| 102 | +{ |
| 103 | + var completions = await client.CompleteAsync( |
| 104 | + new PromptReference { Name = "my_prompt" }, |
| 105 | + argumentName: "language", |
| 106 | + argumentValue: "py"); |
| 107 | +} |
| 108 | +``` |
| 109 | + |
| 110 | +### Protocol version negotiation |
| 111 | + |
| 112 | +During connection setup, the client and server negotiate a mutually supported MCP protocol version. After initialization, the negotiated version is available on both sides: |
| 113 | + |
| 114 | +```csharp |
| 115 | +// On the client |
| 116 | +string? version = client.NegotiatedProtocolVersion; |
| 117 | + |
| 118 | +// On the server (within a tool or handler) |
| 119 | +string? version = server.NegotiatedProtocolVersion; |
| 120 | +``` |
| 121 | + |
| 122 | +Version negotiation is handled automatically. If the client and server cannot agree on a compatible protocol version, the initialization fails with an error. |
0 commit comments