{"id":3569,"date":"2026-03-05T18:46:52","date_gmt":"2026-03-05T18:46:52","guid":{"rendered":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/2026\/03\/05\/release-v1-0-of-the-official-mcp-c-sdk\/"},"modified":"2026-03-05T18:46:52","modified_gmt":"2026-03-05T18:46:52","slug":"release-v1-0-of-the-official-mcp-c-sdk","status":"publish","type":"post","link":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/2026\/03\/05\/release-v1-0-of-the-official-mcp-c-sdk\/","title":{"rendered":"Release v1.0 of the official MCP C# SDK"},"content":{"rendered":"<p><!-- cspell:ignore CIMD nameof resumability streamable mikekistler --><\/p>\n<p>The <a href=\"https:\/\/github.com\/modelcontextprotocol\/csharp-sdk\">Model Context Protocol (MCP) C# SDK<\/a> has reached its v1.0 milestone, bringing full support for the<br \/>\n<a href=\"https:\/\/modelcontextprotocol.io\/specification\/2025-11-25\">2025-11-25 version of the MCP Specification<\/a>.<br \/>\nThis release delivers a rich set of new capabilities \u2014 from improved authorization flows and richer metadata,<br \/>\nto powerful new patterns for tool calling, elicitation, and long-running request handling.<\/p>\n<p>Here\u2019s a tour of what\u2019s new.<\/p>\n<h2>Enhanced authorization server discovery<\/h2>\n<p>In the previous spec, servers were required to provide a link to their Protected Resource Metadata (PRM) Document<br \/>\nin the <code>resource_metadata<\/code> parameter of the <code>WWW-Authenticate<\/code> header.<br \/>\nThe 2025-11-25 spec broadens this, giving servers three ways to expose the PRM:<\/p>\n<ol>\n<li>Via a URL in the <code>resource_metadata<\/code> parameter of the <code>WWW-Authenticate<\/code> header (as before)<\/li>\n<li>At a \u201cwell-known\u201d URL derived from the server\u2019s MCP endpoint path<br \/>\n(e.g. <code>https:\/\/example.com\/.well-known\/oauth-protected-resource\/public\/mcp<\/code>)<\/li>\n<li>At the root well-known URL (e.g. <code>https:\/\/example.com\/.well-known\/oauth-protected-resource<\/code>)<\/li>\n<\/ol>\n<p>Clients check these locations in order.<\/p>\n<p>On the server side, the SDK\u2019s <a href=\"https:\/\/csharp.sdk.modelcontextprotocol.io\/api\/Microsoft.Extensions.DependencyInjection.McpAuthenticationExtensions.html\">AddMcp extension method on AuthenticationBuilder<\/a><br \/>\nmakes it easy to configure the PRM Document:<\/p>\n<pre><code class=\"language-csharp\">.AddMcp(options =&gt;\n{\n    options.ResourceMetadata = new()\n    {\n        ResourceDocumentation = new Uri(\"https:\/\/docs.example.com\/api\/weather\"),\n        AuthorizationServers = { new Uri(inMemoryOAuthServerUrl) },\n        ScopesSupported = [\"mcp:tools\"],\n    };\n});<\/code><\/pre>\n<p>When configured this way, the SDK automatically hosts the PRM Document at the well-known location<br \/>\nand includes the link in the <code>WWW-Authenticate<\/code> header. On the client side, the SDK handles the<br \/>\nfull discovery sequence automatically.<\/p>\n<h2>Icons for tools, resources, and prompts<\/h2>\n<p>The 2025-11-25 spec adds icon metadata to Tools, Resources, and Prompts. This information is included<br \/>\nin the response to <code>tools\/list<\/code>, <code>resources\/list<\/code>, and <code>prompts\/list<\/code> requests.<br \/>\nImplementation metadata (describing a client or server) has also been extended with icons and a website URL.<\/p>\n<p>The simplest way to add an icon for a tool is with the <a href=\"https:\/\/csharp.sdk.modelcontextprotocol.io\/api\/ModelContextProtocol.Server.McpServerToolAttribute.html#ModelContextProtocol_Server_McpServerToolAttribute_IconSource\">IconSource parameter on the McpServerToolAttribute<\/a>:<\/p>\n<pre><code class=\"language-csharp\">[McpServerTool(Title = \"This is a title\", IconSource = \"https:\/\/example.com\/tool-icon.svg\")]\npublic static string ToolWithIcon(<\/code><\/pre>\n<p>The <a href=\"https:\/\/csharp.sdk.modelcontextprotocol.io\/api\/ModelContextProtocol.Server.McpServerResourceAttribute.html\">McpServerResourceAttribute<\/a>, <code>McpServerResourceTemplateAttribute<\/code>, and <a href=\"https:\/\/csharp.sdk.modelcontextprotocol.io\/api\/ModelContextProtocol.Server.McpServerPromptAttribute.html\">McpServerPromptAttribute<\/a><br \/>\nhave also added an <code>IconSource<\/code> parameter.<\/p>\n<p>For more advanced scenarios \u2014 multiple icons, MIME types, size hints, and theme preferences \u2014 you can<br \/>\nconfigure icons programmatically via <a href=\"https:\/\/csharp.sdk.modelcontextprotocol.io\/api\/ModelContextProtocol.Server.McpServerToolCreateOptions.html#ModelContextProtocol_Server_McpServerToolCreateOptions_Icons\">McpServerToolCreateOptions.Icons<\/a>:<\/p>\n<pre><code class=\"language-csharp\">.WithTools([\n    McpServerTool.Create(\n        typeof(EchoTool).GetMethod(nameof(EchoTool.Echo))!,\n        options: new McpServerToolCreateOptions\n        {\n            Icons = [\n                new Icon\n                {\n                    Source = \"https:\/\/raw.githubusercontent.com\/microsoft\/fluentui-emoji\/main\/assets\/Loudspeaker\/Flat\/loudspeaker_flat.svg\",\n                    MimeType = \"image\/svg+xml\",\n                    Sizes = [\"any\"],\n                    Theme = \"light\"\n                },\n                new Icon\n                {\n                    Source = \"https:\/\/raw.githubusercontent.com\/microsoft\/fluentui-emoji\/main\/assets\/Loudspeaker\/3D\/loudspeaker_3d.png\",\n                    MimeType = \"image\/png\",\n                    Sizes = [\"256x256\"],\n                    Theme = \"dark\"\n                }\n            ]\n        }\n    )\n])<\/code><\/pre>\n<p>Here\u2019s how these icons could be displayed, as illustrated in the MCP Inspector:<\/p>\n<p><img data-opt-id=205808154  fetchpriority=\"high\" decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2026\/03\/icons-for-tools.png\" alt=\"Icons displayed in MCP Inspector showing tool icons with different themes and styles\" \/><\/p>\n<p>This placement works well after the code example showing how to configure multiple icons, providing a visual demonstration of how those icons appear in practice.<\/p>\n<p>The <a href=\"https:\/\/csharp.sdk.modelcontextprotocol.io\/api\/ModelContextProtocol.Protocol.Implementation.html\">Implementation<\/a> class also has<br \/>\n<a href=\"https:\/\/csharp.sdk.modelcontextprotocol.io\/api\/ModelContextProtocol.Protocol.Implementation.html#ModelContextProtocol_Protocol_Implementation_Icons\">Icons<\/a> and<br \/>\n<a href=\"https:\/\/csharp.sdk.modelcontextprotocol.io\/api\/ModelContextProtocol.Protocol.Implementation.html#ModelContextProtocol_Protocol_Implementation_WebsiteUrl\">WebsiteUrl<\/a> properties for server and client metadata:<\/p>\n<pre><code class=\"language-csharp\">.AddMcpServer(options =&gt;\n{\n    options.ServerInfo = new Implementation\n    {\n        Name = \"Everything Server\",\n        Version = \"1.0.0\",\n        Title = \"MCP Everything Server\",\n        Description = \"A comprehensive MCP server demonstrating all MCP features\",\n        WebsiteUrl = \"https:\/\/github.com\/modelcontextprotocol\/csharp-sdk\",\n        Icons = [\n            new Icon\n            {\n                Source = \"https:\/\/raw.githubusercontent.com\/microsoft\/fluentui-emoji\/main\/assets\/Gear\/Flat\/gear_flat.svg\",\n                MimeType = \"image\/svg+xml\",\n                Sizes = [\"any\"],\n                Theme = \"light\"\n            }\n        ]\n    };\n})<\/code><\/pre>\n<h2>Incremental scope consent<\/h2>\n<p>The incremental scope consent feature brings the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Principle_of_least_privilege\">Principle of Least Privilege<\/a><br \/>\nto MCP authorization, allowing clients to request only the minimum access needed for each operation.<\/p>\n<p>MCP uses OAuth 2.0 for authorization, where <em>scopes<\/em> define the level of access a client has.<br \/>\nPreviously, clients might request all possible scopes up front because they couldn\u2019t know which scopes<br \/>\na specific operation would require. With incremental scope consent, clients start with minimal scopes<br \/>\nand request additional ones as needed.<\/p>\n<p>The mechanism works through two flows:<\/p>\n<ul>\n<li>\n<p><strong>Initial scopes<\/strong>: When a client makes an unauthenticated request, the server responds with<br \/>\n<code>401 Unauthorized<\/code> and a <code>WWW-Authenticate<\/code> header that now includes a <code>scopes<\/code> parameter listing<br \/>\nthe scopes needed for the operation. Clients request authorization for only these scopes.<\/p>\n<\/li>\n<li>\n<p><strong>Additional scopes<\/strong>: When a client\u2019s token lacks scopes for a particular operation, the server<br \/>\nresponds with <code>403 Forbidden<\/code> and a <code>WWW-Authenticate<\/code> header containing an <code>error<\/code> parameter<br \/>\nof <code>insufficient_scope<\/code> and a <code>scopes<\/code> parameter with the required scopes. The client then<br \/>\nobtains a new token with the expanded scopes and retries.<\/p>\n<\/li>\n<\/ul>\n<h3>Client support for incremental scope consent<\/h3>\n<p>The MCP C# client SDK handles incremental scope consent automatically. When it receives a <code>401<\/code> or <code>403<\/code> with a <code>scopes<\/code><br \/>\nparameter in the <code>WWW-Authenticate<\/code> header, it extracts the required scopes and initiates the<br \/>\nauthorization flow \u2014 no additional client code needed.<\/p>\n<h3>Server support for incremental scope consent<\/h3>\n<p>Setting up incremental scope consent on the server involves:<\/p>\n<ol>\n<li>\n<p><strong>Adding authentication services<\/strong> configured with the MCP authentication scheme:<\/p>\n<pre><code class=\"language-csharp\">builder.Services.AddAuthentication(options =&gt;\n{\n    options.DefaultAuthenticateScheme = McpAuthenticationDefaults.AuthenticationScheme;\n    options.DefaultChallengeScheme = McpAuthenticationDefaults.AuthenticationScheme;\n})<\/code><\/pre>\n<\/li>\n<li>\n<p><strong>Enabling JWT bearer authentication<\/strong> with appropriate token validation:<\/p>\n<pre><code class=\"language-csharp\">.AddJwtBearer(options =&gt;\n{\n    options.TokenValidationParameters = new TokenValidationParameters\n    {\n        ValidateIssuer = true,\n        ValidateAudience = true,\n        ValidateLifetime = true,\n        ValidateIssuerSigningKey = true,\n        \/\/ Other validation settings as appropriate\n    };\n})<\/code><\/pre>\n<p>The following token validation settings are strongly recommended:<\/p>\n<table>\n<thead>\n<tr>\n<th>Setting<\/th>\n<th>Value<\/th>\n<th>Description<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>ValidateIssuer<\/code><\/td>\n<td><code>true<\/code><\/td>\n<td>Ensures the token was issued by a trusted authority<\/td>\n<\/tr>\n<tr>\n<td><code>ValidateAudience<\/code><\/td>\n<td><code>true<\/code><\/td>\n<td>Verifies the token is intended for this server<\/td>\n<\/tr>\n<tr>\n<td><code>ValidateLifetime<\/code><\/td>\n<td><code>true<\/code><\/td>\n<td>Checks that the token has not expired<\/td>\n<\/tr>\n<tr>\n<td><code>ValidateIssuerSigningKey<\/code><\/td>\n<td><code>true<\/code><\/td>\n<td>Confirms the token signature is valid<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/li>\n<li>\n<p><strong>Specifying authentication scheme metadata<\/strong> to guide clients on obtaining access tokens:<\/p>\n<pre><code class=\"language-csharp\">.AddMcp(options =&gt;\n{\n    options.ResourceMetadata = new()\n    {\n        ResourceDocumentation = new Uri(\"https:\/\/docs.example.com\/api\/weather\"),\n        AuthorizationServers = { new Uri(inMemoryOAuthServerUrl) },\n        ScopesSupported = [\"mcp:tools\"],\n    };\n});<\/code><\/pre>\n<\/li>\n<li>\n<p><strong>Performing authorization checks in middleware<\/strong>.<br \/>\nAuthorization checks should be implemented in ASP.NET Core middleware instead of inside the tool method itself. This is because the MCP HTTP handler may (and in practice does) flush response headers before invoking the tool. By the time the tool call method is invoked, it is too late to set the response status code or headers.<\/p>\n<p>Unfortunately, the middleware may need to inspect the contents of the request to determine which scopes are required, which involves an extra deserialization for incoming requests. But help may be on the way in future versions of the MCP protocol that will avoid this overhead in most cases. Stay tuned\u2026<\/p>\n<p>In addition to inspecting the request, the middleware must also extract the scopes from the access token sent in the request. In the MCP C# SDK, the authentication handler extracts the scopes from the JWT and converts them to claims in the HttpContext.User property. The way these claims are represented depends on the token issuer and the JWT structure. For a token issuer that represents scopes as a space-separated string in the scope claim, you can determine the scopes passed in the request as follows:<\/p>\n<pre><code class=\"language-csharp\">var user = context.User;\nvar userScopes = user?.Claims\n        .Where(c =&gt; c.Type == \"scope\" || c.Type == \"scp\")\n        .SelectMany(c =&gt; c.Value.Split(' '))\n        .Distinct()\n        .ToList();<\/code><\/pre>\n<p>With the scopes extracted from the request, the server can then check if the required scope(s) for the requested operation is included with <code>userScopes.Contains(requiredScope)<\/code>.<\/p>\n<p>If the required scopes are missing, respond with <code>403 Forbidden<\/code> and a <code>WWW-Authenticate<\/code> header, including an <code>error<\/code> parameter indicating insufficient_scope and a <code>scopes<\/code> parameter indicating the scopes required.<br \/>\nThe <a href=\"https:\/\/modelcontextprotocol.io\/specification\/2025-11-25\/basic\/authorization#runtime-insufficient-scope-errors\">MCP Specification<\/a> describes several strategies for choosing which scopes to include:<\/p>\n<ul>\n<li><strong>Minimum approach<\/strong>: Only the newly-required scopes (plus any existing granted scopes that are still relevant)<\/li>\n<li><strong>Recommended approach<\/strong>: Existing relevant scopes plus newly required scopes<\/li>\n<li><strong>Extended approach<\/strong>: Existing scopes, newly required scopes, and related scopes that commonly work together<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<h2>URL mode elicitation<\/h2>\n<p>URL mode elicitation enables secure out-of-band interactions between the server and end-user,<br \/>\nbypassing the MCP host\/client entirely. This is particularly valuable for gathering sensitive data \u2014 like API keys,<br \/>\nthird-party authorizations, and payment information \u2014 that would pose a security risk<br \/>\nif transmitted through the client.<\/p>\n<p>Inspired by web security standards like OAuth, this mechanism lets the MCP client obtain user consent<br \/>\nand direct the user\u2019s browser to a secure server-hosted URL where the sensitive interaction takes place.<\/p>\n<p>The MCP host\/client must present the elicitation request to the user \u2014 including the server\u2019s identity<br \/>\nand the purpose of the request \u2014 and provide options to decline or cancel.<br \/>\nWhat the server does at the elicitation URL is outside the scope of MCP; it could present a form,<br \/>\nredirect to a third-party authorization service, or anything else.<\/p>\n<h3>Client support for URL mode elicitation<\/h3>\n<p>Clients indicate support by setting the <a href=\"https:\/\/csharp.sdk.modelcontextprotocol.io\/api\/ModelContextProtocol.Protocol.ElicitationCapability.html#ModelContextProtocol_Protocol_ElicitationCapability_Url\">Url<\/a> property in <a href=\"https:\/\/csharp.sdk.modelcontextprotocol.io\/api\/ModelContextProtocol.Protocol.ClientCapabilities.html#ModelContextProtocol_Protocol_ClientCapabilities_Elicitation\">Capabilities.Elicitation<\/a>:<\/p>\n<pre><code class=\"language-csharp\">McpClientOptions options = new()\n{\n    Capabilities = new ClientCapabilities\n    {\n        Elicitation = new ElicitationCapability\n        {\n            Url = new UrlElicitationCapability()\n        }\n    }\n    \/\/ other client options<\/code><\/pre>\n<p>The client must also provide an <a href=\"https:\/\/csharp.sdk.modelcontextprotocol.io\/api\/ModelContextProtocol.Client.McpClientHandlers.html#ModelContextProtocol_Client_McpClientHandlers_ElicitationHandler\">ElicitationHandler<\/a>.<br \/>\nSince there\u2019s a single handler for both form mode and URL mode elicitation, the handler should begin by checking the<br \/>\n<a href=\"https:\/\/csharp.sdk.modelcontextprotocol.io\/api\/ModelContextProtocol.Protocol.ElicitRequestParams.html#ModelContextProtocol_Protocol_ElicitRequestParams_Mode\">Mode property of the ElicitationRequest parameters<\/a><br \/>\nto determine which mode is being requested and handle it accordingly.<\/p>\n<pre><code class=\"language-csharp\">async ValueTask&lt;ElicitResult&gt; HandleElicitationAsync(ElicitRequestParams? requestParams, CancellationToken token)\n{\n    if (requestParams is null || requestParams.Mode != \"url\" || requestParams.Url is null)\n    {\n        return new ElicitResult();\n    }\n\n    \/\/ Success path for URL-mode elicitation omitted for brevity.\n}<\/code><\/pre>\n<h3>Server support for URL mode elicitation<\/h3>\n<p>The server must define an endpoint for the elicitation URL and handle the response.<br \/>\nTypically the response is submitted via POST to keep sensitive data out of URLs and logs.<br \/>\nIf the URL serves a form, it should include anti-forgery tokens to prevent CSRF attacks \u2014<br \/>\nASP.NET Core provides built-in support for this.<\/p>\n<p>One approach is to create a Razor Page:<\/p>\n<pre><code class=\"language-csharp\">public class ElicitationFormModel : PageModel\n{\n    public string ElicitationId { get; set; } = string.Empty;\n\n    public IActionResult OnGet(string id)\n    {\n        \/\/ Serves the elicitation URL when the user navigates to it\n    }\n\n    public async Task&lt;IActionResult&gt; OnPostAsync(string id, string name, string ssn, string secret)\n    {\n        \/\/ Handles the elicitation response when the user submits the form\n    }\n}<\/code><\/pre>\n<p>Note the <code>id<\/code> parameter on both methods \u2014 since an MCP server using Streamable HTTP Transport<br \/>\nis inherently multi-tenant, the server must associate each elicitation request and response<br \/>\nwith the correct MCP session. The server must maintain state to track pending elicitation requests<br \/>\nand communicate responses back to the originating MCP request.<\/p>\n<h2>Tool calling support in sampling<\/h2>\n<p>This is one of the most powerful additions in the 2025-11-25 spec. Servers can now include tools<br \/>\nin their sampling requests, which the LLM may invoke to produce a response.<\/p>\n<p>While providing tools to LLMs is a central feature of MCP, tools in sampling requests are fundamentally different<br \/>\nfrom standard MCP tools \u2014 despite sharing the same metadata structure. They don\u2019t need to be implemented<br \/>\nas standard MCP tools, so the server must implement its own logic to handle tool invocations.<\/p>\n<p>The flow is important to understand: when the LLM requests a tool invocation during sampling,<br \/>\nthat\u2019s the <em>response<\/em> to the sampling request. The server executes the tool, then issues a <em>new<\/em><br \/>\nsampling request that includes both the tool call request and the tool call response. This continues<br \/>\nuntil the LLM produces a final response with no tool invocation requests.<\/p>\n<pre><code class=\"language-mermaid\">sequenceDiagram\n    participant Server\n    participant Client\n\n    Server-&gt;&gt;Client: CreateMessage Request\n    Note right of Client: messages: [original prompt]&lt;br\/&gt;tools: [tool definitions]\n    Client--&gt;&gt;Server: CreateMessage Response\n    Note left of Server: stopReason: tool_calls&lt;br\/&gt;toolCalls: [tool call 1, tool call 2]\n\n    Note over Server: Server executes tools locally\n\n    Server-&gt;&gt;Client: CreateMessage Request\n    Note right of Client: messages: [&lt;br\/&gt;  original prompt,&lt;br\/&gt;  tool call 1 request,&lt;br\/&gt;  tool call 1 response,&lt;br\/&gt;  tool call 2 request,&lt;br\/&gt;  tool call 2 response&lt;br\/&gt;]&lt;br\/&gt;tools: [tool definitions]\n    Client--&gt;&gt;Server: CreateMessage Response\n    Note left of Server: stopReason: end_turn&lt;br\/&gt;content: [final response]<\/code><\/pre>\n<h3>Client\/host support for tool calling in sampling<\/h3>\n<p>Clients declare support for tool calling in sampling through their capabilities and must provide<br \/>\na <a href=\"https:\/\/csharp.sdk.modelcontextprotocol.io\/api\/ModelContextProtocol.Client.McpClientHandlers.html#ModelContextProtocol_Client_McpClientHandlers_SamplingHandler\">SamplingHandler<\/a>:<\/p>\n<pre><code class=\"language-csharp\">var mcpClient = await McpClient.CreateAsync(\n    new HttpClientTransport(new()\n    {\n        Endpoint = new Uri(\"http:\/\/localhost:6184\"),\n        Name = \"SamplingWithTools MCP Server\",\n    }),\n    clientOptions: new()\n    {\n        Capabilities = new ClientCapabilities\n        {\n            Sampling = new SamplingCapability\n            {\n                Tools = new SamplingToolsCapability {}\n            }\n        },\n        Handlers = new()\n        {\n            SamplingHandler = async (c, p, t) =&gt;\n            {\n                return await samplingHandler(c, p, t);\n            },\n        }\n    });<\/code><\/pre>\n<p>Implementing the <a href=\"https:\/\/csharp.sdk.modelcontextprotocol.io\/api\/ModelContextProtocol.Client.McpClientHandlers.html#ModelContextProtocol_Client_McpClientHandlers_SamplingHandler\">SamplingHandler<\/a> from scratch would be complex, but the <code>Microsoft.Extensions.AI<\/code><br \/>\npackage makes it straightforward. You can obtain an <code>IChatClient<\/code> from your LLM provider and use<br \/>\n<a href=\"https:\/\/csharp.sdk.modelcontextprotocol.io\/api\/ModelContextProtocol.AIContentExtensions.html\">CreateSamplingHandler<\/a> to get a handler that translates between MCP and your LLM\u2019s tool invocation format:<\/p>\n<pre><code class=\"language-csharp\">IChatClient chatClient =\n    new OpenAIClient(new ApiKeyCredential(token), new OpenAIClientOptions { Endpoint = new Uri(baseUrl) })\n        .GetChatClient(modelId)\n        .AsIChatClient();\n\nvar samplingHandler = chatClient.CreateSamplingHandler();<\/code><\/pre>\n<p>The sampling handler from <code>IChatClient<\/code> handles format translation but does not implement user consent<br \/>\nfor tool invocations. You can wrap it in a custom handler to add consent logic.<br \/>\nNote that it will be important to cache user approvals to avoid prompting the user multiple times for the same tool invocation during a single sampling session.<\/p>\n<h3>Server support for tool calling in sampling<\/h3>\n<p>Servers can take advantage of the tool calling support in sampling if they are connected to a client\/host that also supports this feature.<br \/>\nServers can check whether the connected client supports tool calling in sampling:<\/p>\n<pre><code class=\"language-csharp\">if (_mcpServer?.ClientCapabilities?.Sampling?.Tools is not {})\n{\n    return \"Error: Client does not support sampling with tools.\";\n}<\/code><\/pre>\n<p>Tools for sampling can be described as simple <a href=\"https:\/\/csharp.sdk.modelcontextprotocol.io\/api\/ModelContextProtocol.Protocol.Tool.html\">Tool<\/a> objects:<\/p>\n<pre><code class=\"language-csharp\">Tool rollDieTool = new Tool()\n{\n    Name = \"roll_die\",\n    Description = \"Rolls a single six-sided die and returns the result (1-6).\"\n};<\/code><\/pre>\n<p>But the real power comes from using <code>Microsoft.Extensions.AI<\/code> on the server side too. The <a href=\"https:\/\/csharp.sdk.modelcontextprotocol.io\/api\/ModelContextProtocol.Server.McpServer.html#ModelContextProtocol_Server_McpServer_AsSamplingChatClient_System_Text_Json_JsonSerializerOptions_\">McpServer.AsSamplingChatClient()<\/a><br \/>\nmethod returns an <code>IChatClient<\/code> that supports sampling, and <code>UseFunctionInvocation<\/code> adds tool calling support:<\/p>\n<pre><code class=\"language-csharp\">IChatClient chatClient =\n    ChatClientBuilderChatClientExtensions.AsBuilder(_mcpServer.AsSamplingChatClient())\n    .UseFunctionInvocation()\n    .Build();<\/code><\/pre>\n<p>Define tools as <code>AIFunction<\/code> objects and pass them in <code>ChatOptions<\/code>:<\/p>\n<pre><code class=\"language-csharp\">AIFunction rollDieTool = AIFunctionFactory.Create(\n    () =&gt; Random.Shared.Next(1, 7),\n    name: \"roll_die\",\n    description: \"Rolls a single six-sided die and returns the result (1-6).\"\n);\n\nvar chatOptions = new ChatOptions\n{\n    Tools = [rollDieTool],\n    ToolMode = ChatToolMode.Auto\n};\n\nvar pointRollResponse = await chatClient.GetResponseAsync(\n    \"&lt;Prompt that may use the roll_die tool&gt;\",\n    chatOptions,\n    cancellationToken\n);<\/code><\/pre>\n<p>The <code>IChatClient<\/code> handles all the complexity: sending sampling requests with tools, processing<br \/>\ntool invocation requests, executing tools, and translating between MCP and LLM formats.<\/p>\n<h2>OAuth Client ID Metadata Documents<\/h2>\n<p>The 2025-11-25 spec introduces Client ID Metadata Documents (CIMDs) as an alternative<br \/>\nto Dynamic Client Registration (DCR) for establishing client identity with an authorization server.<br \/>\nCIMD is now the preferred method for client registration in MCP.<\/p>\n<p>The idea is simple: the client specifies a URL as its <code>client_id<\/code> in authorization requests.<br \/>\nThat URL resolves to a JSON document hosted by the client containing its metadata \u2014 identifiers,<br \/>\nredirect URIs, and other descriptive information. When an authorization server encounters this <code>client_id<\/code>,<br \/>\nit dereferences the URL and uses the metadata to understand and apply policy to the client.<\/p>\n<p>In the C# SDK, clients specify a CIMD URL via <a href=\"https:\/\/csharp.sdk.modelcontextprotocol.io\/api\/ModelContextProtocol.Authentication.ClientOAuthOptions.html\">ClientOAuthOptions<\/a>:<\/p>\n<pre><code class=\"language-csharp\">const string ClientMetadataDocumentUrl = $\"{ClientUrl}\/client-metadata\/cimd-client.json\";\n\nawait using var transport = new HttpClientTransport(new()\n{\n    Endpoint = new(McpServerUrl),\n    OAuth = new ClientOAuthOptions()\n    {\n        RedirectUri = new Uri(\"http:\/\/localhost:1179\/callback\"),\n        AuthorizationRedirectDelegate = HandleAuthorizationUrlAsync,\n        ClientMetadataDocumentUri = new Uri(ClientMetadataDocumentUrl)\n    },\n}, HttpClient, LoggerFactory);<\/code><\/pre>\n<p>The CIMD URL must use HTTPS, have a non-empty path, and cannot contain dot segments or a fragment component.<br \/>\nThe document itself must include at least <code>client_id<\/code>, <code>client_name<\/code>, and <code>redirect_uris<\/code>.<\/p>\n<p>The SDK will attempt CIMD first, and fall back to DCR if the authorization server doesn\u2019t support it<br \/>\n(provided DCR is enabled in the OAuth options).<\/p>\n<h2>Long-running requests over HTTP with polling<\/h2>\n<p>At the data layer, MCP is a message-based protocol with no inherent time limits.<br \/>\nBut over HTTP, timeouts are a fact of life. The 2025-11-25 spec significantly improves the story<br \/>\nfor long-running requests.<\/p>\n<p>Previously, clients could disconnect and reconnect if the server provided an Event ID in SSE events,<br \/>\nbut few servers implemented this \u2014 partly because it implied supporting stream resumption from any<br \/>\nevent ID all the way back to the start. And servers couldn\u2019t proactively disconnect; they had to<br \/>\nwait for clients to do so.<\/p>\n<p>The new approach is cleaner. Servers that open an SSE stream for a request begin with an empty event<br \/>\nthat includes an Event ID and optionally a Retry-After field. After sending this initial event,<br \/>\nservers can close the stream at any time, since the client can reconnect using the Event ID.<\/p>\n<h3>Server support for long-running requests<\/h3>\n<p>To enable this, the server provides an <a href=\"https:\/\/csharp.sdk.modelcontextprotocol.io\/api\/ModelContextProtocol.Server.ISseEventStreamStore.html\">ISseEventStreamStore<\/a> implementation. The SDK includes<br \/>\n<a href=\"https:\/\/csharp.sdk.modelcontextprotocol.io\/api\/ModelContextProtocol.Server.DistributedCacheEventStreamStore.html\">DistributedCacheEventStreamStore<\/a>, which works with any <code>IDistributedCache<\/code>:<\/p>\n<pre><code class=\"language-csharp\">\/\/ Add a MemoryDistributedCache to the service collection\nbuilder.Services.AddDistributedMemoryCache();\n\/\/ Add the MCP server with DistributedCacheEventStreamStore for SSE stream storage\nbuilder.Services\n    .AddMcpServer()\n    .WithHttpTransport()\n    .WithDistributedCacheEventStreamStore()\n    .WithTools&lt;RandomNumberTools&gt;();<\/code><\/pre>\n<p>When a request handler wants to drop the SSE connection and let the client poll for the result,<br \/>\nit calls <a href=\"https:\/\/csharp.sdk.modelcontextprotocol.io\/api\/ModelContextProtocol.Server.RequestContext-1.html\">EnablePollingAsync<\/a> on the <a href=\"https:\/\/csharp.sdk.modelcontextprotocol.io\/api\/ModelContextProtocol.Server.RequestContext-1.html\">McpRequestContext<\/a>:<\/p>\n<pre><code class=\"language-csharp\">await context.EnablePollingAsync(retryInterval: TimeSpan.FromSeconds(retryIntervalInSeconds));<\/code><\/pre>\n<p>The <a href=\"https:\/\/csharp.sdk.modelcontextprotocol.io\/api\/ModelContextProtocol.Server.RequestContext-1.html\">McpRequestContext<\/a> is available in handlers for MCP requests by simply adding it as a parameter to the handler method.<\/p>\n<h3>Implementation considerations<\/h3>\n<p>Event stream stores can be susceptible to unbounded memory growth, so consider these retention strategies:<\/p>\n<ul>\n<li>\n<p><strong>Delete streams for terminated sessions<\/strong>: The client terminates a session with a DELETE request.<br \/>\nUse a <a href=\"https:\/\/csharp.sdk.modelcontextprotocol.io\/api\/ModelContextProtocol.AspNetCore.HttpServerTransportOptions.html#ModelContextProtocol_AspNetCore_HttpServerTransportOptions_RunSessionHandler\">RunSessionHandler<\/a> to detect this and clean up associated streams.<\/p>\n<\/li>\n<li>\n<p><strong>Time-based expiration<\/strong>: <a href=\"https:\/\/csharp.sdk.modelcontextprotocol.io\/api\/ModelContextProtocol.Server.DistributedCacheEventStreamStore.html\">DistributedCacheEventStreamStore<\/a> supports configurable cache timeouts<br \/>\nvia <a href=\"https:\/\/csharp.sdk.modelcontextprotocol.io\/api\/ModelContextProtocol.Server.DistributedCacheEventStreamStoreOptions.html\">DistributedCacheEventStreamStoreOptions<\/a>:<\/p>\n<ul>\n<li><a href=\"https:\/\/csharp.sdk.modelcontextprotocol.io\/api\/ModelContextProtocol.Server.DistributedCacheEventStreamStoreOptions.html#ModelContextProtocol_Server_DistributedCacheEventStreamStoreOptions_EventSlidingExpiration\">EventSlidingExpiration<\/a> and <a href=\"https:\/\/csharp.sdk.modelcontextprotocol.io\/api\/ModelContextProtocol.Server.DistributedCacheEventStreamStoreOptions.html#ModelContextProtocol_Server_DistributedCacheEventStreamStoreOptions_EventAbsoluteExpiration\">EventAbsoluteExpiration<\/a> for individual events<\/li>\n<li><a href=\"https:\/\/csharp.sdk.modelcontextprotocol.io\/api\/ModelContextProtocol.Server.DistributedCacheEventStreamStoreOptions.html#ModelContextProtocol_Server_DistributedCacheEventStreamStoreOptions_MetadataSlidingExpiration\">MetadataSlidingExpiration<\/a> and <a href=\"https:\/\/csharp.sdk.modelcontextprotocol.io\/api\/ModelContextProtocol.Server.DistributedCacheEventStreamStoreOptions.html#ModelContextProtocol_Server_DistributedCacheEventStreamStoreOptions_MetadataAbsoluteExpiration\">MetadataAbsoluteExpiration<\/a> for stream metadata<\/li>\n<\/ul>\n<\/li>\n<li>\n<p><strong>Selective storage<\/strong>: Store only certain events (e.g. final results) and discard others<br \/>\n(e.g. progress notifications).<\/p>\n<\/li>\n<\/ul>\n<h2>Tasks (experimental)<\/h2>\n<blockquote>\n<p><strong>Note<\/strong>: Tasks are an experimental feature in the 2025-11-25 MCP Specification. The API may change in future releases.<\/p>\n<\/blockquote>\n<p>The 2025-11-25 version of the MCP Specification introduces <em>tasks<\/em>, a new primitive that provides durable state tracking<br \/>\nand deferred result retrieval for MCP requests. While <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/release-v10-of-the-official-mcp-csharp-sdk\/#long-running-requests-over-http-with-polling\">stream resumability<\/a><br \/>\nhandles transport-level concerns like reconnection and event replay, tasks operate at the data layer to ensure<br \/>\nthat request results are durably stored and can be retrieved at any point within a server-defined retention window \u2014<br \/>\neven if the original connection is long gone.<\/p>\n<p>The key concept is that tasks <em>augment<\/em> existing requests rather than replacing them.<br \/>\nA client includes a <code>task<\/code> field in a request (e.g. <code>tools\/call<\/code>) to signal that it wants durable result tracking.<br \/>\nInstead of the normal response, the server returns a <code>CreateTaskResult<\/code> containing task metadata \u2014 a unique task ID, the current status (<code>working<\/code>),<br \/>\ntimestamps, a time-to-live (TTL), and optionally a suggested poll interval.<br \/>\nThe client then uses <code>tasks\/get<\/code> to poll for status, <code>tasks\/result<\/code> to retrieve the stored result,<br \/>\n<code>tasks\/list<\/code> to enumerate tasks, and <code>tasks\/cancel<\/code> to cancel a running task.<\/p>\n<p>This durability is valuable in several scenarios:<\/p>\n<ul>\n<li><strong>Resilience to dropped results<\/strong>: If a result is lost due to a network failure, the client can retrieve it again by task ID<br \/>\nrather than re-executing the operation.<\/li>\n<li><strong>Explicit status tracking<\/strong>: Clients can query the server to determine whether a request is still in progress, succeeded, or failed,<br \/>\nrather than relying on notifications or waiting indefinitely.<\/li>\n<li><strong>Integration with workflow systems<\/strong>: MCP servers wrapping existing workflow APIs (e.g. CI\/CD pipelines, batch processing, multi-step analysis)<br \/>\ncan map their existing job tracking directly to the task primitive.<\/li>\n<\/ul>\n<p>Tasks follow a defined lifecycle through these status values:<\/p>\n<table>\n<thead>\n<tr>\n<th>Status<\/th>\n<th>Description<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>working<\/code><\/td>\n<td>Task is actively being processed<\/td>\n<\/tr>\n<tr>\n<td><code>input_required<\/code><\/td>\n<td>Task is waiting for additional input (e.g., elicitation)<\/td>\n<\/tr>\n<tr>\n<td><code>completed<\/code><\/td>\n<td>Task finished successfully; results are available<\/td>\n<\/tr>\n<tr>\n<td><code>failed<\/code><\/td>\n<td>Task encountered an error<\/td>\n<\/tr>\n<tr>\n<td><code>cancelled<\/code><\/td>\n<td>Task was cancelled by the client<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>The last three states (<code>completed<\/code>, <code>failed<\/code>, and <code>cancelled<\/code>) are terminal \u2014 once a task reaches one of these states, it cannot transition to any other state.<\/p>\n<p>Task support is negotiated through explicit capability declarations during initialization.<br \/>\nServers declare that they support task-augmented <code>tools\/call<\/code> requests, while clients can declare support for<br \/>\ntask-augmented <code>sampling\/createMessage<\/code> and <code>elicitation\/create<\/code> requests.<\/p>\n<h3>Server support for tasks<\/h3>\n<p>To enable task support on an MCP server, configure a task store when setting up the server.<br \/>\nThe task store is responsible for managing task state \u2014 creating tasks, storing results, and handling cleanup.<\/p>\n<pre><code class=\"language-csharp\">var taskStore = new InMemoryMcpTaskStore();\n\nbuilder.Services.AddMcpServer(options =&gt;\n{\n    options.TaskStore = taskStore;\n})\n.WithHttpTransport()\n.WithTools&lt;MyTools&gt;();\n\n\/\/ Alternatively, you can register an IMcpTaskStore globally with DI, but you only need to configure it one way.\n\/\/builder.Services.AddSingleton&lt;IMcpTaskStore&gt;(taskStore);<\/code><\/pre>\n<p>The <a href=\"https:\/\/modelcontextprotocol.github.io\/csharp-sdk\/api\/ModelContextProtocol.InMemoryMcpTaskStore.html\">InMemoryMcpTaskStore<\/a> is a reference implementation suitable for development and single-server deployments.<br \/>\nFor production multi-server scenarios, implement <a href=\"https:\/\/modelcontextprotocol.github.io\/csharp-sdk\/api\/ModelContextProtocol.IMcpTaskStore.html\">IMcpTaskStore<\/a><br \/>\nwith a persistent backing store (database, Redis, etc.).<\/p>\n<p>The <code>InMemoryMcpTaskStore<\/code> constructor accepts several optional parameters to control task retention, polling behavior,<br \/>\nand resource limits:<\/p>\n<pre><code class=\"language-csharp\">var taskStore = new InMemoryMcpTaskStore(\n    defaultTtl: TimeSpan.FromHours(1),        \/\/ Default task retention time\n    maxTtl: TimeSpan.FromHours(24),           \/\/ Maximum allowed TTL\n    pollInterval: TimeSpan.FromSeconds(1),    \/\/ Suggested client poll interval\n    cleanupInterval: TimeSpan.FromMinutes(5), \/\/ Background cleanup frequency\n    pageSize: 100,                            \/\/ Tasks per page for listing\n    maxTasks: 1000,                           \/\/ Maximum total tasks allowed\n    maxTasksPerSession: 100                   \/\/ Maximum tasks per session\n);<\/code><\/pre>\n<p>Tools automatically advertise task support when they return <code>Task<\/code>, <code>ValueTask<\/code>, <code>Task&lt;T&gt;<\/code>, or <code>ValueTask&lt;T&gt;<\/code> (i.e. async methods).<br \/>\nYou can explicitly control task support on individual tools using the <code>ToolTaskSupport<\/code> enum:<\/p>\n<ul>\n<li><code>Forbidden<\/code> (default for sync methods): Tool cannot be called with task augmentation<\/li>\n<li><code>Optional<\/code> (default for async methods): Tool can be called with or without task augmentation<\/li>\n<li><code>Required<\/code>: Tool must be called with task augmentation<\/li>\n<\/ul>\n<p>Set <code>TaskSupport<\/code> on 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(TaskSupport = ToolTaskSupport.Required)]\n[Description(\"Processes a batch of data records. Always runs as a task.\")]\npublic static async Task&lt;string&gt; ProcessData(\n    [Description(\"Number of records to process\")] int recordCount,\n    CancellationToken cancellationToken)\n{\n    await Task.Delay(TimeSpan.FromSeconds(8), cancellationToken);\n    return $\"Processed {recordCount} records successfully.\";\n}<\/code><\/pre>\n<p>Or set it via <code>McpServerToolCreateOptions.Execution<\/code> when registering tools explicitly:<\/p>\n<pre><code class=\"language-csharp\">builder.Services.AddMcpServer()\n    .WithTools([\n        McpServerTool.Create(\n            (int count, CancellationToken ct) =&gt; ProcessAsync(count, ct),\n            new McpServerToolCreateOptions\n            {\n                Name = \"requiredTaskTool\",\n                Execution = new ToolExecution\n                {\n                    TaskSupport = ToolTaskSupport.Required\n                }\n            })\n    ]);<\/code><\/pre>\n<p>For more control over the task lifecycle, a tool can directly interact with<br \/>\n<a href=\"https:\/\/modelcontextprotocol.github.io\/csharp-sdk\/api\/ModelContextProtocol.IMcpTaskStore.html\">IMcpTaskStore<\/a> and return an <code>McpTask<\/code>.<br \/>\nThis bypasses automatic task wrapping and allows the tool to create a task, schedule background work, and return immediately.<br \/>\nNote: use a <strong>static<\/strong> method and accept <code>IMcpTaskStore<\/code> as a <strong>method parameter<\/strong> rather than via constructor injection<br \/>\nto avoid DI scope issues when the SDK executes the tool in a background context.<\/p>\n<h3>Client support for tasks<\/h3>\n<p>To execute a tool as a task, a client includes the <code>Task<\/code> property in the request parameters:<\/p>\n<pre><code class=\"language-csharp\">var result = await client.CallToolAsync(\n    new CallToolRequestParams\n    {\n        Name = \"processDataset\",\n        Arguments = new Dictionary&lt;string, JsonElement&gt;\n        {\n            [\"recordCount\"] = JsonSerializer.SerializeToElement(1000)\n        },\n        Task = new McpTaskMetadata\n        {\n            TimeToLive = TimeSpan.FromHours(2)\n        }\n    },\n    cancellationToken);\n\nif (result.Task != null)\n{\n    Console.WriteLine($\"Task created: {result.Task.TaskId}\");\n    Console.WriteLine($\"Status: {result.Task.Status}\");\n}<\/code><\/pre>\n<p>The client can then poll for status updates and retrieve the final result:<\/p>\n<pre><code class=\"language-csharp\">\/\/ Poll until task reaches a terminal state\nvar completedTask = await client.PollTaskUntilCompleteAsync(\n    taskId,\n    cancellationToken: cancellationToken);\n\nswitch (completedTask.Status)\n{\n    case McpTaskStatus.Completed:\n        \/\/ ...\n        break;\n    case McpTaskStatus.Failed:\n        \/\/ ...\n        break;\n    case McpTaskStatus.Cancelled:\n        \/\/ ...\n        break;\n{\n    var resultJson = await client.GetTaskResultAsync(\n        taskId,\n        cancellationToken: cancellationToken);\n\n    var result = resultJson.Deserialize&lt;CallToolResult&gt;(McpJsonUtilities.DefaultOptions);\n    foreach (var content in result?.Content ?? [])\n    {\n        if (content is TextContentBlock text)\n        {\n            Console.WriteLine(text.Text);\n        }\n    }\n}<\/code><\/pre>\n<p>The SDK also provides methods to list all tasks (<a href=\"https:\/\/csharp.sdk.modelcontextprotocol.io\/api\/ModelContextProtocol.Client.McpClient.html#ModelContextProtocol_Client_McpClient_ListTasksAsync_ModelContextProtocol_RequestOptions_System_Threading_CancellationToken_\">ListTasksAsync<\/a>)<br \/>\nand cancel running tasks (<a href=\"https:\/\/csharp.sdk.modelcontextprotocol.io\/api\/ModelContextProtocol.Client.McpClient.html#ModelContextProtocol_Client_McpClient_CancelTaskAsync_System_String_ModelContextProtocol_RequestOptions_System_Threading_CancellationToken_\">CancelTaskAsync<\/a>):<\/p>\n<pre><code class=\"language-csharp\">\/\/ List all tasks for the current session\nvar tasks = await client.ListTasksAsync(cancellationToken: cancellationToken);\n\n\/\/ Cancel a running task\nvar cancelledTask = await client.CancelTaskAsync(taskId, cancellationToken: cancellationToken);<\/code><\/pre>\n<p>Clients can optionally register a handler to receive status notifications as they arrive,<br \/>\nbut should always use polling as the primary mechanism since notifications are optional:<\/p>\n<pre><code class=\"language-csharp\">var options = new McpClientOptions\n{\n    Handlers = new McpClientHandlers\n    {\n        TaskStatusHandler = (task, cancellationToken) =&gt;\n        {\n            Console.WriteLine($\"Task {task.TaskId} status changed to {task.Status}\");\n            return ValueTask.CompletedTask;\n        }\n    }\n};<\/code><\/pre>\n<h2>Summary<\/h2>\n<p>The v1.0 release of the MCP C# SDK represents a major step forward for building MCP servers and clients in .NET.<br \/>\nWhether you\u2019re implementing secure authorization flows, building rich tool experiences with sampling,<br \/>\nor handling long-running operations gracefully, the SDK has you covered.<\/p>\n<p>Check out the <a href=\"https:\/\/modelcontextprotocol.io\/specification\/2025-11-25\/changelog\">full changelog<\/a><br \/>\nand the <a href=\"https:\/\/github.com\/modelcontextprotocol\/csharp-sdk\">C# SDK repository<\/a> to get started.<\/p>\n<p>Demo projects for many of the features described here are available in the<br \/>\n<a href=\"https:\/\/github.com\/mikekistler\/mcp-whats-new\">mcp-whats-new demo repository<\/a>.<\/p>\n<p>The post <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/release-v10-of-the-official-mcp-csharp-sdk\/\">Release v1.0 of the official MCP C# SDK<\/a> appeared first on <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\">.NET Blog<\/a>.<\/p>","protected":false},"excerpt":{"rendered":"<p>The Model Context Protocol (MCP) C# SDK has reached its v1.0 milestone, bringing full support for the 2025-11-25 version of [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":3570,"comment_status":"","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[7],"tags":[],"class_list":["post-3569","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dotnet"],"_links":{"self":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts\/3569","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/comments?post=3569"}],"version-history":[{"count":0,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/posts\/3569\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/media\/3570"}],"wp:attachment":[{"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/media?parent=3569"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/categories?post=3569"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rssfeedtelegrambot.bnaya.co.il\/index.php\/wp-json\/wp\/v2\/tags?post=3569"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}