<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>AI Apps | The .NET Blog</title><link>https://thedotnetblog.com/tags/ai-apps/</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>Sun, 26 Apr 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://thedotnetblog.com/tags/ai-apps/index.xml" rel="self" type="application/rss+xml"/><item><title>SQL Server 2025 as Your Agent-Ready Database: Security, Backup, and MCP in One Engine</title><link>https://thedotnetblog.com/posts/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/posts/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>68 Minutes a Day Re-Explaining Code to Copilot? There's a Fix for That</title><link>https://thedotnetblog.com/posts/emiliano-montesdeoca/auto-memory-stop-re-explaining-code-to-copilot/</link><pubDate>Thu, 23 Apr 2026 00:00:00 +0000</pubDate><author>Emiliano Montesdeoca</author><guid>https://thedotnetblog.com/posts/emiliano-montesdeoca/auto-memory-stop-re-explaining-code-to-copilot/</guid><description>Context rot is real — your AI agent drifts after 30 turns, and you're paying the compaction tax every hour. auto-memory gives GitHub Copilot CLI surgical recall without burning thousands of tokens.</description><content:encoded>&lt;p&gt;You know that moment when your Copilot session hits &lt;code&gt;/compact&lt;/code&gt; and the agent completely forgets what you were doing? You spend the next five minutes re-explaining the file structure, the failing test, the three approaches you already tried. Then it happens again. And again.&lt;/p&gt;
&lt;p&gt;Desi Villanueva timed it: &lt;strong&gt;68 minutes per day&lt;/strong&gt; — just on re-orientation. Not writing code. Not reviewing PRs. Just catching the AI up on things it already knew.&lt;/p&gt;
&lt;p&gt;Turns out there&amp;rsquo;s a concrete reason this happens, and a concrete fix.&lt;/p&gt;
&lt;h2 id="the-context-window-lie"&gt;The Context Window Lie&lt;/h2&gt;
&lt;p&gt;Your agent ships with a big number on the box. 200K tokens. Sounds massive. In practice it&amp;rsquo;s a ceiling, not a guarantee.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the actual math:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;200K total context&lt;/li&gt;
&lt;li&gt;Minus ~65K for MCP tools loaded at startup (~33%)&lt;/li&gt;
&lt;li&gt;Minus ~10K for instruction files like &lt;code&gt;AGENTS.md&lt;/code&gt; or &lt;code&gt;copilot-instructions.md&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That leaves you with roughly &lt;strong&gt;125K before you type a word&lt;/strong&gt;. And it gets worse — LLMs don&amp;rsquo;t degrade gracefully as context fills up. They hit a wall at around 60% capacity. The model starts losing things mentioned 30 turns ago, contradicts earlier responses, hallucinates file names it stated confidently 10 minutes prior. The industry calls this the &amp;ldquo;lost in the middle&amp;rdquo; problem.&lt;/p&gt;
&lt;p&gt;Effective limit: &lt;strong&gt;45K tokens&lt;/strong&gt; before quality degrades. That&amp;rsquo;s maybe 20-30 turns of active conversation before the agent starts drifting. Which is why you&amp;rsquo;re hitting &lt;code&gt;/compact&lt;/code&gt; every 45 minutes — not because you&amp;rsquo;ve filled 200K tokens, but because the model is already rotting at 120K.&lt;/p&gt;
&lt;h2 id="the-compaction-tax"&gt;The Compaction Tax&lt;/h2&gt;
&lt;p&gt;Every &lt;code&gt;/compact&lt;/code&gt; costs you flow state. You&amp;rsquo;re deep in a debugging session. Shared context built up over 30 minutes. The agent knows the file structure, the failing test, the hypothesis. Then the warning hits.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ignore it → agent gets progressively dumber, hallucinates old state&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;/compact&lt;/code&gt; → agent has a 2-paragraph summary of a 30-minute investigation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Either way you lose. Either way you&amp;rsquo;re narrating your own project back to it like a new hire on day one.&lt;/p&gt;
&lt;p&gt;The cruel part? &lt;strong&gt;The memory already exists.&lt;/strong&gt; Copilot CLI writes every session to a local SQLite database at &lt;code&gt;~/.copilot/session-store.db&lt;/code&gt; — every file touched, every turn, every checkpoint. It&amp;rsquo;s all sitting on disk. The agent just can&amp;rsquo;t read it.&lt;/p&gt;
&lt;h2 id="auto-memory-a-recall-layer-not-a-memory-system"&gt;auto-memory: A Recall Layer, Not a Memory System&lt;/h2&gt;
&lt;p&gt;That&amp;rsquo;s the key insight behind &lt;a href="https://github.com/dezgit2025/auto-memory"&gt;auto-memory&lt;/a&gt;: don&amp;rsquo;t build a new memory system — build a read-only query layer over the one that already exists.&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;pip install auto-memory
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;~1,900 lines of Python. Zero dependencies. Installs in 30 seconds.&lt;/p&gt;
&lt;p&gt;Instead of flooding the context with grep results, you give the agent surgical access to what actually matters:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Tokens&lt;/th&gt;
&lt;th&gt;What you get&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;grep -r &amp;quot;auth&amp;quot; src/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;~5,000–10,000&lt;/td&gt;
&lt;td&gt;500 results, most irrelevant&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;find . -name &amp;quot;*.py&amp;quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;~2,000&lt;/td&gt;
&lt;td&gt;Every Python file, no context&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Agent re-orientation&lt;/td&gt;
&lt;td&gt;~2,000&lt;/td&gt;
&lt;td&gt;You explaining what it should know&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;auto-memory files --json --limit 10&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~50&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;The 10 files you touched yesterday&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;That&amp;rsquo;s a 200x improvement. The agent skips the archaeological dig and goes straight to what matters.&lt;/p&gt;
&lt;p&gt;The recommended flow: when you&amp;rsquo;re approaching 50-70% context usage, run &lt;code&gt;/clear&lt;/code&gt; and then prompt with &amp;ldquo;review last sessions we discussed topic X&amp;rdquo;. Instead of burning 12K tokens on blind searches, auto-memory pulls the relevant context in 50.&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 using GitHub Copilot CLI for .NET work — scaffolding services, debugging EF Core queries, iterating on Blazor components — the context rot problem hits just as hard. Complex solutions with multiple projects, shared libraries, and deep call chains are exactly the kind of codebase where the agent loses track fastest.&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://github.com/dezgit2025/auto-memory/blob/main/deploy/install.md"&gt;install guide&lt;/a&gt; walks through pointing Copilot CLI at it. It&amp;rsquo;s a one-time setup.&lt;/p&gt;
&lt;p&gt;Honestly? 68 minutes a day back in your pocket is not a minor quality-of-life tweak. That&amp;rsquo;s almost 6 hours a week.&lt;/p&gt;
&lt;h2 id="wrapping-up"&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;Context rot is a real architectural constraint, not a bug that will get patched. auto-memory works around it by giving your agent a cheap, precise recall mechanism instead of expensive, noisy re-exploration. If you&amp;rsquo;re doing serious AI-assisted development with GitHub Copilot CLI, it&amp;rsquo;s worth the 30-second install.&lt;/p&gt;
&lt;p&gt;Check it out: &lt;a href="https://github.com/dezgit2025/auto-memory"&gt;auto-memory on GitHub&lt;/a&gt;. Original post by Desi Villanueva: &lt;a href="https://devblogs.microsoft.com/all-things-azure/i-wasted-68-minutes-a-day-re-explaining-my-code-then-i-built-auto-memory/"&gt;I Wasted 68 Minutes a Day Re-Explaining My Code&lt;/a&gt;.&lt;/p&gt;</content:encoded></item></channel></rss>