<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Ai | The .NET Blog</title><link>https://thedotnetblog.com/tags/ai/</link><description>Articles, tutorials and insights from the .NET community.</description><generator>Hugo</generator><language>en</language><managingEditor>@thedotnetblog (The .NET Blog)</managingEditor><webMaster>@thedotnetblog</webMaster><lastBuildDate>Wed, 03 Jun 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://thedotnetblog.com/tags/ai/index.xml" rel="self" type="application/rss+xml"/><item><title>NL2SQL Is the SQL Injection of the Agentic Age</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/nl2sql-agentic-sql-injection-mcp-server/</link><pubDate>Wed, 03 Jun 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/nl2sql-agentic-sql-injection-mcp-server/</guid><description>Before you let an agent query your database with natural language, read this. NL2SQL looks simple until you think through schema completeness, indeterminism, and what SQL MCP Server actually solves.</description><content:encoded>&lt;p&gt;There&amp;rsquo;s a version of the NL2SQL pitch that sounds perfect: users ask questions in natural language, agents generate SQL, data comes back. Fewer screens, fewer queries, less code. Simple.&lt;/p&gt;
&lt;p&gt;Then you think about it for five more minutes.&lt;/p&gt;
&lt;h2 id="the-problems-nobody-talks-about-in-the-demo"&gt;The Problems Nobody Talks About in the Demo&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Schemas weren&amp;rsquo;t designed to explain things.&lt;/strong&gt; Cryptic table names, inconsistent column names, technically valid relationships that are semantically invalid without additional predicates — these are normal for enterprise databases. They&amp;rsquo;re not bugs, they&amp;rsquo;re just the accumulated history of business changes. But when you ask a model to infer intent from a schema that wasn&amp;rsquo;t designed to communicate intent, the model will try anyway. It won&amp;rsquo;t give up. It&amp;rsquo;ll generate its best-effort query and return results with confidence.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Models are not deterministic.&lt;/strong&gt; Ask the same question about the same database twice and you might get different SQL. The model is calculating probabilities, and slight variations in context drive different outputs. You cannot test your way to a guarantee that the agent always generates the right query.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;User review doesn&amp;rsquo;t scale.&lt;/strong&gt; &amp;ldquo;Just review every query before execution&amp;rdquo; sounds safe. But it assumes users are experts in both the data model and SQL — exactly the people who didn&amp;rsquo;t need the natural language interface. It also introduces cognitive overload and a new class of confirmation bias, where users overwhelmed by query complexity approve invalid queries rather than investigate them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;And then there&amp;rsquo;s injection.&lt;/strong&gt; In traditional SQL development, parameterization solved injection because user input filled parameters, not SQL structure. With NL2SQL, the model is generating the SQL itself. The prompt, schema context, conversation history, and retrieved data all influence what gets executed. If someone crafts a prompt that changes what the model generates, that&amp;rsquo;s injection — not at the parameter level, but at the query generation level. And unlike dropping a table (obvious, recoverable), NL2SQL injection produces queries that return incorrect results with no visible error. Business decisions get made on wrong data.&lt;/p&gt;
&lt;h2 id="what-sql-mcp-server-actually-solves"&gt;What SQL MCP Server Actually Solves&lt;/h2&gt;
&lt;p&gt;This is where the article makes its most useful practical point. Instead of giving an agent arbitrary schema access and hoping for the best, SQL MCP Server exposes a &lt;strong&gt;curated API surface&lt;/strong&gt; built on top of &lt;a href="https://learn.microsoft.com/en-us/azure/data-api-builder/overview"&gt;Data API builder&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The difference matters: the agent doesn&amp;rsquo;t generate SQL. It calls named endpoints that return predefined result shapes. The SQL is written once, by a developer, and is deterministic. The agent&amp;rsquo;s nondeterminism is limited to choosing &lt;em&gt;which&lt;/em&gt; endpoint to call, not constructing arbitrary queries.&lt;/p&gt;
&lt;p&gt;This is analogous to what parameterization did for SQL injection in the traditional app model — you remove the ability to construct arbitrary queries from untrusted input.&lt;/p&gt;
&lt;h2 id="the-right-question"&gt;The Right Question&lt;/h2&gt;
&lt;p&gt;The article doesn&amp;rsquo;t say &amp;ldquo;never use NL2SQL.&amp;rdquo; It says: be deliberate about &lt;em&gt;where&lt;/em&gt; you apply it and &lt;em&gt;what&lt;/em&gt; you expose. For exploratory analysis in a controlled environment, with a scoped schema and read-only access, NL2SQL might be fine. For production systems where business decisions depend on the results, a curated API layer is significantly safer.&lt;/p&gt;
&lt;p&gt;Honesty: some problems are genuinely better solved with structured queries behind named endpoints than with natural language to SQL. SQL MCP Server gives you that option without abandoning the agentic interface entirely.&lt;/p&gt;
&lt;p&gt;Original post: &lt;a href="https://devblogs.microsoft.com/azure-sql/sql-mcp-server-nl2sql/"&gt;Considering NL2SQL? Should your database really be the prompt? How can SQL MCP Server help?&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>Microsoft Foundry April 2026: Foundry Local GA, GPT-5.5, CodeAct with Hyperlight</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/microsoft-foundry-april-2026-whats-new/</link><pubDate>Tue, 02 Jun 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/microsoft-foundry-april-2026-whats-new/</guid><description>April's Foundry recap is heavy: Foundry Local hits GA, GPT-5.5 arrives, Agent Framework gets OpenTelemetry tracing, CodeAct runs Python in Hyperlight micro-VMs, and the Agent Monitoring Dashboard lands.</description><content:encoded>&lt;p&gt;A busy month for Microsoft Foundry. Here are the announcements that matter most.&lt;/p&gt;
&lt;h2 id="foundry-local-is-generally-available"&gt;Foundry Local Is Generally Available&lt;/h2&gt;
&lt;p&gt;Foundry Local — Microsoft&amp;rsquo;s cross-platform local AI runtime — graduates from preview to GA on Windows, macOS (Apple Silicon), and Linux x64. Production-ready local model inference with a developer-friendly SDK. The 1.1 release (detailed in &lt;a href="https://devblogs.microsoft.com/foundry/foundry-local-v1-1/"&gt;a separate post&lt;/a&gt;) adds transcription, embeddings, and Responses API support.&lt;/p&gt;
&lt;h2 id="gpt-55"&gt;GPT-5.5&lt;/h2&gt;
&lt;p&gt;The latest GPT-5 family model is now available in Foundry. Default quota for Tier 5 and Tier 6 subscriptions. If you&amp;rsquo;ve been working with earlier GPT-5 variants, this is worth evaluating for your use cases.&lt;/p&gt;
&lt;h2 id="agent-framework-tracing-in-foundry"&gt;Agent Framework Tracing in Foundry&lt;/h2&gt;
&lt;p&gt;Two tracing features ship in preview this month:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Microsoft Agent Framework tracing&lt;/strong&gt; — MAF agents can now emit OpenTelemetry traces into Foundry. Debug agent behavior, trace multi-step execution, surface latency and errors across tool calls. This fills a real gap: knowing &lt;em&gt;what your agent actually did&lt;/em&gt; in production, not just what it returned.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Hosted-agent tracing&lt;/strong&gt; — Sessions, tool calls, and run steps from hosted agents also surface in Foundry traces. Same observability story extended to the hosted tier.&lt;/p&gt;
&lt;h2 id="codeact-with-hyperlight-alpha"&gt;CodeAct with Hyperlight (Alpha)&lt;/h2&gt;
&lt;p&gt;This is the most technically interesting addition: Agent Framework can now execute Python code inside &lt;a href="https://github.com/hyperlight-dev/hyperlight"&gt;Hyperlight&lt;/a&gt; micro-virtual machines.&lt;/p&gt;
&lt;p&gt;CodeAct is the pattern where an agent generates and executes Python code as a tool. The obvious concern is security — you&amp;rsquo;re running model-generated code. Hyperlight&amp;rsquo;s micro-VMs provide process-level isolation with near-native startup time, making sandboxed code execution practical without the overhead of full containers or VMs.&lt;/p&gt;
&lt;p&gt;For agentic workflows where code execution is necessary, this is a significant safety improvement over running code in the host process.&lt;/p&gt;
&lt;h2 id="agent-monitoring-dashboard-preview"&gt;Agent Monitoring Dashboard (Preview)&lt;/h2&gt;
&lt;p&gt;A unified operations dashboard combining token usage, latency, run success rate, and evaluator scores in one view. The distinction from regular observability dashboards: it includes evaluation results alongside operational metrics, so you can correlate &amp;ldquo;the agent is slower&amp;rdquo; with &amp;ldquo;evaluator scores dropped&amp;rdquo; — or confirm they&amp;rsquo;re unrelated.&lt;/p&gt;
&lt;h2 id="continuous-evaluation-custom-evaluators-preview"&gt;Continuous Evaluation Custom Evaluators (Preview)&lt;/h2&gt;
&lt;p&gt;You can now bring your own code-based or prompt-based evaluators into continuous evaluation pipelines. Previously, continuous eval was limited to built-in evaluators. Custom evaluators let you enforce team-specific quality criteria in your production monitoring loop.&lt;/p&gt;
&lt;h2 id="agent-inventory-in-control-plane"&gt;Agent Inventory in Control Plane&lt;/h2&gt;
&lt;p&gt;The Foundry Control Plane Operate view now shows all supported agents across a subscription: Foundry agents, Azure SRE Agent, Logic Apps agent loops, and registered custom agents. One view to understand what&amp;rsquo;s deployed and where.&lt;/p&gt;
&lt;p&gt;Original post: &lt;a href="https://devblogs.microsoft.com/foundry/whats-new-in-microsoft-foundry-apr-2026/"&gt;What&amp;rsquo;s new in Microsoft Foundry | April 2026&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>The Handoff Pattern: When One Agent Isn't Enough</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/maf-handoff-orchestration-pattern-tour/</link><pubDate>Mon, 01 Jun 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/maf-handoff-orchestration-pattern-tour/</guid><description>Microsoft Agent Framework's Handoff orchestration pattern lets agents decide who handles the next turn — without losing conversation context or breaking topology rules.</description><content:encoded>&lt;p&gt;At some point every multi-agent system outgrows a simple router. The first sign is usually when a specialist agent needs to ask a follow-up question, or realizes mid-turn that another agent should continue. A fixed pipeline breaks there. A one-shot router breaks there.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s exactly the problem the Handoff orchestration pattern in Microsoft Agent Framework is designed for.&lt;/p&gt;
&lt;h2 id="how-handoff-works"&gt;How Handoff Works&lt;/h2&gt;
&lt;p&gt;The developer declares a graph: here are the agents, here are the edges between them. The framework does the rest — it synthesizes a handoff tool per outbound edge and injects it into each agent. When an agent decides to pass control, it calls the tool. The framework enforces the topology.&lt;/p&gt;
&lt;p&gt;Three things make this different from just having agents call each other:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;One shared transcript&lt;/strong&gt; — the receiving agent sees the full conversation history. No starting from scratch.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Topology enforcement&lt;/strong&gt; — an agent can only hand off to declared targets. You catch routing bugs at authoring time, not in production.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Natural termination&lt;/strong&gt; — when the active agent finishes its turn without calling a handoff tool, the workflow yields to the user. No polling, no explicit exit conditions.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="a-minimal-example"&gt;A Minimal Example&lt;/h2&gt;
&lt;p&gt;In .NET, building a handoff workflow looks like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Agents.AI&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Agents.AI.Workflows&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;AIAgent&lt;/span&gt; &lt;span class="n"&gt;triage&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;chatClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AsAIAgent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;instructions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Route to the right specialist.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Triage&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;AIAgent&lt;/span&gt; &lt;span class="n"&gt;billing&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;chatClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AsAIAgent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;instructions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Handle billing questions.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Billing&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;AIAgent&lt;/span&gt; &lt;span class="n"&gt;tech&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;chatClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AsAIAgent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;instructions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Handle technical support.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Tech&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;workflow&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HandoffWorkflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;triage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;targets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;billing&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tech&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;billing&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;targets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;triage&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tech&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;targets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;triage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;billing&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Triage can send to either specialist. Both specialists can send back to triage. The graph is acyclic-friendly but supports back-edges when you need them (&amp;ldquo;I need more info&amp;rdquo; → back to research).&lt;/p&gt;
&lt;h2 id="when-to-use-handoff-and-when-not-to"&gt;When to Use Handoff (and When Not To)&lt;/h2&gt;
&lt;p&gt;Handoff is a good fit when:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Ownership can change mid-conversation&lt;/strong&gt; — an agent may realize it&amp;rsquo;s the wrong specialist&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Back-edges matter&lt;/strong&gt; — you might need to revisit an earlier step without restarting&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Routing decisions are fuzzy&lt;/strong&gt; — the choice to hand off is contextual and better made by the model than typed predicates&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It&amp;rsquo;s &lt;em&gt;not&lt;/em&gt; the right choice when:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Your pipeline is fixed and sequential — use the &lt;code&gt;Sequential&lt;/code&gt; workflow for that&lt;/li&gt;
&lt;li&gt;Each step is independent — agents sharing a transcript where only one of them needed it is just noise&lt;/li&gt;
&lt;li&gt;You need strict processing guarantees — the non-determinism of model-driven routing isn&amp;rsquo;t what you want&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="back-edges-and-human-in-the-loop"&gt;Back-Edges and Human-in-the-Loop&lt;/h2&gt;
&lt;p&gt;One of the more interesting shapes Handoff enables is genuine back-edges. An agent can decide &amp;ldquo;I don&amp;rsquo;t have enough information&amp;rdquo; and route back to a research step, not with a hardcoded loop, but because the model decides it&amp;rsquo;s the right call.&lt;/p&gt;
&lt;p&gt;Human-in-the-loop interactions also compose naturally. When a specialist needs user input, the workflow yields back to the user via the default turn loop, collects the response, and resumes with full context. The agent never lost the conversation.&lt;/p&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;Handoff is one of those patterns that sounds simple but enables a lot once you internalize it: decentralized routing, shared context, enforced topology, natural termination. It&amp;rsquo;s the right next step when your agents start saying &amp;ldquo;actually, someone else should handle this.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Read the full walkthrough in the original post: &lt;a href="https://devblogs.microsoft.com/agent-framework/a-tour-of-handoff-orchestration-pattern/"&gt;A Tour of the Handoff Orchestration Pattern&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>Durable Workflows in Microsoft Agent Framework: From In-Memory to Azure Functions</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/maf-durable-workflows-azure-functions-durable-task/</link><pubDate>Sun, 31 May 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/maf-durable-workflows-azure-functions-durable-task/</guid><description>MAF's workflow programming model now supports durable execution backed by Durable Task — here's how to build composable agent workflows that survive process restarts and scale across Azure Functions.</description><content:encoded>&lt;p&gt;One of the pain points with early AI agent workflows: they&amp;rsquo;re fragile. A long-running multi-step workflow tied to a single process means process restart = lost state. For simple demos this is fine. For production workloads it isn&amp;rsquo;t.&lt;/p&gt;
&lt;p&gt;Microsoft Agent Framework&amp;rsquo;s workflow programming model now supports &lt;strong&gt;durable execution&lt;/strong&gt;, backed by the Durable Task framework, with Azure Functions hosting. Here&amp;rsquo;s how the programming model works and why the durability story matters.&lt;/p&gt;
&lt;h2 id="the-core-building-blocks"&gt;The Core Building Blocks&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Executors&lt;/strong&gt; are the fundamental unit of work. Each one is typed — it takes a specific input and produces a specific output:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Agents.AI.Workflows&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;internal&lt;/span&gt; &lt;span class="kd"&gt;sealed&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderLookup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Executor&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;OrderCancelRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;OrderLookup&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="n"&gt;ValueTask&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;HandleAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;OrderCancelRequest&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;IWorkflowContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// look up the order, return it&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OrderId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Workflows&lt;/strong&gt; wire executors into directed graphs using a fluent builder. The framework handles execution, data flow between steps, and error propagation.&lt;/p&gt;
&lt;p&gt;You can model:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sequential chains (step A → step B → step C)&lt;/li&gt;
&lt;li&gt;Parallel fan-out/fan-in (run agents A, B, C in parallel, aggregate results)&lt;/li&gt;
&lt;li&gt;Conditional branching&lt;/li&gt;
&lt;li&gt;Human-in-the-loop approvals (pause workflow, wait for external signal)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-in-memory-runner-for-local-dev"&gt;The In-Memory Runner for Local Dev&lt;/h2&gt;
&lt;p&gt;Getting started is fast:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;dotnet&lt;/span&gt; &lt;span class="k"&gt;add&lt;/span&gt; &lt;span class="n"&gt;package&lt;/span&gt; &lt;span class="n"&gt;Microsoft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Agents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AI&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;dotnet&lt;/span&gt; &lt;span class="k"&gt;add&lt;/span&gt; &lt;span class="n"&gt;package&lt;/span&gt; &lt;span class="n"&gt;Microsoft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Agents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Workflows&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The core package includes a lightweight in-process runner. No external dependencies, no database, no Azure resources. Works great for local development and unit testing.&lt;/p&gt;
&lt;h2 id="adding-durability-with-durable-task"&gt;Adding Durability with Durable Task&lt;/h2&gt;
&lt;p&gt;When a workflow needs to survive process restarts — because it&amp;rsquo;s long-running, because it has human-in-the-loop steps, because it fans out across many parallel agent calls — the in-memory runner isn&amp;rsquo;t enough.&lt;/p&gt;
&lt;p&gt;MAF&amp;rsquo;s Durable Task integration stores workflow state in Azure Storage. If the process restarts, the workflow resumes from where it left off. The programming model stays the same; you just swap the runner.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;dotnet&lt;/span&gt; &lt;span class="k"&gt;add&lt;/span&gt; &lt;span class="n"&gt;package&lt;/span&gt; &lt;span class="n"&gt;Microsoft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Agents&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Workflows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DurableTask&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The same executors, the same workflow graph — backed by durable state.&lt;/p&gt;
&lt;h2 id="azure-functions-hosting"&gt;Azure Functions Hosting&lt;/h2&gt;
&lt;p&gt;The third layer is Azure Functions hosting. Your workflow becomes a Function app: trigger the workflow via an HTTP endpoint, and the durable runtime handles scaling, state, and reliability.&lt;/p&gt;
&lt;p&gt;This means a multi-agent workflow with parallel calls, conditional branches, and human approvals can scale across a serverless Functions environment without custom state management.&lt;/p&gt;
&lt;h2 id="why-this-matters"&gt;Why This Matters&lt;/h2&gt;
&lt;p&gt;The combination is significant for real AI systems:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Parallel agent calls&lt;/strong&gt; — fan out to multiple specialized agents simultaneously without blocking, aggregate results when all complete&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Long-running processes&lt;/strong&gt; — workflows that involve human approval or external events can pause and resume across hours or days&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scale&lt;/strong&gt; — Azure Functions scales the execution horizontally; the Durable Task framework handles coordinating the parallel state&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you&amp;rsquo;re building MAF workflows beyond simple local demos, this is the path to production-grade execution.&lt;/p&gt;
&lt;p&gt;Original post: &lt;a href="https://devblogs.microsoft.com/dotnet/durable-workflows-in-microsoft-agent-framework/"&gt;Durable Workflows in the Microsoft Agent Framework&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>Your Local MAF Agent Just Got a Production Home</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/maf-agent-local-to-production-foundry-hosted-agents/</link><pubDate>Sat, 30 May 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/maf-agent-local-to-production-foundry-hosted-agents/</guid><description>Foundry Hosted Agents gives your Microsoft Agent Framework agent identity, scaling, session persistence, and zero-extra-wiring observability. Here's what that looks like in practice.</description><content:encoded>&lt;p&gt;Getting an agent to work locally is the fun part. The tricky part is everything that comes after: deploying it without losing your mind, managing sessions, setting up identity, wiring observability. Usually that means a lot of custom infrastructure glue.&lt;/p&gt;
&lt;p&gt;Foundry Hosted Agents just removed most of that glue for Microsoft Agent Framework (MAF) users.&lt;/p&gt;
&lt;h2 id="what-foundry-hosted-agents-actually-does"&gt;What Foundry Hosted Agents Actually Does&lt;/h2&gt;
&lt;p&gt;When you deploy a MAF agent to Foundry Hosted Agents, the platform handles a surprisingly long list of things you&amp;rsquo;d otherwise build yourself:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Scale to zero&lt;/strong&gt; — your agent costs nothing while idle and spins back up automatically&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Per-session VM-isolated sandboxes&lt;/strong&gt; — every user session gets its own sandbox with filesystem persistence that survives scale-down events&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Built-in Entra ID&lt;/strong&gt; — each agent gets its own identity so it can call Foundry models, Toolbox, and Azure services without secrets baked into the image&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Versioned deployments&lt;/strong&gt; — every deployment is an immutable snapshot, with blue/green and canary rollout support&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Zero-config observability&lt;/strong&gt; — &lt;code&gt;APPLICATIONINSIGHTS_CONNECTION_STRING&lt;/code&gt; is injected at runtime so MAF&amp;rsquo;s OpenTelemetry traces flow into App Insights automatically&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That last one is genuinely nice. No extra wiring, no additional config. Traces just show up.&lt;/p&gt;
&lt;h2 id="the-code-difference-is-tiny"&gt;The Code Difference Is Tiny&lt;/h2&gt;
&lt;p&gt;This is what I appreciate most about this integration. You don&amp;rsquo;t rewrite your agent. You just wrap it:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In .NET:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Agents.AI.Foundry.Hosting&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WebApplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddFoundryResponses&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MapFoundryResponses&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;In Python:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ResponsesHostServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s it. The same logic you tested locally is what runs in production. The platform wraps it in the session management, identity, and scaling infrastructure.&lt;/p&gt;
&lt;h2 id="two-protocols-one-agent"&gt;Two Protocols, One Agent&lt;/h2&gt;
&lt;p&gt;Hosted Agents support two endpoint styles:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Responses&lt;/strong&gt; (&lt;code&gt;/responses&lt;/code&gt;) — OpenAI-compatible, manages conversation history and streaming. Good default for chat-shaped agents.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Invocations&lt;/strong&gt; (&lt;code&gt;/invocations&lt;/code&gt;) — you define the request/response schema. Good for non-conversational workflows.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you&amp;rsquo;re building something that looks like a conversation, start with Responses. If you&amp;rsquo;re building an API-shaped agent that takes structured input and returns structured output, Invocations gives you the flexibility.&lt;/p&gt;
&lt;h2 id="the-deployment-flow-with-azd"&gt;The Deployment Flow with &lt;code&gt;azd&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;When you run &lt;code&gt;azd up&lt;/code&gt; with a MAF agent:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Optionally creates a Foundry project and deploys a model&lt;/li&gt;
&lt;li&gt;Packages your code and pushes an image to Azure Container Registry&lt;/li&gt;
&lt;li&gt;Provisions compute from the ACR image&lt;/li&gt;
&lt;li&gt;Assigns a dedicated Entra ID to the agent&lt;/li&gt;
&lt;li&gt;Exposes a stable endpoint (&lt;code&gt;https://{project_endpoint}/agents/{agent_name}&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Handles everything else from that point on&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Sessions persist for up to 30 days. Idle compute is deprovisioned after 15 minutes and restored transparently on the next request. From the agent&amp;rsquo;s perspective, nothing changed.&lt;/p&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;The distance between &amp;ldquo;working locally&amp;rdquo; and &amp;ldquo;running in production&amp;rdquo; has historically been long and painful for AI agents. Foundry Hosted Agents + MAF closes that gap significantly. If you already have a local agent built with Agent Framework, this is worth trying today.&lt;/p&gt;
&lt;p&gt;The team says GA is coming soon — this is currently in preview. Check the &lt;a href="https://learn.microsoft.com/en-us/agent-framework/hosting/foundry-hosted-agent"&gt;MAF Hosted Agent Integration docs&lt;/a&gt; and the &lt;a href="https://github.com/microsoft/agent-framework/tree/main/dotnet/samples/04-hosting/FoundryHostedAgents"&gt;.NET samples&lt;/a&gt; to get started.&lt;/p&gt;
&lt;p&gt;Original article: &lt;a href="https://devblogs.microsoft.com/agent-framework/from-local-to-production-deploy-your-microsoft-agent-framework-agent-with-foundry-hosted-agents/"&gt;From Local to Production: Deploy Your Microsoft Agent Framework Agent with Foundry Hosted Agents&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>Building Agents Is the Easy Part — Running Them Safely Is the Hard Part</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/maf-agent-governance-toolkit-runtime-policy/</link><pubDate>Fri, 29 May 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/maf-agent-governance-toolkit-runtime-policy/</guid><description>Microsoft Agent Framework and Agent Governance Toolkit pair up to enforce runtime policy, govern tool calls, and provide Merkle-chained audit logs — without touching your agent prompts.</description><content:encoded>&lt;p&gt;There&amp;rsquo;s a pattern in AI agent development that I&amp;rsquo;ve started calling &amp;ldquo;demo regret.&amp;rdquo; The agent works great in demos. Then someone asks: what happens if it calls the wrong tool? What if it accesses data it shouldn&amp;rsquo;t? Who audited that?&lt;/p&gt;
&lt;p&gt;Microsoft Agent Framework has your back for building and orchestrating. Agent Governance Toolkit (AGT) covers the part after that — governance, policy enforcement, and auditability at runtime.&lt;/p&gt;
&lt;h2 id="what-each-project-actually-does"&gt;What Each Project Actually Does&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Microsoft Agent Framework (MAF)&lt;/strong&gt; gives you the programming model: multi-agent workflows, A2A protocol interoperability, middleware hooks, memory, and managed hosting via Foundry Agent Service. It handles content safety at the model input/output level.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Agent Governance Toolkit (AGT)&lt;/strong&gt; plugs into that same middleware pipeline to govern &lt;em&gt;actions&lt;/em&gt;. Every tool call, resource access, and inter-agent message gets evaluated against policy before execution. Sub-millisecond overhead. No sidecars, no proxies, no prompts modified.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;Agent Action --&amp;gt; Policy Check --&amp;gt; Allow / Deny --&amp;gt; Audit Log (&amp;lt; 0.1 ms)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Different layers, complete coverage, one pipeline.&lt;/p&gt;
&lt;h2 id="plugging-in-is-just-adding-middleware"&gt;Plugging In Is Just Adding Middleware&lt;/h2&gt;
&lt;p&gt;In Python, AGT adds to the same &lt;code&gt;middleware&lt;/code&gt; parameter you&amp;rsquo;d use for logging or content filters:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;OpenAIChatClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;gpt-5.3&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Contoso Loan Officer&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;instructions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;You are a governed loan assistant.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;check_credit_score&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;get_loan_rates&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;approve_small_loan&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;AuditTrailMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;audit_log&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;audit_log&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;agent_did&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;loan-agent&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;GovernancePolicyMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;evaluator&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;evaluator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;audit_log&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;audit_log&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;CapabilityGuardMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;allowed_tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;check_credit_score&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;get_loan_rates&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;RogueDetectionMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;detector&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;detector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;agent_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;loan-agent&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In .NET, same pattern via &lt;code&gt;.Use()&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BuildAIAgent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;gpt-5.3&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;GovernancePolicyMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;evaluator&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;CapabilityGuardMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;allowedTools&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;AuditTrailMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;auditLog&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Same agent, same orchestration, same tools. AGT adds governance capabilities without touching the agent logic.&lt;/p&gt;
&lt;h2 id="what-you-get"&gt;What You Get&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;GovernancePolicyMiddleware&lt;/strong&gt; — evaluates every action against declarative policy rules&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CapabilityGuardMiddleware&lt;/strong&gt; — allowlists which tools an agent is permitted to call (the &lt;code&gt;approve_small_loan&lt;/code&gt; tool isn&amp;rsquo;t in the allowed list above — deliberate)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RogueDetectionMiddleware&lt;/strong&gt; — detects anomalous behavior patterns at runtime&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AuditTrailMiddleware&lt;/strong&gt; — Merkle-chained audit log so every action is cryptographically tamper-evident&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That last one matters for compliance. A Merkle chain means if anyone modifies the log, the chain breaks. The audit is the evidence.&lt;/p&gt;
&lt;h2 id="five-industry-scenarios"&gt;Five Industry Scenarios&lt;/h2&gt;
&lt;p&gt;The AGT repo ships five complete end-to-end scenarios: financial services (loan officer), healthcare (patient data), legal (contract review), government (citizen services), and manufacturing (quality control). Each one pairs real MAF agents with real AGT governance middleware.&lt;/p&gt;
&lt;p&gt;These aren&amp;rsquo;t toy demos. They&amp;rsquo;re the kind of scenarios where you&amp;rsquo;d actually need governance in production.&lt;/p&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;re building agents that touch real data, make decisions with consequences, or run unattended in production — governance isn&amp;rsquo;t optional. The combination of MAF + AGT gives you the whole stack: build it with Agent Framework, govern it with AGT.&lt;/p&gt;
&lt;p&gt;Both projects are open source. The original article has links to the full code samples.&lt;/p&gt;
&lt;p&gt;Original post: &lt;a href="https://devblogs.microsoft.com/agent-framework/governance-at-the-speed-of-agents-microsoft-agent-framework-and-agent-governance-toolkit-better-together/"&gt;Governance at the Speed of Agents: Microsoft Agent Framework and Agent Governance Toolkit, Better Together&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>Foundry Local 1.1: Real-Time Transcription, Embeddings, and the Responses API</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/foundry-local-11-transcription-embeddings-responses-api/</link><pubDate>Thu, 28 May 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/foundry-local-11-transcription-embeddings-responses-api/</guid><description>Foundry Local 1.1 adds live microphone transcription, text embeddings, and Responses API support — all running locally with no cloud dependency, no network latency, no per-token cost.</description><content:encoded>&lt;p&gt;Foundry Local 1.0 proved the concept: run AI models locally on Windows, macOS (Apple Silicon), and Linux x64 with a developer-friendly SDK. Version 1.1 adds three capabilities that cover a lot of real production use cases.&lt;/p&gt;
&lt;h2 id="live-audio-transcription"&gt;Live Audio Transcription&lt;/h2&gt;
&lt;p&gt;The most significant new feature: real-time speech-to-text streaming directly from the microphone. Captions, voice UIs, meeting transcription, accessibility tooling — all running locally with zero cloud dependency.&lt;/p&gt;
&lt;p&gt;The API is session-based and streams results as they arrive, with &lt;code&gt;is_final&lt;/code&gt; markers to distinguish interim from finalized text. Available across all language bindings: JavaScript, C#, Python, and Rust.&lt;/p&gt;
&lt;p&gt;Load a streaming speech model from the catalog, create a session with audio settings (sample rate, channels, language), start it, push raw PCM audio chunks, and consume the async stream of results. The post has full Python and C# examples.&lt;/p&gt;
&lt;h2 id="text-embeddings"&gt;Text Embeddings&lt;/h2&gt;
&lt;p&gt;Semantic search, RAG pipelines, clustering, similarity matching — these all require embeddings. Foundry Local 1.1 adds embedding model support so you can generate vectors locally from the same SDK, without sending data to a cloud endpoint.&lt;/p&gt;
&lt;p&gt;For applications where data residency matters or where you&amp;rsquo;re processing sensitive content, local embedding generation is a meaningful capability.&lt;/p&gt;
&lt;h2 id="responses-api"&gt;Responses API&lt;/h2&gt;
&lt;p&gt;Foundry Local now supports the &lt;a href="https://platform.openai.com/docs/api-reference/responses"&gt;Responses API&lt;/a&gt; — the structured interface designed for agentic interactions. This adds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tool calling&lt;/strong&gt; — let locally-running models invoke tools you define&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multimodal vision-language input&lt;/strong&gt; — pass image + text to vision-capable models&lt;/li&gt;
&lt;li&gt;Compatible with the standard API shape, so existing agents targeting OpenAI&amp;rsquo;s Responses API work against local models&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="package-size-improvements"&gt;Package Size Improvements&lt;/h2&gt;
&lt;p&gt;Two changes reduce the JavaScript package size:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;koffi&lt;/code&gt; FFI layer has been replaced with a custom Node-API C addon&lt;/li&gt;
&lt;li&gt;WebGPU execution provider ships as a separate plugin, so applications that don&amp;rsquo;t need GPU acceleration don&amp;rsquo;t pay the size cost&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The C# SDK now targets lower framework versions for broader .NET compatibility.&lt;/p&gt;
&lt;h2 id="why-this-matters"&gt;Why This Matters&lt;/h2&gt;
&lt;p&gt;The three capabilities together — transcription, embeddings, tool calling — cover the core building blocks of many AI applications. Running them locally means:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;No internet required&lt;/li&gt;
&lt;li&gt;No per-token costs&lt;/li&gt;
&lt;li&gt;No data leaving the machine&lt;/li&gt;
&lt;li&gt;Consistent latency regardless of network conditions&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Foundry Local is the right choice for edge scenarios, privacy-sensitive workloads, offline applications, or anything where you want to avoid cloud dependency during development.&lt;/p&gt;
&lt;p&gt;Original post: &lt;a href="https://devblogs.microsoft.com/foundry/foundry-local-v1-1/"&gt;Foundry Local 1.1: Live Transcription, Embeddings, and Responses API&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>Cosmos DB Shell Is in Public Preview — And It Has an MCP Server Built In</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/cosmosdb-shell-public-preview-mcp-server-cli/</link><pubDate>Sun, 24 May 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/cosmosdb-shell-public-preview-mcp-server-cli/</guid><description>Azure Cosmos DB Shell is a new open-source CLI that exposes database commands as MCP tools. Your AI agents can navigate containers, run queries, and manage data using the same interface you use.</description><content:encoded>&lt;p&gt;If you&amp;rsquo;ve ever had to bounce between a portal tab, an SDK sample, and a half-finished script just to answer one Cosmos DB question, you already know the friction this project is designed to remove.&lt;/p&gt;
&lt;p&gt;Azure Cosmos DB Shell just entered public preview. It&amp;rsquo;s an open-source CLI with bash-like syntax and — the part that makes this interesting — an integrated MCP server.&lt;/p&gt;
&lt;h2 id="what-makes-this-different-from-other-database-clis"&gt;What Makes This Different From Other Database CLIs&lt;/h2&gt;
&lt;p&gt;The CLI itself is useful: familiar commands, scripting support, CI/CD integration. That part is table stakes for a developer-focused database tool.&lt;/p&gt;
&lt;p&gt;The interesting part is the MCP server integration. Every command the CLI exposes becomes available as an MCP tool that your AI agents can call. There&amp;rsquo;s no custom API layer, no integration code to write. Your agent can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Navigate database hierarchies with &lt;code&gt;cd&lt;/code&gt;, &lt;code&gt;ls&lt;/code&gt;, &lt;code&gt;pwd&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Run SQL queries with &lt;code&gt;query&lt;/code&gt; and get structured results back&lt;/li&gt;
&lt;li&gt;Create and modify items with &lt;code&gt;create item&lt;/code&gt;, &lt;code&gt;update&lt;/code&gt;, &lt;code&gt;rm&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Manage databases and containers with &lt;code&gt;mkdb&lt;/code&gt;, &lt;code&gt;mkcon&lt;/code&gt;, &lt;code&gt;rmdb&lt;/code&gt;, &lt;code&gt;rmcon&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Inspect current context with &lt;code&gt;endpoint&lt;/code&gt;, &lt;code&gt;pwd&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The key shift: your agent isn&amp;rsquo;t talking to a Cosmos DB API — it&amp;rsquo;s talking to the same shell interface you use. The commands are deterministic, auditable, and open source so you can inspect exactly what&amp;rsquo;s happening.&lt;/p&gt;
&lt;h2 id="the-open-source-foundation-matters"&gt;The Open-Source Foundation Matters&lt;/h2&gt;
&lt;p&gt;This isn&amp;rsquo;t a black-box managed service. The shell is open source, which means:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Security teams can audit the implementation&lt;/li&gt;
&lt;li&gt;Platform teams can fork and extend it for their specific standards&lt;/li&gt;
&lt;li&gt;Developers can contribute improvements that benefit everyone&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For enterprise teams adopting AI tooling, &amp;ldquo;can we see exactly how it works&amp;rdquo; is increasingly not an optional requirement. Open source here is a meaningful differentiator.&lt;/p&gt;
&lt;h2 id="three-scenarios-that-become-easier"&gt;Three Scenarios That Become Easier&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Intelligent data analysis&lt;/strong&gt; — connect an agent to the shell, ask natural language questions, get structured query results. The agent handles the query construction; the shell handles execution.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Autonomous data management&lt;/strong&gt; — workflows that need to create, update, or remove data in Cosmos DB can do so through the MCP tools without needing a custom integration.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Real-time monitoring and alerts&lt;/strong&gt; — an agent can periodically query containers, compare results, and surface anomalies through whatever notification channel makes sense.&lt;/p&gt;
&lt;p&gt;The MCP interface makes these scenarios composable with any AI platform that speaks MCP — not just Microsoft&amp;rsquo;s tooling.&lt;/p&gt;
&lt;h2 id="getting-started"&gt;Getting Started&lt;/h2&gt;
&lt;p&gt;The shell is in public preview. Install it, configure your Cosmos DB connection, and enable the MCP server. From there, any MCP-compatible agent host can discover and use the tools.&lt;/p&gt;
&lt;p&gt;Original post: &lt;a href="https://devblogs.microsoft.com/cosmosdb/azure-cosmos-db-shell-public-preview-ai-mcp-cli/"&gt;Announcing the Public Preview of Azure Cosmos DB Shell: Open-Source Power Meets AI-Driven Database Automation&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>Azure SQL Can Generate Embeddings Now — In Pure T-SQL, No App Layer Needed</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/azure-sql-ai-generate-embeddings-ga-rag-tsql/</link><pubDate>Fri, 22 May 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/azure-sql-ai-generate-embeddings-ga-rag-tsql/</guid><description>AI_GENERATE_EMBEDDINGS and CREATE EXTERNAL MODEL are now GA in Azure SQL Database and Managed Instance. RAG pipelines built entirely in T-SQL, no data movement required.</description><content:encoded>&lt;p&gt;If you&amp;rsquo;ve ever built a RAG pipeline, you know the pipeline tax: your data lives in SQL, but to generate embeddings you need to extract it, call an embedding API, handle batching and rate limits, and store the results somewhere vector-searchable. Often in a different database entirely.&lt;/p&gt;
&lt;p&gt;Azure SQL just removed most of that with two features that are now generally available: &lt;code&gt;CREATE EXTERNAL MODEL&lt;/code&gt; and &lt;code&gt;AI_GENERATE_EMBEDDINGS&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="what-they-do"&gt;What They Do&lt;/h2&gt;
&lt;p&gt;These two T-SQL features work as an integrated pipeline:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;CREATE EXTERNAL MODEL&lt;/code&gt;&lt;/strong&gt; — registers an external AI model endpoint as a named database object. You set the location, API format, model type, and credentials once. Reuse it everywhere.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;AI_GENERATE_EMBEDDINGS&lt;/code&gt;&lt;/strong&gt; — a scalar T-SQL function that calls the registered model and returns a JSON array of vector values. Works in SELECT, INSERT, UPDATE, and MERGE statements.&lt;/p&gt;
&lt;p&gt;Together they form an end-to-end embedding pipeline without leaving the SQL engine.&lt;/p&gt;
&lt;h2 id="the-complete-workflow"&gt;The Complete Workflow&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;-- Step 1: Register your embedding provider once
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXTERNAL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MODEL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MyEmbeddingModel&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LOCATION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;https://your-aoai-resource.openai.azure.com/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;API_FORMAT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Azure OpenAI&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MODEL_TYPE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EMBEDDINGS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MODEL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;text-embedding-ada-002&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;-- Step 2: Generate embeddings inline in T-SQL
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;docs&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;embedding&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AI_GENERATE_EMBEDDINGS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;USE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MODEL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MyEmbeddingModel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;documents&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;docs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;-- Step 3: Search with vector distance
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TOP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;documents&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;VECTOR_DISTANCE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;cosine&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;embedding&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AI_GENERATE_EMBEDDINGS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;USE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MODEL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MyEmbeddingModel&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s the whole pipeline: data in SQL, embeddings generated in SQL, similarity search in SQL. No orchestration layer, no ETL, no separate vector database.&lt;/p&gt;
&lt;h2 id="supported-api-formats-and-options"&gt;Supported API Formats and Options&lt;/h2&gt;
&lt;p&gt;At GA, &lt;code&gt;API_FORMAT&lt;/code&gt; supports &lt;strong&gt;Azure OpenAI&lt;/strong&gt; and &lt;strong&gt;OpenAI&lt;/strong&gt;. &lt;code&gt;MODEL_TYPE&lt;/code&gt; is locked to &lt;code&gt;EMBEDDINGS&lt;/code&gt; for now. The &lt;code&gt;PARAMETERS&lt;/code&gt; JSON lets you set model-level defaults including retry count:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;PARAMETERS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;{&amp;#34;sql_rest_options&amp;#34;:{&amp;#34;retry_count&amp;#34;:3}}&amp;#39;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Authentication uses database credentials, so secrets stay out of your application code.&lt;/p&gt;
&lt;h2 id="what-this-enables-for-net-applications"&gt;What This Enables for .NET Applications&lt;/h2&gt;
&lt;p&gt;For .NET developers building AI features on top of existing SQL data, this is significant. You don&amp;rsquo;t need to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Extract data to an intermediate store for embedding&lt;/li&gt;
&lt;li&gt;Manage an external embedding pipeline&lt;/li&gt;
&lt;li&gt;Set up a separate vector database (though you can use Azure AI Search if you want a full-featured vector store)&lt;/li&gt;
&lt;li&gt;Change your application&amp;rsquo;s data access layer&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can add semantic search to existing SQL applications incrementally, using the same T-SQL tooling you already have.&lt;/p&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;RAG patterns on SQL data just got dramatically simpler. &lt;code&gt;AI_GENERATE_EMBEDDINGS&lt;/code&gt; + &lt;code&gt;CREATE EXTERNAL MODEL&lt;/code&gt; means your existing SQL application can gain vector search capabilities without adding new infrastructure.&lt;/p&gt;
&lt;p&gt;Both features are GA in Azure SQL Database and Azure SQL Managed Instance today.&lt;/p&gt;
&lt;p&gt;Original post: &lt;a href="https://devblogs.microsoft.com/azure-sql/generate-embeddings-function-and-external-model-object-support-are-now-generally-available-in-azure-sql/"&gt;Generate Embeddings Function and External Model Object Support Are Now Generally Available in Azure SQL&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>Your AI Agent Has an Identity Problem (And Here's the Template That Solves It)</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/azd-least-privilege-ai-agents-oauth-token-pattern/</link><pubDate>Wed, 20 May 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/azd-least-privilege-ai-agents-oauth-token-pattern/</guid><description>A new azd template from Curity and Microsoft shows how to build AI agents that use short-lived OAuth tokens with fine-grained scopes — so agents can never see data they shouldn't.</description><content:encoded>&lt;p&gt;There&amp;rsquo;s a moment in every AI agent project that goes something like this: the demo works perfectly, the agent interprets natural language, calls the right APIs, returns the right data. Then you start thinking about real users.&lt;/p&gt;
&lt;p&gt;What stops one user&amp;rsquo;s agent session from seeing another user&amp;rsquo;s data? What if the agent is tricked through prompt injection? What if it calls a tool in an unexpected way?&lt;/p&gt;
&lt;p&gt;These aren&amp;rsquo;t edge cases. They&amp;rsquo;re design decisions you need to make before shipping.&lt;/p&gt;
&lt;p&gt;A new &lt;code&gt;azd&lt;/code&gt; template from Curity and Microsoft gives you a working reference for exactly this problem.&lt;/p&gt;
&lt;h2 id="the-core-problem-authentication--authorization"&gt;The Core Problem: Authentication ≠ Authorization&lt;/h2&gt;
&lt;p&gt;Most agent samples handle user authentication well. They handle authorization poorly. Knowing &lt;em&gt;who&lt;/em&gt; the user is doesn&amp;rsquo;t tell you &lt;em&gt;what data&lt;/em&gt; they should see.&lt;/p&gt;
&lt;p&gt;A traditional client app makes predictable API calls. An AI agent is nondeterministic — it interprets natural language and decides what to call. It can be creative. It can also be wrong. And if it&amp;rsquo;s manipulated through prompt injection, you need rules that don&amp;rsquo;t depend on the AI being well-behaved.&lt;/p&gt;
&lt;p&gt;The solution this template demonstrates: &lt;strong&gt;short-lived tokens that carry exactly the right information for each hop&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id="how-the-token-chain-works"&gt;How the Token Chain Works&lt;/h2&gt;
&lt;p&gt;The template uses OAuth 2.0 access tokens with token exchange to narrow permissions at each step. A user token gets exchanged twice before it reaches the MCP server:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;First exchange&lt;/strong&gt; — narrows the scope and converts the opaque token to a JWT&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Second exchange&lt;/strong&gt; — adds the agent identity and a new audience for the MCP server hop&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;What the MCP server token looks like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;scope&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;stocks/read&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;sub&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;62c839b8...&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;aud&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;https://mcp.demo.example&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;customer_id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;178&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;region&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;USA&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;customer_id&lt;/code&gt; is baked into the token by the authorization server, not passed as a parameter the agent controls. The API checks the token, not the agent&amp;rsquo;s instructions.&lt;/p&gt;
&lt;p&gt;This means: even if someone tricks the agent into trying to fetch another customer&amp;rsquo;s data, the token won&amp;rsquo;t authorize it.&lt;/p&gt;
&lt;h2 id="what-the-template-deploys"&gt;What the Template Deploys&lt;/h2&gt;
&lt;p&gt;With a few &lt;code&gt;azd&lt;/code&gt; commands you get:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A backend agent on Microsoft Foundry (C#, Microsoft A2A and MCP SDKs)&lt;/li&gt;
&lt;li&gt;An MCP server exposing a sample portfolio API&lt;/li&gt;
&lt;li&gt;Curity Identity Server as the authorization server, alongside Entra ID for authentication&lt;/li&gt;
&lt;li&gt;External and internal API gateways handling token exchange and audit logging&lt;/li&gt;
&lt;li&gt;Bicep for all the Azure infrastructure: Container Apps, VNet, ACR, Azure AI Foundry, Key Vault, Azure SQL Database, storage&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The whole pattern is inspectable and customizable.&lt;/p&gt;
&lt;h2 id="the-design-principle-worth-borrowing"&gt;The Design Principle Worth Borrowing&lt;/h2&gt;
&lt;p&gt;Even if you don&amp;rsquo;t use Curity, the pattern is transferable: &lt;strong&gt;agents should never hold permanent API access&lt;/strong&gt;. Every action should use a short-lived token with the minimum scope needed for that specific call, issued to the specific agent identity, carrying the claims the API needs to make authorization decisions.&lt;/p&gt;
&lt;p&gt;This holds up against creative agents, mistakes, and prompt injection in ways that &amp;ldquo;just make sure the agent doesn&amp;rsquo;t do bad things&amp;rdquo; never will.&lt;/p&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;Security patterns for AI agents are still being worked out across the industry. This template is one of the more complete reference implementations I&amp;rsquo;ve seen — it covers the actual authorization flow, not just authentication.&lt;/p&gt;
&lt;p&gt;Original post: &lt;a href="https://devblogs.microsoft.com/azure-sdk/azd-curity-least-privilege-ai-agents/"&gt;Least privilege AI agents: A new azd template from Curity and Microsoft&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>Aspire 13.3: Kubernetes Support, Browser Logs, and the Aspireify Skill</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/aspire-133-kubernetes-browser-logs-aspireify/</link><pubDate>Mon, 18 May 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/aspire-133-kubernetes-browser-logs-aspireify/</guid><description>Five weeks after 13.2, Aspire 13.3 lands with 45 new features including first-class AKS deployment, an AI-assisted onboarding skill, browser log capture, and structured command results.</description><content:encoded>&lt;p&gt;Five weeks is not a long time for a release, but Aspire 13.3 doesn&amp;rsquo;t feel like it. The headline items are meaningful: first-class Kubernetes and AKS deployment with Helm, an agent-assisted onboarding skill called Aspireify, browser log capture directly in the dashboard, and structured command results. Plus 45 new features, 134 improvements, and 93 bug fixes.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s hit the highlights.&lt;/p&gt;
&lt;h2 id="aspireify-agent-assisted-onboarding"&gt;Aspireify: Agent-Assisted Onboarding&lt;/h2&gt;
&lt;p&gt;Adding Aspire to an existing project sounds simple — drop an AppHost in, done. In practice it involves a lot of archaeology: which ports matter, which environment variables are real dependencies, which Docker Compose services should map to Aspire integrations.&lt;/p&gt;
&lt;p&gt;The new &lt;strong&gt;Aspireify skill&lt;/strong&gt; gives your coding agent a guided workflow for exactly this. When &lt;code&gt;aspire init&lt;/code&gt; drops a skeleton AppHost, the Aspireify skill helps the agent inspect the repo, understand how it already runs, and wire the AppHost to fit the app — not the other way around.&lt;/p&gt;
&lt;p&gt;The default stance is &amp;ldquo;minimize changes to your code.&amp;rdquo; If your app already reads &lt;code&gt;DATABASE_URL&lt;/code&gt;, the agent maps that with &lt;code&gt;WithEnvironment()&lt;/code&gt; instead of asking you to rewrite your configuration. If a port is hardcoded, the skill tells the agent when to preserve it.&lt;/p&gt;
&lt;p&gt;This is the kind of AI tooling that actually saves time rather than generating more work to review.&lt;/p&gt;
&lt;h2 id="first-class-kubernetes-and-aks-deployment"&gt;First-Class Kubernetes and AKS Deployment&lt;/h2&gt;
&lt;p&gt;This one has been on the wishlist for a while. Aspire 13.3 ships &lt;strong&gt;first-class Kubernetes and AKS deployment support with Helm&lt;/strong&gt;. You can now target AKS as a deployment target directly from the Aspire tooling.&lt;/p&gt;
&lt;p&gt;For teams already running production workloads on AKS, this closes a significant gap. Your Aspire app model now has a clean path from local dev to Kubernetes without manual Helm chart authoring.&lt;/p&gt;
&lt;h2 id="browser-logs-in-the-dashboard"&gt;Browser Logs in the Dashboard&lt;/h2&gt;
&lt;p&gt;This is one of those features that sounds small until you&amp;rsquo;re debugging a frontend issue.&lt;/p&gt;
&lt;p&gt;The new &lt;code&gt;WithBrowserLogs()&lt;/code&gt; API attaches a tracked browser resource to any endpoint-capable resource. Aspire launches Chromium using a private CDP pipe and streams console logs, network requests, and errors directly into the resource log stream:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;frontend&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddViteApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;frontend&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;../frontend&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithHttpEndpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithBrowserLogs&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;TypeScript AppHost supports the same:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;frontend&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addViteApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;frontend&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;../frontend&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;withHttpEndpoint&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;port&lt;/span&gt;: &lt;span class="kt"&gt;3000&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;withBrowserLogs&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Console errors, failed network requests, client-side exceptions — all visible in the same dashboard where you&amp;rsquo;re already watching traces and metrics. No more tab-switching to browser DevTools for the basic stuff.&lt;/p&gt;
&lt;h2 id="structured-command-results"&gt;Structured Command Results&lt;/h2&gt;
&lt;p&gt;Resource commands got a meaningful upgrade. Until now, commands returned success/failure. Now they return structured results: text, JSON, or markdown that flows through the model, dashboard UI, CLI, and MCP tools.&lt;/p&gt;
&lt;p&gt;The dashboard ties this together with a new notification center in the header. Command results show up as timestamped notifications with markdown rendering and a &amp;ldquo;View response&amp;rdquo; action.&lt;/p&gt;
&lt;p&gt;This makes resource commands genuinely composable. An integration can now expose a command that returns meaningful output — like a tunnel URL — rather than just changing state somewhere.&lt;/p&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;Aspire 13.3 is worth the upgrade even just for the Kubernetes support. The browser logs and structured command results feel like the kind of quality-of-life improvements that accumulate quickly in a day-to-day development workflow.&lt;/p&gt;
&lt;p&gt;Full release notes: &lt;a href="https://devblogs.microsoft.com/aspire/whats-new-aspire-13-3/"&gt;What&amp;rsquo;s New in Aspire 13.3&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title>SDD Conference 2026</title><link>https://thedotnetblog.com/events/sdd-conference-2026/</link><pubDate>Mon, 11 May 2026 00:00:00 +0000</pubDate><guid>https://thedotnetblog.com/events/sdd-conference-2026/</guid><description>A 5-day software development conference at the Barbican Centre in London with 78 sessions and 14 workshops covering architecture, .NET, AI, Azure, DevOps, and more.</description><content:encoded>&lt;p&gt;&lt;strong&gt;SDD 2026&lt;/strong&gt; runs from &lt;strong&gt;May 11–15, 2026&lt;/strong&gt; at the &lt;strong&gt;Barbican Centre in London&lt;/strong&gt;. The core 3-day conference is Tuesday through Thursday, with optional full-day workshops on Monday and Friday.&lt;/p&gt;
&lt;p&gt;With &lt;strong&gt;78 sessions&lt;/strong&gt; and &lt;strong&gt;14 workshops&lt;/strong&gt;, this is one of the most packed developer conferences in Europe.&lt;/p&gt;
&lt;h2 id="topics"&gt;Topics&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Architectural Thinking&lt;/li&gt;
&lt;li&gt;Functional Code in C# 13&lt;/li&gt;
&lt;li&gt;Serverless Design&lt;/li&gt;
&lt;li&gt;Semantic AI&lt;/li&gt;
&lt;li&gt;Azure Kubernetes Services&lt;/li&gt;
&lt;li&gt;Lean DevOps Strategies&lt;/li&gt;
&lt;li&gt;The Model Context Protocol (MCP)&lt;/li&gt;
&lt;li&gt;Agentic AI in .NET&lt;/li&gt;
&lt;li&gt;Refactoring the Monolith&lt;/li&gt;
&lt;li&gt;Coding Faster with LLMs&lt;/li&gt;
&lt;li&gt;Cryptography in a Post-Quantum World&lt;/li&gt;
&lt;li&gt;Local First Development&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="speakers"&gt;Speakers&lt;/h2&gt;
&lt;p&gt;World-class lineup including &lt;strong&gt;Kevlin Henney&lt;/strong&gt;, &lt;strong&gt;Neal Ford&lt;/strong&gt;, &lt;strong&gt;Sander Hoogendoorn&lt;/strong&gt;, &lt;strong&gt;Andrew Clymer&lt;/strong&gt;, &lt;strong&gt;Jacqui Read&lt;/strong&gt;, &lt;strong&gt;Christian Weyer&lt;/strong&gt;, &lt;strong&gt;Jeff Prosise&lt;/strong&gt;, &lt;strong&gt;Jules May&lt;/strong&gt;, &lt;strong&gt;Oliver Sturm&lt;/strong&gt;, and &lt;strong&gt;Raju Gandhi&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id="tickets-and-info"&gt;Tickets and info&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://sddconf.com/"&gt;Event website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sddvault.s3.amazonaws.com/assets/SDD_2026_schedule.pdf"&gt;Full agenda PDF&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sddconf.com/register"&gt;Registration options&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;98% of SDD 2025 attendees rated the overall experience as good, very good, or excellent.&lt;/p&gt;</content:encoded></item><item><title>Building an AI-Powered Conference App with .NET's Composable Stack</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/ai-conference-app-dotnet-composable-stack/</link><pubDate>Wed, 06 May 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/ai-conference-app-dotnet-composable-stack/</guid><description>Microsoft built ConferencePulse — a live conference Blazor app — by composing Microsoft.Extensions.AI, DataIngestion, VectorData, MCP, and Agent Framework together. Here's how the pieces fit.</description><content:encoded>&lt;p&gt;&lt;a href="https://devblogs.microsoft.com/dotnet/building-ai-conference-app-dotnet-composable-stack/"&gt;Building an AI-Powered Conference App with .NET&amp;rsquo;s Composable Stack&lt;/a&gt; — Microsoft built ConferencePulse, a Blazor Server app for live conference sessions, by composing five .NET extension libraries together. They used it at MVP Summit.&lt;/p&gt;
&lt;h2 id="what-conferencepulse-does"&gt;What ConferencePulse does&lt;/h2&gt;
&lt;p&gt;ConferencePulse runs during live sessions and provides: AI-generated polls from session content, audience Q&amp;amp;A with a RAG pipeline pulling from a live knowledge base, auto-generated insights, and session summaries produced by multiple concurrent AI agents. The stack is .NET 10, Blazor Server, Aspire, split across five projects: Web, Core, Ingestion, Agents, Mcp, and AppHost.&lt;/p&gt;
&lt;h2 id="microsoftextensionsai-one-abstraction-for-everything"&gt;Microsoft.Extensions.AI: one abstraction for everything&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;IChatClient&lt;/code&gt; is the unified abstraction — you wire it up once and the same interface works for Azure OpenAI, OpenAI, Anthropic, or any other provider. Six lines to get a fully configured client with function invocation, OpenTelemetry tracing, and logging middleware:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddChatClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;AzureOpenAIClient&lt;/span&gt;&lt;span class="p"&gt;(...).&lt;/span&gt;&lt;span class="n"&gt;GetChatClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;gpt-4o&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UseFunctionInvocation&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UseOpenTelemetry&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UseLogging&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The same &lt;code&gt;IChatClient&lt;/code&gt; is reused later for the data ingestion enrichment step — no separate client for that.&lt;/p&gt;
&lt;h2 id="dataingestion-pipeline"&gt;DataIngestion pipeline&lt;/h2&gt;
&lt;p&gt;Session content flows through a pipeline: &lt;code&gt;MarkdownReader&lt;/code&gt; → &lt;code&gt;HeaderChunker&lt;/code&gt; (500 tokens, 50 token overlap) → &lt;code&gt;SummaryEnricher&lt;/code&gt; + &lt;code&gt;KeywordEnricher&lt;/code&gt; → &lt;code&gt;VectorStoreWriter&lt;/code&gt; (Qdrant). The enrichers use the same &lt;code&gt;IChatClient&lt;/code&gt; to generate summaries and extract keywords before indexing. Audience questions, Q&amp;amp;A pairs, and poll results are ingested in real-time as the session progresses — the knowledge base grows during the talk.&lt;/p&gt;
&lt;h2 id="vectordata-provider-agnostic-search"&gt;VectorData: provider-agnostic search&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;VectorStoreCollection.SearchAsync()&lt;/code&gt; works the same whether the backing store is Qdrant or Azure AI Search. Hybrid search (vector + full-text) is supported. The RAG pipeline for audience Q&amp;amp;A queries this collection and gets back relevant chunks to pass as context to the chat client.&lt;/p&gt;
&lt;h2 id="mcp-session-content-as-tools"&gt;MCP: session content as tools&lt;/h2&gt;
&lt;p&gt;The session content is exposed via MCP so any MCP-compatible client can access it. Both the server and client are implemented — the server exposes session knowledge as MCP tools, and the client allows calling those tools from within the agent pipeline.&lt;/p&gt;
&lt;h2 id="agent-framework-parallel-multi-agent-summary"&gt;Agent Framework: parallel multi-agent summary&lt;/h2&gt;
&lt;p&gt;The session summary is generated by three agents running concurrently — &lt;code&gt;PollSummaryAgent&lt;/code&gt;, &lt;code&gt;QuestionSummaryAgent&lt;/code&gt;, and &lt;code&gt;InsightSummaryAgent&lt;/code&gt; — then merged. This uses the group chat or parallel execution pattern from Microsoft Agent Framework. Each agent handles one concern; the orchestrator merges the outputs.&lt;/p&gt;
&lt;h2 id="the-design-principle"&gt;The design principle&lt;/h2&gt;
&lt;p&gt;The post makes a point worth keeping: use the simplest tool that fits. Direct &lt;code&gt;IChatClient&lt;/code&gt; calls for simple generation tasks. Tool/function calling for structured data extraction. Full agents only when you need autonomous multi-step reasoning. The library layering enforces this — you can pick up &lt;code&gt;Microsoft.Extensions.AI&lt;/code&gt; without pulling in the full Agent Framework.&lt;/p&gt;
&lt;p&gt;See the &lt;a href="https://devblogs.microsoft.com/dotnet/building-ai-conference-app-dotnet-composable-stack/"&gt;full post&lt;/a&gt; for the complete project structure and source links.&lt;/p&gt;</content:encoded></item><item><title>Microsoft Agent Framework Part 3: From Tools to Workflows — The Building Blocks Click Into Place</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/maf-building-blocks-part-3-agents-tools-workflows/</link><pubDate>Tue, 05 May 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/maf-building-blocks-part-3-agents-tools-workflows/</guid><description>Part 3 of the .NET AI building blocks series covers the Microsoft Agent Framework — from single agents with tools to multi-agent workflows with memory. Here's what actually matters.</description><content:encoded>&lt;p&gt;If you&amp;rsquo;ve been following the Building Blocks for AI in .NET series, you know Part 1 gave us &lt;code&gt;IChatClient&lt;/code&gt; (the universal model interface) and Part 2 gave us &lt;code&gt;Microsoft.Extensions.VectorData&lt;/code&gt; (semantic search and RAG). Both are foundational, both are useful on their own. But this is where everything starts to connect.&lt;/p&gt;
&lt;p&gt;Part 3 is about the &lt;a href="https://github.com/microsoft/agent-framework"&gt;Microsoft Agent Framework&lt;/a&gt; — and honestly, it&amp;rsquo;s the piece I&amp;rsquo;ve been waiting to see land in .NET. 1.0 shipped in April. The API is stable. It&amp;rsquo;s time to actually build agents.&lt;/p&gt;
&lt;h2 id="what-an-agent-actually-is-vs-a-chatbot"&gt;What an Agent Actually Is (vs. a Chatbot)&lt;/h2&gt;
&lt;p&gt;Before diving into code, let&amp;rsquo;s get this distinction out of the way. A chatbot receives input, calls a model, returns output. Simple loop.&lt;/p&gt;
&lt;p&gt;An agent has &lt;em&gt;autonomy&lt;/em&gt;. It can reason about a task, decide which tools to use, call those tools, evaluate results, and decide what to do next — all without you writing explicit step-by-step logic for every scenario. You give it tools and instructions, and it figures out the orchestration.&lt;/p&gt;
&lt;p&gt;Think of it this way: &lt;code&gt;IChatClient&lt;/code&gt; is like having a conversation. An agent is like handing someone a task list.&lt;/p&gt;
&lt;h2 id="your-first-agent-in-10-lines"&gt;Your First Agent in 10 Lines&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dotnet add package Microsoft.Agents.AI
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;AIAgent&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;AzureOpenAIClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;DefaultAzureCredential&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetChatClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deploymentName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AsAIAgent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;instructions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;You are good at telling jokes.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Joker&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RunAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Tell me a joke about a pirate.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;.AsAIAgent()&lt;/code&gt; extension method is the bridge. Same pattern as &lt;code&gt;.AsIChatClient()&lt;/code&gt; from MEAI — it wraps a provider&amp;rsquo;s SDK in a stable abstraction. It works with Azure OpenAI, OpenAI, GitHub Models, Microsoft Foundry, or local models via Foundry Local or Ollama.&lt;/p&gt;
&lt;p&gt;Streaming works too:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RunStreamingAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Tell me a joke about a pirate.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="giving-the-agent-tools"&gt;Giving the Agent Tools&lt;/h2&gt;
&lt;p&gt;This is where agents stop being fancy chatbots. Tools are functions the model can decide to call based on what the user asks. No routing logic needed on your part — the model figures it out.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;[Description(&amp;#34;Get the weather for a given location.&amp;#34;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;GetWeather&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt; [Description(&amp;#34;The location to get the weather for.&amp;#34;)]&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;$&amp;#34;The weather in {location} is cloudy with a high of 15°C.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;AIAgent&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;chatClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AsAIAgent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;instructions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;You are a helpful assistant&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;AIFunctionFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GetWeather&lt;/span&gt;&lt;span class="p"&gt;)]);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Two things to notice here. First, &lt;code&gt;AIFunctionFactory&lt;/code&gt; is from MEAI — same tool factory you&amp;rsquo;d use with a plain &lt;code&gt;IChatClient&lt;/code&gt;. If you&amp;rsquo;ve already defined tools for your chat scenarios, they work here too.&lt;/p&gt;
&lt;p&gt;Second, those &lt;code&gt;Description&lt;/code&gt; attributes matter a lot. They&amp;rsquo;re how the model understands what a tool does and when to use it. Treat them as documentation for your AI, not for humans.&lt;/p&gt;
&lt;h2 id="sessions-conversations-that-actually-remember"&gt;Sessions: Conversations That Actually Remember&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;AgentSession&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateSessionAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RunAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Tell me a joke about a pirate.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RunAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;Now add some emojis and tell it in the voice of a pirate&amp;#39;s parrot.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Without a session, each &lt;code&gt;RunAsync&lt;/code&gt; call is stateless. With a session, the agent knows which joke you&amp;rsquo;re referring to. The &lt;code&gt;AgentSession&lt;/code&gt; preserves conversation history between turns.&lt;/p&gt;
&lt;p&gt;For production stateless services, sessions serialize cleanly:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;JsonElement&lt;/span&gt; &lt;span class="n"&gt;sessionState&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SerializeSessionAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// ... store it somewhere ...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;restoredSession&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DeserializeSessionAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sessionState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RunAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;What were we just talking about?&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;restoredSession&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This is critical if your agent runs in a serverless or horizontally-scaled environment.&lt;/p&gt;
&lt;h2 id="aicontextprovider-memory-that-persists-across-sessions"&gt;AIContextProvider: Memory That Persists Across Sessions&lt;/h2&gt;
&lt;p&gt;Sessions preserve conversation history &lt;em&gt;within&lt;/em&gt; a session. But what about knowing things about a user across sessions? &lt;code&gt;AIContextProvider&lt;/code&gt; handles that.&lt;/p&gt;
&lt;p&gt;It has two hooks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;ProvideAIContextAsync&lt;/code&gt;&lt;/strong&gt; — runs &lt;em&gt;before&lt;/em&gt; each interaction, injects context into the agent (e.g., &amp;ldquo;The user&amp;rsquo;s name is Emiliano&amp;rdquo;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;StoreAIContextAsync&lt;/code&gt;&lt;/strong&gt; — runs &lt;em&gt;after&lt;/em&gt; each interaction, lets you learn from what was said and persist it&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The pattern is elegant: you can stack multiple providers — one for user preferences, one for recent interactions, one that queries your VectorData store for relevant documents. That last one is exactly the RAG pattern from Part 2, now running automatically as part of every agent call.&lt;/p&gt;
&lt;h2 id="multi-agent-workflows"&gt;Multi-Agent Workflows&lt;/h2&gt;
&lt;p&gt;This is where the framework earns its name. The Agent Framework includes a graph-based workflow system where executors (agents, functions, whatever) connect via edges.&lt;/p&gt;
&lt;p&gt;Some patterns that are natively supported:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Sequential&lt;/strong&gt;: Agent A&amp;rsquo;s output feeds Agent B&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Concurrent (fan-out/fan-in)&lt;/strong&gt;: Dispatch to multiple agents in parallel, collect results&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Conditional routing&lt;/strong&gt;: Route work to different agents based on output&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Writer-critic loops&lt;/strong&gt;: One agent writes, another evaluates, loop until approved&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sub-workflows&lt;/strong&gt;: Compose workflows hierarchically&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A writer-critic example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;WorkflowBuilder&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;writerAgent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;builder&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddEdge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;writerAgent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;criticAgent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddEdge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;criticAgent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;writerAgent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;condition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsApproved&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithOutputFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;criticAgent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;condition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsApproved&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;workflow&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Clean, readable, and the condition-based routing means you don&amp;rsquo;t write loop logic yourself. The framework drives the iteration.&lt;/p&gt;
&lt;h2 id="human-in-the-loop"&gt;Human-in-the-Loop&lt;/h2&gt;
&lt;p&gt;Not everything should run fully autonomously. For sensitive operations — database writes, financial transactions, sending communications — you want a human to approve before the agent executes.&lt;/p&gt;
&lt;p&gt;The framework has built-in support for this via &lt;code&gt;FunctionApprovalRequestContent&lt;/code&gt; and &lt;code&gt;FunctionApprovalResponseContent&lt;/code&gt;. The agent proposes the tool call, your application code presents it to the user, and the response determines whether execution proceeds.&lt;/p&gt;
&lt;p&gt;This is the right way to think about agents in enterprise settings: not fully autonomous, but &lt;em&gt;autonomy-with-guardrails&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id="the-full-picture"&gt;The Full Picture&lt;/h2&gt;
&lt;p&gt;If you step back for a second:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;MEAI&lt;/strong&gt; gives you a universal interface to any model&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;VectorData&lt;/strong&gt; gives your agents access to your organization&amp;rsquo;s knowledge through semantic search&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Agent Framework&lt;/strong&gt; orchestrates everything — it uses &lt;code&gt;IChatClient&lt;/code&gt; under the hood, composes with context providers, and coordinates through workflows&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each piece was designed to compose with the others. You can use any of them independently, but together they form a coherent stack for building AI applications in .NET.&lt;/p&gt;
&lt;p&gt;Check out the &lt;a href="https://devblogs.microsoft.com/dotnet/microsoft-agent-framework-building-blocks-for-ai-part-3/"&gt;original post by Jeremy Likness&lt;/a&gt; and the &lt;a href="https://github.com/microsoft/agent-framework/tree/main/dotnet"&gt;Agent Framework GitHub repo&lt;/a&gt; for the full samples.&lt;/p&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;The Microsoft Agent Framework Part 3 post closes the loop on the building blocks series (with MCP coming next). For .NET developers who want to build AI agents — not just chatbots, actual agents that use tools, remember things, and coordinate — this is your path forward.&lt;/p&gt;
&lt;p&gt;The 1.0 stable release means you can build on this in production. The composition with MEAI and VectorData means you&amp;rsquo;re not learning a parallel set of abstractions. It all fits together.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;ve been waiting to jump into agent development in .NET, the timing is right now.&lt;/p&gt;</content:encoded></item><item><title>Azure MCP Server Is Now a .mcpb — Install It Without Any Runtime</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/azure-mcp-server-mcpb-no-runtime-install/</link><pubDate>Sat, 25 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/azure-mcp-server-mcpb-no-runtime-install/</guid><description>The Azure MCP Server is now available as an MCP Bundle (.mcpb) — download it, drag it into Claude Desktop, and you're done. No Node.js, Python, or .NET runtime required.</description><content:encoded>&lt;p&gt;You know what was annoying about setting up MCP servers? You needed a runtime. Node.js for the npm version, Python for pip/uvx, .NET SDK for the dotnet flavor, Docker if you wanted containers. Just to get a tool connected to your AI client.&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://devblogs.microsoft.com/azure-sdk/azure-mcp-server-mcpb-support/"&gt;Azure MCP Server just changed that&lt;/a&gt;. It&amp;rsquo;s now available as an &lt;code&gt;.mcpb&lt;/code&gt; — an MCP Bundle — and the setup is drag-and-drop.&lt;/p&gt;
&lt;h2 id="whats-an-mcp-bundle"&gt;What&amp;rsquo;s an MCP Bundle?&lt;/h2&gt;
&lt;p&gt;Think of it like a VS Code extension (&lt;code&gt;.vsix&lt;/code&gt;) or a browser extension (&lt;code&gt;.crx&lt;/code&gt;), but for MCP servers. A &lt;code&gt;.mcpb&lt;/code&gt; file is a self-contained ZIP archive that includes the server binary and all its dependencies. Everything needed to run on your platform, packaged together.&lt;/p&gt;
&lt;p&gt;The end result: you download one file, open it in a supported client, and the server runs. No runtime to install, no &lt;code&gt;package.json&lt;/code&gt; to manage, no version conflicts.&lt;/p&gt;
&lt;h2 id="how-to-install-it"&gt;How to install it&lt;/h2&gt;
&lt;p&gt;Three steps:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Download the bundle for your platform&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Go to the &lt;a href="https://github.com/microsoft/mcp/releases?q=Azure.Mcp.Server"&gt;GitHub Releases page&lt;/a&gt; and grab the &lt;code&gt;.mcpb&lt;/code&gt; file for your OS and architecture. Make sure you pick the right one — &lt;code&gt;osx-arm64&lt;/code&gt; for Apple Silicon, &lt;code&gt;osx-x64&lt;/code&gt; for Intel Mac, etc.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Install in Claude Desktop&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The easiest way: drag and drop the &lt;code&gt;.mcpb&lt;/code&gt; file into the Claude Desktop window while you&amp;rsquo;re on the Extensions settings page (&lt;code&gt;☰ → File → Settings → Extensions&lt;/code&gt;). Review the server details, click Install, confirm. Done.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Tip: You can also set Claude Desktop as the default app for &lt;code&gt;.mcpb&lt;/code&gt; files and double-click to install.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;3. Authenticate to Azure&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;az login
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s it. The Azure MCP Server uses your existing Azure credentials.&lt;/p&gt;
&lt;h2 id="what-you-can-do-with-it"&gt;What you can do with it&lt;/h2&gt;
&lt;p&gt;Once installed, you have access to 100+ Azure service tools directly from your AI client:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Query and manage Cosmos DB, Storage, Key Vault, App Service, Foundry&lt;/li&gt;
&lt;li&gt;Generate &lt;code&gt;az&lt;/code&gt; CLI commands for any task&lt;/li&gt;
&lt;li&gt;Create Bicep and Terraform templates&lt;/li&gt;
&lt;li&gt;Get architecture recommendations and diagnostics&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Try prompts like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&amp;ldquo;List all resource groups in my subscription&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Generate a Bicep template for a web app with a SQL database&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;What Cosmos DB databases do I have?&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Show me the secrets in my Key Vault named my-vault&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="which-install-method-should-you-use"&gt;Which install method should you use?&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Best for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.mcpb&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Claude Desktop users who want zero-config&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;VS Code Extension&lt;/td&gt;
&lt;td&gt;Developers working in VS Code + GitHub Copilot&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;npm/npx&lt;/td&gt;
&lt;td&gt;Developers who already have Node.js&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pip/uvx&lt;/td&gt;
&lt;td&gt;Python developers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Docker&lt;/td&gt;
&lt;td&gt;CI/CD pipelines and containers&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;All methods give you the same tools. The &lt;code&gt;.mcpb&lt;/code&gt; is just the most frictionless path for Claude Desktop users.&lt;/p&gt;
&lt;h2 id="why-this-matters"&gt;Why this matters&lt;/h2&gt;
&lt;p&gt;MCP servers are genuinely useful — they let AI clients interact with external systems in a structured way. But the setup friction has been a real barrier, especially for users who aren&amp;rsquo;t developers or who just don&amp;rsquo;t want to manage runtimes for every tool they install.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;.mcpb&lt;/code&gt; format feels like the right direction. It&amp;rsquo;s the same principle as VS Code extensions or browser extensions: one file, platform-native binary, install and go.&lt;/p&gt;
&lt;p&gt;If the MCP ecosystem keeps moving this direction, connecting AI clients to services will get a lot simpler.&lt;/p&gt;
&lt;h2 id="get-started"&gt;Get started&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Download&lt;/strong&gt;: &lt;a href="https://github.com/microsoft/mcp/releases?q=Azure.Mcp.Server-"&gt;GitHub Releases&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Repo&lt;/strong&gt;: &lt;a href="https://aka.ms/azmcp"&gt;aka.ms/azmcp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Docs&lt;/strong&gt;: &lt;a href="https://aka.ms/azmcp/docs"&gt;aka.ms/azmcp/docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Check the &lt;a href="https://devblogs.microsoft.com/azure-sdk/azure-mcp-server-mcpb-support/"&gt;full post&lt;/a&gt; for troubleshooting tips and a comparison of all install methods.&lt;/p&gt;</content:encoded></item><item><title>CodeAct in Agent Framework: How to Cut Your Agent's Latency in Half</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/codeact-agent-framework-hyperlight-50-percent-faster/</link><pubDate>Sat, 25 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/codeact-agent-framework-hyperlight-50-percent-faster/</guid><description>CodeAct collapses multi-step tool chains into a single sandboxed code block — cutting latency by 52% and token usage by 64%. Here's what it means for your agents and when to reach for it.</description><content:encoded>&lt;p&gt;There&amp;rsquo;s a moment in every agent project where you look at the trace and think: &amp;ldquo;why is this taking so long?&amp;rdquo; The model is fine. The tools work. But there are seven round trips to get a result you could compute in one shot.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s exactly the problem CodeAct solves — and the &lt;a href="https://devblogs.microsoft.com/agent-framework/codeact-with-hyperlight/"&gt;Agent Framework team just shipped alpha support for it&lt;/a&gt; via a new &lt;code&gt;agent-framework-hyperlight&lt;/code&gt; package.&lt;/p&gt;
&lt;h2 id="what-is-codeact"&gt;What is CodeAct?&lt;/h2&gt;
&lt;p&gt;The &lt;a href="https://arxiv.org/abs/2402.01030"&gt;CodeAct pattern&lt;/a&gt; is elegantly simple: instead of giving the model a list of tools and letting it call them one by one, you give it a single &lt;code&gt;execute_code&lt;/code&gt; tool and let it express the &lt;em&gt;entire plan&lt;/em&gt; as a short Python program. The agent writes the code once, the sandbox runs it, and you get back a single consolidated result.&lt;/p&gt;
&lt;p&gt;A five-step plan that used to be five model turns becomes one &lt;code&gt;execute_code&lt;/code&gt; turn containing a Python script that calls your tools via &lt;code&gt;call_tool(...)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The benchmark in the repo makes this concrete. Eight users, dozens of orders, five tools (list users, get orders, discount rate, tax rate, compute line total). Same model, same tools, same prompt — just different wiring:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Wiring&lt;/th&gt;
&lt;th&gt;Time&lt;/th&gt;
&lt;th&gt;Tokens&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Traditional&lt;/td&gt;
&lt;td&gt;27.81s&lt;/td&gt;
&lt;td&gt;6,890&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CodeAct&lt;/td&gt;
&lt;td&gt;13.23s&lt;/td&gt;
&lt;td&gt;2,489&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Improvement&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;52.4%&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;63.9%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;That&amp;rsquo;s not a micro-benchmark. That&amp;rsquo;s a realistic workload with real orchestration overhead.&lt;/p&gt;
&lt;h2 id="the-safety-piece-hyperlight-micro-vms"&gt;The safety piece: Hyperlight micro-VMs&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s the thing that made me actually excited about this: safety has historically been CodeAct&amp;rsquo;s Achilles heel. If you&amp;rsquo;re running model-generated code, where exactly is it running? Against your process? In a shared container?&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;agent-framework-hyperlight&lt;/code&gt; package solves this with &lt;a href="https://github.com/hyperlight-dev/hyperlight"&gt;Hyperlight&lt;/a&gt; micro-VMs. Every single &lt;code&gt;execute_code&lt;/code&gt; call gets its own freshly created micro-VM — with its own memory, no host filesystem access beyond what you explicitly mount, and no network access beyond the domains you allow. Startup is measured in milliseconds. The isolation is basically free.&lt;/p&gt;
&lt;p&gt;Your tools still run on the host (they&amp;rsquo;re your code, with your access). The model-generated &lt;em&gt;glue&lt;/em&gt; — the Python that decides which tools to call and in what order — runs sandboxed. That&amp;rsquo;s the right split.&lt;/p&gt;
&lt;h2 id="wiring-it-up"&gt;Wiring it up&lt;/h2&gt;
&lt;p&gt;The minimal setup is straightforward:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;agent_framework&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tool&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;agent_framework_hyperlight&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;HyperlightCodeActProvider&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nd"&gt;@tool&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_weather&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&amp;#34;Return the current weather for a city.&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;city&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;temperature_c&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;21.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;conditions&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;partly cloudy&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;codeact&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HyperlightCodeActProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;get_weather&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;approval_mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;never_require&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;CodeActAgent&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;instructions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;You are a helpful assistant.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;context_providers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;codeact&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;Get the weather for Seattle and Amsterdam and compare them.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The provider registers &lt;code&gt;execute_code&lt;/code&gt; on every run and injects the CodeAct instructions into the system prompt automatically. You don&amp;rsquo;t need to write a custom prompt fragment.&lt;/p&gt;
&lt;h2 id="mixing-codeact-with-approval-gated-tools"&gt;Mixing CodeAct with approval-gated tools&lt;/h2&gt;
&lt;p&gt;This is where it gets interesting. Not every tool should run inside the sandbox without approval. You might want to gate &lt;code&gt;send_email&lt;/code&gt; or &lt;code&gt;charge_credit_card&lt;/code&gt; individually. The framework handles this cleanly:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nd"&gt;@tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;approval_mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;always_require&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;send_email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&amp;#34;Send an email. Requires approval on every call.&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;MixedToolsAgent&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;instructions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;You are a helpful assistant.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;context_providers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;codeact&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;send_email&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="c1"&gt;# invoked directly, approval-gated&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Tools on the provider → the model reaches them via &lt;code&gt;call_tool(...)&lt;/code&gt; inside the sandbox, cheap and chainable.&lt;br&gt;
Tools on the agent directly → the model calls them as first-class tool calls, approval applies individually.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s a clean split: chainable data-lookup tools go through CodeAct, side-effect tools stay on the agent.&lt;/p&gt;
&lt;h2 id="when-to-use-codeact-and-when-not-to"&gt;When to use CodeAct (and when not to)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Reach for CodeAct when:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The task chains many small tool calls (lookups, joins, computations, formatting)&lt;/li&gt;
&lt;li&gt;You care about latency and token cost&lt;/li&gt;
&lt;li&gt;You want strong per-call isolation on model-generated code by default&lt;/li&gt;
&lt;li&gt;Tools are cheap and safe to invoke in sequence&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Stick with traditional tool-calling when:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The agent only makes one or two tool calls per turn&lt;/li&gt;
&lt;li&gt;Each tool has side effects you want approved individually&lt;/li&gt;
&lt;li&gt;Tool descriptions are sparse or ambiguous — CodeAct relies on good docstrings&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That last point matters. Because the model writes Python that calls your tools by name, docstrings and parameter annotations become part of the contract the model reasons about. Weak descriptions hurt CodeAct more than traditional tool-calling.&lt;/p&gt;
&lt;h2 id="try-it-now"&gt;Try it now&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pip install agent-framework-hyperlight --pre
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# or&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;uv add --prerelease&lt;span class="o"&gt;=&lt;/span&gt;allow agent-framework-hyperlight
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Samples are under &lt;a href="https://github.com/microsoft/agent-framework/tree/main/python/packages/hyperlight/samples"&gt;&lt;code&gt;python/packages/hyperlight/samples/&lt;/code&gt;&lt;/a&gt;. The &lt;a href="https://github.com/microsoft/agent-framework/blob/main/python/packages/hyperlight/samples/codeact_benchmark.py"&gt;benchmark sample&lt;/a&gt; is the best place to start — run it against your own tools to see if the wins apply to your workload.&lt;/p&gt;
&lt;p&gt;Worth noting: Linux and Windows are supported today. macOS support is on the way. A .NET counterpart is also coming, so if you&amp;rsquo;re on C#, keep an eye on the repo.&lt;/p&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;CodeAct isn&amp;rsquo;t magic — it&amp;rsquo;s a sensible pattern that was just too risky to use without proper sandboxing. Hyperlight changes that equation. Per-call micro-VM isolation, millisecond startup, 50%+ latency improvement on the right workloads. That&amp;rsquo;s a combination worth experimenting with.&lt;/p&gt;
&lt;p&gt;Check the &lt;a href="https://devblogs.microsoft.com/agent-framework/codeact-with-hyperlight/"&gt;full post on the Agent Framework blog&lt;/a&gt; for deeper coverage on filesystem mounts, network policy, and the standalone &lt;code&gt;HyperlightExecuteCodeTool&lt;/code&gt; wiring.&lt;/p&gt;</content:encoded></item><item><title>GPT-5.5 Is Here and It's Coming to Azure Foundry — What .NET Developers Need to Know</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/gpt-55-foundry-ga-what-dotnet-developers-need-to-know/</link><pubDate>Sat, 25 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/gpt-55-foundry-ga-what-dotnet-developers-need-to-know/</guid><description>GPT-5.5 is generally available in Microsoft Foundry. Here's the progression from GPT-5 to 5.5, what's actually improved, and how to start using it in your agents today.</description><content:encoded>&lt;p&gt;Microsoft just announced that &lt;a href="https://azure.microsoft.com/en-us/blog/openais-gpt-5-5-in-microsoft-foundry-frontier-intelligence-on-an-enterprise-ready-platform/"&gt;GPT-5.5 is generally available in Microsoft Foundry&lt;/a&gt;. If you&amp;rsquo;ve been building agents on Azure, this is the update you&amp;rsquo;ve been waiting for.&lt;/p&gt;
&lt;p&gt;Let me break down what actually changed and why it matters for developers building on this stack.&lt;/p&gt;
&lt;h2 id="the-gpt-5-progression"&gt;The GPT-5 progression&lt;/h2&gt;
&lt;p&gt;It helps to understand the arc. This isn&amp;rsquo;t just a version bump:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;GPT-5&lt;/strong&gt;: unified reasoning and speed into a single system&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GPT-5.4&lt;/strong&gt;: stronger multi-step reasoning, early agentic capabilities for enterprise use&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GPT-5.5&lt;/strong&gt;: deeper long-context reasoning, more reliable agentic execution, improved computer-use accuracy, better token efficiency&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each step has been deliberately aimed at production agentic workloads. GPT-5.5 continues that arc with a specific focus on sustained, high-stakes professional workflows — not just one-shot queries.&lt;/p&gt;
&lt;h2 id="whats-actually-different"&gt;What&amp;rsquo;s actually different&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Improved agentic coding&lt;/strong&gt;: GPT-5.5 holds context across large codebases, can diagnose architectural-level failures, and anticipates downstream testing requirements. That last point is interesting — the model reasons about &lt;em&gt;what else&lt;/em&gt; a fix affects before making a move. Less back-and-forth to get to a working result.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Token efficiency&lt;/strong&gt;: Higher-quality outputs with fewer tokens and fewer retries. This translates directly to lower cost and latency for production deployments. If you&amp;rsquo;re running agents at scale, this compounds fast.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Long-context analysis&lt;/strong&gt;: Handles extensive documents, codebases, and multi-session histories without losing the thread. For agentic workflows that maintain large working state, this matters.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s also a &lt;strong&gt;GPT-5.5 Pro&lt;/strong&gt; variant for the most demanding enterprise workloads — deeper reasoning, higher cost.&lt;/p&gt;
&lt;h2 id="pricing"&gt;Pricing&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Input ($/M tokens)&lt;/th&gt;
&lt;th&gt;Cached Input&lt;/th&gt;
&lt;th&gt;Output ($/M tokens)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GPT-5.5&lt;/td&gt;
&lt;td&gt;$5.00&lt;/td&gt;
&lt;td&gt;$0.50&lt;/td&gt;
&lt;td&gt;$30.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT-5.5 Pro&lt;/td&gt;
&lt;td&gt;$30.00&lt;/td&gt;
&lt;td&gt;$3.00&lt;/td&gt;
&lt;td&gt;$180.00&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;GPT-5.5 is priced at the same input rate as GPT-5 but the token efficiency improvements mean you&amp;rsquo;re actually paying less per useful output. Worth running a benchmark on your specific workload before committing.&lt;/p&gt;
&lt;h2 id="why-foundry-matters-here"&gt;Why Foundry matters here&lt;/h2&gt;
&lt;p&gt;Access to a frontier model is just the starting point. What matters for .NET developers is how you operationalize it.&lt;/p&gt;
&lt;p&gt;Foundry Agent Service lets you define agents in YAML or wire them up with Microsoft Agent Framework, GitHub Copilot SDK, LangGraph, or OpenAI Agents SDK — and run them as isolated hosted agents with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A persistent filesystem&lt;/li&gt;
&lt;li&gt;A distinct Microsoft Entra identity&lt;/li&gt;
&lt;li&gt;Scale-to-zero pricing&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;One command to deploy. No infrastructure to manage. Your agents get GPT-5.5 as the model underneath.&lt;/p&gt;
&lt;h2 id="getting-started"&gt;Getting started&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;re already using Azure AI Foundry, GPT-5.5 shows up as a new model option. Point your client at it and you&amp;rsquo;re done:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// C# — just update the model name&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;AIAgent&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;aiProjectClient&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AsAIAgent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;gpt-5.5&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;instructions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;You are a helpful assistant.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;MyAgent&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you haven&amp;rsquo;t tried Foundry yet, &lt;a href="https://ai.azure.com/"&gt;ai.azure.com&lt;/a&gt; is where to start. The model catalog has a direct link to try GPT-5.5.&lt;/p&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;GPT-5.5 is a real step forward for production agentic workloads. The combination of better long-context handling, improved agentic execution, and token efficiency makes it worth evaluating for anything you&amp;rsquo;re running at scale.&lt;/p&gt;
&lt;p&gt;The frontier is moving fast. Keep building.&lt;/p&gt;
&lt;p&gt;See the &lt;a href="https://azure.microsoft.com/en-us/blog/openais-gpt-5-5-in-microsoft-foundry-frontier-intelligence-on-an-enterprise-ready-platform/"&gt;full announcement&lt;/a&gt; for the complete feature breakdown and enterprise details.&lt;/p&gt;</content:encoded></item><item><title>Where Does Your Agent Remember Things? A Practical Guide to Chat History Storage</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/chat-history-storage-patterns-agent-framework/</link><pubDate>Sat, 25 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/chat-history-storage-patterns-agent-framework/</guid><description>Service-managed or client-managed? Linear or forking? The architectural decision that shapes what your AI agent can actually do — with code examples in C# and Python.</description><content:encoded>&lt;p&gt;When you build an AI agent, you spend most of your energy on the model, the tools, and the prompts. The question of &lt;em&gt;where the conversation history lives&lt;/em&gt; feels like an implementation detail — but it&amp;rsquo;s actually one of the most important architectural decisions you&amp;rsquo;ll make.&lt;/p&gt;
&lt;p&gt;It determines whether users can branch conversations, undo responses, resume sessions after a restart, and whether your data ever leaves your infrastructure. The &lt;a href="https://devblogs.microsoft.com/agent-framework/chat-history-storage-patterns-in-microsoft-agent-framework/"&gt;Agent Framework team published a deep dive on this&lt;/a&gt; and it&amp;rsquo;s worth understanding the full landscape.&lt;/p&gt;
&lt;h2 id="two-fundamental-patterns"&gt;Two fundamental patterns&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Service-managed&lt;/strong&gt;: the AI service stores the conversation state. Your app holds a reference (a thread ID, a response ID) and the service automatically includes relevant history on each request. Simpler to set up. Less control.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Client-managed&lt;/strong&gt;: your app maintains the full history and sends relevant messages with every request. The service is stateless. You control everything — what gets sent, how it&amp;rsquo;s compressed, where it lives.&lt;/p&gt;
&lt;p&gt;Neither is universally better. The right choice depends on what you&amp;rsquo;re building.&lt;/p&gt;
&lt;h2 id="service-managed-linear-vs-forking"&gt;Service-managed: linear vs forking&lt;/h2&gt;
&lt;p&gt;Not all service-managed storage is the same. There are two distinct models:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Linear (single-threaded)&lt;/strong&gt;: messages form an ordered sequence. You can append, but you can&amp;rsquo;t branch. This is the traditional chat model — used by Foundry Prompt Agents and the now-deprecated OpenAI Assistants API. Great for chatbots and support agents. Terrible if you want &amp;ldquo;try again&amp;rdquo; or parallel exploration.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Forking-capable&lt;/strong&gt;: each response has a unique ID, and new requests can reference &lt;em&gt;any&lt;/em&gt; previous response as the continuation point. This is what the Responses API (Microsoft Foundry, Azure OpenAI, OpenAI) supports. Users can branch conversations, build &amp;ldquo;undo&amp;rdquo; flows, explore multiple answer paths.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re building any kind of agentic workflow where multiple paths might be explored, forking is a capability you want.&lt;/p&gt;
&lt;h2 id="client-managed-you-own-the-complexity"&gt;Client-managed: you own the complexity&lt;/h2&gt;
&lt;p&gt;When the service doesn&amp;rsquo;t store history, your app does everything:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Context window management&lt;/strong&gt; — you can&amp;rsquo;t send unlimited history. You need truncation, sliding windows, summarization, or tool-call collapse strategies.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Persistence&lt;/strong&gt; — in-memory works for demos. Production needs a database, Redis, or blob storage.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Privacy&lt;/strong&gt; — conversation data never leaves your infrastructure unless you explicitly send it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The upside on privacy is real. For sensitive applications where you can&amp;rsquo;t have conversation history sitting on a third-party server, client-managed is the only option.&lt;/p&gt;
&lt;p&gt;Agent Framework ships built-in compaction strategies for all the common patterns, so you don&amp;rsquo;t have to build them from scratch. But you do need to choose and configure the right one.&lt;/p&gt;
&lt;h2 id="how-agent-framework-abstracts-this"&gt;How Agent Framework abstracts this&lt;/h2&gt;
&lt;p&gt;The beauty of the framework is that your agent invocation code stays the same regardless of which storage model you&amp;rsquo;re using. The &lt;code&gt;AgentSession&lt;/code&gt; handles the underlying differences.&lt;/p&gt;
&lt;p&gt;In C#:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Works with Chat Completions (client-managed)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// AND with Responses API (service-managed)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// The session handles the details.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;AgentSession&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateSessionAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;first&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RunAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;My name is Alice.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;second&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RunAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;What is my name?&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In Python:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_session&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;first&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;My name is Alice.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;second&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;What is my name?&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When you switch from OpenAI Chat Completions to the Responses API, you change the client configuration — not the agent invocation code.&lt;/p&gt;
&lt;h2 id="the-responses-api-is-uniquely-flexible"&gt;The Responses API is uniquely flexible&lt;/h2&gt;
&lt;p&gt;Most providers have a fixed storage model. The Responses API is the exception — it&amp;rsquo;s configurable via the &lt;code&gt;store&lt;/code&gt; parameter:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;store=true&lt;/code&gt; (default)&lt;/strong&gt;: service stores each response, supports forking via response IDs. Service handles compaction.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;store=false&lt;/code&gt;&lt;/strong&gt;: service is stateless, Agent Framework manages history client-side. You control compaction.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Conversations API&lt;/strong&gt;: linear thread model on top of Responses. Pass a conversation ID instead of a response ID.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&amp;rsquo;s the client-managed mode in practice (C#):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;AIAgent&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;OpenAIClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&amp;lt;your_api_key&amp;gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetResponseClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;gpt-5.4-mini&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AsIChatClientWithStoredOutputDisabled&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AsAIAgent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;ChatClientAgentOptions&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ChatOptions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Instructions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;You are a helpful assistant.&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ChatHistoryProvider&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;InMemoryChatHistoryProvider&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And in Python:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;OpenAIChatClient&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;StatelessAgent&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;instructions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;You are a helpful assistant.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;default_options&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;store&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;context_providers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;InMemoryHistoryProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;memory&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;load_messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Swap &lt;code&gt;InMemoryHistoryProvider&lt;/code&gt; for your &lt;code&gt;DatabaseHistoryProvider&lt;/code&gt; when you&amp;rsquo;re ready for production persistence.&lt;/p&gt;
&lt;h2 id="provider-quick-reference"&gt;Provider quick reference&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Provider&lt;/th&gt;
&lt;th&gt;Storage&lt;/th&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Compaction&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;OpenAI / Azure OpenAI Chat Completions&lt;/td&gt;
&lt;td&gt;Client&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;td&gt;You&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Foundry Agent Service&lt;/td&gt;
&lt;td&gt;Service&lt;/td&gt;
&lt;td&gt;Linear&lt;/td&gt;
&lt;td&gt;Service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Responses API (default)&lt;/td&gt;
&lt;td&gt;Service&lt;/td&gt;
&lt;td&gt;Forking&lt;/td&gt;
&lt;td&gt;Service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Responses API (&lt;code&gt;store=false&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Client&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;td&gt;You&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Anthropic Claude, Ollama&lt;/td&gt;
&lt;td&gt;Client&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;td&gt;You&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="how-to-choose"&gt;How to choose&lt;/h2&gt;
&lt;p&gt;Start with these questions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Do you need conversation branching or &amp;ldquo;undo&amp;rdquo;?&lt;/strong&gt; → Forking service-managed (Responses API)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Do you need full data sovereignty?&lt;/strong&gt; → Client-managed, with a database-backed provider&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Is this a simple chatbot or support flow?&lt;/strong&gt; → Service-managed linear is fine&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Do you need to migrate between providers later?&lt;/strong&gt; → Client-managed gives you portability&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The most important thing: don&amp;rsquo;t default to whatever is easiest to start with and forget to revisit it. Changing storage patterns after launch is painful.&lt;/p&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;Chat history storage shapes what your agents can actually do — not just in demos but in production, under real user behavior. Agent Framework&amp;rsquo;s abstractions let you evolve your choice without rewriting your application logic, which is genuinely useful when you&amp;rsquo;re still figuring out the right model.&lt;/p&gt;
&lt;p&gt;Read the &lt;a href="https://devblogs.microsoft.com/agent-framework/chat-history-storage-patterns-in-microsoft-agent-framework/"&gt;full post&lt;/a&gt; for the complete decision tree, the Conversations API walkthrough, and the compaction strategy details.&lt;/p&gt;</content:encoded></item><item><title>Foundry Toolboxes: One Endpoint for All Your Agent Tools</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/foundry-toolboxes-curate-manage-tools-ai-agents/</link><pubDate>Thu, 23 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/foundry-toolboxes-curate-manage-tools-ai-agents/</guid><description>Microsoft Foundry just launched Toolboxes in public preview — a way to curate, manage, and expose AI agent tools through a single MCP-compatible endpoint without re-wiring everything per agent.</description><content:encoded>&lt;p&gt;Here&amp;rsquo;s a problem that sounds boring until you&amp;rsquo;ve actually hit it: your organization is building multiple AI agents, each one needs tools, and every team is wiring those tools up from scratch. Same Web Search integration, same Azure AI Search config, same GitHub MCP server connection — just in a different repo, by a different team, with different credentials and no shared governance.&lt;/p&gt;
&lt;p&gt;Microsoft Foundry just shipped &lt;a href="https://devblogs.microsoft.com/foundry/introducing-toolboxes-in-foundry/"&gt;Toolboxes&lt;/a&gt; in public preview, and it&amp;rsquo;s a direct answer to that problem.&lt;/p&gt;
&lt;h2 id="whats-a-toolbox"&gt;What&amp;rsquo;s a Toolbox?&lt;/h2&gt;
&lt;p&gt;A Toolbox is a named, reusable bundle of tools that you define once in Foundry and expose through a single MCP-compatible endpoint. Any agent runtime that speaks MCP can consume it — you&amp;rsquo;re not locked to Foundry Agents.&lt;/p&gt;
&lt;p&gt;The pitch is simple: &lt;strong&gt;build once, consume anywhere&lt;/strong&gt;. Define the tools, configure auth centrally (OAuth passthrough, Entra managed identity), publish the endpoint. Every agent that needs those tools connects to the endpoint and gets them all.&lt;/p&gt;
&lt;p&gt;No per-tool wiring. No per-agent credential management.&lt;/p&gt;
&lt;h2 id="the-four-pillars-two-of-which-ship-today"&gt;The four pillars (two of which ship today)&lt;/h2&gt;
&lt;p&gt;The Toolbox feature is organized around four ideas:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pillar&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Discover&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Coming soon&lt;/td&gt;
&lt;td&gt;Find existing approved tools without hunting&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Build&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Available now&lt;/td&gt;
&lt;td&gt;Curate tools into a named, reusable bundle&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Consume&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Available now&lt;/td&gt;
&lt;td&gt;Single MCP endpoint exposes all tools&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Govern&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Coming soon&lt;/td&gt;
&lt;td&gt;Centralized auth + observability across all tool calls&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Today the focus is on Build and Consume. That&amp;rsquo;s enough to remove the most immediate friction.&lt;/p&gt;
&lt;h2 id="getting-started-in-practice"&gt;Getting started in practice&lt;/h2&gt;
&lt;p&gt;The SDK is Python-first for now. You start by creating an &lt;code&gt;AIProjectClient&lt;/code&gt; and then build a toolbox:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;azure.identity&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;DefaultAzureCredential&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;azure.ai.projects&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AIProjectClient&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AIProjectClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;FOUNDRY_PROJECT_ENDPOINT&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;credential&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;DefaultAzureCredential&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then you create a toolbox version with the tools you want to bundle:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;toolbox_version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;beta&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;toolboxes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_toolbox_version&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;toolbox_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;customer-feedback-triaging-toolbox&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Search public and internal docs, then respond to GitHub issues.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;web_search&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;description&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Search approved public documentation&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;azure_ai_search&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;index_name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;internal-docs&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;mcp_server&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;server_url&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;https://your-github-mcp-server.com&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Once published, Foundry gives you a unified endpoint:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;https://zava.services.ai.azure.com/api/projects/&amp;lt;project&amp;gt;/toolbox/&amp;lt;toolbox-name&amp;gt;/mcp?api-version=v1
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Point any MCP-compatible agent runtime at that URL and it discovers all the tools in the bundle dynamically. One connection. All tools.&lt;/p&gt;
&lt;h2 id="not-locked-to-foundry-agents"&gt;Not locked to Foundry Agents&lt;/h2&gt;
&lt;p&gt;This is worth spelling out because it&amp;rsquo;s a common concern when Microsoft ships something under the Foundry brand.&lt;/p&gt;
&lt;p&gt;Toolboxes are &lt;strong&gt;created and governed&lt;/strong&gt; in Foundry, but the consumption surface is the open MCP protocol. That means you can use them from:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Custom agents&lt;/strong&gt; built with Microsoft Agent Framework, LangGraph, or your own code&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GitHub Copilot&lt;/strong&gt; and other MCP-enabled IDEs&lt;/li&gt;
&lt;li&gt;Any other runtime that speaks MCP&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You&amp;rsquo;re not locked in. The toolbox is Foundry-homed (that&amp;rsquo;s where you manage it) but not Foundry-bound (you can consume it from anywhere).&lt;/p&gt;
&lt;h2 id="why-it-matters-now"&gt;Why it matters now&lt;/h2&gt;
&lt;p&gt;The multi-agent wave is hitting production. Teams are building 5, 10, 20 agents — and the tool-wiring problem compounds fast. Every new agent is a new surface for duplicated config, stale credentials, and inconsistent behavior.&lt;/p&gt;
&lt;p&gt;Toolboxes don&amp;rsquo;t solve governance and discovery yet (those are &amp;ldquo;coming soon&amp;rdquo;), but the Build + Consume foundation is enough to start centralizing. Once the Govern pillar ships, you&amp;rsquo;ll have a proper observable, centrally-controlled tool layer for your entire agent fleet.&lt;/p&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;This is early — public preview, Python SDK first, with Discover and Govern still coming. But the model is sound, and the MCP-native design means it works with the tools you&amp;rsquo;re already building on. Take a look at the &lt;a href="https://devblogs.microsoft.com/foundry/introducing-toolboxes-in-foundry/"&gt;official announcement&lt;/a&gt; to get started.&lt;/p&gt;</content:encoded></item><item><title>Windows App Dev CLI v0.3: F5 from the Terminal and UI Automation for Agents</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/windows-app-dev-cli-v03-run-ui-automation/</link><pubDate>Thu, 23 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/windows-app-dev-cli-v03-run-ui-automation/</guid><description>Windows App Development CLI v0.3 ships winapp run for terminal-based debug launches, winapp ui for UI automation, and a new NuGet package that makes dotnet run work with packaged apps.</description><content:encoded>&lt;p&gt;Visual Studio&amp;rsquo;s F5 experience is great. But having to open VS just to launch and debug a packaged Windows app is a bit much when you&amp;rsquo;re deep in a CI pipeline, running an automated workflow, or — increasingly — when an AI agent is doing the testing.&lt;/p&gt;
&lt;p&gt;Windows App Development CLI v0.3 just &lt;a href="https://devblogs.microsoft.com/ifdef-windows/windows-app-development-cli-v0-3-new-run-and-ui-commands-plus-dotnet-run-support-for-packaged-apps/"&gt;shipped&lt;/a&gt;, and it addresses this directly with two headline features: &lt;code&gt;winapp run&lt;/code&gt; and &lt;code&gt;winapp ui&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="winapp-run-f5-from-anywhere"&gt;winapp run: F5 from anywhere&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;winapp run&lt;/code&gt; takes an unpackaged app folder and a manifest, and does everything VS does for a debug launch: registers a loose package, launches the app, and preserves your &lt;code&gt;LocalState&lt;/code&gt; across re-deploys.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Build your app, then run it as a packaged app&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;winapp run ./bin/Debug
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Works for WinUI, WPF, WinForms, Console, Avalonia, and more. The modes are designed for both developers and automated workflows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;--detach&lt;/code&gt;&lt;/strong&gt;: Launch and return control to the terminal immediately. Good for CI/automation where you need the app running but don&amp;rsquo;t want to block.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;--unregister-on-exit&lt;/code&gt;&lt;/strong&gt;: Cleans up the registered package when the app closes. Clean test runs, no leftover state.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;--debug-output&lt;/code&gt;&lt;/strong&gt;: Captures &lt;code&gt;OutputDebugString&lt;/code&gt; messages and exceptions in real time. When a crash happens, a minidump is captured and analyzed in-process — managed (.NET) crashes via ClrMD, native (C++/WinRT) crashes via DbgEng. Add &lt;code&gt;--symbols&lt;/code&gt; to pull PDBs from the Microsoft Symbol Server.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is the kind of setup that makes headless test runs and agent-driven validation actually work. An agent can now launch your app, interact with it, verify behavior, and clean up — all without Visual Studio.&lt;/p&gt;
&lt;h2 id="new-nuget-package-dotnet-run-for-packaged-apps"&gt;New NuGet package: dotnet run for packaged apps&lt;/h2&gt;
&lt;p&gt;For .NET developers specifically, there&amp;rsquo;s a new NuGet package: &lt;code&gt;Microsoft.Windows.SDK.BuildTools.WinApp&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Add it to your project (or let &lt;code&gt;winapp init&lt;/code&gt; do it), and &lt;code&gt;dotnet run&lt;/code&gt; handles the entire inner loop: build, prepare a loose-layout package, register with Windows, and launch — all in one step.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Let winapp init set it up&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;winapp init
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Or install directly&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dotnet add package Microsoft.Windows.SDK.BuildTools.WinApp
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Works with WinUI, WPF, WinForms, Console, Avalonia. No manual registration, no extra commands. Just &lt;code&gt;dotnet run&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This is a big quality-of-life win. If you&amp;rsquo;ve been maintaining a Makefile or PowerShell script just to wire together the build-and-register-and-launch cycle, that&amp;rsquo;s now a solved problem.&lt;/p&gt;
&lt;h2 id="winapp-ui-ui-automation-from-the-command-line"&gt;winapp ui: UI Automation from the command line&lt;/h2&gt;
&lt;p&gt;This is the one that opens up agentic scenarios. &lt;code&gt;winapp ui&lt;/code&gt; gives you full UI Automation access to any running Windows app — WPF, WinForms, Win32, Electron, WinUI3 — all from the terminal.&lt;/p&gt;
&lt;p&gt;What you can do:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;List all top-level windows&lt;/li&gt;
&lt;li&gt;Walk the full UI Automation tree of any window&lt;/li&gt;
&lt;li&gt;Find elements by name, type, or automation ID&lt;/li&gt;
&lt;li&gt;Click, invoke, and set values&lt;/li&gt;
&lt;li&gt;Take screenshots (per-window or multi-window composites)&lt;/li&gt;
&lt;li&gt;Wait for elements to appear — useful for test synchronization&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Combine &lt;code&gt;winapp ui&lt;/code&gt; with &lt;code&gt;winapp run&lt;/code&gt; and you have a complete build → launch → verify workflow from the terminal. An agent can run your app, inspect the UI state, interact with it programmatically, and validate the result. No Visual Studio, no test framework bootstrapping, no manual steps.&lt;/p&gt;
&lt;p&gt;For those building CI pipelines that do actual UI validation on Windows desktop apps, this is genuinely useful.&lt;/p&gt;
&lt;h2 id="other-bits-worth-noting"&gt;Other bits worth noting&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;winapp unregister&lt;/code&gt;&lt;/strong&gt;: The cleanup counterpart to &lt;code&gt;winapp run&lt;/code&gt;. Removes a sideloaded dev package when you&amp;rsquo;re done.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;winapp manifest add-alias&lt;/code&gt;&lt;/strong&gt;: Adds a &lt;code&gt;uap5:AppExecutionAlias&lt;/code&gt; so a packaged app can be launched by name from the terminal.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tab completion&lt;/strong&gt;: One command to set up completions for PowerShell, then every &lt;code&gt;winapp&lt;/code&gt; command and option is tab-completable.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Package.appxmanifest&lt;/code&gt; by default&lt;/strong&gt;: &lt;code&gt;winapp init&lt;/code&gt; now creates &lt;code&gt;Package.appxmanifest&lt;/code&gt; (VS convention) instead of &lt;code&gt;appxmanifest.xml&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="get-it"&gt;Get it&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;winget install Microsoft.WinAppCli
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# or&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;npm install -g @microsoft/winappcli
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The CLI is in public preview. Check the &lt;a href="https://github.com/microsoft/WinAppCli"&gt;GitHub repo&lt;/a&gt; for full docs, guides for .NET, C++, Electron, Rust, Flutter, and more — and to file issues. The &lt;a href="https://devblogs.microsoft.com/ifdef-windows/windows-app-development-cli-v0-3-new-run-and-ui-commands-plus-dotnet-run-support-for-packaged-apps/"&gt;original announcement&lt;/a&gt; has all the details.&lt;/p&gt;</content:encoded></item><item><title>VS Code 1.117: Agents Are Getting Their Own Git Branches and I'm Here For It</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/vscode-1-117-agents-autopilot-worktrees/</link><pubDate>Sun, 19 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/vscode-1-117-agents-autopilot-worktrees/</guid><description>VS Code 1.117 ships worktree isolation for agent sessions, persistent Autopilot mode, and subagent support. The agentic coding workflow just got way more real.</description><content:encoded>&lt;p&gt;The line between &amp;ldquo;AI assistant&amp;rdquo; and &amp;ldquo;AI teammate&amp;rdquo; keeps getting thinner. VS Code 1.117 just dropped and the &lt;a href="https://code.visualstudio.com/updates/v1_117"&gt;full release notes&lt;/a&gt; are packed, but the story here is clear: agents are becoming first-class citizens in your dev workflow.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s what actually matters.&lt;/p&gt;
&lt;h2 id="autopilot-mode-finally-remembers-your-preference"&gt;Autopilot mode finally remembers your preference&lt;/h2&gt;
&lt;p&gt;Previously, you had to re-enable Autopilot every time you started a new session. Annoying. Now your permission mode persists across sessions, and you can configure the default.&lt;/p&gt;
&lt;p&gt;The Agent Host supports three session configs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Default&lt;/strong&gt; — tools ask for confirmation before running&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bypass&lt;/strong&gt; — auto-approves everything&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Autopilot&lt;/strong&gt; — fully autonomous, answers its own questions and keeps going&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you&amp;rsquo;re scaffolding a new .NET project with migrations, Docker, and CI — set it to Autopilot once and forget about it. That preference sticks.&lt;/p&gt;
&lt;h2 id="worktree-and-git-isolation-for-agent-sessions"&gt;Worktree and git isolation for agent sessions&lt;/h2&gt;
&lt;p&gt;This is the big one. Agent sessions now support full worktree and git isolation. That means when an agent works on a task, it gets its own branch and working directory. Your main branch stays untouched.&lt;/p&gt;
&lt;p&gt;Even better — Copilot CLI generates meaningful branch names for these worktree sessions. No more &lt;code&gt;agent-session-abc123&lt;/code&gt;. You get something that actually describes what the agent is doing.&lt;/p&gt;
&lt;p&gt;For .NET developers running multiple feature branches or fixing bugs while a long scaffolding task runs, this is a game changer. You can have an agent building out your API controllers in one worktree while you&amp;rsquo;re debugging a service layer issue in another. No conflicts. No stashing. No mess.&lt;/p&gt;
&lt;h2 id="subagents-and-agent-teams"&gt;Subagents and agent teams&lt;/h2&gt;
&lt;p&gt;The Agent Host Protocol now supports subagents. An agent can spin up other agents to handle parts of a task. Think of it as delegating — your main agent coordinates, and specialized agents handle the pieces.&lt;/p&gt;
&lt;p&gt;This is early, but the potential for .NET workflows is obvious. Imagine one agent handling your EF Core migrations while another sets up your integration tests. We&amp;rsquo;re not fully there yet, but the protocol support landing now means tooling will follow fast.&lt;/p&gt;
&lt;h2 id="terminal-output-auto-included-when-agents-send-input"&gt;Terminal output auto-included when agents send input&lt;/h2&gt;
&lt;p&gt;Small but meaningful. When an agent sends input to the terminal, the terminal output is now automatically included in the context. Before, the agent had to make an extra turn just to read what happened.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;ve ever watched an agent run &lt;code&gt;dotnet build&lt;/code&gt;, fail, and then take another round-trip just to see the error — that friction is gone. It sees the output immediately and reacts.&lt;/p&gt;
&lt;h2 id="self-updating-agents-app-on-macos"&gt;Self-updating Agents app on macOS&lt;/h2&gt;
&lt;p&gt;The standalone Agents app on macOS now self-updates. No more manually downloading new versions. It just stays current.&lt;/p&gt;
&lt;h2 id="the-smaller-stuff-worth-knowing"&gt;The smaller stuff worth knowing&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;package.json hovers&lt;/strong&gt; now show both the installed version and the latest available. Useful if you manage npm tooling alongside your .NET projects.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Images in JSDoc&lt;/strong&gt; comments render correctly in hovers and completions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Copilot CLI sessions&lt;/strong&gt; now indicate whether they were created by VS Code or externally — handy when you&amp;rsquo;re jumping between terminals.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Copilot CLI, Claude Code, and Gemini CLI&lt;/strong&gt; are recognized as shell types. The editor knows what you&amp;rsquo;re running.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="the-takeaway"&gt;The takeaway&lt;/h2&gt;
&lt;p&gt;VS Code 1.117 isn&amp;rsquo;t a flashy feature dump. It&amp;rsquo;s infrastructure. Worktree isolation, persistent permissions, subagent protocols — these are the building blocks for a workflow where agents handle real, parallel tasks without stepping on your code.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re building with .NET and haven&amp;rsquo;t leaned into the agentic workflow yet, honestly, now&amp;rsquo;s the time to start.&lt;/p&gt;</content:encoded></item><item><title>Foundry's RFT Just Got Cheaper and Smarter — Here's What Changed</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/foundry-fine-tuning-april-2026-rft-graders/</link><pubDate>Sat, 18 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/foundry-fine-tuning-april-2026-rft-graders/</guid><description>Microsoft Foundry shipped three RFT updates this month: global training for o4-mini, new GPT-4.1 model graders, and a best practices guide that'll save you hours of debugging.</description><content:encoded>&lt;p&gt;If you&amp;rsquo;re building .NET apps that rely on fine-tuned models, this month&amp;rsquo;s Foundry updates are worth paying attention to. Reinforcement Fine-Tuning just got more accessible and significantly cheaper.&lt;/p&gt;
&lt;p&gt;The full details are in the &lt;a href="https://devblogs.microsoft.com/foundry/whats-new-in-foundry-finetune-april-2026/"&gt;official announcement&lt;/a&gt;, but here&amp;rsquo;s the practical breakdown.&lt;/p&gt;
&lt;h2 id="global-training-for-o4-mini"&gt;Global Training for o4-mini&lt;/h2&gt;
&lt;p&gt;o4-mini is the go-to model for reasoning-heavy and agentic workloads. The big news: you can now launch fine-tuning jobs from 13+ Azure regions with lower per-token training rates compared to Standard training. Same infrastructure, same quality, broader reach.&lt;/p&gt;
&lt;p&gt;If your team is spread across geographies, this matters. You&amp;rsquo;re no longer pinned to a handful of regions to train.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the REST API call to kick off a global training job:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -X POST &lt;span class="s2"&gt;&amp;#34;https://&amp;lt;your-resource&amp;gt;.openai.azure.com/openai/fine_tuning/jobs?api-version=2025-04-01-preview&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -H &lt;span class="s2"&gt;&amp;#34;Content-Type: application/json&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -H &lt;span class="s2"&gt;&amp;#34;api-key: &lt;/span&gt;&lt;span class="nv"&gt;$AZURE_OPENAI_API_KEY&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -d &lt;span class="s1"&gt;&amp;#39;{
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; &amp;#34;model&amp;#34;: &amp;#34;o4-mini&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; &amp;#34;training_file&amp;#34;: &amp;#34;&amp;lt;your-training-file-id&amp;gt;&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; &amp;#34;method&amp;#34;: {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; &amp;#34;type&amp;#34;: &amp;#34;reinforcement&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; &amp;#34;reinforcement&amp;#34;: {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; &amp;#34;grader&amp;#34;: {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; &amp;#34;type&amp;#34;: &amp;#34;string_check&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; &amp;#34;name&amp;#34;: &amp;#34;answer-check&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; &amp;#34;input&amp;#34;: &amp;#34;{{sample.output_text}}&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; &amp;#34;reference&amp;#34;: &amp;#34;{{item.reference_answer}}&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; &amp;#34;operation&amp;#34;: &amp;#34;eq&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; &amp;#34;hyperparameters&amp;#34;: {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; &amp;#34;n_epochs&amp;#34;: 2,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; &amp;#34;compute_multiplier&amp;#34;: 1.0
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; &amp;#34;trainingType&amp;#34;: &amp;#34;globalstandard&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s1"&gt; }&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That &lt;code&gt;trainingType: globalstandard&lt;/code&gt; flag is the key difference.&lt;/p&gt;
&lt;h2 id="new-model-graders-gpt-41-family"&gt;New Model Graders: GPT-4.1 Family&lt;/h2&gt;
&lt;p&gt;Graders define the reward signal your model optimizes against. Until now, model-based graders were limited to a smaller set of models. Now you get three new options: GPT-4.1, GPT-4.1-mini, and GPT-4.1-nano.&lt;/p&gt;
&lt;p&gt;When should you reach for model graders instead of deterministic ones? When your task output is open-ended, when you need partial credit scoring across multiple dimensions, or when you&amp;rsquo;re building agentic workflows where tool-call correctness depends on semantic context.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the thing &amp;ndash; the tiering strategy is practical:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;GPT-4.1-nano&lt;/strong&gt; for initial iterations. Low cost, fast feedback loops.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GPT-4.1-mini&lt;/strong&gt; once your grading rubric is stable and you need higher fidelity.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GPT-4.1&lt;/strong&gt; for production grading or complex rubrics where every scoring decision counts.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can even mix grader types in a single RFT job. Use string-match for the &amp;ldquo;correct answer&amp;rdquo; dimension and a model grader for evaluating reasoning quality. That flexibility is honestly what makes this useful for real workloads.&lt;/p&gt;
&lt;h2 id="the-rft-data-format-gotcha"&gt;The RFT Data Format Gotcha&lt;/h2&gt;
&lt;p&gt;This trips people up. RFT data format is different from SFT. The last message in each row must be a User or Developer role &amp;ndash; not Assistant. The expected answer goes in a top-level key like &lt;code&gt;reference_answer&lt;/code&gt; that the grader references directly.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;ve been doing supervised fine-tuning and want to switch to RFT, you need to restructure your training data. Don&amp;rsquo;t skip this step or your jobs will fail silently.&lt;/p&gt;
&lt;h2 id="why-this-matters-for-net-developers"&gt;Why This Matters for .NET Developers&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;re calling fine-tuned models from your .NET apps through the Azure OpenAI SDK, cheaper training means you can iterate more aggressively. The model grader options mean you can fine-tune for nuanced tasks &amp;ndash; not just exact-match scenarios. And the best practices guide on &lt;a href="https://github.com/microsoft-foundry/fine-tuning/blob/main/Demos/Agentic_RFT_PrivatePreview/RFT_Best_Practice.md"&gt;GitHub&lt;/a&gt; will save you real debugging time.&lt;/p&gt;
&lt;p&gt;Start small. Ten to a hundred samples. Simple grader. Validate the loop. Then scale.&lt;/p&gt;</content:encoded></item><item><title>Global Azure Spain 2026</title><link>https://thedotnetblog.com/events/global-azure-spain-2026/</link><pubDate>Sat, 18 Apr 2026 00:00:00 +0000</pubDate><guid>https://thedotnetblog.com/events/global-azure-spain-2026/</guid><description>The biggest Azure community event in Spain — a full day of sessions on Azure, AI, data, security, and cloud-native development with 38 speakers across 3 tracks.</description><content:encoded>&lt;p&gt;Global Azure Spain 2026 takes place on &lt;strong&gt;April 18, 2026&lt;/strong&gt; at &lt;strong&gt;Kinépolis Diversia&lt;/strong&gt; in Alcobendas, Madrid. It&amp;rsquo;s the largest community-driven Azure event in Spain, bringing together 38 speakers across 3 parallel tracks covering AI agents, Azure networking, Cosmos DB, Fabric, IoT, security, and much more.&lt;/p&gt;
&lt;p&gt;The event runs from &lt;strong&gt;08:30 to 18:30&lt;/strong&gt; and includes keynote, coffee breaks, lunch, and a closing Q&amp;amp;A session.&lt;/p&gt;
&lt;h2 id="highlights-from-the-agenda"&gt;Highlights from the agenda&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Domando Agentes de IA&lt;/strong&gt;: governance, tools, and APIs with Azure AI Foundry and Azure API Management&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Construyendo agentes con LibreChat en Azure&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;How Can I Steal Your Data with Azure Private Endpoints&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stop Building APIs. Forge Agents with Azure&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Agentic DevOps Meets IoT: Real-Time Systems with Fabric and GitHub Copilot&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;El regreso de los tamagotchis!&lt;/strong&gt;: multi-agent systems in action&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Foundry Control Plane como plataforma de Agentes global&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rompiendo el perímetro: Zero Trust aplicado en Azure&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="tickets"&gt;Tickets&lt;/h2&gt;
&lt;p&gt;Registration is a symbolic donation — the full ticket price goes directly to &lt;strong&gt;Plan International&lt;/strong&gt;, supporting children&amp;rsquo;s rights and equality worldwide. Limited capacity, so grab your spot early.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.eventbrite.es/e/entradas-global-azure-spain-2026-en-madrid-1981594189564"&gt;Get tickets on Eventbrite&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://globalazure.es/"&gt;Event website&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="azure-tour-2026"&gt;Azure Tour 2026&lt;/h2&gt;
&lt;p&gt;Beyond Madrid, the Global Azure Tour 2026 also includes stops in &lt;strong&gt;Zaragoza&lt;/strong&gt;, &lt;strong&gt;Tenerife&lt;/strong&gt;, and &lt;strong&gt;Sevilla&lt;/strong&gt;.&lt;/p&gt;</content:encoded></item><item><title>Your AI Experiments on Azure Are Burning Money — Here's How to Fix That</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/cloud-cost-optimization-ai-workloads-azure/</link><pubDate>Sat, 18 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/cloud-cost-optimization-ai-workloads-azure/</guid><description>AI workloads on Azure can get expensive fast. Let's talk about what actually works for keeping costs under control without slowing down your development.</description><content:encoded>&lt;p&gt;If you&amp;rsquo;re building AI-powered apps on Azure right now, you&amp;rsquo;ve probably noticed something: your cloud bill looks different than it used to. Not just higher — weirder. Spiky. Hard to predict.&lt;/p&gt;
&lt;p&gt;Microsoft just published a great piece on &lt;a href="https://azure.microsoft.com/en-us/blog/cloud-cost-optimization-principles-that-still-matter/"&gt;cloud cost optimization principles that still matter&lt;/a&gt;, and honestly, the timing couldn&amp;rsquo;t be better. Because AI workloads have changed the game when it comes to costs.&lt;/p&gt;
&lt;h2 id="why-ai-workloads-hit-different"&gt;Why AI workloads hit different&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s the thing. Traditional .NET workloads are relatively predictable. You know your App Service tier, you know your SQL DTUs, you can estimate monthly spend pretty accurately. AI workloads? Not so much.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;re testing multiple models to see which one fits. You&amp;rsquo;re spinning up GPU-backed infrastructure for fine-tuning. You&amp;rsquo;re making API calls to Azure OpenAI where token consumption varies wildly depending on prompt length and user behavior. Every experiment costs real money, and you might run dozens before you land on the right approach.&lt;/p&gt;
&lt;p&gt;That unpredictability is what makes cost optimization critical — not as an afterthought, but from day one.&lt;/p&gt;
&lt;h2 id="management-vs-optimization--know-the-difference"&gt;Management vs. optimization — know the difference&lt;/h2&gt;
&lt;p&gt;One distinction from the article that I think developers overlook: there&amp;rsquo;s a difference between cost &lt;em&gt;management&lt;/em&gt; and cost &lt;em&gt;optimization&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Management is tracking and reporting. You set up budgets in Azure Cost Management, you get alerts, you see dashboards. That&amp;rsquo;s table stakes.&lt;/p&gt;
&lt;p&gt;Optimization is where you actually make decisions. Do you really need that S3 tier, or would S1 handle your load? Is that always-on compute instance sitting idle on weekends? Could you use spot instances for your training jobs?&lt;/p&gt;
&lt;p&gt;As .NET developers, we tend to focus on the code and leave the infrastructure decisions to &amp;ldquo;the ops team.&amp;rdquo; But if you&amp;rsquo;re deploying to Azure, those decisions are your decisions too.&lt;/p&gt;
&lt;h2 id="what-actually-works"&gt;What actually works&lt;/h2&gt;
&lt;p&gt;Based on the article and my own experience, here&amp;rsquo;s what moves the needle:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Know what you&amp;rsquo;re spending and where.&lt;/strong&gt; Tag your resources. Seriously. If you can&amp;rsquo;t tell which project or experiment is eating your budget, you can&amp;rsquo;t optimize anything. Azure Cost Management with proper tagging is your best friend.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Set guardrails before you experiment.&lt;/strong&gt; Use Azure Policy to restrict expensive SKUs in dev/test environments. Set spending limits on your Azure OpenAI deployments. Don&amp;rsquo;t wait until the bill arrives to realize someone left a GPU cluster running over the weekend.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Rightsize continuously.&lt;/strong&gt; That VM you picked during prototyping? It&amp;rsquo;s probably wrong for production. Azure Advisor gives you recommendations — actually look at them. Review monthly, not yearly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Think about lifecycle.&lt;/strong&gt; Dev resources should spin down. Test environments don&amp;rsquo;t need to run 24/7. Use auto-shutdown policies. For AI workloads specifically, consider serverless options where you pay per execution instead of keeping compute warm.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Measure value, not just cost.&lt;/strong&gt; This one&amp;rsquo;s easy to forget. A model that costs more but delivers significantly better results might be the right call. The goal isn&amp;rsquo;t to spend the least — it&amp;rsquo;s to spend smart.&lt;/p&gt;
&lt;h2 id="the-takeaway"&gt;The takeaway&lt;/h2&gt;
&lt;p&gt;Cloud cost optimization isn&amp;rsquo;t a one-time cleanup. It&amp;rsquo;s a habit. And with AI workloads making spend less predictable than ever, building that habit early saves you from painful surprises later.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re a .NET developer building on Azure, start treating your cloud bill like you treat your code — review it regularly, refactor when it gets messy, and never deploy without understanding what it&amp;rsquo;s going to cost you.&lt;/p&gt;</content:encoded></item><item><title>Docker Sandbox Lets Copilot Agents Refactor Your Code Without Risking Your Machine</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/copilot-docker-sandbox-agentic-refactoring/</link><pubDate>Fri, 17 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/copilot-docker-sandbox-agentic-refactoring/</guid><description>Docker Sandbox gives GitHub Copilot agents a secure microVM to run wild with refactoring — no permission prompts, no risk to your host. Here's why that changes everything for large-scale .NET modernization.</description><content:encoded>&lt;p&gt;If you&amp;rsquo;ve used Copilot&amp;rsquo;s agent mode for anything beyond small edits, you know the pain. Every file write, every terminal command — another permission prompt. Now imagine running that across 50 projects. Not fun.&lt;/p&gt;
&lt;p&gt;The Azure team just dropped a post about &lt;a href="https://devblogs.microsoft.com/all-things-azure/best-of-both-worlds-for-agentic-refactoring-github-copilot-microvms-via-docker-sandbox/"&gt;Docker Sandbox for GitHub Copilot agents&lt;/a&gt;, and honestly, this is one of the most practical agentic tooling improvements I&amp;rsquo;ve seen. It uses microVMs to give Copilot a fully isolated environment where it can go wild — install packages, run builds, execute tests — without touching your host system.&lt;/p&gt;
&lt;h2 id="what-docker-sandbox-actually-gives-you"&gt;What Docker Sandbox actually gives you&lt;/h2&gt;
&lt;p&gt;The core idea is simple: spin up a lightweight microVM with a full Linux environment, sync your workspace into it, and let the Copilot agent operate freely inside. When it&amp;rsquo;s done, changes sync back.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s what makes it more than just &amp;ldquo;run stuff in a container&amp;rdquo;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Bidirectional workspace sync&lt;/strong&gt; that preserves absolute paths. Your project structure looks identical inside the sandbox. No path-related build failures.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Private Docker daemon&lt;/strong&gt; running inside the microVM. The agent can build and run containers without ever mounting your host&amp;rsquo;s Docker socket. That&amp;rsquo;s a big deal for security.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;HTTP/HTTPS filtering proxies&lt;/strong&gt; that control what the agent can reach on the network. You decide which registries and endpoints are allowed. Supply chain attacks from a rogue &lt;code&gt;npm install&lt;/code&gt; inside the sandbox? Blocked.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;YOLO mode&lt;/strong&gt; — yes, that&amp;rsquo;s what they call it. The agent runs without permission prompts because it literally cannot damage your host. Every destructive action is contained.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="why-net-developers-should-care"&gt;Why .NET developers should care&lt;/h2&gt;
&lt;p&gt;Think about the modernization work so many teams are facing right now. You have a .NET Framework solution with 30 projects, and you need to move it to .NET 9. That&amp;rsquo;s hundreds of file changes — project files, namespace updates, API replacements, NuGet migrations.&lt;/p&gt;
&lt;p&gt;With Docker Sandbox, you can point a Copilot agent at a project, let it refactor freely inside the microVM, run &lt;code&gt;dotnet build&lt;/code&gt; and &lt;code&gt;dotnet test&lt;/code&gt; to validate, and only accept the changes that actually work. No risk of it accidentally nuking your local dev environment while experimenting.&lt;/p&gt;
&lt;p&gt;The post also describes running a &lt;strong&gt;fleet of parallel agents&lt;/strong&gt; — each in its own sandbox — tackling different projects simultaneously. For large .NET solutions or microservice architectures, that&amp;rsquo;s a massive time saver. One agent per service, all running isolated, all validated independently.&lt;/p&gt;
&lt;h2 id="the-security-angle-matters"&gt;The security angle matters&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s the thing most people skip over: when you let an AI agent execute arbitrary commands, you&amp;rsquo;re trusting it with your entire machine. Docker Sandbox flips that model. The agent gets full autonomy inside a throwaway environment. The network proxy ensures it can only pull from approved sources. Your host filesystem, Docker daemon, and credentials stay untouched.&lt;/p&gt;
&lt;p&gt;For teams with compliance requirements — and that&amp;rsquo;s most enterprise .NET shops — this is the difference between &amp;ldquo;we can&amp;rsquo;t use agentic AI&amp;rdquo; and &amp;ldquo;we can adopt it safely.&amp;rdquo;&lt;/p&gt;
&lt;h2 id="takeaway"&gt;Takeaway&lt;/h2&gt;
&lt;p&gt;Docker Sandbox solves the fundamental tension of agentic coding: agents need freedom to be useful, but freedom on your host machine is dangerous. MicroVMs give you both. If you&amp;rsquo;re planning any large-scale .NET refactoring or modernization, this is worth setting up now. The combination of Copilot&amp;rsquo;s code intelligence with a safe execution environment is exactly what production teams have been waiting for.&lt;/p&gt;</content:encoded></item><item><title>Where Should You Host Your AI Agents on Azure? A Practical Decision Guide</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/azure-ai-agent-hosting-options-guide/</link><pubDate>Wed, 15 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/azure-ai-agent-hosting-options-guide/</guid><description>Azure offers six ways to host AI agents — from raw containers to fully managed Foundry Hosted Agents. Here's how to pick the right one for your .NET workload.</description><content:encoded>&lt;p&gt;If you&amp;rsquo;re building AI agents with .NET right now, you&amp;rsquo;ve probably noticed something: there are a &lt;em&gt;lot&lt;/em&gt; of ways to host them on Azure. Container Apps, AKS, Functions, App Service, Foundry Agents, Foundry Hosted Agents — and they all sound reasonable until you actually need to pick one. Microsoft just published a &lt;a href="https://devblogs.microsoft.com/all-things-azure/hostedagent/"&gt;comprehensive guide to Azure AI agent hosting&lt;/a&gt; that clears this up, and I want to break it down from a practical .NET developer perspective.&lt;/p&gt;
&lt;h2 id="the-six-options-at-a-glance"&gt;The six options at a glance&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s how I&amp;rsquo;d summarize the landscape:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;Best for&lt;/th&gt;
&lt;th&gt;You manage&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Container Apps&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Full container control without K8s complexity&lt;/td&gt;
&lt;td&gt;Observability, state, lifecycle&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AKS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Enterprise compliance, multi-cluster, custom networking&lt;/td&gt;
&lt;td&gt;Everything (that&amp;rsquo;s the point)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Azure Functions&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Event-driven, short-running agent tasks&lt;/td&gt;
&lt;td&gt;Not much — true serverless&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;App Service&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Simple HTTP agents, predictable traffic&lt;/td&gt;
&lt;td&gt;Deployment, scaling config&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Foundry Agents&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Code-optional agents via portal/SDK&lt;/td&gt;
&lt;td&gt;Almost nothing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Foundry Hosted Agents&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Custom framework agents with managed infra&lt;/td&gt;
&lt;td&gt;Your agent code only&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The first four are general-purpose compute — you &lt;em&gt;can&lt;/em&gt; run agents on them, but they weren&amp;rsquo;t designed for it. The last two are agent-native: they understand conversations, tool calls, and agent lifecycles as first-class concepts.&lt;/p&gt;
&lt;h2 id="foundry-hosted-agents--the-sweet-spot-for-net-agent-developers"&gt;Foundry Hosted Agents — the sweet spot for .NET agent developers&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s what caught my attention. Foundry Hosted Agents sit right in the middle: you get the flexibility of running your own code (Semantic Kernel, Agent Framework, LangGraph — whatever) but the platform handles infrastructure, observability, and conversation management.&lt;/p&gt;
&lt;p&gt;The key piece is the &lt;strong&gt;Hosting Adapter&lt;/strong&gt; — a thin abstraction layer that bridges your agent framework to the Foundry platform. For Microsoft Agent Framework, it looks like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;azure.ai.agentserver.agentframework&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;from_agent_framework&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ChatAgent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;chat_client&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;AzureAIAgentClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;instructions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;You are a helpful assistant.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;get_local_time&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vm"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;__main__&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;from_agent_framework&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s your entire hosting story. The adapter handles protocol translation, streaming via server-sent events, conversation history, and OpenTelemetry tracing — all automatically. No custom middleware, no manual plumbing.&lt;/p&gt;
&lt;h2 id="deploying-is-genuinely-simple"&gt;Deploying is genuinely simple&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve deployed agents to Container Apps before and it works, but you end up writing a lot of glue code for state management and observability. With Hosted Agents and &lt;code&gt;azd&lt;/code&gt;, the deployment is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Install the AI agent extension&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;azd ext install azure.ai.agents
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Init from a template&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;azd ai agent init
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Build, push, deploy — done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;azd up
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That single &lt;code&gt;azd up&lt;/code&gt; builds your container, pushes it to ACR, provisions the Foundry project, deploys model endpoints, and starts your agent. Five steps collapsed into one command.&lt;/p&gt;
&lt;h2 id="built-in-conversation-management"&gt;Built-in conversation management&lt;/h2&gt;
&lt;p&gt;This is the part that saves the most time in production. Instead of building your own conversation state store, Hosted Agents handle it natively:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Create a persistent conversation&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;conversation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;openai_client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;conversations&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# First turn&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;response1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;openai_client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;responses&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;conversation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;conversation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;extra_body&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;agent_reference&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;MyAgent&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;agent_reference&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;}},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Remember: my favorite number is 42.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Second turn — context is preserved&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;response2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;openai_client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;responses&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;conversation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;conversation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;extra_body&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;agent_reference&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;MyAgent&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;agent_reference&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;}},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Multiply my favorite number by 10.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;No Redis. No Cosmos DB session store. No custom middleware for message serialization. The platform just handles it.&lt;/p&gt;
&lt;h2 id="my-decision-framework"&gt;My decision framework&lt;/h2&gt;
&lt;p&gt;After going through all six options, here&amp;rsquo;s my quick mental model:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Do you need zero infrastructure?&lt;/strong&gt; → Foundry Agents (portal/SDK, no containers)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Do you have custom agent code but want managed hosting?&lt;/strong&gt; → Foundry Hosted Agents&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Do you need event-driven, short-lived agent tasks?&lt;/strong&gt; → Azure Functions&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Do you need maximum container control without K8s?&lt;/strong&gt; → Container Apps&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Do you need strict compliance and multi-cluster?&lt;/strong&gt; → AKS&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Do you have a simple HTTP agent with predictable traffic?&lt;/strong&gt; → App Service&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For most .NET developers building with Semantic Kernel or Microsoft Agent Framework, Hosted Agents is likely the right starting point. You get scale-to-zero, built-in OpenTelemetry, conversation management, and framework flexibility — without managing Kubernetes or wiring up your own observability stack.&lt;/p&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;The agent hosting landscape on Azure is maturing fast. If you&amp;rsquo;re starting a new AI agent project today, I&amp;rsquo;d seriously consider Foundry Hosted Agents before reaching for Container Apps or AKS out of habit. The managed infrastructure saves real time, and the hosting adapter pattern lets you keep your framework choice.&lt;/p&gt;
&lt;p&gt;Check out the &lt;a href="https://devblogs.microsoft.com/all-things-azure/hostedagent/"&gt;full guide from Microsoft&lt;/a&gt; and the &lt;a href="https://github.com/microsoft-foundry/foundry-samples/tree/main/samples/python/hosted-agents"&gt;Foundry Samples repo&lt;/a&gt; for working examples.&lt;/p&gt;</content:encoded></item><item><title>Agent Skills in .NET Just Got Seriously Flexible</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/agent-skills-dotnet-three-authoring-patterns/</link><pubDate>Tue, 14 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/agent-skills-dotnet-three-authoring-patterns/</guid><description>The Microsoft Agent Framework now supports three ways to author skills — files, classes, and inline code — all composed through a single provider. Here's why that matters and how to use each one.</description><content:encoded>&lt;p&gt;If you&amp;rsquo;ve been building agents with the Microsoft Agent Framework, you know the drill: you define skills, wire them into a provider, and let the agent figure out which one to invoke. What&amp;rsquo;s new is &lt;em&gt;how&lt;/em&gt; you author those skills — and the flexibility jump is significant.&lt;/p&gt;
&lt;p&gt;The latest update introduces three distinct authoring patterns for agent skills: &lt;strong&gt;file-based&lt;/strong&gt;, &lt;strong&gt;class-based&lt;/strong&gt;, and &lt;strong&gt;inline code-defined&lt;/strong&gt;. All three plug into a single &lt;code&gt;AgentSkillsProviderBuilder&lt;/code&gt;, meaning you can mix and match without any routing logic or special glue code. Let me walk you through each one and when you&amp;rsquo;d reach for it.&lt;/p&gt;
&lt;h2 id="file-based-skills-the-starting-point"&gt;File-based skills: the starting point&lt;/h2&gt;
&lt;p&gt;File-based skills are exactly what they sound like — a directory on disk with a &lt;code&gt;SKILL.md&lt;/code&gt; file, optional scripts, and reference documents. Think of it as the most straightforward way to give your agent new capabilities:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;skills/
└── onboarding-guide/
├── SKILL.md
├── scripts/
│ └── check-provisioning.py
└── references/
└── onboarding-checklist.md
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;SKILL.md&lt;/code&gt; frontmatter declares the skill name and description, and the instructions section tells the agent how to use the scripts and references:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;name: onboarding-guide
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;description: &amp;gt;-
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; Walk new hires through their first-week setup checklist.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="gu"&gt;## Instructions
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;1.&lt;/span&gt; Ask for the employee&amp;#39;s name and start date.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;2.&lt;/span&gt; Run &lt;span class="sb"&gt;`scripts/check-provisioning.py`&lt;/span&gt; to verify accounts.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;3.&lt;/span&gt; Walk through &lt;span class="sb"&gt;`references/onboarding-checklist.md`&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;4.&lt;/span&gt; Follow up on incomplete items.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then you wire it up with &lt;code&gt;SubprocessScriptRunner.RunAsync&lt;/code&gt; for script execution:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;skillsProvider&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;AgentSkillsProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Combine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AppContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BaseDirectory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;skills&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;SubprocessScriptRunner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RunAsync&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;AIAgent&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;AzureOpenAIClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;DefaultAzureCredential&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetResponsesClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AsAIAgent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;ChatClientAgentOptions&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;HRAgent&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ChatOptions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Instructions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;You are a helpful HR assistant.&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;AIContextProviders&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;skillsProvider&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;deploymentName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The agent discovers the skill automatically and invokes the provisioning script when it needs to check account status. Clean and simple.&lt;/p&gt;
&lt;h2 id="class-based-skills-ship-via-nuget"&gt;Class-based skills: ship via NuGet&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s where it gets interesting for teams. Class-based skills derive from &lt;code&gt;AgentClassSkill&amp;lt;T&amp;gt;&lt;/code&gt; and use attributes like &lt;code&gt;[AgentSkillResource]&lt;/code&gt; and &lt;code&gt;[AgentSkillScript]&lt;/code&gt; so the framework discovers everything via reflection:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;sealed&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BenefitsEnrollmentSkill&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;AgentClassSkill&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;BenefitsEnrollmentSkill&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;override&lt;/span&gt; &lt;span class="n"&gt;AgentSkillFrontmatter&lt;/span&gt; &lt;span class="n"&gt;Frontmatter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;benefits-enrollment&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;Enroll an employee in health, dental, or vision plans.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="kd"&gt;override&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Instructions&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="m"&gt;1.&lt;/span&gt; &lt;span class="n"&gt;Read&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;available&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="n"&gt;plans&lt;/span&gt; &lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="m"&gt;2.&lt;/span&gt; &lt;span class="n"&gt;Confirm&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;plan&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;employee&lt;/span&gt; &lt;span class="n"&gt;wants&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="m"&gt;3.&lt;/span&gt; &lt;span class="n"&gt;Use&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;enroll&lt;/span&gt; &lt;span class="n"&gt;script&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;complete&lt;/span&gt; &lt;span class="n"&gt;enrollment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;&amp;#34;&amp;#34;;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt; [AgentSkillResource(&amp;#34;available-plans&amp;#34;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt; [Description(&amp;#34;Plan options with monthly pricing.&amp;#34;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;AvailablePlans&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="err"&gt;##&lt;/span&gt; &lt;span class="n"&gt;Available&lt;/span&gt; &lt;span class="n"&gt;Plans&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2026&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;Health&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Basic&lt;/span&gt; &lt;span class="n"&gt;HMO&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="n"&gt;month&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;Premium&lt;/span&gt; &lt;span class="n"&gt;PPO&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="m"&gt;45&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="n"&gt;month&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;Dental&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Standard&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="m"&gt;12&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="n"&gt;month&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;Enhanced&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="m"&gt;25&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="n"&gt;month&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;Vision&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Basic&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="m"&gt;8&lt;/span&gt;&lt;span class="p"&gt;/&lt;/span&gt;&lt;span class="n"&gt;month&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;&amp;#34;&amp;#34;;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt; [AgentSkillScript(&amp;#34;enroll&amp;#34;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt; [Description(&amp;#34;Enrolls employee in the specified benefit plan.&amp;#34;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Enroll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;employeeId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;planCode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;success&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HrClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EnrollInPlan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;employeeId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;planCode&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;JsonSerializer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Serialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;success&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;employeeId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;planCode&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The beauty here is that a team can package this as a NuGet package. You add it to your project, drop it into the builder, and it works alongside your file-based skills with zero coordination:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;skillsProvider&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;AgentSkillsProviderBuilder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UseFileSkill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Combine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AppContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BaseDirectory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;skills&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UseSkill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;BenefitsEnrollmentSkill&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UseFileScriptRunner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SubprocessScriptRunner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RunAsync&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Both skills show up in the agent&amp;rsquo;s system prompt. The agent decides which one to use based on the conversation — no routing code needed.&lt;/p&gt;
&lt;h2 id="inline-skills-the-quick-bridge"&gt;Inline skills: the quick bridge&lt;/h2&gt;
&lt;p&gt;You know that moment when another team is building exactly the skill you need, but it won&amp;rsquo;t ship for a sprint? &lt;code&gt;AgentInlineSkill&lt;/code&gt; is your bridge:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;timeOffSkill&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;AgentInlineSkill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;time-off-balance&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Calculate remaining vacation and sick days.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;instructions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="m"&gt;1.&lt;/span&gt; &lt;span class="n"&gt;Ask&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;employee&lt;/span&gt; &lt;span class="n"&gt;ID&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;not&lt;/span&gt; &lt;span class="n"&gt;provided&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="m"&gt;2.&lt;/span&gt; &lt;span class="n"&gt;Use&lt;/span&gt; &lt;span class="n"&gt;calculate&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="n"&gt;balance&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;remaining&lt;/span&gt; &lt;span class="n"&gt;balance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="m"&gt;3.&lt;/span&gt; &lt;span class="n"&gt;Present&lt;/span&gt; &lt;span class="n"&gt;used&lt;/span&gt; &lt;span class="n"&gt;and&lt;/span&gt; &lt;span class="n"&gt;remaining&lt;/span&gt; &lt;span class="n"&gt;days&lt;/span&gt; &lt;span class="n"&gt;clearly&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;&amp;#34;&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddScript&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;calculate-balance&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;employeeId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;leaveType&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;totalDays&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HrDatabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetAnnualAllowance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;employeeId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;leaveType&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;daysUsed&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HrDatabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetDaysUsed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;employeeId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;leaveType&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;remaining&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;totalDays&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;daysUsed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;JsonSerializer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Serialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;employeeId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;leaveType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;totalDays&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;daysUsed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;remaining&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Add it to the builder just like the others:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;skillsProvider&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;AgentSkillsProviderBuilder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UseFileSkill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Combine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AppContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BaseDirectory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;skills&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UseSkill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;BenefitsEnrollmentSkill&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UseSkill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timeOffSkill&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UseFileScriptRunner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SubprocessScriptRunner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RunAsync&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When the NuGet package eventually ships, you swap out the inline skill for the class-based one. The agent doesn&amp;rsquo;t know the difference.&lt;/p&gt;
&lt;p&gt;But inline skills aren&amp;rsquo;t just for bridges. They&amp;rsquo;re also the right choice when you need to generate skills dynamically at runtime — think one skill per business unit loaded from config — or when a script needs to close over local state that doesn&amp;rsquo;t belong in a DI container.&lt;/p&gt;
&lt;h2 id="script-approval-human-in-the-loop"&gt;Script approval: human-in-the-loop&lt;/h2&gt;
&lt;p&gt;For us .NET developers building production agents, this is the part that actually unblocks deployment conversations. Some scripts have real consequences — enrolling someone in benefits, querying production infra. Flip on &lt;code&gt;UseScriptApproval&lt;/code&gt; and the agent pauses before executing any script:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;skillsProvider&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;AgentSkillsProviderBuilder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UseFileSkill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Combine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AppContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BaseDirectory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;skills&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UseSkill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;BenefitsEnrollmentSkill&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UseSkill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timeOffSkill&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UseFileScriptRunner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SubprocessScriptRunner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RunAsync&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UseScriptApproval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When the agent wants to run a script, it returns an approval request instead. Your app collects the decision — approve or reject — and the agent continues accordingly. In regulated environments, this is the difference between &amp;ldquo;we can deploy this&amp;rdquo; and &amp;ldquo;legal says no.&amp;rdquo;&lt;/p&gt;
&lt;h2 id="why-this-combination-matters"&gt;Why this combination matters&lt;/h2&gt;
&lt;p&gt;The real power isn&amp;rsquo;t any single authoring pattern — it&amp;rsquo;s the composition. You can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Start small&lt;/strong&gt; with a file-based skill, iterate on the instructions, and ship it without writing C#&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ship reusable skills&lt;/strong&gt; as NuGet packages that other teams can add with one line&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bridge gaps&lt;/strong&gt; with inline skills when you need something &lt;em&gt;now&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Filter shared skill directories&lt;/strong&gt; with predicates so your agent only loads what it should&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Add human oversight&lt;/strong&gt; for scripts that touch production systems&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All of these compose through &lt;code&gt;AgentSkillsProviderBuilder&lt;/code&gt;. No special routing, no conditional logic, no skill type checks.&lt;/p&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;Agent skills in .NET now have a genuinely flexible authoring model. Whether you&amp;rsquo;re a solo developer sketching out a prototype with file-based skills or an enterprise team shipping packaged capabilities via NuGet, the patterns fit. And the script approval mechanism makes it production-ready for environments where you need that human checkpoint.&lt;/p&gt;
&lt;p&gt;Check out the &lt;a href="https://devblogs.microsoft.com/agent-framework/agent-skills-in-net-three-ways-to-author-one-provider-to-run-them/"&gt;original announcement&lt;/a&gt; for the full walkthrough, the &lt;a href="https://learn.microsoft.com/en-us/agent-framework/agents/skills"&gt;Agent Skills documentation&lt;/a&gt; on Microsoft Learn, and the &lt;a href="https://github.com/microsoft/agent-framework/tree/main/dotnet/samples/02-agents/AgentSkills"&gt;.NET samples on GitHub&lt;/a&gt; to get hands-on.&lt;/p&gt;</content:encoded></item><item><title>Azure MCP Server 2.0 Just Dropped — Self-Hosted Agentic Cloud Automation Is Here</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/azure-mcp-server-2-self-hosted-agentic-cloud/</link><pubDate>Sat, 11 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/azure-mcp-server-2-self-hosted-agentic-cloud/</guid><description>Azure MCP Server 2.0 goes stable with self-hosted remote deployments, 276 tools across 57 Azure services, and enterprise-grade security — here's what matters for .NET developers building agentic workflows.</description><content:encoded>&lt;p&gt;If you&amp;rsquo;ve been building anything with MCP and Azure lately, you probably already know the local experience works well. Plug in an MCP server, let your AI agent talk to Azure resources, move on. But the moment you need to share that setup across a team? That&amp;rsquo;s where things got complicated.&lt;/p&gt;
&lt;p&gt;Not anymore. Azure MCP Server &lt;a href="https://devblogs.microsoft.com/azure-sdk/announcing-azure-mcp-server-2-0-stable-release/"&gt;just hit 2.0 stable&lt;/a&gt;, and the headline feature is exactly what enterprise teams have been asking for: &lt;strong&gt;self-hosted remote MCP server support&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id="whats-azure-mcp-server"&gt;What&amp;rsquo;s Azure MCP Server?&lt;/h2&gt;
&lt;p&gt;Quick refresher. Azure MCP Server implements the &lt;a href="https://modelcontextprotocol.io/docs/getting-started/intro"&gt;Model Context Protocol&lt;/a&gt; specification and exposes Azure capabilities as structured, discoverable tools that AI agents can invoke. Think of it as a standardized bridge between your agent and Azure — provisioning, deployment, monitoring, diagnostics, all through one consistent interface.&lt;/p&gt;
&lt;p&gt;The numbers speak for themselves: &lt;strong&gt;276 MCP tools across 57 Azure services&lt;/strong&gt;. That&amp;rsquo;s serious coverage.&lt;/p&gt;
&lt;h2 id="the-big-deal-self-hosted-remote-deployments"&gt;The big deal: self-hosted remote deployments&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s the thing. Running MCP locally on your machine is fine for dev and experiments. But in a real team scenario, you need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Shared access for developers and internal agent systems&lt;/li&gt;
&lt;li&gt;Centralized configuration (tenant context, subscription defaults, telemetry)&lt;/li&gt;
&lt;li&gt;Enterprise network and policy boundaries&lt;/li&gt;
&lt;li&gt;Integration into CI/CD pipelines&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Azure MCP Server 2.0 addresses all of this. You can deploy it as a centrally managed internal service with HTTP-based transport, proper authentication, and consistent governance.&lt;/p&gt;
&lt;p&gt;For auth, you get two solid options:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Managed Identity&lt;/strong&gt; — when running alongside &lt;a href="https://aka.ms/azmcp/self-host/foundry"&gt;Microsoft Foundry&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;On-Behalf-Of (OBO) flow&lt;/strong&gt; — OpenID Connect delegation that calls Azure APIs using the signed-in user&amp;rsquo;s context&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That OBO flow is particularly interesting for us .NET developers. It means your agentic workflows can operate with the user&amp;rsquo;s actual permissions, not some over-privileged service account. Principle of least privilege, built right in.&lt;/p&gt;
&lt;h2 id="security-hardening"&gt;Security hardening&lt;/h2&gt;
&lt;p&gt;This isn&amp;rsquo;t just a feature release — it&amp;rsquo;s a security one too. The 2.0 release adds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Stronger endpoint validation&lt;/li&gt;
&lt;li&gt;Protections against injection patterns in query-oriented tools&lt;/li&gt;
&lt;li&gt;Tighter isolation controls for dev environments&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you&amp;rsquo;re going to expose MCP as a shared service, these safeguards matter. A lot.&lt;/p&gt;
&lt;h2 id="where-can-you-use-it"&gt;Where can you use it?&lt;/h2&gt;
&lt;p&gt;The client compatibility story is broad. Azure MCP Server 2.0 works with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;IDEs&lt;/strong&gt;: VS Code, Visual Studio, IntelliJ, Eclipse, Cursor&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CLI agents&lt;/strong&gt;: GitHub Copilot CLI, Claude Code&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Standalone&lt;/strong&gt;: local server for simple setups&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Self-hosted remote&lt;/strong&gt;: the new star of 2.0&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Plus there&amp;rsquo;s sovereign cloud support for Azure US Government and Azure operated by 21Vianet, which is critical for regulated deployments.&lt;/p&gt;
&lt;h2 id="why-this-matters-for-net-developers"&gt;Why this matters for .NET developers&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;re building agentic applications with .NET — whether that&amp;rsquo;s Semantic Kernel, Microsoft Agent Framework, or your own orchestration — Azure MCP Server 2.0 gives you a production-ready way to let your agents interact with Azure infrastructure. No custom REST wrappers. No service-specific integration patterns. Just MCP.&lt;/p&gt;
&lt;p&gt;Combined with the &lt;a href="https://devblogs.microsoft.com/azure-sdk/mcp-as-easy-as-1-2-3-introducing-the-fluent-api-for-mcp-apps/"&gt;fluent API for MCP Apps&lt;/a&gt; that dropped a few days ago, the .NET MCP ecosystem is maturing fast.&lt;/p&gt;
&lt;h2 id="getting-started"&gt;Getting started&lt;/h2&gt;
&lt;p&gt;Pick your path:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://aka.ms/azmcp"&gt;GitHub Repo&lt;/a&gt;&lt;/strong&gt; — source code, docs, everything&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://aka.ms/azmcp/download/docker"&gt;Docker Image&lt;/a&gt;&lt;/strong&gt; — containerized deployment&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://aka.ms/azmcp/download/vscode"&gt;VS Code Extension&lt;/a&gt;&lt;/strong&gt; — IDE integration&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://aka.ms/azmcp/self-host"&gt;Self-hosting guide&lt;/a&gt;&lt;/strong&gt; — the 2.0 flagship feature&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;Azure MCP Server 2.0 is exactly the kind of infrastructure upgrade that doesn&amp;rsquo;t look flashy in a demo but changes everything in practice. Self-hosted remote MCP with proper auth, security hardening, and sovereign cloud support means MCP is ready for real teams building real agentic workflows on Azure. If you&amp;rsquo;ve been waiting for the &amp;ldquo;enterprise-ready&amp;rdquo; signal — this is it.&lt;/p&gt;</content:encoded></item><item><title>.NET Aspire 13.2 Wants to Be Your AI Agent's Best Friend</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/aspire-agentic-development-build-run-observe/</link><pubDate>Fri, 10 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/aspire-agentic-development-build-run-observe/</guid><description>Aspire 13.2 goes all-in on agentic development — structured CLI output, isolated runs, auto-healing environments, and full OpenTelemetry data so your AI agents can actually build, run, and observe your apps.</description><content:encoded>&lt;p&gt;You know that moment when your AI coding agent writes some solid code, you get excited, and then it completely falls apart trying to actually &lt;em&gt;run&lt;/em&gt; the thing? Port conflicts, phantom processes, wrong environment variables — suddenly your agent is burning tokens troubleshooting startup issues instead of building features.&lt;/p&gt;
&lt;p&gt;The Aspire team just dropped a &lt;a href="https://devblogs.microsoft.com/aspire/agentic-dev-aspirations/"&gt;really thoughtful post&lt;/a&gt; about exactly this problem, and their answer is compelling: Aspire 13.2 is designed not just for humans, but for AI agents.&lt;/p&gt;
&lt;h2 id="the-problem-is-real"&gt;The problem is real&lt;/h2&gt;
&lt;p&gt;AI agents are incredible at writing code. But shipping a working full-stack app involves way more than generating files. You need to start services in the right order, manage ports, set environment variables, connect databases, and get feedback when things break. Right now, most agents handle all of this through trial-and-error — running commands, reading error output, trying again.&lt;/p&gt;
&lt;p&gt;We layer on Markdown instructions, custom skills, and prompts to try to guide them, but those are unpredictable, can&amp;rsquo;t be compiled, and cost tokens just to parse. The Aspire team nailed the core insight: agents need &lt;strong&gt;compilers and structured APIs&lt;/strong&gt;, not more Markdown.&lt;/p&gt;
&lt;h2 id="aspire-as-agent-infrastructure"&gt;Aspire as agent infrastructure&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s what Aspire 13.2 brings to the agentic development table:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Your entire stack in typed code.&lt;/strong&gt; The AppHost defines your full topology — API, frontend, database, cache — in compilable TypeScript or C#:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-typescript" data-lang="typescript"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createBuilder&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="kr"&gt;from&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;./.modules/aspire.js&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;builder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;createBuilder&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;postgres&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addPostgres&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;pg&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;addDatabase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;catalog&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addRedis&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;cache&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kr"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;builder&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addNodeApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;api&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;./api&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;src/index.ts&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;withHttpEndpoint&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;PORT&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;withReference&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;postgres&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;withReference&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;builder&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addViteApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;frontend&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;./frontend&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;withReference&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;waitFor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;api&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;build&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;An agent can read this to understand app topology, add resources, wire up connections, and &lt;em&gt;build to verify&lt;/em&gt;. The compiler tells it immediately if something is wrong. No guessing, no trial-and-error with config files.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;One command to rule them all.&lt;/strong&gt; Instead of agents juggling &lt;code&gt;docker compose up&lt;/code&gt;, &lt;code&gt;npm run dev&lt;/code&gt;, and database startup scripts, everything is just &lt;code&gt;aspire start&lt;/code&gt;. All resources launch in the right order, on the right ports, with the right configuration. Long-running processes don&amp;rsquo;t hang the agent either — Aspire manages them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Isolated mode for parallel agents.&lt;/strong&gt; With &lt;code&gt;--isolated&lt;/code&gt;, each Aspire run gets its own random ports and separate user secrets. Got multiple agents working across git worktrees? They won&amp;rsquo;t collide. This is huge for tools like VS Code&amp;rsquo;s background agents that spin up parallel environments.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Agent eyes through telemetry.&lt;/strong&gt; Here&amp;rsquo;s where it gets really powerful. The Aspire CLI exposes full OpenTelemetry data during development — traces, metrics, structured logs. Your agent isn&amp;rsquo;t just reading console output and hoping for the best. It can trace a failing request across services, profile slow endpoints, and pinpoint exactly where things break. That&amp;rsquo;s production-grade observability in the development loop.&lt;/p&gt;
&lt;h2 id="the-bowling-bumper-analogy"&gt;The bowling bumper analogy&lt;/h2&gt;
&lt;p&gt;The Aspire team uses a great analogy: think of Aspire as bowling lane bumpers for AI agents. If the agent isn&amp;rsquo;t perfect (and it won&amp;rsquo;t be), the bumpers keep it from throwing gutter balls. The stack definition prevents misconfiguration, the compiler catches errors, the CLI handles process management, and the telemetry provides the feedback loop.&lt;/p&gt;
&lt;p&gt;Pair this with something like Playwright CLI, and your agent can actually &lt;em&gt;use&lt;/em&gt; your app — clicking through flows, checking the DOM, seeing broken things in telemetry, fixing the code, restarting, and testing again. Build, run, observe, fix. That&amp;rsquo;s the autonomous development loop we&amp;rsquo;ve been chasing.&lt;/p&gt;
&lt;h2 id="getting-started"&gt;Getting started&lt;/h2&gt;
&lt;p&gt;New to Aspire? Install the CLI from &lt;a href="https://get.aspire.dev"&gt;get.aspire.dev&lt;/a&gt; and follow the &lt;a href="https://aspire.dev/get-started/first-app"&gt;getting started guide&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Already using Aspire? Run &lt;code&gt;aspire update --self&lt;/code&gt; to get 13.2, then point your favorite coding agent at your repo. You might be surprised how much further it gets with Aspire&amp;rsquo;s guardrails in place.&lt;/p&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;Aspire 13.2 isn&amp;rsquo;t just a distributed app framework anymore — it&amp;rsquo;s becoming essential agent infrastructure. Structured stack definitions, one-command startup, isolated parallel runs, and real-time telemetry give AI agents exactly what they need to go from writing code to shipping apps.&lt;/p&gt;
&lt;p&gt;Read the &lt;a href="https://devblogs.microsoft.com/aspire/agentic-dev-aspirations/"&gt;full post&lt;/a&gt; from the Aspire team for all the details and demo videos.&lt;/p&gt;</content:encoded></item><item><title>Building Real-Time Multi-Agent UIs That Don't Feel Like a Black Box</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/ag-ui-real-time-multi-agent-ui-maf/</link><pubDate>Fri, 10 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/ag-ui-real-time-multi-agent-ui-maf/</guid><description>AG-UI and Microsoft Agent Framework team up to give multi-agent workflows a proper frontend — with real-time streaming, human approvals, and full visibility into what your agents are doing.</description><content:encoded>&lt;p&gt;Here&amp;rsquo;s the thing about multi-agent systems: they look incredible in demos. Three agents passing work around, solving problems, making decisions. Then you try to put it in front of actual users and&amp;hellip; silence. A spinning indicator. No idea which agent is doing what or why the system is paused. That&amp;rsquo;s not a product — that&amp;rsquo;s a trust problem.&lt;/p&gt;
&lt;p&gt;The Microsoft Agent Framework team just published a &lt;a href="https://devblogs.microsoft.com/agent-framework/ag-ui-multi-agent-workflow-demo/"&gt;fantastic walkthrough&lt;/a&gt; on pairing MAF workflows with &lt;a href="https://github.com/ag-ui-protocol/ag-ui"&gt;AG-UI&lt;/a&gt;, an open protocol for streaming agent execution events to a frontend over Server-Sent Events. And honestly? This is the kind of bridge we&amp;rsquo;ve been missing.&lt;/p&gt;
&lt;h2 id="why-this-matters-for-net-developers"&gt;Why this matters for .NET developers&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;re building AI-powered apps, you&amp;rsquo;ve probably hit this wall. Your backend orchestration works great — agents hand off to each other, tools fire, decisions get made. But the frontend has no clue what&amp;rsquo;s happening behind the scenes. AG-UI fixes that by defining a standard protocol for streaming agent events (think &lt;code&gt;RUN_STARTED&lt;/code&gt;, &lt;code&gt;STEP_STARTED&lt;/code&gt;, &lt;code&gt;TOOL_CALL_*&lt;/code&gt;, &lt;code&gt;TEXT_MESSAGE_*&lt;/code&gt;) directly to your UI layer over SSE.&lt;/p&gt;
&lt;p&gt;The demo they built is a customer support workflow with three agents: a triage agent that routes requests, a refund agent that handles money stuff, and an order agent that manages replacements. Each agent has its own tools, and the handoff topology is explicitly defined — no &amp;ldquo;figure it out from the prompt&amp;rdquo; vibes.&lt;/p&gt;
&lt;h2 id="the-handoff-topology-is-the-real-star"&gt;The handoff topology is the real star&lt;/h2&gt;
&lt;p&gt;What caught my eye is how &lt;code&gt;HandoffBuilder&lt;/code&gt; lets you declare a directed routing graph between agents:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HandoffBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;ag_ui_handoff_workflow_demo&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;participants&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;triage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;refund&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;termination_condition&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;termination_condition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;builder&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_handoff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;triage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;refund&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Refunds, damaged-item claims...&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_handoff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;triage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Replacement, exchange...&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_handoff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;refund&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Replacement logistics needed after refund.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_handoff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;triage&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;After replacement/shipping tasks complete.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Each &lt;code&gt;add_handoff&lt;/code&gt; creates a directed edge with a natural-language description. The framework generates handoff tools for each agent based on this topology. So routing decisions are grounded in your orchestration structure, not just whatever the LLM feels like doing. That&amp;rsquo;s a huge deal for production reliability.&lt;/p&gt;
&lt;h2 id="human-in-the-loop-that-actually-works"&gt;Human-in-the-loop that actually works&lt;/h2&gt;
&lt;p&gt;The demo showcases two interrupt patterns that any real-world agent app needs:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tool approval interrupts&lt;/strong&gt; — when an agent calls a tool marked with &lt;code&gt;approval_mode=&amp;quot;always_require&amp;quot;&lt;/code&gt;, the workflow pauses and emits an event. The frontend renders an approval modal with the tool name and arguments. No token-burning retry loops — just a clean pause-approve-resume flow.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Information request interrupts&lt;/strong&gt; — when an agent needs more context from the user (like an order ID), it pauses and asks. The frontend shows the question, the user responds, and execution resumes from exactly where it stopped.&lt;/p&gt;
&lt;p&gt;Both patterns stream as standard AG-UI events, so your frontend doesn&amp;rsquo;t need custom logic per agent — it just renders whatever event comes through the SSE connection.&lt;/p&gt;
&lt;h2 id="wiring-it-up-is-surprisingly-simple"&gt;Wiring it up is surprisingly simple&lt;/h2&gt;
&lt;p&gt;The integration between MAF and AG-UI is a single function call:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;agent_framework.ag_ui&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;AgentFrameworkWorkflow&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;add_agent_framework_fastapi_endpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;demo_workflow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AgentFrameworkWorkflow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;workflow_factory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;_thread_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;create_handoff_workflow&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;ag_ui_handoff_workflow_demo&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;add_agent_framework_fastapi_endpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;demo_workflow&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;/handoff_demo&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;workflow_factory&lt;/code&gt; creates a fresh workflow per thread, so each conversation gets isolated state. The endpoint handles all the SSE plumbing automatically. If you&amp;rsquo;re already using FastAPI (or can add it as a lightweight layer), this is almost zero friction.&lt;/p&gt;
&lt;h2 id="my-take"&gt;My take&lt;/h2&gt;
&lt;p&gt;For us .NET developers, the immediate question is: &amp;ldquo;Can I do this in C#?&amp;rdquo; The Agent Framework is available for both .NET and Python, and the AG-UI protocol is language-agnostic (it&amp;rsquo;s just SSE). So while this specific demo uses Python and FastAPI, the pattern translates directly. You could wire up an ASP.NET Core minimal API with SSE endpoints following the same AG-UI event schema.&lt;/p&gt;
&lt;p&gt;The bigger takeaway is that multi-agent UIs are becoming a first-class concern, not an afterthought. If you&amp;rsquo;re building anything where agents interact with humans — customer support, approval workflows, document processing — this combination of MAF orchestration and AG-UI transparency is the pattern to follow.&lt;/p&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;AG-UI + Microsoft Agent Framework gives you the best of both worlds: robust multi-agent orchestration on the backend and real-time visibility on the frontend. No more black-box agent interactions.&lt;/p&gt;
&lt;p&gt;Check out the &lt;a href="https://devblogs.microsoft.com/agent-framework/ag-ui-multi-agent-workflow-demo/"&gt;full walkthrough&lt;/a&gt; and the &lt;a href="https://github.com/ag-ui-protocol/ag-ui"&gt;AG-UI protocol repo&lt;/a&gt; to dig deeper.&lt;/p&gt;</content:encoded></item><item><title>Connect Your MCP Servers on Azure Functions to Foundry Agents — Here's How</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/foundry-agents-mcp-servers-azure-functions/</link><pubDate>Fri, 10 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/foundry-agents-mcp-servers-azure-functions/</guid><description>Build your MCP server once, deploy it to Azure Functions, and connect it to Microsoft Foundry agents with proper auth. Your tools work everywhere — VS Code, Cursor, and now enterprise AI agents.</description><content:encoded>&lt;p&gt;Here&amp;rsquo;s something I love about the MCP ecosystem: you build your server once, and it works everywhere. VS Code, Visual Studio, Cursor, ChatGPT — every MCP client can discover and use your tools. Now, Microsoft is adding another consumer to that list: Foundry agents.&lt;/p&gt;
&lt;p&gt;Lily Ma from the Azure SDK team &lt;a href="https://devblogs.microsoft.com/azure-sdk/give-your-foundry-agent-custom-tools-with-mcp-servers-on-azure-functions/"&gt;published a practical guide&lt;/a&gt; on connecting MCP servers deployed to Azure Functions with Microsoft Foundry agents. If you already have an MCP server, this is pure value-add — no rebuilding required.&lt;/p&gt;
&lt;h2 id="why-this-combination-makes-sense"&gt;Why this combination makes sense&lt;/h2&gt;
&lt;p&gt;Azure Functions gives you scalable infrastructure, built-in auth, and serverless billing for hosting MCP servers. Microsoft Foundry gives you AI agents that can reason, plan, and take actions. Connecting the two means your custom tools — querying a database, calling a business API, running validation logic — become capabilities that enterprise AI agents can discover and use autonomously.&lt;/p&gt;
&lt;p&gt;The key point: your MCP server stays the same. You&amp;rsquo;re just adding Foundry as another consumer. The same tools that work in your VS Code setup now power an AI agent your team or customers interact with.&lt;/p&gt;
&lt;h2 id="authentication-options"&gt;Authentication options&lt;/h2&gt;
&lt;p&gt;This is where the post really adds value. Four auth methods depending on your scenario:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Use Case&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Key-based&lt;/strong&gt; (default)&lt;/td&gt;
&lt;td&gt;Development or servers without Entra auth&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Microsoft Entra&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Production with managed identities&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;OAuth identity passthrough&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Production where each user authenticates individually&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Unauthenticated&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Dev/testing or public data only&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;For production, Microsoft Entra with agent identity is the recommended path. OAuth identity passthrough is for when user context matters — the agent prompts users to sign in, and each request carries the user&amp;rsquo;s own token.&lt;/p&gt;
&lt;h2 id="setting-it-up"&gt;Setting it up&lt;/h2&gt;
&lt;p&gt;The high-level flow:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Deploy your MCP server to Azure Functions&lt;/strong&gt; — samples available for &lt;a href="https://github.com/Azure-Samples/remote-mcp-functions-dotnet"&gt;.NET&lt;/a&gt;, Python, TypeScript, and Java&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enable built-in MCP authentication&lt;/strong&gt; on your function app&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Get your endpoint URL&lt;/strong&gt; — &lt;code&gt;https://&amp;lt;FUNCTION_APP_NAME&amp;gt;.azurewebsites.net/runtime/webhooks/mcp&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Add the MCP server as a tool in Foundry&lt;/strong&gt; — navigate to your agent in the portal, add a new MCP tool, provide endpoint and credentials&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Then test it in the Agent Builder playground by sending a prompt that would trigger one of your tools.&lt;/p&gt;
&lt;h2 id="my-take"&gt;My take&lt;/h2&gt;
&lt;p&gt;The composability story here is getting really strong. Build your MCP server once in .NET (or Python, TypeScript, Java), deploy to Azure Functions, and every MCP-compatible client can use it — coding tools, chat apps, and now enterprise AI agents. That&amp;rsquo;s a &amp;ldquo;write once, use everywhere&amp;rdquo; pattern that actually works.&lt;/p&gt;
&lt;p&gt;For .NET developers specifically, the &lt;a href="https://github.com/Azure-Samples/remote-mcp-functions-dotnet"&gt;Azure Functions MCP extension&lt;/a&gt; makes this straightforward. You define your tools as Azure Functions, deploy, and you&amp;rsquo;ve got a production-grade MCP server with all the security and scaling Azure Functions provides.&lt;/p&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;If you have MCP tools running on Azure Functions, connecting them to Foundry agents is a quick win — your custom tools become enterprise AI capabilities with proper auth and no code changes to the server itself.&lt;/p&gt;
&lt;p&gt;Read the &lt;a href="https://devblogs.microsoft.com/azure-sdk/give-your-foundry-agent-custom-tools-with-mcp-servers-on-azure-functions/"&gt;full guide&lt;/a&gt; for step-by-step instructions on each authentication method, and check the &lt;a href="https://learn.microsoft.com/azure/azure-functions/functions-mcp-foundry-tools?tabs=entra%2Cmcp-extension%2Cfoundry"&gt;detailed docs&lt;/a&gt; for production setups.&lt;/p&gt;</content:encoded></item><item><title>MCP Apps Get a Fluent API — Build Rich AI Tool UIs in .NET with Three Steps</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/mcp-fluent-api-azure-functions-dotnet/</link><pubDate>Fri, 10 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/mcp-fluent-api-azure-functions-dotnet/</guid><description>The new fluent configuration API for MCP Apps on Azure Functions lets you turn any .NET MCP tool into a full app with views, permissions, and CSP policies in just a few lines of code.</description><content:encoded>&lt;p&gt;MCP tools are great for giving AI agents capabilities. But what if your tool needs to show something to the user — a dashboard, a form, an interactive visualization? That&amp;rsquo;s where MCP Apps come in, and they just got a lot easier to build.&lt;/p&gt;
&lt;p&gt;Lilian Kasem from the Azure SDK team &lt;a href="https://devblogs.microsoft.com/azure-sdk/mcp-as-easy-as-1-2-3-introducing-the-fluent-api-for-mcp-apps/"&gt;introduced the new fluent configuration API&lt;/a&gt; for MCP Apps on .NET Azure Functions, and it&amp;rsquo;s the kind of developer experience improvement that makes you wonder why it wasn&amp;rsquo;t always this simple.&lt;/p&gt;
&lt;h2 id="what-are-mcp-apps"&gt;What are MCP Apps?&lt;/h2&gt;
&lt;p&gt;MCP Apps extend the Model Context Protocol by letting tools carry their own UI views, static assets, and security controls. Instead of just returning text, your MCP tool can render full HTML experiences — interactive dashboards, data visualizations, configuration forms — all invocable by AI agents and presented to users by MCP clients.&lt;/p&gt;
&lt;p&gt;The catch was that wiring all this up manually required knowing the MCP spec intimately: &lt;code&gt;ui://&lt;/code&gt; URIs, special mime types, metadata coordination between tools and resources. Not hard, but fiddly.&lt;/p&gt;
&lt;h2 id="the-fluent-api-in-three-steps"&gt;The fluent API in three steps&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Step 1: Define your function.&lt;/strong&gt; Just a standard Azure Functions MCP tool:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;[Function(nameof(HelloApp))]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;HelloApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt; [McpToolTrigger(&amp;#34;HelloApp&amp;#34;, &amp;#34;A simple MCP App that says hello.&amp;#34;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ToolInvocationContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Hello from app&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Step 2: Promote it to an MCP App.&lt;/strong&gt; In your program startup:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ConfigureMcpTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;HelloApp&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AsMcpApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;assets/hello-app.html&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithTitle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Hello App&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithPermissions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;McpAppPermissions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ClipboardWrite&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;McpAppPermissions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ClipboardRead&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithCsp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;csp&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;csp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AllowBaseUri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;https://www.microsoft.com&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ConnectTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;https://www.microsoft.com&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Step 3: Add your HTML view.&lt;/strong&gt; Create &lt;code&gt;assets/hello-app.html&lt;/code&gt; with whatever UI you need.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s it. The fluent API handles all the MCP spec plumbing — generating the synthetic resource function, setting the correct mime type, injecting the metadata that connects your tool to its view.&lt;/p&gt;
&lt;h2 id="the-api-surface-is-well-designed"&gt;The API surface is well-designed&lt;/h2&gt;
&lt;p&gt;A few things I really like:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;View sources are flexible.&lt;/strong&gt; You can serve HTML from files on disk, or embed resources directly in your assembly for self-contained deployments:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;McpViewSource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FromFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;assets/my-view.html&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;McpViewSource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FromEmbeddedResource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;MyApp.Resources.view.html&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;CSP is composable.&lt;/strong&gt; You explicitly allowlist origins your app needs, following least-privilege principles. Call &lt;code&gt;WithCsp&lt;/code&gt; multiple times and origins accumulate:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithCsp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;csp&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;csp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ConnectTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;https://api.example.com&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LoadResourcesFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;https://cdn.example.com&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AllowFrame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;https://youtube.com&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Visibility control.&lt;/strong&gt; You can make a tool visible to the LLM only, the host UI only, or both. Want a tool that only renders UI and shouldn&amp;rsquo;t be called by the model? Easy:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithVisibility&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;McpVisibility&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;App&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// UI-only, hidden from the model&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="getting-started"&gt;Getting started&lt;/h2&gt;
&lt;p&gt;Add the preview package:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dotnet add package Microsoft.Azure.Functions.Worker.Extensions.Mcp --version 1.5.0-preview.1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If you&amp;rsquo;re already building MCP tools with Azure Functions, this is just a package update. The &lt;a href="https://learn.microsoft.com/azure/azure-functions/scenario-mcp-apps?tabs=bash%2Clinux&amp;amp;pivots=programming-language-csharp"&gt;MCP Apps quickstart&lt;/a&gt; is the best place to start if you&amp;rsquo;re new to the concept.&lt;/p&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;MCP Apps are one of the more exciting developments in the AI tooling space — tools that don&amp;rsquo;t just &lt;em&gt;do things&lt;/em&gt; but can &lt;em&gt;show things&lt;/em&gt; to users. The fluent API removes the protocol complexity and lets you focus on what matters: your tool&amp;rsquo;s logic and its UI.&lt;/p&gt;
&lt;p&gt;Read the &lt;a href="https://devblogs.microsoft.com/azure-sdk/mcp-as-easy-as-1-2-3-introducing-the-fluent-api-for-mcp-apps/"&gt;full post&lt;/a&gt; for the complete API reference and examples.&lt;/p&gt;</content:encoded></item><item><title>Microsoft Foundry March 2026 — GPT-5.4, Agent Service GA, and the SDK Refresh That Changes Everything</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/microsoft-foundry-march-2026-whats-new/</link><pubDate>Fri, 10 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/microsoft-foundry-march-2026-whats-new/</guid><description>Microsoft Foundry's March 2026 update is massive: Agent Service hits GA, GPT-5.4 brings reliable reasoning, the azure-ai-projects SDK goes stable across all languages, and Fireworks AI brings open models to Azure.</description><content:encoded>&lt;p&gt;The monthly &amp;ldquo;What&amp;rsquo;s New in Microsoft Foundry&amp;rdquo; posts are usually a mix of incremental improvements and the occasional headline feature. The &lt;a href="https://devblogs.microsoft.com/foundry/whats-new-in-microsoft-foundry-mar-2026/"&gt;March 2026 edition&lt;/a&gt;? It&amp;rsquo;s basically all headline features. Foundry Agent Service goes GA, GPT-5.4 ships for production, the SDK gets a major stable release, and Fireworks AI brings open model inference to Azure. Let me break down what matters for .NET developers.&lt;/p&gt;
&lt;h2 id="foundry-agent-service-is-production-ready"&gt;Foundry Agent Service is production-ready&lt;/h2&gt;
&lt;p&gt;This is the big one. The next-gen agent runtime is generally available — built on the OpenAI Responses API, wire-compatible with OpenAI agents, and open to models from multiple providers. If you&amp;rsquo;re building with the Responses API today, migrating to Foundry adds enterprise security, private networking, Entra RBAC, full tracing, and evaluation on top of your existing agent logic.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;azure.ai.projects&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AIProjectClient&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;azure.ai.projects.models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;PromptAgentDefinition&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;project_client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AIProjectClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;AZURE_AI_PROJECT_ENDPOINT&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;credential&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;DefaultAzureCredential&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;project_client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;agents&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_version&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;agent_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;my-enterprise-agent&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;definition&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;PromptAgentDefinition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;AZURE_AI_MODEL_DEPLOYMENT_NAME&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;instructions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;You are a helpful assistant.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Key additions: end-to-end private networking, MCP auth expansion (including OAuth passthrough), Voice Live preview for speech-to-speech agents, and hosted agents in 6 new regions.&lt;/p&gt;
&lt;h2 id="gpt-54--reliability-over-raw-intelligence"&gt;GPT-5.4 — reliability over raw intelligence&lt;/h2&gt;
&lt;p&gt;GPT-5.4 isn&amp;rsquo;t about being smarter. It&amp;rsquo;s about being more reliable. Stronger reasoning over long interactions, better instruction adherence, fewer mid-workflow failures, and integrated computer use capabilities. For production agents, that reliability matters way more than benchmark scores.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Model&lt;/th&gt;
&lt;th&gt;Pricing (per M tokens)&lt;/th&gt;
&lt;th&gt;Best For&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GPT-5.4 (≤272K)&lt;/td&gt;
&lt;td&gt;$2.50 / $15 output&lt;/td&gt;
&lt;td&gt;Production agents, coding, document workflows&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT-5.4 Pro&lt;/td&gt;
&lt;td&gt;$30 / $180 output&lt;/td&gt;
&lt;td&gt;Deep analysis, scientific reasoning&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPT-5.4 Mini&lt;/td&gt;
&lt;td&gt;Cost-effective&lt;/td&gt;
&lt;td&gt;Classification, extraction, lightweight tool calls&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The smart play is a routing strategy: GPT-5.4 Mini handles high-volume, low-latency work while GPT-5.4 takes the reasoning-heavy requests.&lt;/p&gt;
&lt;h2 id="the-sdk-is-finally-stable"&gt;The SDK is finally stable&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;azure-ai-projects&lt;/code&gt; SDK shipped stable releases across all languages — Python 2.0.0, JS/TS 2.0.0, Java 2.0.0, and .NET 2.0.0 (April 1). The &lt;code&gt;azure-ai-agents&lt;/code&gt; dependency is gone — everything lives under &lt;code&gt;AIProjectClient&lt;/code&gt;. Install with &lt;code&gt;pip install azure-ai-projects&lt;/code&gt; and the package bundles &lt;code&gt;openai&lt;/code&gt; and &lt;code&gt;azure-identity&lt;/code&gt; as direct dependencies.&lt;/p&gt;
&lt;p&gt;For .NET developers, this means a single NuGet package for the full Foundry surface. No more juggling separate agent SDKs.&lt;/p&gt;
&lt;h2 id="fireworks-ai-brings-open-models-to-azure"&gt;Fireworks AI brings open models to Azure&lt;/h2&gt;
&lt;p&gt;Perhaps the most architecturally interesting addition: Fireworks AI processing 13+ trillion tokens daily at ~180K requests/second, now available through Foundry. DeepSeek V3.2, gpt-oss-120b, Kimi K2.5, and MiniMax M2.5 at launch.&lt;/p&gt;
&lt;p&gt;The real story is &lt;strong&gt;bring-your-own-weights&lt;/strong&gt; — upload quantized or fine-tuned weights from anywhere without changing the serving stack. Deploy via serverless pay-per-token or provisioned throughput.&lt;/p&gt;
&lt;h2 id="other-highlights"&gt;Other highlights&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Phi-4 Reasoning Vision 15B&lt;/strong&gt; — multimodal reasoning for charts, diagrams, and document layouts&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Evaluations GA&lt;/strong&gt; — out-of-the-box evaluators with continuous production monitoring piped into Azure Monitor&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Priority Processing&lt;/strong&gt; (Preview) — dedicated compute lane for latency-sensitive workloads&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Voice Live&lt;/strong&gt; — speech-to-speech runtime that connects directly to Foundry agents&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tracing GA&lt;/strong&gt; — end-to-end agent trace inspection with sort and filter&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PromptFlow deprecation&lt;/strong&gt; — migration to Microsoft Framework Workflows by January 2027&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;March 2026 is a turning point for Foundry. The Agent Service GA, stable SDKs across all languages, GPT-5.4 for reliable production agents, and open model inference via Fireworks AI — the platform is ready for serious workloads.&lt;/p&gt;
&lt;p&gt;Read the &lt;a href="https://devblogs.microsoft.com/foundry/whats-new-in-microsoft-foundry-mar-2026/"&gt;full roundup&lt;/a&gt; and &lt;a href="https://learn.microsoft.com/azure/foundry/quickstarts/get-started-code"&gt;build your first agent&lt;/a&gt; to get started.&lt;/p&gt;</content:encoded></item><item><title>SQL MCP Server — The Right Way to Give AI Agents Database Access</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/sql-mcp-server-data-api-builder/</link><pubDate>Fri, 10 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/sql-mcp-server-data-api-builder/</guid><description>SQL MCP Server from Data API builder gives AI agents secure, deterministic database access without exposing schemas or relying on NL2SQL. RBAC, caching, multi-database support — all built in.</description><content:encoded>&lt;p&gt;Let&amp;rsquo;s be honest: most database MCP servers available today are terrifying. They take a natural language query, generate SQL on the fly, and run it against your production data. What could go wrong? (Everything. Everything could go wrong.)&lt;/p&gt;
&lt;p&gt;The Azure SQL team just &lt;a href="https://devblogs.microsoft.com/azure-sql/introducing-sql-mcp-server/"&gt;introduced SQL MCP Server&lt;/a&gt;, and it takes a fundamentally different approach. Built as a feature of Data API builder (DAB) 2.0, it gives AI agents structured, deterministic access to database operations — without NL2SQL, without exposing your schema, and with full RBAC at every step.&lt;/p&gt;
&lt;h2 id="why-no-nl2sql"&gt;Why no NL2SQL?&lt;/h2&gt;
&lt;p&gt;This is the most interesting design decision. Models aren&amp;rsquo;t deterministic, and complex queries are the most likely to produce subtle errors. The exact queries users hope AI can generate are also the ones that need the most scrutiny when produced non-deterministically.&lt;/p&gt;
&lt;p&gt;Instead, SQL MCP Server uses an &lt;strong&gt;NL2DAB&lt;/strong&gt; approach. The agent works with Data API builder&amp;rsquo;s entity abstraction layer and built-in query builder to produce accurate, well-formed T-SQL deterministically. Same result for the user, but without the risk of hallucinated JOINs or accidental data exposure.&lt;/p&gt;
&lt;h2 id="seven-tools-not-seven-hundred"&gt;Seven tools, not seven hundred&lt;/h2&gt;
&lt;p&gt;SQL MCP Server exposes exactly seven DML tools, regardless of database size:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;describe_entities&lt;/code&gt; — discover available entities and operations&lt;/li&gt;
&lt;li&gt;&lt;code&gt;create_record&lt;/code&gt; — insert rows&lt;/li&gt;
&lt;li&gt;&lt;code&gt;read_records&lt;/code&gt; — query tables and views&lt;/li&gt;
&lt;li&gt;&lt;code&gt;update_record&lt;/code&gt; — modify rows&lt;/li&gt;
&lt;li&gt;&lt;code&gt;delete_record&lt;/code&gt; — remove rows&lt;/li&gt;
&lt;li&gt;&lt;code&gt;execute_entity&lt;/code&gt; — run stored procedures&lt;/li&gt;
&lt;li&gt;&lt;code&gt;aggregate_records&lt;/code&gt; — aggregation queries&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is smart because context windows are the agent&amp;rsquo;s thinking space. Flooding them with hundreds of tool definitions leaves less room for reasoning. Seven fixed tools keep the agent focused on &lt;em&gt;thinking&lt;/em&gt; rather than &lt;em&gt;navigating&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Each tool can be individually enabled or disabled:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;&amp;#34;runtime&amp;#34;&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;mcp&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;enabled&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;path&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;/mcp&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;dml-tools&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;describe-entities&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;create-record&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;read-records&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;update-record&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;delete-record&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;execute-entity&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;aggregate-records&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="getting-started-in-three-commands"&gt;Getting started in three commands&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dab init &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --database-type mssql &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --connection-string &lt;span class="s2"&gt;&amp;#34;@env(&amp;#39;sql_connection_string&amp;#39;)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dab add Customers &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --source dbo.Customers &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --permissions &lt;span class="s2"&gt;&amp;#34;anonymous:*&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dab start
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s a running SQL MCP Server exposing your Customers table. The entity abstraction layer means you can alias names and columns, limit fields per role, and control exactly what agents see — without exposing internal schema details.&lt;/p&gt;
&lt;h2 id="the-security-story-is-solid"&gt;The security story is solid&lt;/h2&gt;
&lt;p&gt;This is where Data API builder&amp;rsquo;s maturity pays off:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;RBAC at every layer&lt;/strong&gt; — each entity defines which roles can read, create, update, or delete, and which fields are visible&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Azure Key Vault integration&lt;/strong&gt; — connection strings and secrets managed securely&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Microsoft Entra + custom OAuth&lt;/strong&gt; — production-grade authentication&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Content Security Policy&lt;/strong&gt; — agents interact through a controlled contract, not raw SQL&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The schema abstraction is particularly important. Your internal table and column names never get exposed to the agent. You define entities, aliases, and descriptions that make sense for the AI interaction — not your database ERD.&lt;/p&gt;
&lt;h2 id="multi-database-and-multi-protocol"&gt;Multi-database and multi-protocol&lt;/h2&gt;
&lt;p&gt;SQL MCP Server supports Microsoft SQL, PostgreSQL, Azure Cosmos DB, and MySQL. And because it&amp;rsquo;s a DAB feature, you get REST, GraphQL, and MCP endpoints simultaneously from the same configuration. Same entity definitions, same RBAC rules, same security — across all three protocols.&lt;/p&gt;
&lt;p&gt;Auto-configuration in DAB 2.0 can even inspect your database and build the configuration dynamically, if you&amp;rsquo;re comfortable with less abstraction for rapid prototyping.&lt;/p&gt;
&lt;h2 id="my-take"&gt;My take&lt;/h2&gt;
&lt;p&gt;This is how enterprise database access for AI agents should work. Not &amp;ldquo;hey LLM, write me some SQL and YOLO it against production.&amp;rdquo; Instead: a well-defined entity layer, deterministic query generation, RBAC at every step, caching, monitoring, and telemetry. It&amp;rsquo;s boring in the best possible way.&lt;/p&gt;
&lt;p&gt;For .NET developers, the integration story is clean — DAB is a .NET tool, the MCP Server runs as a container, and it works with Azure SQL, which most of us are already using. If you&amp;rsquo;re building AI agents that need data access, start here.&lt;/p&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;SQL MCP Server is free, open-source, and runs anywhere. It&amp;rsquo;s the prescriptive approach from Microsoft for giving AI agents secure database access. Check out the &lt;a href="https://devblogs.microsoft.com/azure-sql/introducing-sql-mcp-server/"&gt;full post&lt;/a&gt; and the &lt;a href="https://aka.ms/sql/mcp"&gt;documentation&lt;/a&gt; to get started.&lt;/p&gt;</content:encoded></item><item><title>VS Code 1.115 — Background Terminal Notifications, SSH Agent Mode, and More</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/vscode-1-115-agent-improvements/</link><pubDate>Mon, 06 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/vscode-1-115-agent-improvements/</guid><description>VS Code 1.115 brings background terminal notifications for agents, SSH remote agent hosting, file paste in terminals, and session-aware edit tracking. Here's what matters for .NET developers.</description><content:encoded>&lt;p&gt;VS Code 1.115 just &lt;a href="https://code.visualstudio.com/updates/v1_115"&gt;dropped&lt;/a&gt;, and while it&amp;rsquo;s a lighter release in terms of headline features, the agent-related improvements are genuinely useful if you&amp;rsquo;re working with AI coding assistants daily.&lt;/p&gt;
&lt;p&gt;Let me highlight what&amp;rsquo;s actually worth knowing.&lt;/p&gt;
&lt;h2 id="background-terminals-talk-back-to-agents"&gt;Background terminals talk back to agents&lt;/h2&gt;
&lt;p&gt;This is the standout feature. Background terminals now automatically notify agents when commands complete, including the exit code and terminal output. Input prompts in background terminals are also detected and surfaced to the user.&lt;/p&gt;
&lt;p&gt;Why does this matter? If you&amp;rsquo;ve used Copilot&amp;rsquo;s agent mode to run build commands or test suites in the background, you know the pain of &amp;ldquo;did that finish yet?&amp;rdquo; — background terminals were essentially fire-and-forget. Now the agent gets notified when your &lt;code&gt;dotnet build&lt;/code&gt; or &lt;code&gt;dotnet test&lt;/code&gt; completes, sees the output, and can react accordingly. It&amp;rsquo;s a small change that makes agent-driven workflows significantly more reliable.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s also a new &lt;code&gt;send_to_terminal&lt;/code&gt; tool that lets agents send commands to background terminals with user confirmation, fixing the issue where &lt;code&gt;run_in_terminal&lt;/code&gt; with a timeout would move terminals to the background and make them read-only.&lt;/p&gt;
&lt;h2 id="ssh-remote-agent-hosting"&gt;SSH remote agent hosting&lt;/h2&gt;
&lt;p&gt;VS Code now supports connecting to remote machines over SSH, automatically installing the CLI and starting it in agent host mode. This means your AI agent sessions can target remote environments directly — useful for .NET developers who build and test on Linux servers or cloud VMs.&lt;/p&gt;
&lt;h2 id="edit-tracking-in-agent-sessions"&gt;Edit tracking in agent sessions&lt;/h2&gt;
&lt;p&gt;File edits made during agent sessions are now tracked and restored, with diffs, undo/redo, and state restoration. If an agent makes changes to your code and something goes wrong, you can see exactly what changed and roll it back. Peace of mind for letting agents modify your codebase.&lt;/p&gt;
&lt;h2 id="browser-tab-awareness-and-other-improvements"&gt;Browser tab awareness and other improvements&lt;/h2&gt;
&lt;p&gt;A few more quality-of-life additions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Browser tab tracking&lt;/strong&gt; — chat can now track and link to browser tabs opened during a session, so agents can reference web pages you&amp;rsquo;re looking at&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;File paste in terminal&lt;/strong&gt; — paste files (including images) into the terminal with Ctrl+V, drag-and-drop, or right-click&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Test coverage in minimap&lt;/strong&gt; — test coverage indicators now show in the minimap for a quick visual overview&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pinch-to-zoom on Mac&lt;/strong&gt; — integrated browser supports pinch-to-zoom gestures&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Copilot entitlements in Sessions&lt;/strong&gt; — status bar shows usage info in the Sessions view&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Favicon in Go to File&lt;/strong&gt; — open web pages show favicons in the quick pick list&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;VS Code 1.115 is an incremental release, but the agent improvements — background terminal notifications, SSH agent hosting, and edit tracking — add up to a noticeably smoother experience for AI-assisted development. If you&amp;rsquo;re using Copilot&amp;rsquo;s agent mode for .NET projects, these are the kinds of quality-of-life fixes that reduce friction daily.&lt;/p&gt;
&lt;p&gt;Check out the &lt;a href="https://code.visualstudio.com/updates/v1_115"&gt;full release notes&lt;/a&gt; for every detail.&lt;/p&gt;</content:encoded></item><item><title>Aspire 13.2 Ships a Docs CLI — and Your AI Agent Can Use It Too</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/aspire-docs-cli-ai-skills/</link><pubDate>Sat, 04 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/aspire-docs-cli-ai-skills/</guid><description>.NET Aspire 13.2 adds aspire docs — a CLI for searching, browsing, and reading official documentation without leaving your terminal. It also works as a tool for AI agents. Here's why this matters.</description><content:encoded>&lt;p&gt;You know that moment when you&amp;rsquo;re deep in an Aspire AppHost, wiring up integrations, and you need to check exactly which parameters the Redis integration expects? You alt-tab to your browser, hunt through aspire.dev, squint at the API docs, then come back to your editor. Context lost. Flow broken.&lt;/p&gt;
&lt;p&gt;Aspire 13.2 just &lt;a href="https://devblogs.microsoft.com/aspire/aspire-docs-in-your-terminal/"&gt;shipped a fix for that&lt;/a&gt;. The &lt;code&gt;aspire docs&lt;/code&gt; CLI lets you search, browse, and read official Aspire documentation directly from your terminal. And because it&amp;rsquo;s backed by reusable services, AI agents and skills can use the same commands to look up docs instead of hallucinating APIs that don&amp;rsquo;t exist.&lt;/p&gt;
&lt;h2 id="the-problem-this-actually-solves"&gt;The problem this actually solves&lt;/h2&gt;
&lt;p&gt;David Pine nails it in the original post: AI agents were &lt;em&gt;terrible&lt;/em&gt; at helping developers build Aspire apps. They&amp;rsquo;d recommend &lt;code&gt;dotnet run&lt;/code&gt; instead of &lt;code&gt;aspire run&lt;/code&gt;, reference learn.microsoft.com for docs that live on aspire.dev, suggest outdated NuGet packages, and — my personal favorite — hallucinate APIs that don&amp;rsquo;t exist.&lt;/p&gt;
&lt;p&gt;Why? Because Aspire was .NET-specific far longer than it&amp;rsquo;s been polyglot, and LLMs are working off training data that predates the latest features. When you give an AI agent the ability to actually look up the current docs, it stops guessing and starts being useful.&lt;/p&gt;
&lt;h2 id="three-commands-zero-browser-tabs"&gt;Three commands, zero browser tabs&lt;/h2&gt;
&lt;p&gt;The CLI is refreshingly simple:&lt;/p&gt;
&lt;h3 id="list-all-docs"&gt;List all docs&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aspire docs list
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Returns every documentation page available on aspire.dev. Need machine-readable output? Add &lt;code&gt;--format Json&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id="search-for-a-topic"&gt;Search for a topic&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aspire docs search &lt;span class="s2"&gt;&amp;#34;redis&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Searches both titles and content with weighted relevance scoring. Same search engine that powers the documentation tooling internally. You get ranked results with titles, slugs, and relevance scores.&lt;/p&gt;
&lt;h3 id="read-a-full-page-or-just-one-section"&gt;Read a full page (or just one section)&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aspire docs get redis-integration
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Streams the full page as markdown to your terminal. Need just one section?&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aspire docs get redis-integration --section &lt;span class="s2"&gt;&amp;#34;Add Redis resource&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Surgical precision. No scrolling through 500 lines. Just the part you need.&lt;/p&gt;
&lt;h2 id="the-ai-agent-angle"&gt;The AI agent angle&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s where it gets interesting for us developers building with AI tooling. The same &lt;code&gt;aspire docs&lt;/code&gt; commands work as tools for AI agents — through skills, MCP servers, or simple CLI wrappers.&lt;/p&gt;
&lt;p&gt;Instead of your AI assistant making up Aspire APIs based on stale training data, it can call &lt;code&gt;aspire docs search &amp;quot;postgres&amp;quot;&lt;/code&gt;, find the official integration docs, read the right page, and give you the documented approach. Real-time, current documentation — not what the model memorized six months ago.&lt;/p&gt;
&lt;p&gt;The architecture behind this is intentional. The Aspire team built reusable services (&lt;code&gt;IDocsIndexService&lt;/code&gt;, &lt;code&gt;IDocsSearchService&lt;/code&gt;, &lt;code&gt;IDocsFetcher&lt;/code&gt;, &lt;code&gt;IDocsCache&lt;/code&gt;) rather than a one-off integration. That means the same search engine works for humans in the terminal, AI agents in your editor, and automation in your CI pipeline.&lt;/p&gt;
&lt;h2 id="real-world-scenarios"&gt;Real-world scenarios&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Quick terminal lookups:&lt;/strong&gt; You&amp;rsquo;re three files deep and need Redis config parameters. Two commands, ninety seconds, back to work:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aspire docs search &lt;span class="s2"&gt;&amp;#34;redis&amp;#34;&lt;/span&gt; --limit &lt;span class="m"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aspire docs get redis-integration --section &lt;span class="s2"&gt;&amp;#34;Configuration&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;AI-assisted development:&lt;/strong&gt; Your VS Code skill wraps the CLI commands. You ask &amp;ldquo;Add a PostgreSQL database to my AppHost&amp;rdquo; and the agent looks up the real docs before answering. No hallucinations.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CI/CD validation:&lt;/strong&gt; Your pipeline validates AppHost configurations against official documentation programmatically. &lt;code&gt;--format Json&lt;/code&gt; output pipes cleanly to &lt;code&gt;jq&lt;/code&gt; and other tools.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Custom knowledge bases:&lt;/strong&gt; Building your own AI tooling? Pipe structured JSON output directly into your knowledge base:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;aspire docs search &lt;span class="s2"&gt;&amp;#34;monitoring&amp;#34;&lt;/span&gt; --format Json &lt;span class="p"&gt;|&lt;/span&gt; jq &lt;span class="s1"&gt;&amp;#39;[.[] | {slug, title, summary}]&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;No web scraping. No API keys. Same structured data the docs tooling uses internally.&lt;/p&gt;
&lt;h2 id="the-documentation-is-always-live"&gt;The documentation is always live&lt;/h2&gt;
&lt;p&gt;This is the part I appreciate most. The CLI doesn&amp;rsquo;t download a snapshot — it queries aspire.dev with ETag-based caching. The moment the docs update, your CLI and any skill built on top of it reflects that. No stale copies, no &amp;ldquo;but the wiki said&amp;hellip;&amp;rdquo; moments.&lt;/p&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;aspire docs&lt;/code&gt; is one of those small features that solves a real problem cleanly. Humans get terminal-native documentation access. AI agents get a way to stop guessing and start referencing actual docs. And it&amp;rsquo;s all backed by the same source of truth.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re building with .NET Aspire and haven&amp;rsquo;t tried the CLI yet, run &lt;code&gt;aspire docs search &amp;quot;your-topic-here&amp;quot;&lt;/code&gt; and see how it feels. Then consider wrapping those commands into whatever AI skill or automation setup you&amp;rsquo;re using — your agents will thank you.&lt;/p&gt;
&lt;p&gt;Check out &lt;a href="https://davidpine.dev/posts/aspire-docs-mcp-tools/"&gt;David Pine&amp;rsquo;s deep dive&lt;/a&gt; on how the docs tooling came together, and the &lt;a href="https://aspire.dev/reference/cli/commands/aspire-docs/"&gt;official CLI reference&lt;/a&gt; for all the details.&lt;/p&gt;</content:encoded></item><item><title>Microsoft Agent Framework Hits 1.0 — Here's What Actually Matters for .NET Developers</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/agent-framework-1-0-production-ready/</link><pubDate>Fri, 03 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/agent-framework-1-0-production-ready/</guid><description>Microsoft Agent Framework 1.0 is production-ready with stable APIs, multi-agent orchestration, and connectors for every major AI provider. Here's what you need to know as a .NET developer.</description><content:encoded>&lt;p&gt;If you&amp;rsquo;ve been following the Agent Framework journey from the early Semantic Kernel and AutoGen days, this one is significant. Microsoft Agent Framework just &lt;a href="https://devblogs.microsoft.com/agent-framework/microsoft-agent-framework-version-1-0/"&gt;hit version 1.0&lt;/a&gt; — production-ready, stable APIs, long-term support commitment. It&amp;rsquo;s available for both .NET and Python, and it&amp;rsquo;s genuinely ready for real workloads.&lt;/p&gt;
&lt;p&gt;Let me cut through the announcement noise and focus on what matters if you&amp;rsquo;re building AI-powered apps with .NET.&lt;/p&gt;
&lt;h2 id="the-short-version"&gt;The short version&lt;/h2&gt;
&lt;p&gt;Agent Framework 1.0 unifies what used to be Semantic Kernel and AutoGen into a single, open-source SDK. One agent abstraction. One orchestration engine. Multiple AI providers. If you&amp;rsquo;ve been bouncing between Semantic Kernel for enterprise patterns and AutoGen for research-grade multi-agent workflows, you can stop. This is the one SDK now.&lt;/p&gt;
&lt;h2 id="getting-started-is-almost-unfairly-simple"&gt;Getting started is almost unfairly simple&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s a working agent in .NET:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// dotnet add package Microsoft.Agents.AI.OpenAI --prerelease&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Agents.AI&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Agents.AI.Foundry&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Azure.Identity&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;AIProjectClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;https://your-project.services.ai.azure.com&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetResponsesClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;gpt-5.3&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AsAIAgent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;HaikuBot&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;instructions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;You are an upbeat assistant that writes beautifully.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RunAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Write a haiku about shipping 1.0.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s it. A handful of lines and you have an AI agent running against Azure Foundry. The Python equivalent is equally concise. Add function tools, multi-turn conversations, and streaming as you go — the API surface scales up without getting weird.&lt;/p&gt;
&lt;h2 id="multi-agent-orchestration--this-is-the-real-deal"&gt;Multi-agent orchestration — this is the real deal&lt;/h2&gt;
&lt;p&gt;Single agents are fine for demos, but production scenarios usually need coordination. Agent Framework 1.0 ships with battle-tested orchestration patterns straight from Microsoft Research and AutoGen:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Sequential&lt;/strong&gt; — agents process in order (writer → reviewer → editor)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Concurrent&lt;/strong&gt; — fan out to multiple agents in parallel, converge results&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Handoff&lt;/strong&gt; — one agent delegates to another based on intent&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Group chat&lt;/strong&gt; — multiple agents discuss and converge on a solution&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Magentic-One&lt;/strong&gt; — the research-grade multi-agent pattern from MSR&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All of them support streaming, checkpointing, human-in-the-loop approvals, and pause/resume. The checkpointing part is crucial — long-running workflows survive process restarts. For us .NET developers who&amp;rsquo;ve built durable workflows with Azure Functions, this feels familiar.&lt;/p&gt;
&lt;h2 id="the-features-that-matter-most"&gt;The features that matter most&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s my shortlist of what&amp;rsquo;s worth knowing:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Middleware hooks.&lt;/strong&gt; You know how ASP.NET Core has middleware pipelines? Same concept, but for agent execution. Intercept every stage — add content safety, logging, compliance policies — without touching agent prompts. This is how you make agents enterprise-ready.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pluggable memory.&lt;/strong&gt; Conversational history, persistent key-value state, vector-based retrieval. Choose your backend: Foundry Agent Service, Mem0, Redis, Neo4j, or roll your own. Memory is what turns a stateless LLM call into an agent that actually remembers context.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Declarative YAML agents.&lt;/strong&gt; Define your agent&amp;rsquo;s instructions, tools, memory, and orchestration topology in version-controlled YAML files. Load and run with a single API call. This is a game-changer for teams that want to iterate on agent behavior without redeploying code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A2A and MCP support.&lt;/strong&gt; MCP (Model Context Protocol) lets agents discover and invoke external tools dynamically. A2A (Agent-to-Agent protocol) enables cross-runtime collaboration — your .NET agents can coordinate with agents running in other frameworks. A2A 1.0 support is coming soon.&lt;/p&gt;
&lt;h2 id="the-preview-features-worth-watching"&gt;The preview features worth watching&lt;/h2&gt;
&lt;p&gt;Some features shipped as preview in 1.0 — functional but APIs may evolve:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;DevUI&lt;/strong&gt; — a browser-based local debugger for visualizing agent execution, message flows, and tool calls in real time. Think Application Insights, but for agent reasoning.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GitHub Copilot SDK and Claude Code SDK&lt;/strong&gt; — use Copilot or Claude as an agent harness directly from your orchestration code. Compose a coding-capable agent alongside your other agents in the same workflow.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Agent Harness&lt;/strong&gt; — a customizable local runtime giving agents access to shell, file system, and messaging loops. Think coding agents and automation patterns.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Skills&lt;/strong&gt; — reusable domain capability packages that give agents structured capabilities out of the box.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="migrating-from-semantic-kernel-or-autogen"&gt;Migrating from Semantic Kernel or AutoGen&lt;/h2&gt;
&lt;p&gt;If you have existing Semantic Kernel or AutoGen code, there are dedicated migration assistants that analyze your code and generate step-by-step migration plans. The &lt;a href="https://learn.microsoft.com/en-us/agent-framework/migration-guide/from-semantic-kernel"&gt;Semantic Kernel migration guide&lt;/a&gt; and &lt;a href="https://learn.microsoft.com/en-us/agent-framework/migration-guide/from-autogen"&gt;AutoGen migration guide&lt;/a&gt; walk you through everything.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;ve been on the RC packages, upgrading to 1.0 is just a version bump.&lt;/p&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;Agent Framework 1.0 is the production milestone that enterprise teams have been waiting for. Stable APIs, multi-provider support, orchestration patterns that actually work at scale, and migration paths from both Semantic Kernel and AutoGen.&lt;/p&gt;
&lt;p&gt;The framework is &lt;a href="https://github.com/microsoft/agent-framework"&gt;fully open source on GitHub&lt;/a&gt;, and you can get started today with &lt;code&gt;dotnet add package Microsoft.Agents.AI&lt;/code&gt;. Check out the &lt;a href="https://learn.microsoft.com/en-us/agent-framework/get-started/"&gt;quickstart guide&lt;/a&gt; and the &lt;a href="https://github.com/microsoft/agent-framework"&gt;samples&lt;/a&gt; to get your hands dirty.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;ve been waiting for the &amp;ldquo;safe to use in production&amp;rdquo; signal — this is it.&lt;/p&gt;</content:encoded></item><item><title>Aspire 13.2's Dashboard Just Got a Telemetry API — and It Changes Everything</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/aspire-132-dashboard-export-telemetry/</link><pubDate>Thu, 02 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/aspire-132-dashboard-export-telemetry/</guid><description>.NET Aspire 13.2 ships smarter telemetry export, a programmable API for traces and logs, and GenAI visualization improvements. Here's why this matters for your debugging workflow.</description><content:encoded>&lt;p&gt;If you&amp;rsquo;ve been building distributed apps with .NET Aspire, you already know the dashboard is the single best thing about the whole experience. All your traces, logs, and metrics in one place — no external Jaeger, no Seq setup, no &amp;ldquo;let me check the other terminal&amp;rdquo; moments.&lt;/p&gt;
&lt;p&gt;Aspire 13.2 just made it significantly better. James Newton-King &lt;a href="https://devblogs.microsoft.com/aspire/aspire-dashboard-improvements-export-and-telemetry/"&gt;announced the update&lt;/a&gt;, and honestly? The telemetry export and API features alone are worth the upgrade.&lt;/p&gt;
&lt;h2 id="export-telemetry-like-a-sane-person"&gt;Export telemetry like a sane person&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s the scenario we&amp;rsquo;ve all lived through: you&amp;rsquo;re debugging a distributed issue, you finally reproduce it after twenty minutes of setup, and now you need to share what happened with your team. Before? Screenshots. Copy-pasting trace IDs. The usual mess.&lt;/p&gt;
&lt;p&gt;Aspire 13.2 adds a proper &lt;strong&gt;Manage logs and telemetry&lt;/strong&gt; dialog where you can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Clear all telemetry (useful before a repro attempt)&lt;/li&gt;
&lt;li&gt;Export selected telemetry to a ZIP file in standard OTLP/JSON format&lt;/li&gt;
&lt;li&gt;Re-import that ZIP into any Aspire dashboard later&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That last part is the killer feature. You reproduce a bug, export the telemetry, attach it to your work item, and your teammate can import it into their own dashboard to see exactly what you saw. No more &amp;ldquo;can you reproduce it on your machine?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Individual traces, spans, and logs also get an &amp;ldquo;Export JSON&amp;rdquo; option in their context menus. Need to share one specific trace? Right-click, copy JSON, paste into your PR description. Done.&lt;/p&gt;
&lt;h2 id="the-telemetry-api-is-the-real-game-changer"&gt;The telemetry API is the real game changer&lt;/h2&gt;
&lt;p&gt;This is what I&amp;rsquo;m most excited about. The dashboard now exposes an HTTP API under &lt;code&gt;/api/telemetry&lt;/code&gt; for querying telemetry data programmatically. Available endpoints:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GET /api/telemetry/resources&lt;/code&gt; — list resources with telemetry&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /api/telemetry/spans&lt;/code&gt; — query spans with filters&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /api/telemetry/logs&lt;/code&gt; — query logs with filters&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /api/telemetry/traces&lt;/code&gt; — list traces&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET /api/telemetry/traces/{traceId}&lt;/code&gt; — get all spans for a specific trace&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Everything comes back in OTLP JSON format. This powers the new &lt;code&gt;aspire agent mcp&lt;/code&gt; and &lt;code&gt;aspire otel&lt;/code&gt; CLI commands, but the real implication is bigger: you can now build tooling, scripts, and AI agent integrations that query your app&amp;rsquo;s telemetry directly.&lt;/p&gt;
&lt;p&gt;Imagine an AI coding agent that can look at your actual distributed traces while debugging. That&amp;rsquo;s not hypothetical anymore — that&amp;rsquo;s what this API enables.&lt;/p&gt;
&lt;h2 id="genai-telemetry-gets-practical"&gt;GenAI telemetry gets practical&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;re building AI-powered apps with Semantic Kernel or Microsoft.Extensions.AI, you&amp;rsquo;ll appreciate the improved GenAI telemetry visualizer. Aspire 13.2 adds:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AI tool descriptions rendered as Markdown&lt;/li&gt;
&lt;li&gt;A dedicated GenAI button on the traces page for quick AI trace access&lt;/li&gt;
&lt;li&gt;Better error handling for truncated or non-standard GenAI JSON&lt;/li&gt;
&lt;li&gt;Click-to-highlight navigation between tool definitions&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The blog post mentions that VS Code Copilot chat, Copilot CLI, and OpenCode all support configuring an &lt;code&gt;OTEL_EXPORTER_OTLP_ENDPOINT&lt;/code&gt;. Point them at the Aspire dashboard and you can literally watch your AI agents think in real time through telemetry. That&amp;rsquo;s a debugging experience you won&amp;rsquo;t find anywhere else.&lt;/p&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;Aspire 13.2 takes the dashboard from &amp;ldquo;nice debugging UI&amp;rdquo; to &amp;ldquo;programmable observability platform.&amp;rdquo; The export/import workflow alone saves real time on distributed debugging, and the telemetry API opens the door to AI-assisted diagnostics.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re already on Aspire, upgrade. If you&amp;rsquo;re not — this is a good reason to check out &lt;a href="https://aspire.dev"&gt;aspire.dev&lt;/a&gt; and see what the fuss is about.&lt;/p&gt;</content:encoded></item><item><title>azd Now Lets You Run and Debug AI Agents Locally — Here's What Changed in March 2026</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/azd-march-2026-local-ai-agent-debugging/</link><pubDate>Thu, 02 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/azd-march-2026-local-ai-agent-debugging/</guid><description>The Azure Developer CLI shipped seven releases in March 2026. The highlights: a local run-and-debug loop for AI agents, GitHub Copilot integration in project setup, and Container App Jobs support.</description><content:encoded>&lt;p&gt;Seven releases in one month. That&amp;rsquo;s what the Azure Developer CLI (&lt;code&gt;azd&lt;/code&gt;) team pushed in March 2026, and the headline feature is the one I&amp;rsquo;ve been waiting for: &lt;strong&gt;a local run-and-debug loop for AI agents&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;PC Chan &lt;a href="https://devblogs.microsoft.com/azure-sdk/azure-developer-cli-azd-march-2026/"&gt;published the full roundup&lt;/a&gt;, and while there&amp;rsquo;s a lot in there, let me filter it down to what actually matters for .NET developers building AI-powered apps.&lt;/p&gt;
&lt;h2 id="run-and-debug-ai-agents-without-deploying"&gt;Run and debug AI agents without deploying&lt;/h2&gt;
&lt;p&gt;This is the big one. The new &lt;code&gt;azure.ai.agents&lt;/code&gt; extension adds a set of commands that give you a proper inner-loop experience for AI agents:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;azd ai agent run&lt;/code&gt; — starts your agent locally&lt;/li&gt;
&lt;li&gt;&lt;code&gt;azd ai agent invoke&lt;/code&gt; — sends messages to it (local or deployed)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;azd ai agent show&lt;/code&gt; — displays container status and health&lt;/li&gt;
&lt;li&gt;&lt;code&gt;azd ai agent monitor&lt;/code&gt; — streams container logs in real time&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Before this, testing an AI agent meant deploying to Microsoft Foundry every time you made a change. Now you can iterate locally, test your agent&amp;rsquo;s behavior, and only deploy when you&amp;rsquo;re ready. If you&amp;rsquo;ve been building agents with the Microsoft Agent Framework or Semantic Kernel, this changes your daily workflow.&lt;/p&gt;
&lt;p&gt;The invoke command works against both local and deployed agents, which means you can use the same testing workflow regardless of where the agent is running. That&amp;rsquo;s the kind of detail that saves you from maintaining two sets of test scripts.&lt;/p&gt;
&lt;h2 id="github-copilot-scaffolds-your-azd-project"&gt;GitHub Copilot scaffolds your azd project&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;azd init&lt;/code&gt; now offers a &amp;ldquo;Set up with GitHub Copilot (Preview)&amp;rdquo; option. Instead of manually answering prompts about your project structure, a Copilot agent scaffolds the configuration for you. It checks for a dirty working directory before modifying anything and asks for MCP server tool consent upfront.&lt;/p&gt;
&lt;p&gt;When a command fails, &lt;code&gt;azd&lt;/code&gt; now offers AI-assisted troubleshooting: pick a category (explain, guidance, troubleshoot, or skip), let the agent suggest a fix, and retry — all without leaving the terminal. For complex infrastructure setups, that&amp;rsquo;s a real time saver.&lt;/p&gt;
&lt;h2 id="container-app-jobs-and-deployment-improvements"&gt;Container App Jobs and deployment improvements&lt;/h2&gt;
&lt;p&gt;A few deployment features worth noting:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Container App Jobs&lt;/strong&gt;: &lt;code&gt;azd&lt;/code&gt; now deploys &lt;code&gt;Microsoft.App/jobs&lt;/code&gt; through the existing &lt;code&gt;host: containerapp&lt;/code&gt; config. Your Bicep template determines whether the target is a Container App or a Job — no extra setup.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Configurable deployment timeouts&lt;/strong&gt;: New &lt;code&gt;--timeout&lt;/code&gt; flag on &lt;code&gt;azd deploy&lt;/code&gt; and a &lt;code&gt;deployTimeout&lt;/code&gt; field in &lt;code&gt;azure.yaml&lt;/code&gt;. No more guessing the default 1200-second limit.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Remote build fallback&lt;/strong&gt;: When remote ACR build fails, &lt;code&gt;azd&lt;/code&gt; falls back to local Docker/Podman build automatically.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Local preflight validation&lt;/strong&gt;: Bicep parameters get validated locally before deploying, catching missing params without a round-trip to Azure.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="developer-experience-polish"&gt;Developer experience polish&lt;/h2&gt;
&lt;p&gt;Some smaller improvements that add up:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Automatic pnpm/yarn detection&lt;/strong&gt; for JS/TS projects&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;pyproject.toml support&lt;/strong&gt; for Python packaging&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Local template directories&lt;/strong&gt; — &lt;code&gt;azd init --template&lt;/code&gt; now accepts filesystem paths for offline iteration&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Better error messages&lt;/strong&gt; in &lt;code&gt;--no-prompt&lt;/code&gt; mode — all missing values reported at once with resolution commands&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Build environment variables&lt;/strong&gt; injected into all framework build subprocesses (.NET, Node.js, Java, Python)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That last one is subtle but important: your .NET build now has access to &lt;code&gt;azd&lt;/code&gt; environment variables, which means you can do build-time configuration injection without extra scripting.&lt;/p&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;The local AI agent debugging loop is the star of this release, but the accumulation of deployment improvements and DX polish makes &lt;code&gt;azd&lt;/code&gt; feel more mature than ever. If you&amp;rsquo;re deploying .NET apps to Azure — especially AI agents — this update is worth the install.&lt;/p&gt;
&lt;p&gt;Check the &lt;a href="https://devblogs.microsoft.com/azure-sdk/azure-developer-cli-azd-march-2026/"&gt;full release notes&lt;/a&gt; for every detail, or get started with &lt;a href="https://learn.microsoft.com/azure/developer/azure-developer-cli/install-azd"&gt;azd install&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title>Visual Studio's March Update Lets You Build Custom Copilot Agents — and the find_symbol Tool Is a Big Deal</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/visual-studio-march-2026-custom-copilot-agents/</link><pubDate>Thu, 02 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/visual-studio-march-2026-custom-copilot-agents/</guid><description>Visual Studio's March 2026 update ships custom Copilot agents, reusable agent skills, a language-aware find_symbol tool, and Copilot-powered profiling from Test Explorer. Here's what matters.</description><content:encoded>&lt;p&gt;Visual Studio just got its most significant Copilot update yet. Mark Downie &lt;a href="https://devblogs.microsoft.com/visualstudio/visual-studio-march-update-build-your-own-custom-agents/"&gt;announced the March release&lt;/a&gt;, and the headline is custom agents — but honestly, the &lt;code&gt;find_symbol&lt;/code&gt; tool buried further down might be the feature that changes your workflow the most.&lt;/p&gt;
&lt;p&gt;Let me break down what&amp;rsquo;s actually here.&lt;/p&gt;
&lt;h2 id="custom-copilot-agents-in-your-repo"&gt;Custom Copilot agents in your repo&lt;/h2&gt;
&lt;p&gt;Want Copilot to follow your team&amp;rsquo;s coding standards, run your build pipeline, or query your internal docs? Now you can build exactly that.&lt;/p&gt;
&lt;p&gt;Custom agents are defined as &lt;code&gt;.agent.md&lt;/code&gt; files that you drop into &lt;code&gt;.github/agents/&lt;/code&gt; in your repository. Each agent gets full access to workspace awareness, code understanding, tools, your preferred model, and MCP connections to external services. They show up in the agent picker alongside the built-in agents.&lt;/p&gt;
&lt;p&gt;This is the same pattern VS Code has been supporting — and it&amp;rsquo;s great to see Visual Studio catch up. For teams that have already built agents for VS Code, your &lt;code&gt;.agent.md&lt;/code&gt; files should work across both IDEs (though tool names can vary, so test them).&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://github.com/github/awesome-copilot"&gt;awesome-copilot&lt;/a&gt; repo has community-contributed agent configurations you can use as starting points.&lt;/p&gt;
&lt;h2 id="agent-skills-reusable-instruction-packs"&gt;Agent skills: reusable instruction packs&lt;/h2&gt;
&lt;p&gt;Skills are automatically picked up from &lt;code&gt;.github/skills/&lt;/code&gt; in your repo or &lt;code&gt;~/.copilot/skills/&lt;/code&gt; in your profile. Each skill is a &lt;code&gt;SKILL.md&lt;/code&gt; file following the &lt;a href="https://agentskills.io/specification"&gt;Agent Skills specification&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Think of skills as modular expertise you can mix and match. You might have a skill for your API conventions, another for your testing patterns, and another for your deployment workflow. When a skill activates, it shows up in the chat so you know it&amp;rsquo;s being applied.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;ve been using skills in VS Code, they work the same way in Visual Studio now.&lt;/p&gt;
&lt;h2 id="find_symbol-language-aware-navigation-for-agents"&gt;find_symbol: language-aware navigation for agents&lt;/h2&gt;
&lt;p&gt;This is where things get really interesting. The new &lt;code&gt;find_symbol&lt;/code&gt; tool gives Copilot&amp;rsquo;s agent mode actual language-service-powered symbol navigation. Instead of searching your code as text, the agent can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Find all references to a symbol across your project&lt;/li&gt;
&lt;li&gt;Access type information, declarations, and scope metadata&lt;/li&gt;
&lt;li&gt;Navigate call sites with full language awareness&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What this means in practice: when you ask Copilot to refactor a method or update a parameter signature across call sites, it can actually see your code&amp;rsquo;s structure. No more &amp;ldquo;the agent changed the method but missed three call sites&amp;rdquo; situations.&lt;/p&gt;
&lt;p&gt;Supported languages include C#, C++, Razor, TypeScript, and anything with a supported LSP extension. For .NET developers, this is a massive improvement — C# codebases with deep type hierarchies and interfaces benefit enormously from symbol-aware navigation.&lt;/p&gt;
&lt;h2 id="profile-tests-with-copilot"&gt;Profile tests with Copilot&lt;/h2&gt;
&lt;p&gt;There&amp;rsquo;s now a &lt;strong&gt;Profile with Copilot&lt;/strong&gt; command in the Test Explorer context menu. Select a test, click profile, and the Profiling Agent automatically runs it and analyzes performance — combining CPU usage and instrumentation data to deliver actionable insights.&lt;/p&gt;
&lt;p&gt;No more manually configuring profiler sessions, running the test, exporting results, and trying to read a flame graph. The agent does the analysis and tells you what&amp;rsquo;s slow and why. Currently .NET only, which makes sense given Visual Studio&amp;rsquo;s deep .NET diagnostics integration.&lt;/p&gt;
&lt;h2 id="perf-tips-during-live-debugging"&gt;Perf tips during live debugging&lt;/h2&gt;
&lt;p&gt;Performance optimization now happens while you debug, not after. As you step through code, Visual Studio shows execution time and performance signals inline. See a slow line? Click the Perf Tip and ask Copilot for optimization suggestions right there.&lt;/p&gt;
&lt;p&gt;The Profiling Agent captures runtime data automatically — elapsed time, CPU usage, memory behavior — and Copilot uses it to pinpoint hot spots. This keeps performance work as part of your debugging flow instead of a separate task you keep postponing.&lt;/p&gt;
&lt;h2 id="fix-nuget-vulnerabilities-from-solution-explorer"&gt;Fix NuGet vulnerabilities from Solution Explorer&lt;/h2&gt;
&lt;p&gt;When a vulnerability is detected in a NuGet package, you now see a notification with a &lt;strong&gt;Fix with GitHub Copilot&lt;/strong&gt; link directly in Solution Explorer. Click through and Copilot analyzes the vulnerability, recommends the right package updates, and implements them.&lt;/p&gt;
&lt;p&gt;For teams that struggle to keep dependencies up to date (which is basically everyone), this removes the friction of &amp;ldquo;I know there&amp;rsquo;s a vulnerability but figuring out the right update path is a project in itself.&amp;rdquo;&lt;/p&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;Custom agents and skills are the headline, but &lt;code&gt;find_symbol&lt;/code&gt; is the sleeper hit — it fundamentally changes how accurate Copilot can be when refactoring .NET code. Combined with live profiling integration and vulnerability fixes, this update makes Visual Studio&amp;rsquo;s AI features feel genuinely practical rather than demo-ready.&lt;/p&gt;
&lt;p&gt;Download &lt;a href="https://visualstudio.microsoft.com/downloads/"&gt;Visual Studio 2026 Insiders&lt;/a&gt; to try it all out.&lt;/p&gt;</content:encoded></item><item><title>KubeCon Europe 2026: What .NET Developers Should Actually Care About</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/kubecon-2026-aks-updates-dotnet-developers/</link><pubDate>Sun, 29 Mar 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/kubecon-2026-aks-updates-dotnet-developers/</guid><description>Microsoft dropped a wall of Kubernetes announcements at KubeCon Europe 2026. Here's the filtered version — only the AKS and cloud-native updates that matter if you're shipping .NET apps.</description><content:encoded>&lt;p&gt;You know that feeling when a massive announcement post drops and you&amp;rsquo;re scrolling through it thinking &amp;ldquo;cool, but what does this actually change for me&amp;rdquo;? That&amp;rsquo;s me every KubeCon season.&lt;/p&gt;
&lt;p&gt;Microsoft just published &lt;a href="https://opensource.microsoft.com/blog/2026/03/24/whats-new-with-microsoft-in-open-source-and-kubernetes-at-kubecon-cloudnativecon-europe-2026/"&gt;their full KubeCon Europe 2026 roundup&lt;/a&gt; — written by Brendan Burns himself — and honestly? There&amp;rsquo;s real substance here. Not just feature checkboxes, but the kind of operational improvements that change how you run things in production.&lt;/p&gt;
&lt;p&gt;Let me break down what actually matters for us .NET developers.&lt;/p&gt;
&lt;h2 id="mtls-without-the-service-mesh-tax"&gt;mTLS without the service mesh tax&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s the thing about service meshes: everyone wants the security guarantees, nobody wants the operational overhead. AKS is finally closing that gap.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://aka.ms/aks/application-network"&gt;Azure Kubernetes Application Network&lt;/a&gt; gives you mutual TLS, application-aware authorization, and traffic telemetry — without deploying a full sidecar-heavy mesh. Combined with &lt;a href="https://aka.ms/acns/cilium-mtls"&gt;Cilium mTLS in Advanced Container Networking Services&lt;/a&gt;, you get encrypted pod-to-pod communication using X.509 certificates and SPIRE for identity management.&lt;/p&gt;
&lt;p&gt;What this means in practice: your ASP.NET Core APIs talking to background workers, your gRPC services calling each other — all encrypted and identity-verified at the network level, with zero application code changes. That&amp;rsquo;s huge.&lt;/p&gt;
&lt;p&gt;For teams migrating off &lt;code&gt;ingress-nginx&lt;/code&gt;, there&amp;rsquo;s also &lt;a href="https://aka.ms/aks/app-routing/gateway-api"&gt;Application Routing with Meshless Istio&lt;/a&gt; with full Kubernetes Gateway API support. No sidecars. Standards-based. And they shipped &lt;code&gt;ingress2gateway&lt;/code&gt; tooling for incremental migration.&lt;/p&gt;
&lt;h2 id="gpu-observability-thats-not-an-afterthought"&gt;GPU observability that&amp;rsquo;s not an afterthought&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;re running AI inference alongside your .NET services (and let&amp;rsquo;s be honest, who isn&amp;rsquo;t starting to?), you&amp;rsquo;ve probably hit the GPU monitoring blind spot. You&amp;rsquo;d get great CPU/memory dashboards and then&amp;hellip; nothing for GPUs without manual exporter plumbing.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://aka.ms/aks/managed-gpu-metrics"&gt;AKS now surfaces GPU metrics natively&lt;/a&gt; into managed Prometheus and Grafana. Same stack, same dashboards, same alerting pipeline. No custom exporters, no third-party agents.&lt;/p&gt;
&lt;p&gt;On the network side, they added per-flow visibility for HTTP, gRPC, and Kafka traffic with a &lt;a href="https://learn.microsoft.com/en-us/azure/aks/container-network-observability-logs"&gt;one-click Azure Monitor experience&lt;/a&gt;. IPs, ports, workloads, flow direction, policy decisions — all in built-in dashboards.&lt;/p&gt;
&lt;p&gt;And here&amp;rsquo;s the one that made me do a double-take: &lt;a href="https://learn.microsoft.com/en-us/azure/aks/advanced-container-networking-services-overview"&gt;agentic container networking&lt;/a&gt; adds a web UI where you can ask natural-language questions about your cluster&amp;rsquo;s network state. &amp;ldquo;Why is pod X not reaching service Y?&amp;rdquo; → read-only diagnostics from live telemetry. That&amp;rsquo;s genuinely useful at 2 AM.&lt;/p&gt;
&lt;h2 id="cross-cluster-networking-that-doesnt-require-a-phd"&gt;Cross-cluster networking that doesn&amp;rsquo;t require a PhD&lt;/h2&gt;
&lt;p&gt;Multi-cluster Kubernetes has historically been a &amp;ldquo;bring your own networking glue&amp;rdquo; experience. Azure Kubernetes Fleet Manager now ships &lt;a href="https://aka.ms/kubernetes-fleet/networking/cross-cluster"&gt;cross-cluster networking&lt;/a&gt; through managed Cilium cluster mesh:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Unified connectivity across AKS clusters&lt;/li&gt;
&lt;li&gt;Global service registry for cross-cluster discovery&lt;/li&gt;
&lt;li&gt;Configuration managed centrally, not repeated per cluster&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you&amp;rsquo;re running .NET microservices across regions for resilience or compliance, this replaces a lot of fragile custom plumbing. Service A in West Europe can discover and call Service B in East US through the mesh, with consistent routing and security policies.&lt;/p&gt;
&lt;h2 id="upgrades-that-dont-require-courage"&gt;Upgrades that don&amp;rsquo;t require courage&lt;/h2&gt;
&lt;p&gt;Let&amp;rsquo;s be honest — Kubernetes upgrades in production are stressful. &amp;ldquo;Upgrade and hope&amp;rdquo; has been the de facto strategy for too many teams, and it&amp;rsquo;s the main reason clusters fall behind on versions.&lt;/p&gt;
&lt;p&gt;Two new capabilities change this:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Blue-green agent pool upgrades&lt;/strong&gt; create a parallel node pool with the new configuration. Validate behavior, shift traffic gradually, and keep a clean rollback path. No more in-place mutations on production nodes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Agent pool rollback&lt;/strong&gt; lets you revert a node pool to its previous Kubernetes version and node image after an upgrade goes sideways — without rebuilding the cluster.&lt;/p&gt;
&lt;p&gt;Together, these finally give operators real control over the upgrade lifecycle. For .NET teams, this matters because platform velocity directly controls how fast you can adopt new runtimes, security patches, and networking capabilities.&lt;/p&gt;
&lt;h2 id="ai-workloads-are-becoming-first-class-kubernetes-citizens"&gt;AI workloads are becoming first-class Kubernetes citizens&lt;/h2&gt;
&lt;p&gt;The upstream open-source work is equally important. Dynamic Resource Allocation (DRA) just went GA in Kubernetes 1.36, making GPU scheduling a proper first-class feature instead of a workaround.&lt;/p&gt;
&lt;p&gt;A few projects worth watching:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Project&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/kaito-project/kubeairunway"&gt;AI Runway&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Common Kubernetes API for inference — deploy models without knowing K8s, with HuggingFace discovery and cost estimates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://www.cncf.io/blog/2026/01/07/holmesgpt-agentic-troubleshooting-built-for-the-cloud-native-era/"&gt;HolmesGPT&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Agentic troubleshooting for cloud-native — now a CNCF Sandbox project&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/project-dalec/dalec"&gt;Dalec&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Declarative container image builds with SBOM generation — fewer CVEs at the build stage&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The direction is clear: your .NET API, your Semantic Kernel orchestration layer, and your inference workloads should all run on one consistent platform model. We&amp;rsquo;re getting there.&lt;/p&gt;
&lt;h2 id="where-id-start-this-week"&gt;Where I&amp;rsquo;d start this week&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;re evaluating these changes for your team, here&amp;rsquo;s my honest priority list:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Observability first&lt;/strong&gt; — enable GPU metrics and network flow logs in a non-prod cluster. See what you&amp;rsquo;ve been missing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Try blue-green upgrades&lt;/strong&gt; — test the rollback workflow before your next production cluster upgrade. Build confidence in the process.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pilot identity-aware networking&lt;/strong&gt; — pick one internal service path and enable mTLS with Cilium. Measure the overhead (spoiler: it&amp;rsquo;s minimal).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Evaluate Fleet Manager&lt;/strong&gt; — if you run more than two clusters, cross-cluster networking pays for itself in reduced custom glue.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Small experiments, fast feedback. That&amp;rsquo;s always the move.&lt;/p&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;KubeCon announcements can be overwhelming, but this batch genuinely moves the needle for .NET teams on AKS. Better networking security without mesh overhead, real GPU observability, safer upgrades, and stronger AI infrastructure foundations.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re already on AKS, this is a great moment to tighten your operational baseline. And if you&amp;rsquo;re planning to move .NET workloads to Kubernetes — the platform just got significantly more production-ready.&lt;/p&gt;</content:encoded></item><item><title>SQL MCP Server, Copilot in SSMS, and a Database Hub with AI Agents: What Actually Matters from SQLCon 2026</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/agentic-ai-microsoft-databases-what-matters/</link><pubDate>Sat, 28 Mar 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/agentic-ai-microsoft-databases-what-matters/</guid><description>Microsoft dropped a stack of database announcements at SQLCon 2026. Here's the stuff that actually matters if you're building AI-powered apps on Azure SQL.</description><content:encoded>&lt;p&gt;Microsoft just kicked off &lt;a href="https://www.microsoft.com/en-us/sql-server/blog/2026/03/18/advancing-agentic-ai-with-microsoft-databases-across-a-unified-data-estate/"&gt;SQLCon 2026 alongside FabCon in Atlanta&lt;/a&gt;, and there&amp;rsquo;s a lot to unpack. The original announcement covers everything from savings plans to enterprise compliance features. I&amp;rsquo;m going to skip the enterprise pricing slides and focus on the pieces that matter if you&amp;rsquo;re a developer building things with Azure SQL and AI.&lt;/p&gt;
&lt;h2 id="sql-mcp-server-is-in-public-preview"&gt;SQL MCP Server is in public preview&lt;/h2&gt;
&lt;p&gt;This is the headline for me. Azure SQL Database Hyperscale now has a &lt;strong&gt;SQL MCP Server&lt;/strong&gt; in public preview that lets you securely connect your SQL data to AI agents and Copilots using the &lt;a href="https://modelcontextprotocol.io/"&gt;Model Context Protocol&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;ve been following the MCP wave — and honestly, it&amp;rsquo;s hard to miss right now — this is a big deal. Instead of building custom data pipelines to feed your AI agents context from your database, you get a standardized protocol to expose SQL data directly. Your agents can query, reason over, and act on live database information.&lt;/p&gt;
&lt;p&gt;For those of us building AI agents with Semantic Kernel or the Microsoft Agent Framework, this opens up a clean integration path. Your agent needs to check inventory? Look up a customer record? Validate an order? MCP gives it a structured way to do that without you writing bespoke data-fetching code for every scenario.&lt;/p&gt;
&lt;h2 id="github-copilot-in-ssms-22-is-now-ga"&gt;GitHub Copilot in SSMS 22 is now GA&lt;/h2&gt;
&lt;p&gt;If you spend any time in SQL Server Management Studio — and let&amp;rsquo;s be honest, most of us still do — GitHub Copilot is now generally available in SSMS 22. Same Copilot experience you already use in VS Code and Visual Studio, but for T-SQL.&lt;/p&gt;
&lt;p&gt;The practical value here is straightforward: chat-based assistance for writing queries, refactoring stored procedures, troubleshooting performance issues, and handling admin tasks. Nothing revolutionary in concept, but having it right there in SSMS means you don&amp;rsquo;t need to context-switch to another editor just to get AI help with your database work.&lt;/p&gt;
&lt;h2 id="vector-indexes-got-a-serious-upgrade"&gt;Vector indexes got a serious upgrade&lt;/h2&gt;
&lt;p&gt;Azure SQL Database now has faster, more capable vector indexes with full insert, update, and delete support. That means your vector data stays current in real time — no batch reindexing needed.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s what&amp;rsquo;s new:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Quantization&lt;/strong&gt; for smaller index sizes without losing too much accuracy&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Iterative filtering&lt;/strong&gt; for more precise results&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tighter query optimizer integration&lt;/strong&gt; for predictable performance&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you&amp;rsquo;re doing retrieval-augmented generation (RAG) with Azure SQL as your vector store, these improvements are directly useful. You can keep your vectors alongside your relational data in the same database, which simplifies your architecture significantly compared to running a separate vector database.&lt;/p&gt;
&lt;p&gt;The same vector enhancements are also available in SQL database in Fabric, since both run on the same SQL engine underneath.&lt;/p&gt;
&lt;h2 id="database-hub-in-fabric-agentic-management"&gt;Database Hub in Fabric: agentic management&lt;/h2&gt;
&lt;p&gt;This one is more forward-looking, but it&amp;rsquo;s interesting. Microsoft announced the &lt;strong&gt;Database Hub in Microsoft Fabric&lt;/strong&gt; (early access), which gives you a single pane of glass across Azure SQL, Cosmos DB, PostgreSQL, MySQL, and SQL Server via Arc.&lt;/p&gt;
&lt;p&gt;The interesting angle isn&amp;rsquo;t just the unified view — it&amp;rsquo;s the agentic approach to management. AI agents continuously monitor your database estate, surface what changed, explain why it matters, and suggest what to do next. It&amp;rsquo;s a human-in-the-loop model where the agent does the legwork and you make the calls.&lt;/p&gt;
&lt;p&gt;For teams managing more than a handful of databases, this could genuinely reduce the operational noise. Instead of jumping between portals and manually checking metrics, the agent brings the signal to you.&lt;/p&gt;
&lt;h2 id="what-this-means-for-net-developers"&gt;What this means for .NET developers&lt;/h2&gt;
&lt;p&gt;The thread connecting all these announcements is clear: Microsoft is embedding AI agents at every layer of the database stack. Not as a gimmick, but as a practical tooling layer.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re building .NET apps backed by Azure SQL, here&amp;rsquo;s what I&amp;rsquo;d actually do:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Try the SQL MCP Server&lt;/strong&gt; if you&amp;rsquo;re building AI agents. It&amp;rsquo;s the cleanest way to give your agents database access without custom plumbing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enable Copilot in SSMS&lt;/strong&gt; if you haven&amp;rsquo;t already — free productivity win for daily SQL work.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Look into vector indexes&lt;/strong&gt; if you&amp;rsquo;re doing RAG and currently running a separate vector store. Consolidating to Azure SQL means one less service to manage.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;The full announcement has more — savings plans, migration assistants, compliance features — but the developer story is in the MCP Server, the vector improvements, and the agentic management layer. These are the pieces that change how you build, not just how you budget.&lt;/p&gt;
&lt;p&gt;Check out the &lt;a href="https://www.microsoft.com/en-us/sql-server/blog/2026/03/18/advancing-agentic-ai-with-microsoft-databases-across-a-unified-data-estate/"&gt;full announcement from Shireesh Thota&lt;/a&gt; for the complete picture, and &lt;a href="https://aka.ms/database-hub"&gt;sign up for the Database Hub early access&lt;/a&gt; if you want to try the new management experience.&lt;/p&gt;</content:encoded></item><item><title>Azure DevOps MCP Server Lands in Microsoft Foundry: What This Means for Your AI Agents</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/azure-devops-mcp-server-microsoft-foundry/</link><pubDate>Thu, 26 Mar 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/azure-devops-mcp-server-microsoft-foundry/</guid><description>The Azure DevOps MCP Server is now available in Microsoft Foundry. Connect your AI agents directly to DevOps workflows — work items, repos, pipelines — with a few clicks.</description><content:encoded>&lt;p&gt;MCP (Model Context Protocol) has been having a moment. If you&amp;rsquo;ve been following the AI agent ecosystem, you&amp;rsquo;ve probably noticed MCP servers popping up everywhere — giving agents the ability to interact with external tools and services through a standardized protocol.&lt;/p&gt;
&lt;p&gt;Now the &lt;a href="https://devblogs.microsoft.com/devops/remote-mcp-server-preview-in-microsoft-foundry/"&gt;Azure DevOps MCP Server is available in Microsoft Foundry&lt;/a&gt;, and this is one of those integrations that makes you think about the practical possibilities.&lt;/p&gt;
&lt;h2 id="whats-actually-happening-here"&gt;What&amp;rsquo;s actually happening here&lt;/h2&gt;
&lt;p&gt;Microsoft already released the Azure DevOps MCP Server as a &lt;a href="https://devblogs.microsoft.com/devops/azure-devops-remote-mcp-server-public-preview"&gt;public preview&lt;/a&gt; — that&amp;rsquo;s the MCP server itself. What&amp;rsquo;s new is the Foundry integration. You can now add the Azure DevOps MCP Server to your Foundry agents directly from the tool catalog.&lt;/p&gt;
&lt;p&gt;For those not familiar with Foundry yet: it&amp;rsquo;s Microsoft&amp;rsquo;s unified platform for building and managing AI-powered applications and agents at scale. Model access, orchestration, evaluation, deployment — all in one place.&lt;/p&gt;
&lt;h2 id="setting-it-up"&gt;Setting it up&lt;/h2&gt;
&lt;p&gt;The setup is surprisingly straightforward:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;In your Foundry agent, go to &lt;strong&gt;Add Tools&lt;/strong&gt; &amp;gt; &lt;strong&gt;Catalog&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Search for &amp;ldquo;Azure DevOps&amp;rdquo;&lt;/li&gt;
&lt;li&gt;Select the Azure DevOps MCP Server (preview) and click &lt;strong&gt;Create&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Enter your organization name and connect&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That&amp;rsquo;s it. Your agent now has access to Azure DevOps tools.&lt;/p&gt;
&lt;h2 id="controlling-what-your-agent-can-access"&gt;Controlling what your agent can access&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s the part I appreciate: you&amp;rsquo;re not stuck with an all-or-nothing approach. You can specify which tools are available to your agent. So if you only want it to read work items but not touch pipelines, you can configure that. Principle of least privilege, applied to your AI agents.&lt;/p&gt;
&lt;p&gt;This matters for enterprise scenarios where you don&amp;rsquo;t want an agent accidentally triggering a deployment pipeline because someone asked it to &amp;ldquo;help with the release.&amp;rdquo;&lt;/p&gt;
&lt;h2 id="why-this-is-interesting-for-net-teams"&gt;Why this is interesting for .NET teams&lt;/h2&gt;
&lt;p&gt;Think about what this enables in practice:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Sprint planning assistants&lt;/strong&gt; — agents that can pull work items, analyze velocity data, and suggest sprint capacity&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Code review bots&lt;/strong&gt; — agents that understand your PR context because they can actually read your repos and linked work items&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Incident response&lt;/strong&gt; — agents that can create work items, query recent deployments, and correlate bugs with recent changes&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Developer onboarding&lt;/strong&gt; — &amp;ldquo;What should I work on?&amp;rdquo; gets a real answer backed by actual project data&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For .NET teams already using Azure DevOps for their CI/CD pipelines and project management, having an AI agent that can actually interact with those systems directly is a significant step toward useful automation (not just chatbot-as-a-service).&lt;/p&gt;
&lt;h2 id="the-bigger-mcp-picture"&gt;The bigger MCP picture&lt;/h2&gt;
&lt;p&gt;This is part of a broader trend: MCP servers are becoming the standard way AI agents interact with the outside world. We&amp;rsquo;re seeing them for GitHub, Azure DevOps, databases, SaaS APIs — and Foundry is becoming the hub where these connections all come together.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re building agents in the .NET ecosystem, MCP is worth paying attention to. The protocol is standardized, the tooling is maturing, and the Foundry integration makes it accessible without having to manually wire up server connections.&lt;/p&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;The Azure DevOps MCP Server in Foundry is in preview, so expect it to evolve. But the core workflow is solid: connect, configure tool access, and let your agents work with your DevOps data. If you&amp;rsquo;re already in the Foundry ecosystem, this is a few clicks away. Give it a try and see what workflows you can build.&lt;/p&gt;
&lt;p&gt;Check out the &lt;a href="https://devblogs.microsoft.com/devops/remote-mcp-server-preview-in-microsoft-foundry/"&gt;full announcement&lt;/a&gt; for the step-by-step setup and more details.&lt;/p&gt;</content:encoded></item><item><title>Background Responses in Microsoft Agent Framework: No More Timeout Anxiety</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/background-responses-agent-framework-long-running-tasks/</link><pubDate>Thu, 26 Mar 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/background-responses-agent-framework-long-running-tasks/</guid><description>Microsoft Agent Framework now lets you offload long-running AI tasks with continuation tokens. Here's how background responses work and why they matter for your .NET agents.</description><content:encoded>&lt;p&gt;If you&amp;rsquo;ve built anything with reasoning models like o3 or GPT-5.2, you know the pain. Your agent starts thinking through a complex task, the client sits there waiting, and somewhere between &amp;ldquo;this is fine&amp;rdquo; and &amp;ldquo;did it crash?&amp;rdquo; your connection times out. All that work? Gone.&lt;/p&gt;
&lt;p&gt;Microsoft Agent Framework just shipped &lt;a href="https://devblogs.microsoft.com/agent-framework/handling-long-running-operations-with-background-responses/"&gt;background responses&lt;/a&gt; — and honestly, this is one of those features that should&amp;rsquo;ve existed from day one.&lt;/p&gt;
&lt;h2 id="the-problem-with-blocking-calls"&gt;The problem with blocking calls&lt;/h2&gt;
&lt;p&gt;In a traditional request-response pattern, your client blocks until the agent finishes. That works fine for quick tasks. But when you&amp;rsquo;re asking a reasoning model to do deep research, multi-step analysis, or generate a 20-page report? You&amp;rsquo;re looking at minutes of wall-clock time. During that window:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;HTTP connections can time out&lt;/li&gt;
&lt;li&gt;Network blips kill the entire operation&lt;/li&gt;
&lt;li&gt;Your user stares at a spinner wondering if anything is happening&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Background responses flip this on its head.&lt;/p&gt;
&lt;h2 id="how-continuation-tokens-work"&gt;How continuation tokens work&lt;/h2&gt;
&lt;p&gt;Instead of blocking, you kick off the agent task and get back a &lt;strong&gt;continuation token&lt;/strong&gt;. Think of it like a claim ticket at a repair shop — you don&amp;rsquo;t stand at the counter waiting, you come back when it&amp;rsquo;s ready.&lt;/p&gt;
&lt;p&gt;The flow is straightforward:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Send your request with &lt;code&gt;AllowBackgroundResponses = true&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;If the agent supports background processing, you get a continuation token&lt;/li&gt;
&lt;li&gt;Poll on your schedule until the token comes back &lt;code&gt;null&lt;/code&gt; — that means the result is ready&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Here&amp;rsquo;s the .NET version:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;AIAgent&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;AzureOpenAIClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;https://&amp;lt;myresource&amp;gt;.openai.azure.com&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;DefaultAzureCredential&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetResponsesClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&amp;lt;deployment-name&amp;gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AsAIAgent&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;AgentRunOptions&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;AllowBackgroundResponses&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;AgentSession&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateSessionAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;AgentResponse&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RunAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;Write a detailed market analysis for the Q4 product launch.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Poll until complete&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ContinuationToken&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="n"&gt;not&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TimeSpan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FromSeconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ContinuationToken&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ContinuationToken&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RunAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;If the agent completes immediately (simple tasks, models that don&amp;rsquo;t need background processing), no continuation token is returned. Your code just works — no special handling needed.&lt;/p&gt;
&lt;h2 id="streaming-with-resume-the-real-magic"&gt;Streaming with resume: the real magic&lt;/h2&gt;
&lt;p&gt;Polling is fine for fire-and-forget scenarios, but what about when you want real-time progress? Background responses also support streaming with built-in resumption.&lt;/p&gt;
&lt;p&gt;Each streamed update carries its own continuation token. If your connection drops mid-stream, you pick up exactly where you left off:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;AgentRunOptions&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;AllowBackgroundResponses&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;AgentSession&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateSessionAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;AgentResponseUpdate&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;latestUpdate&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RunStreamingAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;Write a detailed market analysis for the Q4 product launch.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;latestUpdate&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Simulate a network interruption&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// Resume from exactly where we left off&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ContinuationToken&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;latestUpdate&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;ContinuationToken&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RunStreamingAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The agent keeps processing server-side regardless of what&amp;rsquo;s happening with your client. That&amp;rsquo;s built-in fault tolerance without you writing retry logic or circuit breakers.&lt;/p&gt;
&lt;h2 id="when-to-actually-use-this"&gt;When to actually use this&lt;/h2&gt;
&lt;p&gt;Not every agent call needs background responses. For quick completions, you&amp;rsquo;re adding complexity for no reason. But here&amp;rsquo;s where they shine:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Complex reasoning tasks&lt;/strong&gt; — multi-step analysis, deep research, anything that makes a reasoning model actually think&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Long content generation&lt;/strong&gt; — detailed reports, multi-part documents, extensive analysis&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Unreliable networks&lt;/strong&gt; — mobile clients, edge deployments, flaky corporate VPNs&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Async UX patterns&lt;/strong&gt; — submit a task, go do something else, come back for results&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For us .NET developers building enterprise apps, that last one is particularly interesting. Think about a Blazor app where a user requests a complex report — you fire off the agent task, show them a progress indicator, and let them keep working. No WebSocket gymnastics, no custom queue infrastructure, just a token and a poll loop.&lt;/p&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;Background responses are available now in both .NET and Python through Microsoft Agent Framework. If you&amp;rsquo;re building agents that do anything more complex than simple Q&amp;amp;A, this is worth adding to your toolkit. The continuation token pattern keeps things simple while solving a very real production problem.&lt;/p&gt;
&lt;p&gt;Check out the &lt;a href="https://devblogs.microsoft.com/agent-framework/handling-long-running-operations-with-background-responses/"&gt;full documentation&lt;/a&gt; for the complete API reference and more examples.&lt;/p&gt;</content:encoded></item><item><title>Foundry Agent Service is GA: What Actually Matters for .NET Agent Builders</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/foundry-agent-service-ga-what-matters/</link><pubDate>Thu, 26 Mar 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/foundry-agent-service-ga-what-matters/</guid><description>Microsoft's Foundry Agent Service just hit GA with private networking, Voice Live, production evaluations, and an open multi-model runtime. Here's what you need to know.</description><content:encoded>&lt;p&gt;Let&amp;rsquo;s be honest — building an AI agent prototype is the easy part. The hard part is everything after: getting it into production with proper network isolation, running evaluations that actually mean something, handling compliance requirements, and not breaking things at 2 AM.&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://devblogs.microsoft.com/foundry/foundry-agent-service-ga/"&gt;Foundry Agent Service just went GA&lt;/a&gt;, and this release is laser-focused on that &amp;ldquo;everything after&amp;rdquo; gap.&lt;/p&gt;
&lt;h2 id="built-on-the-responses-api"&gt;Built on the Responses API&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s the headline: the next-gen Foundry Agent Service is built on the OpenAI Responses API. If you&amp;rsquo;re already building with that wire protocol, migrating to Foundry is minimal code changes. What you gain: enterprise security, private networking, Entra RBAC, full tracing, and evaluation — on top of your existing agent logic.&lt;/p&gt;
&lt;p&gt;The architecture is intentionally open. You&amp;rsquo;re not locked to one model provider or one orchestration framework. Use DeepSeek for planning, OpenAI for generation, LangGraph for orchestration — the runtime handles the consistency layer.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;azure.ai.projects&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AIProjectClient&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;azure.ai.projects.models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;PromptAgentDefinition&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;DefaultAzureCredential&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;credential&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;AIProjectClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;AZURE_AI_PROJECT_ENDPOINT&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;credential&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;credential&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;project_client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;project_client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_openai_client&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;openai_client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;project_client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;agents&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_version&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;agent_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;my-enterprise-agent&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;definition&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;PromptAgentDefinition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;AZURE_AI_MODEL_DEPLOYMENT_NAME&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;instructions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;You are a helpful assistant.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;conversation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;openai_client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;conversations&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;openai_client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;responses&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;conversation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;conversation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;What are best practices for building AI agents?&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;extra_body&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;agent_reference&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;agent_reference&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;output_text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;If you&amp;rsquo;re coming from the &lt;code&gt;azure-ai-agents&lt;/code&gt; package, agents are now first-class operations on &lt;code&gt;AIProjectClient&lt;/code&gt; in &lt;code&gt;azure-ai-projects&lt;/code&gt;. Drop the standalone pin and use &lt;code&gt;get_openai_client()&lt;/code&gt; to drive responses.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="private-networking-the-enterprise-blocker-removed"&gt;Private networking: the enterprise blocker removed&lt;/h2&gt;
&lt;p&gt;This is the feature that unblocks enterprise adoption. Foundry now supports full end-to-end private networking with BYO VNet:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;No public egress&lt;/strong&gt; — agent traffic never touches the public internet&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Container/subnet injection&lt;/strong&gt; into your network for local communication&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tool connectivity included&lt;/strong&gt; — MCP servers, Azure AI Search, Fabric data agents all operate over private paths&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That last point is critical. It&amp;rsquo;s not just inference calls that stay private — every tool invocation and retrieval call stays inside your network boundary too. For teams operating under data classification policies that prohibit external routing, this is what was missing.&lt;/p&gt;
&lt;h2 id="mcp-authentication-done-right"&gt;MCP authentication done right&lt;/h2&gt;
&lt;p&gt;MCP server connections now support the full spectrum of auth patterns:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Auth method&lt;/th&gt;
&lt;th&gt;When to use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Key-based&lt;/td&gt;
&lt;td&gt;Simple shared access for org-wide internal tools&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Entra Agent Identity&lt;/td&gt;
&lt;td&gt;Service-to-service; the agent authenticates as itself&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Entra Managed Identity&lt;/td&gt;
&lt;td&gt;Per-project isolation; no credential management&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OAuth Identity Passthrough&lt;/td&gt;
&lt;td&gt;User-delegated access; agent acts on behalf of users&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;OAuth Identity Passthrough is the interesting one. When users need to grant an agent access to their personal data — their OneDrive, their Salesforce org, a SaaS API scoped by user — the agent acts on their behalf with standard OAuth flows. No shared system identity pretending to be everyone.&lt;/p&gt;
&lt;h2 id="voice-live-speech-to-speech-without-the-plumbing"&gt;Voice Live: speech-to-speech without the plumbing&lt;/h2&gt;
&lt;p&gt;Adding voice to an agent used to mean stitching together STT, LLM, and TTS — three services, three latency hops, three billing surfaces, all synchronized by hand. &lt;strong&gt;Voice Live&lt;/strong&gt; collapses that into a single managed API with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Semantic voice activity and end-of-turn detection (understands meaning, not just silence)&lt;/li&gt;
&lt;li&gt;Server-side noise suppression and echo cancellation&lt;/li&gt;
&lt;li&gt;Barge-in support (users can interrupt mid-response)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Voice interactions go through the same agent runtime as text. Same evaluators, same traces, same cost visibility. For customer support, field service, or accessibility scenarios, this replaces what previously required a custom audio pipeline.&lt;/p&gt;
&lt;h2 id="evaluations-from-checkbox-to-continuous-monitoring"&gt;Evaluations: from checkbox to continuous monitoring&lt;/h2&gt;
&lt;p&gt;This is where Foundry gets serious about production quality. The evaluation system now has three layers:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Out-of-the-box evaluators&lt;/strong&gt; — coherence, relevance, groundedness, retrieval quality, safety. Connect to a dataset or live traffic and get scores back.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Custom evaluators&lt;/strong&gt; — encode your own business logic, tone standards, and domain-specific compliance rules.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Continuous evaluation&lt;/strong&gt; — Foundry samples live production traffic, runs your evaluator suite, and surfaces results through dashboards. Set Azure Monitor alerts for when groundedness drops or safety thresholds breach.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Everything publishes to Azure Monitor Application Insights. Agent quality, infrastructure health, cost, and app telemetry — all in one place.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;eval_object&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;openai_client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;evals&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Agent Quality Evaluation&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;data_source_config&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;DataSourceConfigCustom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;custom&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;item_schema&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;object&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;properties&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;query&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;string&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;}},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;required&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;query&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;include_sample_schema&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;),&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;testing_criteria&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;azure_ai_evaluator&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;fluency&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;evaluator_name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;builtin.fluency&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;initialization_parameters&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;deployment_name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;AZURE_AI_MODEL_DEPLOYMENT_NAME&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;data_mapping&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;query&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;{{item.query}}&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;response&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;{{sample.output_text}}&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="six-new-regions-for-hosted-agents"&gt;Six new regions for hosted agents&lt;/h2&gt;
&lt;p&gt;Hosted agents are now available in East US, North Central US, Sweden Central, Southeast Asia, Japan East, and more. This matters for data residency requirements and for compressing latency when your agent runs close to its data sources.&lt;/p&gt;
&lt;h2 id="why-this-matters-for-net-developers"&gt;Why this matters for .NET developers&lt;/h2&gt;
&lt;p&gt;Even though the code samples in the GA announcement are Python-first, the underlying infrastructure is language-agnostic — and the .NET SDK for &lt;code&gt;azure-ai-projects&lt;/code&gt; follows the same patterns. The Responses API, the evaluation framework, the private networking, the MCP auth — all of this is available from .NET.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;ve been waiting for AI agents to go from &amp;ldquo;cool demo&amp;rdquo; to &amp;ldquo;I can actually ship this at work,&amp;rdquo; this GA release is the signal. Private networking, proper auth, continuous evaluation, and production monitoring are the pieces that were missing.&lt;/p&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;Foundry Agent Service is available now. Install the SDK, open &lt;a href="https://ai.azure.com"&gt;the portal&lt;/a&gt;, and start building. The &lt;a href="https://learn.microsoft.com/azure/foundry/quickstarts/get-started-code"&gt;quickstart guide&lt;/a&gt; takes you from zero to a running agent in minutes.&lt;/p&gt;
&lt;p&gt;For the full technical deep-dive with all code samples, check the &lt;a href="https://devblogs.microsoft.com/foundry/foundry-agent-service-ga/"&gt;GA announcement&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title>From Laptop to Production: Deploying AI Agents to Microsoft Foundry with Two Commands</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/deploy-ai-agents-foundry-azd-two-commands/</link><pubDate>Thu, 26 Mar 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/deploy-ai-agents-foundry-azd-two-commands/</guid><description>The Azure Developer CLI now has 'azd ai agent' commands that take your AI agent from local dev to a live Foundry endpoint in minutes. Here's the full workflow.</description><content:encoded>&lt;p&gt;You know that gap between &amp;ldquo;it works on my machine&amp;rdquo; and &amp;ldquo;it&amp;rsquo;s deployed and serving traffic&amp;rdquo;? For AI agents, that gap has been painfully wide. You need to provision resources, deploy models, wire up identity, set up monitoring — and that&amp;rsquo;s before anyone can actually call your agent.&lt;/p&gt;
&lt;p&gt;The Azure Developer CLI just made this a &lt;a href="https://devblogs.microsoft.com/azure-sdk/azd-ai-agent-end-to-end/"&gt;two-command affair&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="the-new-azd-ai-agent-workflow"&gt;The new &lt;code&gt;azd ai agent&lt;/code&gt; workflow&lt;/h2&gt;
&lt;p&gt;Let me walk through what this actually looks like. You have an AI agent project — let&amp;rsquo;s say a hotel concierge agent. It works locally. You want it running on Microsoft Foundry.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;azd ai agent init
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;azd up
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s it. Two commands. &lt;code&gt;azd ai agent init&lt;/code&gt; scaffolds the infrastructure-as-code in your repo, and &lt;code&gt;azd up&lt;/code&gt; provisions everything on Azure and publishes your agent. You get a direct link to your agent in the Foundry portal.&lt;/p&gt;
&lt;h2 id="what-happens-under-the-hood"&gt;What happens under the hood&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;init&lt;/code&gt; command generates real, inspectable Bicep templates in your repo:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;Foundry Resource&lt;/strong&gt; (top-level container)&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;Foundry Project&lt;/strong&gt; (where your agent lives)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Model deployment&lt;/strong&gt; configuration (GPT-4o, etc.)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Managed identity&lt;/strong&gt; with proper RBAC role assignments&lt;/li&gt;
&lt;li&gt;&lt;code&gt;azure.yaml&lt;/code&gt; for the service map&lt;/li&gt;
&lt;li&gt;&lt;code&gt;agent.yaml&lt;/code&gt; with agent metadata and environment variables&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&amp;rsquo;s the key part: you own all of this. It&amp;rsquo;s versioned Bicep in your repo. You can inspect it, customize it, and commit it alongside your agent code. No magic black boxes.&lt;/p&gt;
&lt;h2 id="the-dev-inner-loop"&gt;The dev inner loop&lt;/h2&gt;
&lt;p&gt;What I really like is the local development story. When you&amp;rsquo;re iterating on agent logic, you don&amp;rsquo;t want to redeploy every time you change a prompt:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;azd ai agent run
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This starts your agent locally. Pair it with &lt;code&gt;azd ai agent invoke&lt;/code&gt; to send test prompts, and you&amp;rsquo;ve got a tight feedback loop. Edit code, restart, invoke, repeat.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;invoke&lt;/code&gt; command is smart about routing too — when a local agent is running, it targets that automatically. When it&amp;rsquo;s not, it hits the remote endpoint.&lt;/p&gt;
&lt;h2 id="real-time-monitoring"&gt;Real-time monitoring&lt;/h2&gt;
&lt;p&gt;This is the feature that sold me. Once your agent is deployed:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;azd ai agent monitor --follow
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Every request and response flowing through your agent streams to your terminal in real time. For debugging production issues, this is invaluable. No digging through log analytics, no waiting for metrics to aggregate — you see what&amp;rsquo;s happening right now.&lt;/p&gt;
&lt;h2 id="the-full-command-set"&gt;The full command set&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s the quick reference:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;azd ai agent init&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Scaffold a Foundry agent project with IaC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;azd up&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Provision Azure resources and deploy the agent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;azd ai agent invoke&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Send prompts to the remote or local agent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;azd ai agent run&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Run the agent locally for development&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;azd ai agent monitor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Stream real-time logs from the published agent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;azd ai agent show&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Check agent health and status&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;azd down&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Clean up all Azure resources&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="why-this-matters-for-net-developers"&gt;Why this matters for .NET developers&lt;/h2&gt;
&lt;p&gt;Even though the sample in the announcement is Python-based, the infrastructure story is language-agnostic. Your .NET agent gets the same Bicep scaffolding, the same managed identity setup, the same monitoring pipeline. And if you&amp;rsquo;re already using &lt;code&gt;azd&lt;/code&gt; for your .NET Aspire apps or Azure deployments, this fits right into your existing workflow.&lt;/p&gt;
&lt;p&gt;The deployment gap for AI agents has been one of the biggest friction points in the ecosystem. Going from a working prototype to a production endpoint with proper identity, networking, and monitoring shouldn&amp;rsquo;t require a week of DevOps work. Now it requires two commands and a few minutes.&lt;/p&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;azd ai agent&lt;/code&gt; is available now. If you&amp;rsquo;ve been putting off deploying your AI agents because the infrastructure setup felt like too much work, give this a shot. Check out the &lt;a href="https://devblogs.microsoft.com/azure-sdk/azd-ai-agent-end-to-end/"&gt;full walkthrough&lt;/a&gt; for the complete step-by-step including frontend chat app integration.&lt;/p&gt;</content:encoded></item><item><title>VS Code 1.112: What .NET Developers Should Actually Care About</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/vscode-1-112-dotnet-developers/</link><pubDate>Thu, 26 Mar 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/vscode-1-112-dotnet-developers/</guid><description>VS Code 1.112 just dropped and it's packed with agent upgrades, an integrated browser debugger, MCP sandboxing, and monorepo support. Here's what actually matters if you're building with .NET.</description><content:encoded>&lt;p&gt;VS Code 1.112 just landed, and honestly? This one hits different if you&amp;rsquo;re spending your days in .NET land. There&amp;rsquo;s a lot in the &lt;a href="https://code.visualstudio.com/updates/v1_112"&gt;official release notes&lt;/a&gt;, but let me save you some scrolling and focus on what actually matters for us.&lt;/p&gt;
&lt;h2 id="copilot-cli-just-got-way-more-useful"&gt;Copilot CLI just got way more useful&lt;/h2&gt;
&lt;p&gt;The big theme this release is &lt;strong&gt;agent autonomy&lt;/strong&gt; — giving Copilot more room to do its thing without you babysitting every step.&lt;/p&gt;
&lt;h3 id="message-steering-and-queueing"&gt;Message steering and queueing&lt;/h3&gt;
&lt;p&gt;You know that moment when Copilot CLI is halfway through a task and you realize you forgot to mention something? Before, you had to wait. Now you can just send messages while a request is still running — either to steer the current response or queue up follow-up instructions.&lt;/p&gt;
&lt;p&gt;This is huge for those longer &lt;code&gt;dotnet&lt;/code&gt; scaffolding tasks where you&amp;rsquo;re watching Copilot set up a project and think &amp;ldquo;oh wait, I also need MassTransit in there.&amp;rdquo;&lt;/p&gt;
&lt;h3 id="permission-levels"&gt;Permission levels&lt;/h3&gt;
&lt;p&gt;This is the one I&amp;rsquo;m most excited about. Copilot CLI sessions now support three permission levels:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Default Permissions&lt;/strong&gt; — the usual flow where tools ask for confirmation before running&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bypass Approvals&lt;/strong&gt; — auto-approves everything and retries on errors&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Autopilot&lt;/strong&gt; — goes fully autonomous: approves tools, answers its own questions, and keeps going until the task is done&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you&amp;rsquo;re doing something like scaffolding a new ASP.NET Core API with Entity Framework, migrations, and a Docker setup — Autopilot mode means you describe what you want and go grab a coffee. It&amp;rsquo;ll figure it out.&lt;/p&gt;
&lt;p&gt;You can enable Autopilot with the &lt;code&gt;chat.autopilot.enabled&lt;/code&gt; setting.&lt;/p&gt;
&lt;h3 id="preview-changes-before-delegation"&gt;Preview changes before delegation&lt;/h3&gt;
&lt;p&gt;When you delegate a task to Copilot CLI, it creates a worktree. Before, if you had uncommitted changes, you had to check Source Control to see what would be affected. Now the Chat view shows pending changes right there before you decide whether to copy, move, or ignore them.&lt;/p&gt;
&lt;p&gt;Small thing, but it saves you from that &amp;ldquo;wait, what did I have staged?&amp;rdquo; moment.&lt;/p&gt;
&lt;h2 id="debug-web-apps-without-leaving-vs-code"&gt;Debug web apps without leaving VS Code&lt;/h2&gt;
&lt;p&gt;The integrated browser now supports &lt;strong&gt;full debugging&lt;/strong&gt;. You can set breakpoints, step through code, and inspect variables — all inside VS Code. No more switching to Edge DevTools.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s a new &lt;code&gt;editor-browser&lt;/code&gt; debug type, and if you already have existing &lt;code&gt;msedge&lt;/code&gt; or &lt;code&gt;chrome&lt;/code&gt; launch configurations, migrating is as simple as changing the &lt;code&gt;type&lt;/code&gt; field in your &lt;code&gt;launch.json&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;editor-browser&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;request&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;launch&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Debug Blazor App&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;url&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;https://localhost:5001&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;For Blazor developers, this is a game changer. You&amp;rsquo;re already running &lt;code&gt;dotnet watch&lt;/code&gt; in the terminal — now your debugging stays in the same window too.&lt;/p&gt;
&lt;p&gt;The browser also got independent zoom levels (finally), proper right-click context menus, and the zoom is remembered per website.&lt;/p&gt;
&lt;h2 id="mcp-server-sandboxing"&gt;MCP server sandboxing&lt;/h2&gt;
&lt;p&gt;This one matters more than you might think. If you&amp;rsquo;re using MCP servers — maybe you&amp;rsquo;ve set up a custom one for your Azure resources or database queries — they&amp;rsquo;ve been running with the same permissions as your VS Code process. That means full access to your filesystem, network, everything.&lt;/p&gt;
&lt;p&gt;Now you can sandbox them. In your &lt;code&gt;mcp.json&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;servers&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;my-azure-tools&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;command&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;node&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;args&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;./mcp-server.js&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;sandboxEnabled&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When a sandboxed server needs access to something it doesn&amp;rsquo;t have, VS Code prompts you to grant permission. Much better than the &amp;ldquo;hope nobody does anything weird&amp;rdquo; approach.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Sandboxing is available on macOS and Linux for now. Windows support is coming — remote scenarios like WSL do work though.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="monorepo-customizations-discovery"&gt;Monorepo customizations discovery&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;re working in a monorepo (and let&amp;rsquo;s be honest, many enterprise .NET solutions end up as one), this solves a real pain point.&lt;/p&gt;
&lt;p&gt;Previously, if you opened a subfolder of your repo, VS Code wouldn&amp;rsquo;t find your &lt;code&gt;copilot-instructions.md&lt;/code&gt;, &lt;code&gt;AGENTS.md&lt;/code&gt;, or custom skills sitting at the repository root. Now with the &lt;code&gt;chat.useCustomizationsInParentRepositories&lt;/code&gt; setting, it walks up to the &lt;code&gt;.git&lt;/code&gt; root and discovers everything.&lt;/p&gt;
&lt;p&gt;This means your team can share agent instructions, prompt files, and custom tools across all projects in a monorepo without everyone having to open the root folder.&lt;/p&gt;
&lt;h2 id="troubleshoot-for-agent-debugging"&gt;/troubleshoot for agent debugging&lt;/h2&gt;
&lt;p&gt;Ever set up custom instructions or skills and wonder why they&amp;rsquo;re not being picked up? The new &lt;code&gt;/troubleshoot&lt;/code&gt; skill reads agent debug logs and tells you what happened — which tools were used or skipped, why instructions didn&amp;rsquo;t load, and what&amp;rsquo;s causing slow responses.&lt;/p&gt;
&lt;p&gt;Enable it with:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;github.copilot.chat.agentDebugLog.enabled&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;github.copilot.chat.agentDebugLog.fileLogging.enabled&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then just type &lt;code&gt;/troubleshoot why is my custom skill not loading?&lt;/code&gt; in chat.&lt;/p&gt;
&lt;p&gt;You can also export and import these debug logs now, which is great for sharing with your team when something isn&amp;rsquo;t working as expected.&lt;/p&gt;
&lt;h2 id="image-and-binary-file-support"&gt;Image and binary file support&lt;/h2&gt;
&lt;p&gt;Agents can now read image files from disk and binary files natively. The binary files are presented in hexdump format, and image outputs (like screenshots from the integrated browser) show up in a carousel view.&lt;/p&gt;
&lt;p&gt;For .NET developers, think: paste a screenshot of a UI bug into chat and have the agent understand what&amp;rsquo;s wrong, or have it analyze the output of a Blazor component rendering.&lt;/p&gt;
&lt;h2 id="automatic-symbol-references"&gt;Automatic symbol references&lt;/h2&gt;
&lt;p&gt;Small quality-of-life improvement: when you copy a symbol name (a class, method, etc.) and paste it into chat, VS Code now automatically converts it to a &lt;code&gt;#sym:Name&lt;/code&gt; reference. This gives the agent full context about that symbol without you having to manually add it.&lt;/p&gt;
&lt;p&gt;If you want plain text instead, use &lt;code&gt;Ctrl+Shift+V&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="plugins-can-now-be-enableddisabled"&gt;Plugins can now be enabled/disabled&lt;/h2&gt;
&lt;p&gt;Previously, disabling an MCP server or plugin meant uninstalling it. Now you can toggle them on and off — both globally and per-workspace. Right-click in the Extensions view or the Customizations view and you&amp;rsquo;re done.&lt;/p&gt;
&lt;p&gt;Plugins from npm and pypi can also auto-update now, though they&amp;rsquo;ll ask for approval first since updates mean running new code on your machine.&lt;/p&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;VS Code 1.112 is clearly pushing hard on the agent experience — more autonomy, better debugging, tighter security. For .NET developers, the integrated browser debugging and Copilot CLI improvements are the standout features.&lt;/p&gt;
&lt;p&gt;If you haven&amp;rsquo;t tried running a full Copilot CLI session in Autopilot mode for a .NET project yet, this release is a good time to start. Just remember to set your permissions and let it cook.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://code.visualstudio.com/updates/v1_112"&gt;Download VS Code 1.112&lt;/a&gt; or update from within VS Code via &lt;strong&gt;Help &amp;gt; Check for Updates&lt;/strong&gt;.&lt;/p&gt;</content:encoded></item><item><title>Getting Started with Microsoft Agent Framework</title><link>https://thedotnetblog.com/tutorials/emiliano-montesdeoca/getting-started-microsoft-agent-framework/</link><pubDate>Thu, 05 Mar 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/tutorials/emiliano-montesdeoca/getting-started-microsoft-agent-framework/</guid><description>Build your first multi-agent workflow with the Microsoft Agent Framework — orchestrate specialized agents, connect tools, and handle human-in-the-loop approvals in .NET.</description><content:encoded>&lt;p&gt;The Microsoft Agent Framework (MAF) is a .NET SDK for building multi-agent AI systems. Rather than a single &amp;ldquo;do everything&amp;rdquo; prompt, you compose specialized agents — each with their own tools and instructions — and let them hand off work to each other.&lt;/p&gt;
&lt;p&gt;This tutorial walks you through building a simple two-agent system: a &lt;strong&gt;triage agent&lt;/strong&gt; that routes requests and a &lt;strong&gt;resolver agent&lt;/strong&gt; that handles them.&lt;/p&gt;
&lt;h2 id="prerequisites"&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;.NET 8 or later&lt;/li&gt;
&lt;li&gt;NuGet: &lt;code&gt;Microsoft.AI.Agents.Core&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;An Azure OpenAI or OpenAI API key&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="step-1-install-packages"&gt;Step 1: Install packages&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dotnet new console -n AgentDemo
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; AgentDemo
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dotnet add package Microsoft.AI.Agents.Core
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dotnet add package Microsoft.SemanticKernel
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="step-2-define-your-first-agent"&gt;Step 2: Define your first agent&lt;/h2&gt;
&lt;p&gt;Agents are defined with a name, instructions, and a set of tools (Semantic Kernel plugins):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.AI.Agents.Core&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.SemanticKernel&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;kernel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Kernel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateBuilder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddAzureOpenAIChatCompletion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;deploymentName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;gpt-4o&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;endpoint&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetEnvironmentVariable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;AZURE_OPENAI_ENDPOINT&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)!,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetEnvironmentVariable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;AZURE_OPENAI_KEY&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;triageAgent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;ChatCompletionAgent&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;TriageAgent&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Instructions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;You&lt;/span&gt; &lt;span class="n"&gt;are&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;triage&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;Classify&lt;/span&gt; &lt;span class="n"&gt;incoming&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;either&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;billing&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="n"&gt;questions&lt;/span&gt; &lt;span class="n"&gt;about&lt;/span&gt; &lt;span class="n"&gt;invoices&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payments&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;or&lt;/span&gt; &lt;span class="n"&gt;subscriptions&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;technical&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="n"&gt;questions&lt;/span&gt; &lt;span class="n"&gt;about&lt;/span&gt; &lt;span class="n"&gt;bugs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;features&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;or&lt;/span&gt; &lt;span class="n"&gt;how&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt; &lt;span class="n"&gt;works&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Then&lt;/span&gt; &lt;span class="n"&gt;hand&lt;/span&gt; &lt;span class="n"&gt;off&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;appropriate&lt;/span&gt; &lt;span class="n"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;&amp;#34;&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Kernel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kernel&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="step-3-define-the-resolver-agent"&gt;Step 3: Define the resolver agent&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;resolverAgent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;ChatCompletionAgent&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;ResolverAgent&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Instructions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;&amp;#34;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;You&lt;/span&gt; &lt;span class="n"&gt;are&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;support&lt;/span&gt; &lt;span class="n"&gt;resolver&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;You&lt;/span&gt; &lt;span class="n"&gt;receive&lt;/span&gt; &lt;span class="n"&gt;pre&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="n"&gt;triaged&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt; &lt;span class="n"&gt;and&lt;/span&gt; &lt;span class="n"&gt;provide&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;clear&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;concise&lt;/span&gt; &lt;span class="n"&gt;answers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="n"&gt;Always&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;confirmation&lt;/span&gt; &lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;&amp;#34;&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Kernel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;kernel&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="step-4-set-up-handoff-topology"&gt;Step 4: Set up handoff topology&lt;/h2&gt;
&lt;p&gt;MAF&amp;rsquo;s &lt;code&gt;HandoffBuilder&lt;/code&gt; lets you declare a routing graph between agents:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;chat&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;AgentGroupChat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;triageAgent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resolverAgent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ExecutionSettings&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;AgentGroupChatSettings&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;TerminationStrategy&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;ApprovalTerminationStrategy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="step-5-run-the-workflow"&gt;Step 5: Run the workflow&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddChatMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;ChatMessageContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;AuthorRole&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;My invoice from last month looks wrong — I was charged twice.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InvokeAsync&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$&amp;#34;[{response.AuthorName}]: {response.Content}&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;MAF will call the triage agent first, which classifies the issue as &amp;ldquo;billing&amp;rdquo; and hands off to the resolver agent. You&amp;rsquo;ll see each agent&amp;rsquo;s turn in the output.&lt;/p&gt;
&lt;h2 id="what-to-explore-next"&gt;What to explore next&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tool calling&lt;/strong&gt; — give agents access to APIs, databases, or file systems via SK plugins&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Human-in-the-loop&lt;/strong&gt; — use &lt;code&gt;ApprovalTerminationStrategy&lt;/code&gt; to pause for human confirmation before high-risk actions&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AG-UI integration&lt;/strong&gt; — stream agent events to a frontend using the AG-UI protocol for real-time visibility&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Observability&lt;/strong&gt; — connect to Azure Monitor or OpenTelemetry to trace agent decisions&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;a href="https://devblogs.microsoft.com/agent-framework/"&gt;MAF documentation&lt;/a&gt; and samples on GitHub cover production patterns including state persistence and long-running workflows.&lt;/p&gt;</content:encoded></item><item><title>Getting Started with Semantic Kernel</title><link>https://thedotnetblog.com/tutorials/emiliano-montesdeoca/getting-started-semantic-kernel/</link><pubDate>Tue, 10 Feb 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/tutorials/emiliano-montesdeoca/getting-started-semantic-kernel/</guid><description>A practical first look at Semantic Kernel — the open-source SDK from Microsoft for building AI-powered .NET applications with LLMs, plugins, and memory.</description><content:encoded>&lt;p&gt;Semantic Kernel (SK) is Microsoft&amp;rsquo;s open-source SDK for building AI orchestration into .NET (and Python/Java) applications. It&amp;rsquo;s the layer between your app code and LLMs: it handles prompts, plugins, memory, and multi-step planning so you don&amp;rsquo;t have to wire everything together manually.&lt;/p&gt;
&lt;p&gt;This tutorial gets you from zero to a working SK-powered console app that calls an LLM and uses a plugin.&lt;/p&gt;
&lt;h2 id="prerequisites"&gt;Prerequisites&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;.NET 8 or later&lt;/li&gt;
&lt;li&gt;An OpenAI API key or an Azure OpenAI deployment&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="step-1-install-the-sdk"&gt;Step 1: Install the SDK&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dotnet new console -n SkDemo
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; SkDemo
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dotnet add package Microsoft.SemanticKernel
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="step-2-set-up-the-kernel"&gt;Step 2: Set up the kernel&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;Kernel&lt;/code&gt; is the central object in SK. You configure it with an AI service (OpenAI, Azure OpenAI, or a local model):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.SemanticKernel&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Kernel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateBuilder&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddOpenAIChatCompletion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;modelId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;gpt-4o-mini&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetEnvironmentVariable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;OPENAI_API_KEY&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Kernel&lt;/span&gt; &lt;span class="n"&gt;kernel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="step-3-invoke-a-prompt"&gt;Step 3: Invoke a prompt&lt;/h2&gt;
&lt;p&gt;The simplest thing SK does: send a prompt to the LLM and get a response.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;kernel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InvokePromptAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;Summarize the key features of .NET 10 in three bullet points.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s it for the basics. But SK&amp;rsquo;s real power is in &lt;strong&gt;plugins&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id="step-4-create-a-plugin"&gt;Step 4: Create a plugin&lt;/h2&gt;
&lt;p&gt;A plugin is a C# class whose methods SK can call as tools. Here&amp;rsquo;s a simple one:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.ComponentModel&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.SemanticKernel&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DatePlugin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt; [KernelFunction, Description(&amp;#34;Returns the current date and time.&amp;#34;)]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;GetCurrentDate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UtcNow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;R&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Register it with the kernel:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;kernel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ImportPluginFromObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;DatePlugin&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="step-5-let-the-kernel-call-the-plugin"&gt;Step 5: Let the kernel call the plugin&lt;/h2&gt;
&lt;p&gt;Enable automatic function calling so the LLM can invoke plugins when needed:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;OpenAIPromptExecutionSettings&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;ToolCallBehavior&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ToolCallBehavior&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AutoInvokeKernelFunctions&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;kernel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InvokePromptAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s"&gt;&amp;#34;What is today&amp;#39;s date? Format it nicely.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;KernelArguments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The model will call &lt;code&gt;GetCurrentDate()&lt;/code&gt; automatically and incorporate the result into its response.&lt;/p&gt;
&lt;h2 id="what-to-explore-next"&gt;What to explore next&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Planners&lt;/strong&gt; — have SK break a complex task into steps and execute them&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Memory&lt;/strong&gt; — add semantic search over your documents using embeddings&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Agents&lt;/strong&gt; — build multi-agent workflows using the &lt;code&gt;AgentGroupChat&lt;/code&gt; API&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;a href="https://github.com/microsoft/semantic-kernel"&gt;Semantic Kernel repo on GitHub&lt;/a&gt; has a rich set of samples in &lt;code&gt;dotnet/samples/&lt;/code&gt; covering all of these scenarios.&lt;/p&gt;</content:encoded></item></channel></rss>