<?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>Azure | The .NET Blog</title><link>https://thedotnetblog.com/tags/azure/</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>Tue, 02 Jun 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://thedotnetblog.com/tags/azure/index.xml" rel="self" type="application/rss+xml"/><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>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>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>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>Private Endpoints, VNets, NSGs — Aspire Handles the Networking Now</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/aspire-azure-enterprise-networking-private-endpoints/</link><pubDate>Tue, 19 May 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/aspire-azure-enterprise-networking-private-endpoints/</guid><description>Aspire's new Azure enterprise networking support lets you model VNets, private endpoints, NAT gateways, NSGs, and Network Security Perimeters directly in your AppHost — no infrastructure drift required.</description><content:encoded>&lt;p&gt;Here&amp;rsquo;s a scenario I&amp;rsquo;ve seen too many times. The app is done. The demo is great. Then the security checklist shows up: take storage off the public internet, run inside a VNet, provide outbound IPs for the partner allowlist, prove that only the right subnets talk to the right services.&lt;/p&gt;
&lt;p&gt;At that point the application model and the infrastructure model start drifting apart in ways that are painful to maintain.&lt;/p&gt;
&lt;p&gt;Aspire&amp;rsquo;s new Azure enterprise networking support addresses this directly. You describe the network shape next to the resources that use it, in your AppHost.&lt;/p&gt;
&lt;h2 id="the-building-blocks"&gt;The Building Blocks&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s what each Azure networking concept is for, distilled:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Use it when&lt;/th&gt;
&lt;th&gt;Why it matters&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Virtual network&lt;/td&gt;
&lt;td&gt;You need a private address space&lt;/td&gt;
&lt;td&gt;The network boundary for subnets, private endpoints, and routing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Subnet&lt;/td&gt;
&lt;td&gt;You need to separate workloads inside the VNet&lt;/td&gt;
&lt;td&gt;Each part of the system gets its own address range and policy surface&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Delegated subnet&lt;/td&gt;
&lt;td&gt;A platform service (like ACA) needs to manage a subnet&lt;/td&gt;
&lt;td&gt;Lets the service place managed infrastructure in your VNet safely&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NAT gateway&lt;/td&gt;
&lt;td&gt;You need predictable outbound public IPs&lt;/td&gt;
&lt;td&gt;Stable address for allowlists and auditing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Private endpoint&lt;/td&gt;
&lt;td&gt;You want a PaaS resource reachable privately&lt;/td&gt;
&lt;td&gt;Puts a private IP for that service inside your VNet, removes public exposure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NSG&lt;/td&gt;
&lt;td&gt;You need subnet-level traffic rules&lt;/td&gt;
&lt;td&gt;Explicit allow/deny for inbound and outbound traffic per subnet&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="describing-it-in-your-apphost"&gt;Describing It in Your AppHost&lt;/h2&gt;
&lt;p&gt;The key shift here is that you&amp;rsquo;re modeling the network &lt;em&gt;alongside&lt;/em&gt; the resources that use it, not in a separate Bicep file that drifts away from the app model over time.&lt;/p&gt;
&lt;p&gt;From the AppHost, you can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create VNets and subnets with &lt;code&gt;AddVirtualNetwork()&lt;/code&gt; and &lt;code&gt;AddSubnet()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Attach a NAT gateway to subnets for stable outbound IPs&lt;/li&gt;
&lt;li&gt;Create private endpoints for storage, Key Vault, SQL, and other PaaS services&lt;/li&gt;
&lt;li&gt;Define NSGs with inbound and outbound security rules&lt;/li&gt;
&lt;li&gt;Configure Network Security Perimeters for cross-resource policies&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The result is that when you run &lt;code&gt;azd up&lt;/code&gt;, the infrastructure matches what the app model says it needs. Not what a manually maintained template says.&lt;/p&gt;
&lt;h2 id="why-this-matters-for-real-applications"&gt;Why This Matters for Real Applications&lt;/h2&gt;
&lt;p&gt;A few things that become significantly easier once the network is modeled in Aspire:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Private endpoints for Key Vault and storage&lt;/strong&gt; — you describe &lt;code&gt;WithPrivateEndpoint()&lt;/code&gt; on those resources, and Aspire handles the DNS zone configuration and endpoint attachment. The app never changes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Consistent outbound IPs&lt;/strong&gt; — add a NAT gateway to the relevant subnet and every outbound request from your app goes through a known, stable IP. Partners can allowlist it. Auditors can trace it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NSG rules from code&lt;/strong&gt; — instead of clicking through the portal or maintaining a Bicep snippet, your security rules live in the AppHost alongside the resources they protect.&lt;/p&gt;
&lt;p&gt;This is the kind of integration that doesn&amp;rsquo;t make demos exciting but makes production systems maintainable.&lt;/p&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;Network security showing up late in the project lifecycle is a solved problem if you model it alongside the app from the start. Aspire&amp;rsquo;s enterprise networking support makes that possible without requiring a separate infrastructure track.&lt;/p&gt;
&lt;p&gt;Full details in the original post: &lt;a href="https://devblogs.microsoft.com/aspire/aspire-azure-enterprise-networking/"&gt;Securing Azure apps with Aspire enterprise networking&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>Removing the Monkey Work of Migration with Agentic Platform Engineering</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/agentic-platform-engineering-migration-automation/</link><pubDate>Tue, 05 May 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/agentic-platform-engineering-migration-automation/</guid><description>Git-Ape walks through migrating a real AWS Terraform deployment to Azure Bicep — extracting deployment intent and remapping architecture rather than doing a 1:1 syntax conversion.</description><content:encoded>&lt;p&gt;&lt;a href="https://devblogs.microsoft.com/all-things-azure/removing-the-monkey-work-of-migration-using-agentic-platform-engineering/"&gt;Removing the Monkey Work of Migration with Agentic Platform Engineering&lt;/a&gt; — a walkthrough of Git-Ape (git agentic platform engineering tool) migrating a real AWS Terraform repo to Azure, focusing on intent extraction rather than line-by-line conversion.&lt;/p&gt;
&lt;h2 id="the-input-contoso-migration"&gt;The input: contoso-migration&lt;/h2&gt;
&lt;p&gt;The source is a real Terraform project (&lt;code&gt;contoso-migration&lt;/code&gt;) that deploys a Next.js app on AWS — EC2 for compute, ALB for load balancing, S3 for artifacts, and IAM keys for identity. Cost: ~$34/month. The goal isn&amp;rsquo;t to reproduce the same infrastructure on Azure; it&amp;rsquo;s to figure out what the deployment is actually trying to do and rebuild that on Azure-native services.&lt;/p&gt;
&lt;h2 id="step-1-validation-and-auth"&gt;Step 1: Validation and auth&lt;/h2&gt;
&lt;p&gt;Git-Ape starts by validating all required CLI tools — &lt;code&gt;az&lt;/code&gt;, &lt;code&gt;aws&lt;/code&gt;, &lt;code&gt;gh&lt;/code&gt;, &lt;code&gt;jq&lt;/code&gt;, &lt;code&gt;git&lt;/code&gt; — and confirming active auth sessions before touching anything. No partial runs.&lt;/p&gt;
&lt;h2 id="step-2-intent-extraction"&gt;Step 2: Intent extraction&lt;/h2&gt;
&lt;p&gt;The agent reads the entire source repo through the GitHub API and extracts the deployment intent: runtime (Node.js), compute type, ingress pattern, artifact handling, identity model, networking, and monitoring. This is the key step — it&amp;rsquo;s building a semantic model of what the deployment does, not what Terraform keywords it uses.&lt;/p&gt;
&lt;h2 id="step-3-service-mapping"&gt;Step 3: Service mapping&lt;/h2&gt;
&lt;p&gt;AWS services get mapped to Azure equivalents:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;EC2 → App Service (Linux, Node 20 LTS)&lt;/li&gt;
&lt;li&gt;ALB → App Service built-in load balancing&lt;/li&gt;
&lt;li&gt;IAM roles/keys → Managed Identity&lt;/li&gt;
&lt;li&gt;Terraform → Bicep + GitHub Actions&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="step-4-critique-agent"&gt;Step 4: Critique agent&lt;/h2&gt;
&lt;p&gt;Before generating output, a critique agent runs and catches two blocking issues:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Build-on-startup anti-pattern&lt;/strong&gt; — the original Terraform was running &lt;code&gt;npm install &amp;amp;&amp;amp; npm run build&lt;/code&gt; on EC2 at startup. Fix: build in CI, deploy a ready artifact.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Unnecessary Blob Storage&lt;/strong&gt; — S3 was used for artifact staging that could be eliminated with proper CI/CD. The critique agent dropped it entirely.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="step-5-generated-output"&gt;Step 5: Generated output&lt;/h2&gt;
&lt;p&gt;The result is ~80 lines of Bicep instead of the original 200+ lines of Terraform. The agent created a new GitHub repo with &lt;code&gt;infra/main.bicep&lt;/code&gt; and &lt;code&gt;.github/workflows/deploy.yml&lt;/code&gt; and removed all AWS-specific files.&lt;/p&gt;
&lt;h2 id="security-posture-comparison"&gt;Security posture comparison&lt;/h2&gt;
&lt;p&gt;The migration also produced a meaningful security upgrade:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;AWS original&lt;/th&gt;
&lt;th&gt;Azure output&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;HTTP only&lt;/td&gt;
&lt;td&gt;HTTPS only, TLS 1.2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSH open to 0.0.0.0/0&lt;/td&gt;
&lt;td&gt;No SSH exposure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IAM access keys&lt;/td&gt;
&lt;td&gt;OIDC + Managed Identity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;No monitoring&lt;/td&gt;
&lt;td&gt;Application Insights&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Cost: ~$13/month vs the original $34/month.&lt;/p&gt;
&lt;h2 id="what-makes-this-different-from-a-syntax-converter"&gt;What makes this different from a syntax converter&lt;/h2&gt;
&lt;p&gt;The critique agent step is what separates this from a mechanical translation. It caught patterns that would have worked on AWS but would be wrong on Azure — and fixed them instead of replicating them. The output isn&amp;rsquo;t &amp;ldquo;AWS in Azure syntax&amp;rdquo;; it&amp;rsquo;s an Azure-native deployment that achieves the same goal more cleanly.&lt;/p&gt;
&lt;p&gt;See the &lt;a href="https://devblogs.microsoft.com/all-things-azure/removing-the-monkey-work-of-migration-using-agentic-platform-engineering/"&gt;full walkthrough&lt;/a&gt; for the complete agent trace and generated files.&lt;/p&gt;</content:encoded></item><item><title>SQL MCP Server on Azure App Service — No Containers Required</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/sql-mcp-server-azure-app-service-no-containers/</link><pubDate>Tue, 05 May 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/sql-mcp-server-azure-app-service-no-containers/</guid><description>The SQL MCP Server can now run on Azure App Service without Docker or Kubernetes. Here's what that means for .NET developers building AI agents that talk to SQL databases.</description><content:encoded>&lt;p&gt;Let me be honest with you: every time I see &amp;ldquo;requires a container&amp;rdquo; in a tutorial, a little part of me sighs. Containers are great — until your team doesn&amp;rsquo;t have a container strategy, and suddenly a feature that looked simple is blocked behind orchestration overhead you didn&amp;rsquo;t plan for.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s why this one caught my eye. The SQL MCP Server can now run on Azure App Service — no Docker, no Kubernetes, just the same Data API builder (DAB) configuration that exposes your SQL database through MCP, REST, and GraphQL.&lt;/p&gt;
&lt;h2 id="whats-sql-mcp-server-again"&gt;What&amp;rsquo;s SQL MCP Server, Again?&lt;/h2&gt;
&lt;p&gt;Quick context if you haven&amp;rsquo;t run into it yet. SQL MCP Server sits between your AI agent and your SQL database. Instead of giving your agent direct database access (which is a terrible idea), it exposes your tables and views as an abstraction layer — entities with defined permissions.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s built on top of &lt;a href="https://learn.microsoft.com/en-us/azure/data-api-builder/"&gt;Data API builder&lt;/a&gt;, which means one configuration file drives MCP &lt;em&gt;and&lt;/em&gt; REST &lt;em&gt;and&lt;/em&gt; GraphQL simultaneously. Your agent talks to the MCP endpoint. Your traditional app talks to REST or GraphQL. Same config, same runtime, different surfaces.&lt;/p&gt;
&lt;p&gt;That&amp;rsquo;s genuinely useful. You&amp;rsquo;re not maintaining two separate API layers.&lt;/p&gt;
&lt;h2 id="the-container-problem-and-the-solution"&gt;The Container Problem (and the Solution)&lt;/h2&gt;
&lt;p&gt;The original deployment model for SQL MCP Server was containers. That works well in many shops — but not all. Plenty of .NET teams standardize on Azure App Service or VMs. Requiring a container runtime just to expose a SQL endpoint adds friction nobody asked for.&lt;/p&gt;
&lt;p&gt;The new walkthrough shows you how to skip the container entirely. The whole thing runs with a &lt;code&gt;dab start&lt;/code&gt; command, hosted on App Service as a standard .NET 8 web process.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the local setup flow in a nutshell:&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 Data API builder&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dotnet tool install microsoft.dataapibuilder --prerelease -g
&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;# Initialize the configuration&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dab init --database-type mssql --host-mode Development --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;&lt;span class="c1"&gt;# Add an entity&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dab add products --source dbo.products --permissions &lt;span class="s2"&gt;&amp;#34;authenticated:*&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;&lt;span class="c1"&gt;# Configure App Service auth provider&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;dab configure --runtime.host.authentication.provider AppService
&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;# Start the server&lt;/span&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;At this point you have MCP at &lt;code&gt;/mcp&lt;/code&gt;, REST and GraphQL from the same process, and nothing running in a container.&lt;/p&gt;
&lt;h2 id="authentication-that-doesnt-involve-shared-api-keys"&gt;Authentication That Doesn&amp;rsquo;t Involve Shared API Keys&lt;/h2&gt;
&lt;p&gt;This is the part I appreciate most. When you deploy to App Service, you configure Microsoft Entra ID as the authentication provider. No shared secrets embedded in config files, no API keys to rotate.&lt;/p&gt;
&lt;p&gt;The connection string stays in an App Service environment variable (not in &lt;code&gt;dab-config.json&lt;/code&gt;), and the MCP endpoint is protected by platform authentication. If you&amp;rsquo;re already aligned to Entra ID across your Azure workloads — which you probably are if you&amp;rsquo;re using Azure AI Foundry agents — this fits naturally.&lt;/p&gt;
&lt;p&gt;For local development, you switch to &lt;code&gt;Simulator&lt;/code&gt; mode and STDIO transport. Flip back to &lt;code&gt;AppService&lt;/code&gt; mode when deploying. Clean and explicit.&lt;/p&gt;
&lt;h2 id="deploying-to-app-service"&gt;Deploying to App Service&lt;/h2&gt;
&lt;p&gt;The actual deployment is straightforward Azure CLI 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;&lt;span class="c1"&gt;# Create the App Service plan&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;az appservice plan create &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --name &amp;lt;plan-name&amp;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; --resource-group &amp;lt;resource-group&amp;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; --sku B1 &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --is-linux
&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;# Create the web app (.NET 8 runtime)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;az webapp create &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; --name &amp;lt;app-name&amp;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; --resource-group &amp;lt;resource-group&amp;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; --plan &amp;lt;plan-name&amp;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; --runtime &lt;span class="s2"&gt;&amp;#34;DOTNETCORE:8.0&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;&lt;span class="c1"&gt;# Set the startup command&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;az webapp config &lt;span class="nb"&gt;set&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; --name &amp;lt;app-name&amp;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; --resource-group &amp;lt;resource-group&amp;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; --startup-file &lt;span class="s2"&gt;&amp;#34;dab start&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Then deploy your DAB project using whatever code deployment path your team already uses — VS Code, GitHub Actions, Zip Deploy. The key detail: it&amp;rsquo;s a &lt;strong&gt;code&lt;/strong&gt; deployment, not a container deployment. No image to build, push, or manage.&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 agents in .NET — whether with the Microsoft Agent Framework, Semantic Kernel, or Azure AI Foundry hosted agents — eventually your agent needs to talk to a database. SQL MCP Server gives you a structured way to do that without exposing raw connection strings or writing a custom API layer.&lt;/p&gt;
&lt;p&gt;Running it on App Service closes the gap for teams that aren&amp;rsquo;t running containers. It&amp;rsquo;s the same DAB config, the same Entra auth, the same MCP protocol — just on infrastructure you already know.&lt;/p&gt;
&lt;p&gt;Check out the full walkthrough in the &lt;a href="https://devblogs.microsoft.com/azure-sql/sql-mcp-server-app-service/"&gt;original blog post&lt;/a&gt; and the &lt;a href="https://github.com/Azure-Samples/SQL-MCP-NoContainer"&gt;sample repo on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;The SQL MCP Server on App Service is a solid pragmatic option for .NET teams that want to give their agents structured access to SQL data without a container strategy. The combination of DAB&amp;rsquo;s entity model, App Service&amp;rsquo;s built-in Entra auth, and the &lt;code&gt;dab start&lt;/code&gt; startup command makes for a deployment that&amp;rsquo;s simple to explain and easy to operate.&lt;/p&gt;
&lt;p&gt;Give it a try. Your agents will appreciate the clean API surface. Your ops team will appreciate not having to deal with container registries.&lt;/p&gt;</content:encoded></item><item><title>SQL Server 2025 as Your Agent-Ready Database: Security, Backup, and MCP in One Engine</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/sql-server-2025-agent-ready-security-mcp/</link><pubDate>Sun, 26 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/sql-server-2025-agent-ready-security-mcp/</guid><description>The final part of the Polyglot Tax series tackles the hard production problems: unified Row-Level Security across relational, JSON, graph, and vector data — plus cryptographic audit trails and MCP integration that make SQL Server 2025 genuinely agent-ready.</description><content:encoded>&lt;p&gt;I&amp;rsquo;ve been following the Polyglot Tax series by Aditya Badramraju with a lot of interest. Parts 1-3 built a compelling case for SQL Server 2025 as a genuinely multi-model database — JSON, graph, vectors, and relational data all in one engine with a unified query planner. Part 4 closes the series with the parts that actually determine whether you&amp;rsquo;d trust this architecture in production.&lt;/p&gt;
&lt;p&gt;Spoiler: the production story is solid.&lt;/p&gt;
&lt;h2 id="one-security-model-to-rule-all-data-models"&gt;One Security Model to Rule All Data Models&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s the thing with polyglot stacks: when an auditor asks &amp;ldquo;prove that Tenant A cannot see Tenant B&amp;rsquo;s data,&amp;rdquo; you have to answer that question for each database independently. Five databases, five security models, five proofs.&lt;/p&gt;
&lt;p&gt;With SQL Server 2025, you define one Row-Level Security policy and it covers every data model:&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;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FUNCTION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn_TenantFilter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;TenantID&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;INT&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;RETURNS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SCHEMABINDING&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;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;RETURN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&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;fn_result&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;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;TenantID&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="k"&gt;CAST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SESSION_CONTEXT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;TenantID&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&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="nb"&gt;INT&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="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SECURITY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;POLICY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TenantIsolation&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;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PREDICATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn_TenantFilter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TenantID&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;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Customers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;-- Relational
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PREDICATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn_TenantFilter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TenantID&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;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Events&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;-- JSON data
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PREDICATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn_TenantFilter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TenantID&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;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Relationships&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;-- Graph edges
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FILTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PREDICATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fn_TenantFilter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TenantID&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;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Embeddings&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;-- Vector data
&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="k"&gt;STATE&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="k"&gt;ON&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;From that point, every query — relational joins, JSON path queries, graph traversals, vector similarity searches — is automatically filtered by tenant. The engine injects the predicate into the execution plan before any data leaves storage. Your calling code doesn&amp;rsquo;t need &lt;code&gt;WHERE TenantID = @id&lt;/code&gt; everywhere. You test the policy once.&lt;/p&gt;
&lt;p&gt;The layers compose further: Dynamic Data Masking for columns that shouldn&amp;rsquo;t show full values to certain roles, Always Encrypted for end-to-end encryption (even DBAs can&amp;rsquo;t read it), and stored procedures as the permission boundary so agents only call what you explicitly exposed.&lt;/p&gt;
&lt;p&gt;This is the part of the architecture that matters most for compliance-heavy SaaS. One policy, one proof.&lt;/p&gt;
&lt;h2 id="unified-backup--atomic-recovery"&gt;Unified Backup = Atomic Recovery&lt;/h2&gt;
&lt;p&gt;One statement, all data models, consistent point in time:&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="n"&gt;BACKUP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MultiModelApp&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;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;URL&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://storage.blob.core.windows.net/backups/MultiModelApp.bak&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="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;COMPRESSION&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ENCRYPTION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ALGORITHM&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;AES_256&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SERVER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;CERTIFICATE&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;BackupCert&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="n"&gt;RESTORE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MultiModelApp&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;URL&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://storage.blob.core.windows.net/backups/MultiModelApp.bak&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="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STOPAT&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;2026-02-01 10:30:00&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;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;In a polyglot stack, point-in-time recovery across five databases means coordinating five restore operations and hoping the timestamps line up within a second or two. For financial data, that two-second inconsistency is unacceptable. With one database, one transaction log, one restore — recovery is atomic by definition.&lt;/p&gt;
&lt;h2 id="ledger-tables-for-tamper-evident-audit-trails"&gt;Ledger Tables for Tamper-Evident Audit Trails&lt;/h2&gt;
&lt;p&gt;For regulated industries, you need more than &amp;ldquo;we have logs.&amp;rdquo; You need cryptographic proof that those logs weren&amp;rsquo;t modified:&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;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FinancialTransactions&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="n"&gt;TransactionID&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PRIMARY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;KEY&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;AccountID&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&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;Amount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MONEY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&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;TransactionType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;NVARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&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;TransactionDate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DATETIME2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DEFAULT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SYSUTCDATETIME&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="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;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SYSTEM_VERSIONING&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="k"&gt;ON&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LEDGER&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="k"&gt;ON&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;Every insert, update, and delete gets cryptographically hashed into a blockchain-style structure. You can prove to an auditor — mathematically — that a row hasn&amp;rsquo;t been tampered with since it was written. In a polyglot stack, this capability doesn&amp;rsquo;t exist uniformly across all your databases.&lt;/p&gt;
&lt;h2 id="mcp-integration-agents-without-hand-coded-middleware"&gt;MCP Integration: Agents Without Hand-Coded Middleware&lt;/h2&gt;
&lt;p&gt;The series built toward this: SQL Server 2025 supports the SQL MCP Server directly, which means your agents can call the database through natural language tool calls without you writing middleware for every operation.&lt;/p&gt;
&lt;p&gt;Combine that with stored procedures as the permission boundary and Row-Level Security enforced at the engine, and you have a model where:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Agent calls a tool (e.g., &amp;ldquo;get customer context for account 12345&amp;rdquo;)&lt;/li&gt;
&lt;li&gt;MCP translates to the stored procedure you defined&lt;/li&gt;
&lt;li&gt;SQL engine enforces tenant isolation and column masking automatically&lt;/li&gt;
&lt;li&gt;Agent gets exactly the data it&amp;rsquo;s allowed to see&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;No middleware layer. No ad-hoc query injection risk. The engine handles authorization, not the agent.&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 .NET services with SQL Server as your primary store, the message from this series is: you don&amp;rsquo;t need to add Redis for caching, a graph DB for relationships, or a vector store for embeddings. SQL Server 2025 handles all of that — with better operational consistency than a polyglot stack and unified security that&amp;rsquo;s actually auditable.&lt;/p&gt;
&lt;p&gt;The MCP integration means your Semantic Kernel agents or Microsoft Agent Framework workflows can interact with your data tier through the same SQL MCP Server, with the same security guarantees you&amp;rsquo;d enforce for human queries.&lt;/p&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;The Polyglot Tax series is worth reading end-to-end. Parts 1-3 prove the query planner story. Part 4 proves the production story. For .NET developers building agent-first or AI-augmented applications on Azure SQL, this architecture deserves serious consideration.&lt;/p&gt;
&lt;p&gt;Original post by Aditya Badramraju: &lt;a href="https://devblogs.microsoft.com/azure-sql/the-polyglot-tax-part-4/"&gt;The Polyglot Tax – Part 4&lt;/a&gt;.&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>Azure SDK April 2026: AI Foundry 2.0 and What .NET Developers Should Know</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/azure-sdk-april-2026-ai-foundry-2-stable/</link><pubDate>Sat, 25 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/azure-sdk-april-2026-ai-foundry-2-stable/</guid><description>The April 2026 Azure SDK release ships Azure.AI.Projects 2.0.0 stable with significant breaking changes, critical Cosmos DB security fixes, and a wave of new Provisioning libraries for .NET.</description><content:encoded>&lt;p&gt;Monthly SDK releases are often easy to skip. This one has a few things worth paying attention to — especially if you&amp;rsquo;re building with AI Foundry, Cosmos DB in Java, or doing infrastructure provisioning from .NET code.&lt;/p&gt;
&lt;h2 id="azureaiprojects-200--breaking-changes-that-make-sense"&gt;Azure.AI.Projects 2.0.0 — Breaking Changes That Make Sense&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;Azure.AI.Projects&lt;/code&gt; NuGet package reaches stable 2.0.0 with some significant architectural changes. If you&amp;rsquo;re already using the preview, here&amp;rsquo;s what changed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Namespace splits&lt;/strong&gt;: Evaluations moved to &lt;code&gt;Azure.AI.Projects.Evaluation&lt;/code&gt;, memory operations moved to &lt;code&gt;Azure.AI.Projects.Memory&lt;/code&gt;. Your using statements will need updating.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Renamed types&lt;/strong&gt;: &lt;code&gt;Insights&lt;/code&gt; → &lt;code&gt;ProjectInsights&lt;/code&gt;, &lt;code&gt;Schedules&lt;/code&gt; → &lt;code&gt;ProjectSchedules&lt;/code&gt;, &lt;code&gt;Evaluators&lt;/code&gt; → &lt;code&gt;ProjectEvaluators&lt;/code&gt;, &lt;code&gt;Trigger&lt;/code&gt; → &lt;code&gt;ScheduleTrigger&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Naming conventions&lt;/strong&gt;: Boolean properties now follow the &lt;code&gt;Is*&lt;/code&gt; convention consistently&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are the kinds of breaking changes that hurt once and then feel right forever. If you&amp;rsquo;ve been building on the preview, update your imports and let the compiler point you to the rest.&lt;/p&gt;
&lt;p&gt;The good news: it&amp;rsquo;s stable. You can actually rely on this API now.&lt;/p&gt;
&lt;h2 id="cosmos-db-java-critical-security-fix-rce"&gt;Cosmos DB Java: Critical Security Fix (RCE)&lt;/h2&gt;
&lt;p&gt;This one is serious. The Java Cosmos DB library (&lt;code&gt;azure-cosmos&lt;/code&gt;) version 4.79.0 includes a critical security fix for a &lt;strong&gt;Remote Code Execution vulnerability (CWE-502)&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The issue was Java deserialization in &lt;code&gt;CosmosClientMetadataCachesSnapshot&lt;/code&gt;, &lt;code&gt;AsyncCache&lt;/code&gt;, and &lt;code&gt;DocumentCollection&lt;/code&gt;. The fix replaces Java deserialization with JSON-based serialization, eliminating the entire class of deserialization attacks.&lt;/p&gt;
&lt;p&gt;If you have any Java services using Azure Cosmos DB, update to 4.79.0 immediately. This isn&amp;rsquo;t optional.&lt;/p&gt;
&lt;h2 id="new-provisioning-libraries-for-net"&gt;New Provisioning Libraries for .NET&lt;/h2&gt;
&lt;p&gt;A wave of stable Provisioning libraries hit 1.0.0 this month — these are the libraries that let you define Azure infrastructure in C# code rather than ARM templates or Bicep:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.nuget.org/packages/Azure.Provisioning.Network/1.0.0"&gt;Azure.Provisioning.Network 1.0.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.nuget.org/packages/Azure.Provisioning.PrivateDns/1.0.0"&gt;Azure.Provisioning.PrivateDns 1.0.0&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Several more are in beta.1, covering API Management, Batch, Compute, Monitor, MySQL, and Security Center. If you&amp;rsquo;re doing infrastructure-as-code from .NET — particularly with Aspire deployments — these libraries are your entry point.&lt;/p&gt;
&lt;h2 id="azure-ai-agents-java-200-ga"&gt;Azure AI Agents Java: 2.0.0 GA&lt;/h2&gt;
&lt;p&gt;The Java Azure AI Agents library also reaches general availability this month. The key breaking changes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Several enum types converted to &lt;code&gt;ExpandableStringEnum&lt;/code&gt;-based classes (more flexible for new values)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;*Param&lt;/code&gt; model classes renamed to &lt;code&gt;*Parameter&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MCPToolConnectorId&lt;/code&gt; → &lt;code&gt;McpToolConnectorId&lt;/code&gt; (consistent casing)&lt;/li&gt;
&lt;li&gt;New convenience overload for &lt;code&gt;beginUpdateMemories&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;The headline for .NET developers this month is &lt;code&gt;Azure.AI.Projects 2.0.0&lt;/code&gt; hitting stable — if you&amp;rsquo;re building with AI Foundry, now&amp;rsquo;s the time to pin to stable and update your imports. For Java shops using Cosmos DB, the security update is urgent.&lt;/p&gt;
&lt;p&gt;Full release notes at &lt;a href="https://aka.ms/azsdk/releases"&gt;aka.ms/azsdk/releases&lt;/a&gt;. Original post: &lt;a href="https://devblogs.microsoft.com/azure-sdk/azure-sdk-release-april-2026/"&gt;Azure SDK Release (April 2026)&lt;/a&gt;.&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>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>azd + GitHub Copilot: AI-Powered Project Setup and Smarter Error Fixes</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/azd-copilot-integration-ai-setup-troubleshooting/</link><pubDate>Tue, 21 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/azd-copilot-integration-ai-setup-troubleshooting/</guid><description>The Azure Developer CLI now integrates with GitHub Copilot to scaffold your project and fix deployment errors — all without leaving the terminal.</description><content:encoded>&lt;p&gt;You know that moment when you want to deploy an existing app to Azure and suddenly find yourself staring at a blank &lt;code&gt;azure.yaml&lt;/code&gt;, trying to remember whether your Express API should use Container Apps or App Service? Yeah, that moment. It just got a whole lot shorter.&lt;/p&gt;
&lt;p&gt;The Azure Developer CLI (&lt;code&gt;azd&lt;/code&gt;) now integrates with GitHub Copilot in two meaningful ways: AI-assisted project scaffolding during &lt;code&gt;azd init&lt;/code&gt;, and intelligent error troubleshooting when deployments go sideways. Both features stay entirely in your terminal, which is exactly where I want them.&lt;/p&gt;
&lt;h2 id="setting-up-with-copilot-during-azd-init"&gt;Setting Up with Copilot During azd init&lt;/h2&gt;
&lt;p&gt;When you run &lt;code&gt;azd init&lt;/code&gt;, there&amp;rsquo;s now a &amp;ldquo;Set up with GitHub Copilot (Preview)&amp;rdquo; option. Select it and Copilot analyzes your codebase to generate the &lt;code&gt;azure.yaml&lt;/code&gt;, infrastructure templates, and Bicep modules — based on your actual code, not a template guess.&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;azd init
# Select: &amp;#34;Set up with GitHub Copilot (Preview)&amp;#34;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;For this to work you&amp;rsquo;ll need:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;azd 1.23.11 or later&lt;/strong&gt; — check with &lt;code&gt;azd version&lt;/code&gt; or update with &lt;code&gt;azd update&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;An active GitHub Copilot subscription&lt;/strong&gt; (Individual, Business, or Enterprise)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GitHub CLI (&lt;code&gt;gh&lt;/code&gt;)&lt;/strong&gt; — &lt;code&gt;azd&lt;/code&gt; will prompt for login if needed&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What I find genuinely useful here is that it works both ways. Building from scratch? Copilot helps you set up the right Azure services from the start. Have an existing app you&amp;rsquo;ve been putting off deploying? Point Copilot at it and it generates the configuration without you having to restructure anything.&lt;/p&gt;
&lt;h3 id="what-it-actually-does"&gt;What it actually does&lt;/h3&gt;
&lt;p&gt;Say you have a Node.js Express API with a PostgreSQL dependency. Instead of manually figuring out whether to target Container Apps or App Service, and then writing Bicep from scratch, Copilot detects your stack and generates:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An &lt;code&gt;azure.yaml&lt;/code&gt; with the right &lt;code&gt;language&lt;/code&gt;, &lt;code&gt;host&lt;/code&gt;, and &lt;code&gt;build&lt;/code&gt; settings&lt;/li&gt;
&lt;li&gt;A Bicep module for Azure Container Apps&lt;/li&gt;
&lt;li&gt;A Bicep module for Azure Database for PostgreSQL&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And it runs preflight checks before touching anything — verifies your git working directory is clean, asks for MCP server tool consent upfront. Nothing happens without you knowing exactly what&amp;rsquo;s about to change.&lt;/p&gt;
&lt;h2 id="copilot-powered-error-troubleshooting"&gt;Copilot-Powered Error Troubleshooting&lt;/h2&gt;
&lt;p&gt;Deployment errors are a fact of life. Missing parameters, permission issues, SKU availability problems — and the error message rarely tells you the one thing you actually need to know: &lt;em&gt;how to fix it&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Without Copilot, your loop looks like: copy the error → search docs → read through three unrelated Stack Overflow answers → run some &lt;code&gt;az&lt;/code&gt; CLI commands → try again and hope. With Copilot integrated into &lt;code&gt;azd&lt;/code&gt;, that loop collapses. When any &lt;code&gt;azd&lt;/code&gt; command fails, it immediately offers four options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Explain&lt;/strong&gt; — plain-language description of what went wrong&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Guidance&lt;/strong&gt; — step-by-step fix instructions&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Diagnose and Guide&lt;/strong&gt; — full analysis + Copilot applies the fix (with your approval) + optional retry&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Skip&lt;/strong&gt; — handle it yourself&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The key thing: Copilot already has context about your project, the command that failed, and the error output. Its suggestions are specific to &lt;em&gt;your situation&lt;/em&gt;, not generic docs.&lt;/p&gt;
&lt;h3 id="real-examples-where-this-shines"&gt;Real examples where this shines&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Resource provider not registered:&lt;/strong&gt;&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;ERROR: deployment failed: MissingSubscriptionRegistration:
The subscription is not registered to use namespace &amp;#39;Microsoft.App&amp;#39;.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This trips up anyone deploying to a fresh subscription. Copilot can register the provider and rerun the deployment automatically.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SKU not available:&lt;/strong&gt;&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;ERROR: deployment failed: SkuNotAvailable:
The requested VM size &amp;#39;Standard_D2s_v3&amp;#39; is not available in location &amp;#39;westus&amp;#39;.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Copilot explains which VM size or region is blocked and suggests alternatives that are actually available in your subscription.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Storage account name collision:&lt;/strong&gt;&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;ERROR: deployment failed: StorageAccountAlreadyTaken:
The storage account named &amp;#39;myappstorage&amp;#39; is already taken.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Global uniqueness bites everyone at least once. Copilot suggests adding your environment name or a random suffix to your Bicep parameters.&lt;/p&gt;
&lt;h3 id="set-a-default-behavior"&gt;Set a default behavior&lt;/h3&gt;
&lt;p&gt;If you always want the same option, skip the interactive prompt:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;azd config set copilot.errorHandling.category troubleshoot
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Options: &lt;code&gt;explain&lt;/code&gt;, &lt;code&gt;guidance&lt;/code&gt;, &lt;code&gt;troubleshoot&lt;/code&gt;, &lt;code&gt;fix&lt;/code&gt;, &lt;code&gt;skip&lt;/code&gt;. You can also enable auto-fix and retry:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;azd config set copilot.errorHandling.fix allow
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Reset to interactive at any time:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;azd config unset copilot.errorHandling.category
&lt;/code&gt;&lt;/pre&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 on Azure — whether it&amp;rsquo;s a .NET Aspire app, a containerized API, or anything in between — &lt;code&gt;azd&lt;/code&gt; has been the tool to know for a while now. This Copilot integration removes the last bit of friction that used to make it feel like you needed a cheat sheet just to get started.&lt;/p&gt;
&lt;p&gt;The scaffolding piece is great for brownfield projects. You&amp;rsquo;ve got an ASP.NET Core app running locally, it works perfectly, but getting it &lt;em&gt;onto&lt;/em&gt; Azure has always required a bit of infrastructure knowledge. Now Copilot bridges that gap. And the error troubleshooting feature is something I genuinely wish I&amp;rsquo;d had the last time I spent 45 minutes debugging a &lt;code&gt;SkuNotAvailable&lt;/code&gt; error across three regions.&lt;/p&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;This is exactly the kind of Copilot integration that adds real value — not AI for AI&amp;rsquo;s sake, but AI that understands your context and saves you actual time. Try it out by running &lt;code&gt;azd update&lt;/code&gt; to get the latest version, then use &lt;code&gt;azd init&lt;/code&gt; on your next project. The team is working on deeper features including Copilot-assisted infrastructure customization, so now&amp;rsquo;s a good time to &lt;a href="https://aka.ms/azd-user-research-signup"&gt;sign up for user research&lt;/a&gt; if you want to influence what comes next.&lt;/p&gt;
&lt;p&gt;Read the &lt;a href="https://devblogs.microsoft.com/azure-sdk/azd-copilot-integration/"&gt;original announcement here&lt;/a&gt;.&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>Azure MCP Tools Are Now Baked Into Visual Studio 2022 — No Extension Required</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/azure-mcp-tools-built-into-visual-studio-2022/</link><pubDate>Thu, 16 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/azure-mcp-tools-built-into-visual-studio-2022/</guid><description>Azure MCP tools ship as part of the Azure development workload in Visual Studio 2022. Over 230 tools, 45 Azure services, zero extensions to install.</description><content:encoded>&lt;p&gt;If you&amp;rsquo;ve been using the Azure MCP tools in Visual Studio through the separate extension, you know the drill — install the VSIX, restart, hope it doesn&amp;rsquo;t break, manage version mismatches. That friction is gone.&lt;/p&gt;
&lt;p&gt;Yun Jung Choi &lt;a href="https://devblogs.microsoft.com/visualstudio/azure-mcp-tools-now-ship-built-into-visual-studio-2022-no-extension-required/"&gt;announced&lt;/a&gt; that Azure MCP tools now ship directly as part of the Azure development workload in Visual Studio 2022. No extension. No VSIX. No restart dance.&lt;/p&gt;
&lt;h2 id="what-this-actually-means"&gt;What this actually means&lt;/h2&gt;
&lt;p&gt;Starting with Visual Studio 2022 version 17.14.30, the Azure MCP Server is bundled with the Azure development workload. If you already have that workload installed, you just need to toggle it on in GitHub Copilot Chat and you&amp;rsquo;re done.&lt;/p&gt;
&lt;p&gt;Over 230 tools across 45 Azure services — accessible directly from the chat window. List your storage accounts, deploy an ASP.NET Core app, diagnose App Service issues, query Log Analytics — all without opening a browser tab.&lt;/p&gt;
&lt;h2 id="why-this-matters-more-than-it-sounds"&gt;Why this matters more than it sounds&lt;/h2&gt;
&lt;p&gt;Here&amp;rsquo;s the thing about developer tooling: every extra step is friction, and friction kills adoption. Having MCP as a separate extension meant version mismatches, installation failures, and one more thing to keep updated. Baking it into the workload means:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Single update path&lt;/strong&gt; through the Visual Studio Installer&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;No version drift&lt;/strong&gt; between the extension and the IDE&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Always current&lt;/strong&gt; — the MCP Server updates with regular VS releases&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For teams standardizing on Azure, this is a big deal. You install the workload once, enable the tools, and they&amp;rsquo;re there for every session.&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;The tools cover the full development lifecycle through Copilot Chat:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Learn&lt;/strong&gt; — ask about Azure services, best practices, architecture patterns&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Design &amp;amp; develop&lt;/strong&gt; — get service recommendations, configure app code&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deploy&lt;/strong&gt; — provision resources and deploy directly from the IDE&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Troubleshoot&lt;/strong&gt; — query logs, check resource health, diagnose production issues&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A quick example — type this in Copilot Chat:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;List my storage accounts in my current subscription.
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Copilot calls the Azure MCP tools behind the scenes, queries your subscriptions, and returns a formatted list with names, locations, and SKUs. No portal needed.&lt;/p&gt;
&lt;h2 id="how-to-enable-it"&gt;How to enable it&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Update to Visual Studio 2022 &lt;strong&gt;17.14.30&lt;/strong&gt; or higher&lt;/li&gt;
&lt;li&gt;Make sure the &lt;strong&gt;Azure development&lt;/strong&gt; workload is installed&lt;/li&gt;
&lt;li&gt;Open GitHub Copilot Chat&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;Select tools&lt;/strong&gt; button (the two wrenches icon)&lt;/li&gt;
&lt;li&gt;Toggle &lt;strong&gt;Azure MCP Server&lt;/strong&gt; on&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That&amp;rsquo;s it. It stays enabled across sessions.&lt;/p&gt;
&lt;h2 id="one-caveat"&gt;One caveat&lt;/h2&gt;
&lt;p&gt;The tools are disabled by default — you need to opt in. And VS 2026-specific tools aren&amp;rsquo;t available in VS 2022. Tool availability also depends on your Azure subscription permissions, same as the portal.&lt;/p&gt;
&lt;h2 id="the-bigger-picture"&gt;The bigger picture&lt;/h2&gt;
&lt;p&gt;This is part of a clear trend: MCP is becoming the standard way to surface cloud tools in developer IDEs. We&amp;rsquo;ve already seen the &lt;a href="https://devblogs.microsoft.com/azure-sdk/announcing-azure-mcp-server-2-0-stable-release/"&gt;Azure MCP Server 2.0 stable release&lt;/a&gt; and MCP integrations across VS Code and other editors. Having it built into Visual Studio&amp;rsquo;s workload system is the natural progression.&lt;/p&gt;
&lt;p&gt;For us .NET developers who live in Visual Studio, this removes yet another reason to context-switch to the Azure portal. And honestly, the less tab-switching, the better.&lt;/p&gt;</content:encoded></item><item><title>Aspire 13.2 Gets MongoDB EF Core and Azure Data Lake — Two Integrations Worth Trying</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/aspire-132-mongodb-efcore-data-lake/</link><pubDate>Wed, 15 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/aspire-132-mongodb-efcore-data-lake/</guid><description>Aspire 13.2 adds MongoDB Entity Framework Core and Azure Data Lake Storage integrations with zero-config health checks and service discovery. Here's what they look like in practice.</description><content:encoded>&lt;p&gt;Aspire 13.2 just landed with &lt;a href="https://devblogs.microsoft.com/aspire/aspire-new-database-integrations/"&gt;two new database integrations&lt;/a&gt; that are worth your attention: MongoDB Entity Framework Core and Azure Data Lake Storage. If you&amp;rsquo;ve been wanting to use EF Core with MongoDB in an Aspire app, or need to wire up data lake workloads with proper service discovery, this release delivers both.&lt;/p&gt;
&lt;h2 id="mongodb-meets-ef-core-in-aspire"&gt;MongoDB meets EF Core in Aspire&lt;/h2&gt;
&lt;p&gt;This is the one I&amp;rsquo;m most excited about. Aspire has supported MongoDB for a while, but it was always the raw driver — no EF Core, no &lt;code&gt;DbContext&lt;/code&gt;, no LINQ queries against your documents. Now you get the full EF Core experience with MongoDB, plus Aspire&amp;rsquo;s automatic health checks and service discovery.&lt;/p&gt;
&lt;p&gt;Setting it up is the typical Aspire pattern. In your AppHost:&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;mongodb&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;AddMongoDB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;mongodb&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;WithDataVolume&lt;/span&gt;&lt;span class="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;WithLifetime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ContainerLifetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Persistent&lt;/span&gt;&lt;span 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;apiService&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;AddProject&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Projects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ApiService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;api&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;WithReference&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mongodb&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;Then in your consuming project, add the EF Core integration:&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 Aspire.MongoDB.EntityFrameworkCore
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And register your &lt;code&gt;DbContext&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="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddMongoDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MyDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;mongodb&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;mydb&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;From there, it&amp;rsquo;s standard EF Core. Define your entities, use your &lt;code&gt;DbContext&lt;/code&gt; like you would with any other provider. The integration handles connection pooling, OpenTelemetry traces, and health checks behind the scenes.&lt;/p&gt;
&lt;p&gt;For .NET developers who&amp;rsquo;ve been using MongoDB with the raw driver and manually wiring up connection strings, this is a nice quality-of-life upgrade. You get the full EF Core abstraction without losing Aspire&amp;rsquo;s service discovery.&lt;/p&gt;
&lt;h2 id="azure-data-lake-storage-joins-the-party"&gt;Azure Data Lake Storage joins the party&lt;/h2&gt;
&lt;p&gt;The second big addition is an &lt;a href="https://aspire.dev/integrations/cloud/azure/azure-storage-datalake/"&gt;Azure Data Lake Storage (ADLS) integration&lt;/a&gt;. If you&amp;rsquo;re building data pipelines, ETL processes, or analytics platforms, you can now wire up Data Lake resources the same way you&amp;rsquo;d wire up any other Aspire dependency.&lt;/p&gt;
&lt;p&gt;In the AppHost:&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;storage&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;AddAzureStorage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;azure-storage&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;dataLake&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddDataLake&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;data-lake&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;fileSystem&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddDataLakeFileSystem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;data-lake-file-system&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;analyticsService&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;AddProject&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Projects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AnalyticsService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;analytics&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;WithReference&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dataLake&lt;/span&gt;&lt;span class="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;WithReference&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fileSystem&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 the consuming project:&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;AddAzureDataLakeServiceClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;data-lake&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;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddAzureDataLakeFileSystemClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;data-lake-file-system&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;No manual connection string management, no credential hunting. Aspire provisions resources and injects them. For those of us building cloud-native .NET apps that touch both operational data and analytics workloads, this makes the data lake feel like a first-class citizen in the Aspire model.&lt;/p&gt;
&lt;h2 id="the-small-fixes-that-matter"&gt;The small fixes that matter&lt;/h2&gt;
&lt;p&gt;Beyond the headline features, there are a few quality-of-life improvements worth noting:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;MongoDB connection string fix&lt;/strong&gt; — the forward slash before the database name is now handled correctly. If you&amp;rsquo;ve been working around this, you can remove that workaround&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SQL Server exports&lt;/strong&gt; — &lt;code&gt;Aspire.Hosting.SqlServer&lt;/code&gt; now exports additional server configuration options for finer-grained control&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Emulator updates&lt;/strong&gt; — ServiceBus emulator 2.0.0, App Configuration emulator 1.0.2, and CosmosDB&amp;rsquo;s preview emulator now includes a readiness check&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Azure Managed Redis&lt;/strong&gt; — now defaults to &lt;code&gt;rediss://&lt;/code&gt; (Redis Secure), so connections are encrypted out of the box&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That last one is subtle but important — encrypted Redis by default means one less thing to configure in production.&lt;/p&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;Aspire 13.2 is an incremental release, but the MongoDB EF Core and Data Lake integrations fill real gaps. If you&amp;rsquo;ve been waiting for proper EF Core support with MongoDB in Aspire, or needed Data Lake to be a first-class dependency, &lt;a href="https://get.aspire.dev"&gt;upgrade to 13.2&lt;/a&gt; and give them a spin. The &lt;code&gt;aspire add&lt;/code&gt; command scaffolds everything you need.&lt;/p&gt;
&lt;p&gt;Read the &lt;a href="https://aspire.dev/whats-new/aspire-13-2/#-integrations-updates"&gt;full release notes&lt;/a&gt; for more details, and check out the &lt;a href="https://aspire.dev/integrations/gallery/"&gt;integration gallery&lt;/a&gt; for the complete list.&lt;/p&gt;</content:encoded></item><item><title>azd update — One Command to Rule All Your Package Managers</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/azd-update-universal-upgrade-command/</link><pubDate>Wed, 15 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/azd-update-universal-upgrade-command/</guid><description>The Azure Developer CLI now has a universal update command that works regardless of how you installed it — winget, Homebrew, Chocolatey, or install script.</description><content:encoded>&lt;p&gt;You know that &amp;ldquo;A new version of azd is available&amp;rdquo; message that pops up every few weeks? The one you dismiss because you can&amp;rsquo;t remember whether you installed &lt;code&gt;azd&lt;/code&gt; via winget, Homebrew, or that curl script you ran six months ago? Yeah, that&amp;rsquo;s finally fixed.&lt;/p&gt;
&lt;p&gt;Microsoft just shipped &lt;a href="https://devblogs.microsoft.com/azure-sdk/azd-update/"&gt;&lt;code&gt;azd update&lt;/code&gt;&lt;/a&gt; — a single command that updates the Azure Developer CLI to the latest version regardless of how you originally installed it. Windows, macOS, Linux — doesn&amp;rsquo;t matter. One command.&lt;/p&gt;
&lt;h2 id="how-it-works"&gt;How it works&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;azd update
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;That&amp;rsquo;s it. If you want early access to new features, you can switch to the daily insiders build:&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 update --channel daily
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;azd update --channel stable
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The command detects your current installation method and uses the appropriate update mechanism under the hood. No more &amp;ldquo;wait, did I use winget or choco on this machine?&amp;rdquo;&lt;/p&gt;
&lt;h2 id="the-small-catch"&gt;The small catch&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;azd update&lt;/code&gt; ships starting with version 1.23.x. If you&amp;rsquo;re on an older version, you&amp;rsquo;ll need to do one last manual update using your original installation method. After that, &lt;code&gt;azd update&lt;/code&gt; handles everything going forward.&lt;/p&gt;
&lt;p&gt;Check your current version with &lt;code&gt;azd version&lt;/code&gt;. If you need a fresh install, the &lt;a href="https://learn.microsoft.com/azure/developer/azure-developer-cli/install-azd"&gt;install docs&lt;/a&gt; have you covered.&lt;/p&gt;
&lt;h2 id="why-it-matters"&gt;Why it matters&lt;/h2&gt;
&lt;p&gt;This is a small quality-of-life improvement, but for those of us who use &lt;code&gt;azd&lt;/code&gt; daily for deploying AI agents and Aspire apps to Azure, staying current means fewer &amp;ldquo;this bug was already fixed in the latest version&amp;rdquo; moments. One less thing to think about.&lt;/p&gt;
&lt;p&gt;Read the &lt;a href="https://devblogs.microsoft.com/azure-sdk/azd-update/"&gt;full announcement&lt;/a&gt; and Jon Gallant&amp;rsquo;s &lt;a href="https://blog.jongallant.com/2026/04/azd-update"&gt;deeper dive&lt;/a&gt; for more context.&lt;/p&gt;</content:encoded></item><item><title>Azure Smart Tier Is GA — Automatic Blob Storage Cost Optimization Without Lifecycle Rules</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/azure-smart-tier-blob-storage-ga/</link><pubDate>Wed, 15 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/azure-smart-tier-blob-storage-ga/</guid><description>Azure Blob Storage smart tier is now generally available, automatically moving objects between hot, cool, and cold tiers based on actual access patterns — no lifecycle rules needed.</description><content:encoded>&lt;p&gt;If you&amp;rsquo;ve ever spent time tuning Azure Blob Storage lifecycle policies and then watched them fall apart when access patterns shifted, this one&amp;rsquo;s for you. Microsoft just announced the &lt;a href="https://azure.microsoft.com/en-us/blog/optimize-object-storage-costs-automatically-with-smart-tier-now-generally-available/"&gt;general availability of smart tier&lt;/a&gt; for Azure Blob and Data Lake Storage — a fully managed tiering capability that automatically moves objects between hot, cool, and cold tiers based on real usage.&lt;/p&gt;
&lt;h2 id="what-smart-tier-actually-does"&gt;What smart tier actually does&lt;/h2&gt;
&lt;p&gt;The concept is straightforward: smart tier continuously evaluates the last access time of each object in your storage account. Frequently accessed data stays in hot, inactive data moves to cool after 30 days, and then to cold after another 60 days. When data is accessed again, it&amp;rsquo;s promoted back to hot immediately. The cycle restarts.&lt;/p&gt;
&lt;p&gt;No lifecycle rules to configure. No access pattern predictions. No manual tuning.&lt;/p&gt;
&lt;p&gt;During the preview, Microsoft reported that &lt;strong&gt;over 50% of smart-tier-managed capacity automatically shifted to cooler tiers&lt;/strong&gt; based on actual access patterns. That&amp;rsquo;s a meaningful cost reduction for large storage accounts.&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 applications that generate logs, telemetry, analytics data, or any kind of growing data estate — and honestly, who isn&amp;rsquo;t — storage costs add up fast. The traditional approach was writing lifecycle management policies, testing them, and then re-tuning when your app&amp;rsquo;s access patterns changed. Smart tier removes that entire workflow.&lt;/p&gt;
&lt;p&gt;Some practical scenarios where this helps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Application telemetry and logs&lt;/strong&gt; — hot when debugging, rarely accessed after a few weeks&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Data pipelines and ETL outputs&lt;/strong&gt; — accessed heavily during processing, then mostly cold&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;User-generated content&lt;/strong&gt; — recent uploads are hot, older content gradually cools&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Backup and archival data&lt;/strong&gt; — accessed occasionally for compliance, mostly idle&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="setting-it-up"&gt;Setting it up&lt;/h2&gt;
&lt;p&gt;Enabling smart tier is a one-time configuration:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;New accounts&lt;/strong&gt;: Select smart tier as the default access tier during storage account creation (zonal redundancy required)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Existing accounts&lt;/strong&gt;: Switch the blob access tier from your current default to smart tier&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Objects smaller than 128 KiB stay in hot and don&amp;rsquo;t incur the monitoring fee. For everything else, you pay standard hot/cool/cold capacity rates with no tier transition charges, no early deletion fees, and no data retrieval costs. A monthly monitoring fee per object covers the orchestration.&lt;/p&gt;
&lt;h2 id="the-tradeoff-to-know-about"&gt;The tradeoff to know about&lt;/h2&gt;
&lt;p&gt;Smart tier&amp;rsquo;s tiering rules are static (30 days → cool, 90 days → cold). If you need custom thresholds — say, moving to cool after 7 days for a specific workload — lifecycle rules are still the way to go. And don&amp;rsquo;t mix both: avoid using lifecycle rules on smart-tier-managed objects, as they can conflict.&lt;/p&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;This isn&amp;rsquo;t revolutionary, but it solves a real operational headache. If you manage growing blob storage accounts and you&amp;rsquo;re tired of maintaining lifecycle policies, &lt;a href="https://learn.microsoft.com/en-us/azure/storage/blobs/access-tiers-smart"&gt;enable smart tier&lt;/a&gt; and let Azure handle it. It&amp;rsquo;s available today in nearly all zonal public cloud regions.&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>Agentic Platform Engineering Is Getting Real — Git-APE Shows How</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/agentic-platform-engineering-git-ape/</link><pubDate>Fri, 10 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/agentic-platform-engineering-git-ape/</guid><description>Microsoft's Git-APE project puts agentic platform engineering into practice — using GitHub Copilot agents and Azure MCP to turn natural-language requests into validated cloud infrastructure.</description><content:encoded>&lt;p&gt;Platform engineering has been one of those terms that sounds great in conference talks but usually means &amp;ldquo;we built an internal portal and a Terraform wrapper.&amp;rdquo; The real promise — self-service infrastructure that&amp;rsquo;s actually safe, governed, and fast — has always been a few steps away.&lt;/p&gt;
&lt;p&gt;The Azure team just published &lt;a href="https://devblogs.microsoft.com/all-things-azure/putting-agentic-platform-engineering-to-the-test/"&gt;Part 2 of their agentic platform engineering series&lt;/a&gt;, and this one is all about the hands-on implementation. They call it &lt;strong&gt;Git-APE&lt;/strong&gt; (yes, the acronym is intentional), and it&amp;rsquo;s an open-source project that uses GitHub Copilot agents plus Azure MCP servers to turn natural-language requests into validated, deployed infrastructure.&lt;/p&gt;
&lt;h2 id="what-git-ape-actually-does"&gt;What Git-APE actually does&lt;/h2&gt;
&lt;p&gt;The core idea: instead of developers learning Terraform modules, navigating portal UIs, or filing tickets to a platform team, they talk to a Copilot agent. The agent interprets the intent, generates Infrastructure-as-Code, validates it against policies, and deploys — all within VS Code.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the setup:&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;git clone https://github.com/Azure/git-ape
&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; git-ape
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Open the workspace in VS Code, and the agent configuration files are auto-discovered by GitHub Copilot. You interact with the agent directly:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;@git-ape deploy a function app with storage in West Europe
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The agent uses Azure MCP Server under the hood to interact with Azure services. The MCP configuration in VS Code settings enables specific capabilities:&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;azureMcp.serverMode&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;namespace&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;azureMcp.enabledServices&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;deploy&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;bestpractices&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;group&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;subscription&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;functionapp&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;storage&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;sql&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;monitor&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 class="nt"&gt;&amp;#34;azureMcp.readOnly&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&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="why-this-matters"&gt;Why this matters&lt;/h2&gt;
&lt;p&gt;For those of us building on Azure, this shifts the platform engineering conversation from &amp;ldquo;how do we build a portal&amp;rdquo; to &amp;ldquo;how do we describe our guardrails as APIs.&amp;rdquo; When your platform&amp;rsquo;s interface is an AI agent, the quality of your constraints and policies becomes the product.&lt;/p&gt;
&lt;p&gt;The Part 1 blog laid out the theory: well-described APIs, control schemas, and explicit guardrails make platforms agent-ready. Part 2 proves it works by shipping actual tooling. The agent doesn&amp;rsquo;t just blindly generate resources — it validates against best practices, respects naming conventions, and applies your organization&amp;rsquo;s policies.&lt;/p&gt;
&lt;p&gt;Clean-up is just as easy:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;@git-ape destroy my-resource-group
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="my-take"&gt;My take&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ll be honest — this one is more about the pattern than the specific tool. Git-APE itself is a demo/reference architecture. But the underlying idea — agents as the interface to your platform, MCP as the protocol, GitHub Copilot as the host — is where enterprise developer experience is heading.&lt;/p&gt;
&lt;p&gt;If you&amp;rsquo;re a platform team looking at how to make your internal tooling agent-friendly, there&amp;rsquo;s no better starting point. And if you&amp;rsquo;re a .NET developer wondering how this connects to your world: the Azure MCP Server and GitHub Copilot agents work with any Azure workload. Your ASP.NET Core API, your .NET Aspire stack, your containerized microservices — all of it can be the target of an agentic deployment flow.&lt;/p&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;Git-APE is an early but concrete look at agentic platform engineering in practice. Clone the &lt;a href="https://github.com/Azure/git-ape"&gt;repo&lt;/a&gt;, try the demo, and start thinking about how your platform&amp;rsquo;s APIs and policies would need to look for an agent to safely use them.&lt;/p&gt;
&lt;p&gt;Read the &lt;a href="https://devblogs.microsoft.com/all-things-azure/putting-agentic-platform-engineering-to-the-test/"&gt;full post&lt;/a&gt; for the walkthrough and video demos.&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>GitHub Copilot's Modernization Assessment Is the Best Migration Tool You're Not Using Yet</title><link>https://thedotnetblog.com/news/emiliano-montesdeoca/dotnet-modernization-assessment-github-copilot/</link><pubDate>Fri, 10 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/news/emiliano-montesdeoca/dotnet-modernization-assessment-github-copilot/</guid><description>GitHub Copilot's modernization extension doesn't just suggest code changes — it produces a full migration assessment with actionable issues, Azure target comparisons, and a collaborative workflow. Here's why the assessment document is the key to everything.</description><content:encoded>&lt;p&gt;Migrating a legacy .NET Framework app to modern .NET is one of those tasks everyone knows they should do but nobody wants to start. It&amp;rsquo;s never just &amp;ldquo;change the target framework.&amp;rdquo; It&amp;rsquo;s APIs that disappeared, packages that don&amp;rsquo;t exist anymore, hosting models that work completely differently, and a million small decisions about what to containerize, what to rewrite, and what to leave alone.&lt;/p&gt;
&lt;p&gt;Jeffrey Fritz just published a &lt;a href="https://devblogs.microsoft.com/dotnet/your-migrations-source-of-truth-the-modernization-assessment/"&gt;deep dive into GitHub Copilot&amp;rsquo;s modernization assessment&lt;/a&gt;, and honestly? This is the best migration tooling I&amp;rsquo;ve seen for .NET. Not because of the code generation — that&amp;rsquo;s table stakes now. Because of the assessment document it produces.&lt;/p&gt;
&lt;h2 id="its-not-just-a-code-suggestion-engine"&gt;It&amp;rsquo;s not just a code suggestion engine&lt;/h2&gt;
&lt;p&gt;The VS Code extension follows an &lt;strong&gt;Assess → Plan → Execute&lt;/strong&gt; model. The assessment phase analyzes your entire codebase and produces a structured document that captures everything: what needs to change, what Azure resources to provision, what deployment model to use. Everything downstream — infrastructure-as-code, containerization, deployment manifests — flows from what the assessment finds.&lt;/p&gt;
&lt;p&gt;The assessment is stored under &lt;code&gt;.github/modernize/assessment/&lt;/code&gt; in your project. Each run produces an independent report, so you build up a history and can track how your migration posture evolves as you fix issues.&lt;/p&gt;
&lt;h2 id="two-ways-to-start"&gt;Two ways to start&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Recommended Assessment&lt;/strong&gt; — the fast path. Pick from curated domains (Java/.NET Upgrade, Cloud Readiness, Security) and get meaningful results without touching configuration. Great for a first look at where your app stands.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Custom Assessment&lt;/strong&gt; — the targeted path. Configure exactly what to analyze: target compute (App Service, AKS, Container Apps), target OS, containerization analysis. Pick multiple Azure targets to compare migration approaches side-by-side.&lt;/p&gt;
&lt;p&gt;That comparison view is genuinely useful. An app with 3 mandatory issues for App Service might have 7 for AKS. Seeing both helps drive the hosting decision before you commit to a migration path.&lt;/p&gt;
&lt;h2 id="the-issue-breakdown-is-actionable"&gt;The issue breakdown is actionable&lt;/h2&gt;
&lt;p&gt;Each issue comes with a criticality level:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Mandatory&lt;/strong&gt; — must fix or migration fails&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Potential&lt;/strong&gt; — might impact migration, needs human judgment&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Optional&lt;/strong&gt; — recommended improvements, won&amp;rsquo;t block migration&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And each issue links to affected files and line numbers, provides a detailed description of what&amp;rsquo;s wrong and why it matters for your target platform, gives concrete remediation steps (not just &amp;ldquo;fix this&amp;rdquo;), and includes links to official documentation.&lt;/p&gt;
&lt;p&gt;You can hand individual issues to developers and they have everything they need to act. That&amp;rsquo;s the difference between a tool that tells you &amp;ldquo;there&amp;rsquo;s a problem&amp;rdquo; and one that tells you how to solve it.&lt;/p&gt;
&lt;h2 id="the-upgrade-paths-covered"&gt;The upgrade paths covered&lt;/h2&gt;
&lt;p&gt;For .NET specifically:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;.NET Framework → .NET 10&lt;/li&gt;
&lt;li&gt;ASP.NET → ASP.NET Core&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each upgrade path has detection rules that know which APIs were removed, which patterns have no direct equivalent, and what security issues need attention.&lt;/p&gt;
&lt;p&gt;For teams managing multiple apps, there&amp;rsquo;s also a CLI that supports multi-repo batch assessments — clone all repos, assess them all, get per-app reports plus an aggregated portfolio view.&lt;/p&gt;
&lt;h2 id="my-take"&gt;My take&lt;/h2&gt;
&lt;p&gt;If you&amp;rsquo;re sitting on legacy .NET Framework apps (and let&amp;rsquo;s be real, most enterprise teams are), this is &lt;em&gt;the&lt;/em&gt; tool to start with. The assessment document alone is worth the time — it turns a vague &amp;ldquo;we should modernize&amp;rdquo; into a concrete, prioritized list of work items with clear paths forward.&lt;/p&gt;
&lt;p&gt;The collaborative workflow is smart too: export assessments, share with your team, import them without re-running. Architecture reviews where the decision-makers aren&amp;rsquo;t the ones running the tools? Covered.&lt;/p&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;GitHub Copilot&amp;rsquo;s modernization assessment transforms .NET migration from a scary, undefined project into a structured, trackable process. Start with a recommended assessment to see where you stand, then use custom assessments to compare Azure targets and build your migration plan.&lt;/p&gt;
&lt;p&gt;Read the &lt;a href="https://devblogs.microsoft.com/dotnet/your-migrations-source-of-truth-the-modernization-assessment/"&gt;full walkthrough&lt;/a&gt; and grab the &lt;a href="https://aka.ms/ghcp-appmod/vscode-ext"&gt;VS Code extension&lt;/a&gt; to try it on your own codebase.&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>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>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>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>