{"id":57357,"date":"2025-07-22T10:00:00","date_gmt":"2025-07-22T17:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/dotnet\/?p=57357"},"modified":"2025-07-22T10:00:00","modified_gmt":"2025-07-22T17:00:00","slug":"mcp-csharp-sdk-2025-06-18-update","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/mcp-csharp-sdk-2025-06-18-update\/","title":{"rendered":"MCP C# SDK Gets Major Update: Support for Protocol Version 2025-06-18"},"content":{"rendered":"<p>The Model Context Protocol (MCP) continues to evolve, and we&#8217;re excited to announce that the MCP C# SDK now supports the <a href=\"https:\/\/modelcontextprotocol.io\/specification\/2025-06-18\">latest specification version 2025-06-18<\/a>. This update brings significant new capabilities to .NET developers building AI applications, including an improved authentication protocol, elicitation support, structured tool output, and support for resource links in tool responses.<\/p>\n<p>Whether you&#8217;re building AI assistants, automation tools, or integrating AI capabilities into existing .NET applications, these new features will help you create more robust and secure solutions.<\/p>\n<p>Here&#8217;s a rundown of the new features and how to access them with the MCP C# SDK.<\/p>\n<h2>Improved Authentication Protocol<\/h2>\n<p>The 2025-06-18 specification introduces a new <strong>authentication protocol<\/strong> that enhances security and flexibility for AI applications. The new protocol separates the roles of authentication server and resource server, allowing easier integration with existing OAuth 2.0 and OpenID Connect providers.<\/p>\n<p>This is a large topic and has already been covered in detail in a separate blog post by Den Delimarsky, <a href=\"https:\/\/den.dev\/blog\/mcp-csharp-sdk-authorization\/\">OAuth In The MCP C# SDK: Simple, Secure, Standard<\/a>.<\/p>\n<h2>Elicitation: Interactive User Engagement<\/h2>\n<p>One of the most significant additions is the <strong>elicitation<\/strong> feature, which allows servers to request additional information from users during interactions. This enables more dynamic and interactive AI experiences, making it easier to gather necessary context before executing tasks.<\/p>\n<h3>Server Support for Elicitation<\/h3>\n<p>Servers request structured data from users with the <a href=\"https:\/\/modelcontextprotocol.github.io\/csharp-sdk\/api\/ModelContextProtocol.Server.McpServerExtensions.html#ModelContextProtocol_Server_McpServerExtensions_ElicitAsync_ModelContextProtocol_Server_IMcpServer_ModelContextProtocol_Protocol_ElicitRequestParams_System_Threading_CancellationToken_\">ElicitAsync<\/a> extension method on <a href=\"https:\/\/modelcontextprotocol.github.io\/csharp-sdk\/api\/ModelContextProtocol.Server.IMcpServer.html\">IMcpServer<\/a>.\nThe C# SDK registers an instance of <a href=\"https:\/\/modelcontextprotocol.github.io\/csharp-sdk\/api\/ModelContextProtocol.Server.IMcpServer.html\">IMcpServer<\/a> with the dependency injection container,\nso tools can simply add a parameter of type <a href=\"https:\/\/modelcontextprotocol.github.io\/csharp-sdk\/api\/ModelContextProtocol.Server.IMcpServer.html\">IMcpServer<\/a> to their method signature to access it.<\/p>\n<p>The MCP Server must specify the schema of each input value it is requesting from the user.\nOnly primitive types (string, number, boolean) are supported for elicitation requests.\nThe schema may include a description to help the user understand what is being requested.<\/p>\n<p>The server can request a single input or multiple inputs at once.\nTo help distinguish multiple inputs, each input has a unique name.<\/p>\n<p>The following example demonstrates how a server could request a boolean response from the user.<\/p>\n<pre><code class=\"language-csharp\">[McpServerTool, Description(\"A simple game where the user has to guess a number between 1 and 10.\")]\npublic async Task&lt;string&gt; GuessTheNumber(\n    IMcpServer server, \/\/ Get the McpServer from DI container\n    CancellationToken token\n)\n{\n    \/\/ First ask the user if they want to play\n    var playSchema = new RequestSchema\n    {\n        Properties =\n        {\n            [\"Answer\"] = new BooleanSchema()\n        }\n    };\n\n    var playResponse = await server.ElicitAsync(new ElicitRequestParams\n    {\n        Message = \"Do you want to play a game?\",\n        RequestedSchema = playSchema\n    }, token);\n\n    \/\/ Check if user wants to play\n    if (playResponse.Action != \"accept\" || playResponse.Content?[\"Answer\"].ValueKind != JsonValueKind.True)\n    {\n        return \"Maybe next time!\";\n    }\n\n    \/\/ remaining implementation of GuessTheNumber method<\/code><\/pre>\n<h3>Client Support for Elicitation<\/h3>\n<p>Elicitation is an optional feature so clients declare their support for it in their capabilities as part of the <code>initialize<\/code> request. In the MCP C# SDK, this is done by configuring an <a href=\"https:\/\/modelcontextprotocol.github.io\/csharp-sdk\/api\/ModelContextProtocol.Protocol.ElicitationCapability.html#ModelContextProtocol_Protocol_ElicitationCapability_ElicitationHandler\">ElicitationHandler<\/a> in the <a href=\"https:\/\/modelcontextprotocol.github.io\/csharp-sdk\/api\/ModelContextProtocol.Client.McpClientOptions.html\">McpClientOptions<\/a>:<\/p>\n<pre><code class=\"language-csharp\">McpClientOptions options = new()\n{\n    ClientInfo = new()\n    {\n        Name = \"ElicitationClient\",\n        Version = \"1.0.0\"\n    },\n    Capabilities = new()\n    {\n        Elicitation = new()\n        {\n            ElicitationHandler = HandleElicitationAsync\n        }\n    }\n};<\/code><\/pre>\n<p>The ElicitationHandler is an asynchronous method that will be called when the server requests additional information.\nThe ElicitationHandler must request input from the user and return the data in a format that matches the requested schema.\nThis will be highly dependent on the client application and how it interacts with the user.<\/p>\n<p>If the user provides the requested information, the ElicitationHandler should return an [ElicitResult] with the action set to &#8220;accept&#8221; and the content containing the user&#8217;s input.\nIf the user does not provide the requested information, the ElicitationHandler should return an [ElicitResult] with the action set to &#8220;reject&#8221; and no content.<\/p>\n<p>Below is an example of how a console application might handle elicitation requests.\nHere&#8217;s an example implementation:<\/p>\n<pre><code class=\"language-csharp\">async ValueTask&lt;ElicitResult&gt; HandleElicitationAsync(ElicitRequestParams? requestParams, CancellationToken token)\n{\n    \/\/ Bail out if the requestParams is null or if the requested schema has no properties\n    if (requestParams?.RequestedSchema?.Properties == null)\n    {\n        return new ElicitResult(); \/\/ New ElicitResult with default Action \"reject\"\n    }\n\n    \/\/ Process the elicitation request\n    if (requestParams?.Message is not null)\n    {\n        Console.WriteLine(requestParams.Message);\n    }\n\n    var content = new Dictionary&lt;string, JsonElement&gt;();\n\n    \/\/ Loop through requestParams.requestSchema.Properties dictionary requesting values for each property\n    foreach (var property in requestParams.RequestedSchema.Properties)\n    {\n        if (property.Value is ElicitRequestParams.BooleanSchema booleanSchema)\n        {\n            Console.Write($\"{booleanSchema.Description}: \");\n            var clientInput = Console.ReadLine();\n            bool parsedBool;\n            if (bool.TryParse(clientInput, out parsedBool))\n            {\n                content[property.Key] = JsonSerializer.Deserialize&lt;JsonElement&gt;(JsonSerializer.Serialize(parsedBool));\n            }\n        }\n        else if (property.Value is ElicitRequestParams.NumberSchema numberSchema)\n        {\n            Console.Write($\"{numberSchema.Description}: \");\n            var clientInput = Console.ReadLine();\n            double parsedNumber;\n            if (double.TryParse(clientInput, out parsedNumber))\n            {\n                content[property.Key] = JsonSerializer.Deserialize&lt;JsonElement&gt;(JsonSerializer.Serialize(parsedNumber));\n            }\n        }\n        else if (property.Value is ElicitRequestParams.StringSchema stringSchema)\n        {\n            Console.Write($\"{stringSchema.Description}: \");\n            var clientInput = Console.ReadLine();\n            content[property.Key] = JsonSerializer.Deserialize&lt;JsonElement&gt;(JsonSerializer.Serialize(clientInput));\n        }\n    }\n\n    \/\/ Return the user's input\n    return new ElicitResult\n    {\n        Action = \"accept\",\n        Content = content\n    };\n}<\/code><\/pre>\n<h2>Structured Tool Output<\/h2>\n<p>Another important addition in the 2025-06-18 spec is support for <strong>structured tool output<\/strong>.\nPreviously, tool results were allowed to contain structured data but the host\/LLM had to perform the parsing and interpretation\nwithout any guidance from the tool itself.\nNow, tools can return structured content that is explicitly defined, allowing AI models to better understand and process the output.<\/p>\n<p>The C# SDK supports this by allowing tools to specify that their output is structured, with the <a href=\"https:\/\/modelcontextprotocol.github.io\/csharp-sdk\/api\/ModelContextProtocol.Server.McpServerToolAttribute.html#ModelContextProtocol_Server_McpServerToolAttribute_UseStructuredContent\">UseStructuredContent<\/a> parameter\nof the <a href=\"https:\/\/modelcontextprotocol.github.io\/csharp-sdk\/api\/ModelContextProtocol.Server.McpServerToolAttribute.html\">McpServerTool<\/a> attribute.<\/p>\n<pre><code class=\"language-csharp\">[McpServerTool(UseStructuredContent = true), Description(\"Gets a list of structured product data with detailed information.\")]\npublic static List&lt;Product&gt; GetProducts(int count = 5)<\/code><\/pre>\n<p>The C# SDK will generate a JSON schema for the tool&#8217;s output based on the return type of the method\nand will include this schema in the tool&#8217;s metadata. Here is an example of the response to a <code>tools\/list<\/code> call\nthat shows the output schema for the <code>get_products<\/code> tool:<\/p>\n<pre><code class=\"language-json\">{\n  \"result\": {\n    \"tools\": [\n      {\n        \"name\": \"get_products\",\n        \"description\": \"Gets a list of structured product data with detailed information.\",\n        \"inputSchema\": {\n          \"type\": \"object\",\n          \"properties\": {\n            \"count\": {\n              \"type\": \"integer\",\n              \"default\": 5\n            }\n          }\n        },\n        \"outputSchema\": {\n          \"type\": \"object\",\n          \"properties\": {\n            \"result\": {\n              \"type\": \"array\",\n              \"items\": {\n                \"type\": \"object\",\n                \"properties\": {\n                  \"id\": {\n                    \"description\": \"Unique identifier for the product\",\n                    \"type\": \"integer\"\n                  },\n                  \"name\": {\n                    \"description\": \"Name of the product\",\n                    \"type\": \"string\"\n                  },\n...<\/code><\/pre>\n<p>And when the tool is called, the tool response will include the structured output in the <code>result.structuredContent<\/code> field:<\/p>\n<pre><code class=\"language-json\">{\n  \"result\": {\n    \"content\": [\n      {\n        \"type\": \"text\",\n        \"text\": \"&lt;text content&gt;\"\n      }\n    ],\n    \"structuredContent\": {\n      \"result\": [\n        {\n          \"id\": 1,\n          \"name\": \"Laptop Pro\",\n          \"description\": \"High-quality laptop pro for professional use\",\n          \"price\": 278,\n          \"category\": \"Electronics\",\n          \"brand\": \"TechCorp\",\n          \"inStock\": 24,\n          \"rating\": 4.3,\n          \"features\": [\n            \"Durable construction\",\n            \"Modern design\",\n            \"Easy to use\"\n          ],\n          \"specifications\": {\n            \"Weight\": \"1 lbs\",\n            \"Dimensions\": \"12x12x2 inches\",\n            \"Warranty\": \"2 years\"\n          }\n        },\n        ...\n      ]\n    }\n  },\n  \"id\": 2,\n  \"jsonrpc\": \"2.0\"\n}<\/code><\/pre>\n<h2>Resource Links in Tool Results<\/h2>\n<p>Tools can now include <strong>resource links<\/strong> in their results, enabling better resource discovery and navigation.\nThis is particularly useful for tools that create or manage resources, allowing clients to easily access and interact with those resources.<\/p>\n<p>In the following example, a tool creates a resource with a random value and returns a link to this resource:<\/p>\n<pre><code class=\"language-csharp\">[McpServerTool]\n[Description(\"Creates a resource with a random value and returns a link to this resource.\")]\npublic async Task&lt;CallToolResult&gt; MakeAResource()\n{\n    int id = new Random().Next(1, 101); \/\/ 1 to 100 inclusive\n\n    var resource = ResourceGenerator.CreateResource(id);\n\n    var result = new CallToolResult();\n\n    result.Content.Add(new ResourceLinkBlock()\n    {\n        Uri = resource.Uri,\n        Name = resource.Name\n    });\n\n    return result;\n}<\/code><\/pre>\n<h2>Schema Improvements<\/h2>\n<p>Beyond the major features, several schema improvements enhance the developer experience:<\/p>\n<h3>Enhanced Metadata Support<\/h3>\n<p>The <code>_meta<\/code> field is now available on more interface types, providing better extensibility:<\/p>\n<pre><code class=\"language-csharp\">public class CustomTool : Tool\n{\n    public ToolMetadata Meta { get; set; } = new()\n    {\n        [\"version\"] = \"1.0.0\",\n        [\"author\"] = \"Your Name\",\n        [\"category\"] = \"data-analysis\"\n    };\n}<\/code><\/pre>\n<h3>Human-Friendly Titles<\/h3>\n<p><!-- https:\/\/github.com\/modelcontextprotocol\/csharp-sdk\/pull\/513 --><\/p>\n<p>Tools, Resources, and Prompts all now support separate <code>name<\/code> and <code>title<\/code> fields.<\/p>\n<p>In the MCP C# SDK, you can specify a title for your tool using the <code>Title<\/code> property of the <a href=\"https:\/\/modelcontextprotocol.github.io\/csharp-sdk\/api\/ModelContextProtocol.Server.McpServerToolAttribute.html\">McpServerTool<\/a> attribute.<\/p>\n<pre><code class=\"language-csharp\">[McpServerToolType]\npublic class EchoTool\n{\n    [McpServerTool(Name = \"echo\", Title = \"Echo Tool\")]\n    [Description(\"Echoes the message back to the client.\")]\n    public static string Echo(string message) =&gt; $\"Echo: {message}\";\n}<\/code><\/pre>\n<p>This produces the following tool metadata in the <code>tools\/list<\/code> response:<\/p>\n<pre><code class=\"language-json\">\"tools\": [\n  {\n    \"name\": \"echo\",\n    \"title\": \"Echo Tool\",\n    \"description\": \"Echoes the message back to the client.\",\n    \"inputSchema\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"message\": {\n          \"type\": \"string\"\n        }\n      },\n      \"required\": [\n        \"message\"\n      ]\n    },<\/code><\/pre>\n<p>The <code>name<\/code> and <code>title<\/code> parameters of the <a href=\"https:\/\/modelcontextprotocol.github.io\/csharp-sdk\/api\/ModelContextProtocol.Server.McpServerToolAttribute.html\">McpServerTool<\/a> attribute are optional.\nIf not specified, the <code>name<\/code> defaults to the lower snake case form of the method name and the <code>title<\/code> defaults to an empty string.<\/p>\n<h2>Getting Started with the Updated SDK<\/h2>\n<p>To start using these new features, update your MCP C# SDK package:<\/p>\n<pre><code class=\"language-bash\">dotnet add package ModelContextProtocol --prerelease<\/code><\/pre>\n<p>When implementing these new capabilities, consider the following best practices:<\/p>\n<ul>\n<li>Always implement proper OAuth flows for production applications<\/li>\n<li>Use resource indicators to prevent token misuse<\/li>\n<li>Validate all elicited user input<\/li>\n<li>Follow the <a href=\"https:\/\/modelcontextprotocol.io\/specification\/2025-06-18\/basic\/security_best_practices\">security best practices<\/a> outlined in the specification<\/li>\n<\/ul>\n<h2>What&#8217;s Next<\/h2>\n<p>The MCP ecosystem continues to grow, and we&#8217;re committed to keeping the C# SDK up-to-date with the latest specification changes.<\/p>\n<p>The MCP C# SDK is open source and we welcome contributions! Whether you&#8217;re reporting bugs, suggesting features, or contributing code, your involvement helps make the SDK better for everyone.<\/p>\n<ul>\n<li><strong>GitHub Repository<\/strong>: <a href=\"https:\/\/github.com\/modelcontextprotocol\/csharp-sdk\">modelcontextprotocol\/csharp-sdk<\/a><\/li>\n<li><strong>Documentation<\/strong>: <a href=\"https:\/\/modelcontextprotocol.github.io\/csharp-sdk\/api\/ModelContextProtocol.html\">MCP C# SDK Docs<\/a><\/li>\n<li><strong>Samples<\/strong>: <a href=\"https:\/\/github.com\/modelcontextprotocol\/csharp-sdk\/tree\/main\/samples\">MCP C# Samples<\/a><\/li>\n<\/ul>\n<h2>Summary<\/h2>\n<p>The MCP C# SDK&#8217;s support for protocol version 2025-06-18 brings powerful new capabilities to .NET developers building AI applications. With the new authentication protocol, elicitation support, structured tool output, and support for resource links in tool results, you can create more sophisticated and secure AI integrations than ever before.<\/p>\n<p>Start exploring these new features today by updating your SDK and reviewing the updated documentation. The future of AI application development with .NET just got brighter!<\/p>\n<p><div  class=\"d-flex justify-content-center\"><a class=\"cta_button_link btn-primary mb-24\" href=\"https:\/\/github.com\/modelcontextprotocol\/csharp-sdk\" target=\"_blank\">Get Started with MCP C# SDK<\/a><\/div><\/p>\n","protected":false},"excerpt":{"rendered":"<p>The MCP C# SDK has been updated to support the latest Model Context Protocol specification (2025-06-18), bringing structured tool output, elicitation support, enhanced security, and more to .NET developers building AI applications.<\/p>\n","protected":false},"author":68772,"featured_media":57358,"comment_status":"open","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[685,7781,756],"tags":[4,568,46,8032,8053,7827],"class_list":["post-57357","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dotnet","category-ai","category-csharp","tag-net","tag-ai","tag-c","tag-mcp","tag-model-context-protocol","tag-sdk"],"acf":[],"blog_post_summary":"<p>The MCP C# SDK has been updated to support the latest Model Context Protocol specification (2025-06-18), bringing structured tool output, elicitation support, enhanced security, and more to .NET developers building AI applications.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/57357","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/68772"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=57357"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/57357\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/57358"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=57357"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=57357"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=57357"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}