<?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>Agent on 最后的DBA</title><link>https://lastdba.com/tags/agent/</link><description>Recent content in Agent on 最后的DBA</description><generator>Hugo -- gohugo.io</generator><language>zh-CN</language><copyright>© 2026 liuzhilong62</copyright><lastBuildDate>Wed, 27 May 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://lastdba.com/tags/agent/index.xml" rel="self" type="application/rss+xml"/><item><title>当 PostgreSQL 成为 AI 的双手——Bruce Momjian 的 MCP Server 实战</title><link>https://lastdba.com/2026/05/27/%E5%BD%93-postgresql-%E6%88%90%E4%B8%BA-ai-%E7%9A%84%E5%8F%8C%E6%89%8Bbruce-momjian-%E7%9A%84-mcp-server-%E5%AE%9E%E6%88%98/</link><pubDate>Wed, 27 May 2026 00:00:00 +0000</pubDate><guid>https://lastdba.com/2026/05/27/%E5%BD%93-postgresql-%E6%88%90%E4%B8%BA-ai-%E7%9A%84%E5%8F%8C%E6%89%8Bbruce-momjian-%E7%9A%84-mcp-server-%E5%AE%9E%E6%88%98/</guid><description>&lt;blockquote&gt;&lt;p&gt;原文：&lt;a href="https://momjian.us/main/writings/pgsql/mcp.pdf" target="_blank" rel="noreferrer"&gt;Building an MCP Server Using Postgres&lt;/a&gt;，Bruce Momjian，PGDay Armenia 2026，CC BY 4.0。&lt;/p&gt;
&lt;/blockquote&gt;&lt;blockquote&gt;&lt;p&gt;本文AI率80%&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;Bruce Momjian（PG core team，写了 20 多年发行注记的那位）最近在 PGDay Armenia 2026 做了一个演讲：&lt;a href="https://momjian.us/main/writings/pgsql/mcp.pdf" target="_blank" rel="noreferrer"&gt;Building an MCP Server Using Postgres&lt;/a&gt;。70 页幻灯片，信息密度极高。有理论，有实践，是一个不错的借鉴。&lt;/p&gt;</description><content:encoded>&lt;blockquote&gt;&lt;p&gt;原文：&lt;a href="https://momjian.us/main/writings/pgsql/mcp.pdf" target="_blank" rel="noreferrer"&gt;Building an MCP Server Using Postgres&lt;/a&gt;，Bruce Momjian，PGDay Armenia 2026，CC BY 4.0。&lt;/p&gt;
&lt;/blockquote&gt;&lt;blockquote&gt;&lt;p&gt;本文AI率80%&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;Bruce Momjian（PG core team，写了 20 多年发行注记的那位）最近在 PGDay Armenia 2026 做了一个演讲：&lt;a href="https://momjian.us/main/writings/pgsql/mcp.pdf" target="_blank" rel="noreferrer"&gt;Building an MCP Server Using Postgres&lt;/a&gt;。70 页幻灯片，信息密度极高。有理论，有实践，是一个不错的借鉴。&lt;/p&gt;
&lt;p&gt;直接读是比较费劲的，哪怕是直接让AI解读一下估计也不知道说的是什么，我也是看了一会问了几个问题后才算看明白了。&lt;/p&gt;
&lt;p&gt;这 70 页可以清晰地切成两层——前半部分是理论教学，后半部分是实战 demo。两层之间，关系不大。&lt;/p&gt;
&lt;hr&gt;

&lt;h1 class="relative group"&gt;理论层：用 Transformer 解释 RAG → MCP 的演进（Slide 1-33）
 &lt;div id="理论层用-transformer-解释-rag--mcp-的演进slide-1-33" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e7%90%86%e8%ae%ba%e5%b1%82%e7%94%a8-transformer-%e8%a7%a3%e9%87%8a-rag--mcp-%e7%9a%84%e6%bc%94%e8%bf%9bslide-1-33" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h1&gt;
&lt;p&gt;理论层占了近一半篇幅，从 LLM 基本原理讲到 MCP 的工作方式。Outline 很清楚：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/mcp/outline.png" alt="演讲大纲：Generative AI → LLM 局限 → RAG → MCP → MCP Server 实战" /&gt;&lt;/p&gt;

&lt;h2 class="relative group"&gt;RAG vs MCP：一句话说清
 &lt;div id="rag-vs-mcp一句话说清" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#rag-vs-mcp%e4%b8%80%e5%8f%a5%e8%af%9d%e8%af%b4%e6%b8%85" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;RAG 的流程大家都熟了：程序员决定查什么数据 → 检索结果拼到 system prompt → LLM 读完后生成回答。&lt;strong&gt;预编排&lt;/strong&gt;——LLM 能看到什么，在用户提问之前就定好了。&lt;/p&gt;
&lt;p&gt;MCP 不一样。工具描述注册给 LLM，LLM 在生成过程中&lt;strong&gt;自己判断&lt;/strong&gt;要不要调工具、调哪个。&lt;strong&gt;动态决策&lt;/strong&gt;——程序员只负责暴露工具，LLM 负责编排。&lt;/p&gt;
&lt;p&gt;Bruce 用一句话总结：&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;RAG 只能做程序员预设的事。MCP 可以根据输出质量动态调整，可以迭代调用多个工具，还可以触发外部任务。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 class="relative group"&gt;&amp;ldquo;是词还是 MCP&amp;rdquo;——那套向量嵌入图解
 &lt;div id="是词还是-mcp那套向量嵌入图解" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e6%98%af%e8%af%8d%e8%bf%98%e6%98%af-mcp%e9%82%a3%e5%a5%97%e5%90%91%e9%87%8f%e5%b5%8c%e5%85%a5%e5%9b%be%e8%a7%a3" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;Slide 18-33 是理论层最核心的部分。Bruce 画了一套详细的 Transformer 内部流程图：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/mcp/mcp-servers.png" alt="MCP Server 作为 Tool Embedding Vectors 注册到向量空间" /&gt;&lt;/p&gt;
&lt;p&gt;他的逻辑是：把每个 MCP tool 的描述文本（比如 &amp;ldquo;Return the radiation level (CPM) at 13 Roberts Road&amp;hellip;&amp;quot;）用文本嵌入模型向量化，塞进 attention 层的向量空间里。然后在每一步推理时，output vector 去匹配最近似的向量——&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/mcp/word-or-mcp.png" alt="最近似向量可能是文本 token，也可能是 MCP tool" /&gt;&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;&amp;ldquo;The closest vector might be a word or an MCP.&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 class="relative group"&gt;这个模型对吗？
 &lt;div id="这个模型对吗" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e8%bf%99%e4%b8%aa%e6%a8%a1%e5%9e%8b%e5%af%b9%e5%90%97" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;这是我最疑惑的地方，以下是我的浅见。&lt;/p&gt;
&lt;p&gt;Bruce 这 15 页 slides 画得很好看，但如果当工程实现去理解，是有问题的：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;① MCP tool 不需要&amp;quot;嵌入&amp;rdquo;。&lt;/strong&gt; 实际工程中，tool 定义是作为文本直接写在 system prompt 里的。LLM 读到 &amp;ldquo;你有这些工具：geiger()、get_pretzel_inventory()&amp;hellip;&amp;quot;，靠语义理解决定什么时候调。不需要把 tool 描述算成向量，不需要和词向量做余弦距离比较。Bruce 这套教学模型的本质是把&amp;quot;LLM 决策&amp;quot;解释成&amp;quot;向量最近似匹配&amp;rdquo;，这更像 retrieval 的范式而不是 generation 的范式。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;② Attention 不产出&amp;quot;查最近似&amp;quot;的操作。&lt;/strong&gt; &lt;code&gt;output = Σ(softmax(Q·K) × V)&lt;/code&gt;，产出的是一个加权混合后的上下文向量。没有&amp;quot;在词向量表和 tool 向量表里二选一&amp;quot;这一步。LLM 选工具的实际机制是 attention 产出 hidden state → LM head → softmax over 词表 → 输出 tool call JSON。从来没有在&amp;quot;词和 tool 之间二选一&amp;quot;，只有在整个词表上做 softmax。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;③ system prompt 和 user prompt 在 attention 里没有边界。&lt;/strong&gt; Token 序列就是 token 序列，attention block 对所有 token 一视同仁做 Q·K 点积。不存在&amp;quot;system 区&amp;quot;和&amp;quot;user 区&amp;quot;。&lt;/p&gt;
&lt;p&gt;所以这 33 页理论层，可以看作 Bruce 给非 AI 背景的 DBA 做的一个教学简化模型——好看、好懂，但别当架构图用。MCP 真正革命性的地方在&lt;strong&gt;协议标准化&lt;/strong&gt;（统一的 tool 注册/发现/调用规范），不在向量化的 trick。&lt;/p&gt;
&lt;hr&gt;

&lt;h1 class="relative group"&gt;实践层：两个能跑的 demo（Slide 34-69）
 &lt;div id="实践层两个能跑的-demoslide-34-69" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e5%ae%9e%e8%b7%b5%e5%b1%82%e4%b8%a4%e4%b8%aa%e8%83%bd%e8%b7%91%e7%9a%84-demoslide-34-69" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h1&gt;
&lt;p&gt;从 Slide 34 开始，风格突变——全是代码、终端输出、硬件照片。理论层那套 Transformer 向量模型完全消失了，取而代之的是 &lt;code&gt;curl&lt;/code&gt;、&lt;code&gt;psql&lt;/code&gt;、Perl 脚本。&lt;/p&gt;
&lt;p&gt;两层之间的唯一联系是&amp;quot;它们都在讲 MCP&amp;quot;，但理论层画的向量匹配机制和实战中的实现方式几乎是两套逻辑。 这可能正是 Bruce 演讲的张力所在——理论层让你理解 MCP 为什么比 RAG 强，实践层告诉你现在怎么落地。&lt;/p&gt;

&lt;h2 class="relative group"&gt;Demo 1：让 ChatGPT 读取真实世界的盖革计数器
 &lt;div id="demo-1让-chatgpt-读取真实世界的盖革计数器" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#demo-1%e8%ae%a9-chatgpt-%e8%af%bb%e5%8f%96%e7%9c%9f%e5%ae%9e%e4%b8%96%e7%95%8c%e7%9a%84%e7%9b%96%e9%9d%a9%e8%ae%a1%e6%95%b0%e5%99%a8" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;Bruce 在自家院子里架了一台 GQ GMC-800 盖革计数器（测辐射的），USB 接树莓派，每 15 分钟测一次环境辐射。先看 ChatGPT 用 MCP 调用真实数据的效果：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/mcp/chatgpt-weather.png" alt="ChatGPT 通过 MCP 查询天气" /&gt;&lt;/p&gt;
&lt;p&gt;MCP 可以调用外部工具获取实时数据——这是 RAG 做不到的。&lt;/p&gt;
&lt;p&gt;接上硬件：&lt;/p&gt;
&lt;p&gt;


&lt;img src="https://lastdba.com/img/mcp/geiger-counter.png" alt="GQ GMC-800 盖革计数器" /&gt;&lt;/p&gt;
&lt;p&gt;用 &lt;strong&gt;fastmcp&lt;/strong&gt; 写了 Python wrapper：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;from&lt;/span&gt; fastmcp &lt;span style="color:#f92672"&gt;import&lt;/span&gt; FastMCP
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mcp &lt;span style="color:#f92672"&gt;=&lt;/span&gt; FastMCP(&lt;span style="color:#e6db74"&gt;&amp;#34;Geiger counter MCP server&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@mcp.tool&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;geiger&lt;/span&gt;() &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; int:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&amp;#34;Return the radiation level (CPM) at 13 Roberts Road, Newtown Square, PA, USA&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; subprocess&lt;span style="color:#f92672"&gt;.&lt;/span&gt;check_output(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;/var/lib/postgresql/tmp/geiger&amp;#34;&lt;/span&gt;, shell&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;True&lt;/span&gt;, text&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;底层是一个 Perl 脚本，往串口发 &lt;code&gt;&amp;lt;GETCPM&amp;gt;&amp;gt;&lt;/code&gt; 指令，读回 4 字节 CPM 值。Apache 做 443 端口反代（OpenAI 只跟 443 通信），注册到 ChatGPT 后：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;User: 13 Roberts Road 的辐射水平是多少？
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;GPT: 我没有这个位置的公开数据……
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;User: 用我的 custom app
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;GPT: [调用 geiger tool] → 14 CPM。正常环境背景辐射（5-25 CPM）。
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;User: 测五次，给我平均值
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;GPT: [调用 ×5] 15 16 13 15 15 → 平均 14.8 CPM&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;两个关键行为：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;LLM 可以迭代调工具做计算&lt;/strong&gt;——RAG 是一次性塞数据，MCP 是&amp;quot;调 → 拿结果 → 判断 → 再调 → 算&amp;quot;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;用户必须显式授权&lt;/strong&gt;——第一次问的时候 ChatGPT 没说&amp;quot;我有你的盖革计数器数据&amp;quot;，直到说 &amp;ldquo;use my custom app&amp;rdquo; 才触发 tool call。安全模型很保守&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 class="relative group"&gt;Demo 2：用 PG 做椒盐卷饼店的库存系统
 &lt;div id="demo-2用-pg-做椒盐卷饼店的库存系统" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#demo-2%e7%94%a8-pg-%e5%81%9a%e6%a4%92%e7%9b%90%e5%8d%b7%e9%a5%bc%e5%ba%97%e7%9a%84%e5%ba%93%e5%ad%98%e7%b3%bb%e7%bb%9f" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;从硬件回到软件。建一个椒盐卷饼（pretzel）库存库：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TABLE&lt;/span&gt; pretzel (
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; quantity INTEGER &lt;span style="color:#66d9ef"&gt;CHECK&lt;/span&gt; (quantity &lt;span style="color:#f92672"&gt;&amp;gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;INSERT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;INTO&lt;/span&gt; pretzel &lt;span style="color:#66d9ef"&gt;VALUES&lt;/span&gt; (&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;); &lt;span style="color:#75715e"&gt;-- 初始库存 0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;MCP tool 直接用 &lt;code&gt;psql&lt;/code&gt; 操作 PG：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@mcp.tool&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;get_pretzel_inventory&lt;/span&gt;() &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; int:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&amp;#34;Return the number of unsold pretzels&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; subprocess&lt;span style="color:#f92672"&gt;.&lt;/span&gt;check_output(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;psql --tuples-only -c &amp;#39;SELECT quantity FROM pretzel;&amp;#39; -d mcp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; shell&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;True&lt;/span&gt;, text&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@mcp.tool&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;sold_one_pretzel&lt;/span&gt;() &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; str:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&amp;#34;Call this when a pretzel is sold; reduces inventory by one&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; subprocess&lt;span style="color:#f92672"&gt;.&lt;/span&gt;check_output(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;psql --tuples-only -c &amp;#39;UPDATE pretzel SET quantity = quantity - 1;&amp;#39; -d mcp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; shell&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;True&lt;/span&gt;, text&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;@mcp.tool&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;baked_6_pretzels&lt;/span&gt;() &lt;span style="color:#f92672"&gt;-&amp;gt;&lt;/span&gt; str:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&amp;#34;&amp;#34;Call this when a tray of 6 pretzels is baked; increases inventory&amp;#34;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;return&lt;/span&gt; subprocess&lt;span style="color:#f92672"&gt;.&lt;/span&gt;check_output(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;psql --tuples-only -c &amp;#39;UPDATE pretzel SET quantity = quantity + 6;&amp;#39; -d mcp&amp;#34;&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; shell&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;True&lt;/span&gt;, text&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;True&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;交互流程：&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;User: How many pretzels available?
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;GPT: 0 pretzels.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;User: I just baked a tray → 6 pretzels
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;User: I sold two → 4 remaining
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;User: I sold four → 0 remaining
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;User: I sold one pretzel → ERROR! CHECK constraint 阻止了 quantity 变负数&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;LLM 不直接写 SQL，而是调你预先定义的受控接口。PG 的 CHECK 约束天然构成了一个安全兜底——即使 LLM 被诱导调了不该调的函数，数据库层的约束还能挡一道。&lt;/p&gt;
&lt;p&gt;但也暴露了问题：LLM 忠实执行了 &lt;code&gt;sold_one_pretzel&lt;/code&gt;，但不会预判&amp;quot;库存已经是 0 了调了会报错&amp;quot;。&lt;strong&gt;MCP 是执行层，不是推理层。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;

&lt;h1 class="relative group"&gt;生产还差多远
 &lt;div id="生产还差多远" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e7%94%9f%e4%ba%a7%e8%bf%98%e5%b7%ae%e5%a4%9a%e8%bf%9c" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h1&gt;
&lt;p&gt;Bruce 在最后一页坦承了当前实现的局限：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;没有认证&lt;/strong&gt;——谁都可以调你的 MCP Server&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;没有参数化&lt;/strong&gt;——三个 tool 都是无参函数，现实中的 tool 需要传参数&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;动态 SQL 没做安全限制&lt;/strong&gt;——工具描述声明了语义，但 LLM 可能被注入恶意内容&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;连接池、事务管理、频率限制&lt;/strong&gt;——一概没考虑&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;两篇值得读的实践经验：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.pgedge.com/blog/lessons-learned-writing-an-mcp-server-for-postgresql" target="_blank" rel="noreferrer"&gt;pgedge.com: Lessons Learned Writing an MCP Server for PostgreSQL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cardinalops.com/blog/mcp-defaults-hidden-dangers-of-remote-deployment/" target="_blank" rel="noreferrer"&gt;CardinalOps: MCP Defaults — Hidden Dangers of Remote Deployment&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;

&lt;h1 class="relative group"&gt;两层之间
 &lt;div id="两层之间" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#%e4%b8%a4%e5%b1%82%e4%b9%8b%e9%97%b4" aria-label="锚点"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h1&gt;
&lt;p&gt;回头看这 70 页幻灯片，最有趣的不是任何一个 demo，而是MCP的理论思路和动手说明MCP能做什么：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;理论层用 Transformer 向量空间解释&amp;quot;LLM 如何在词和工具之间做选择&amp;quot;——这是教学模型&lt;/li&gt;
&lt;li&gt;实践层用 &lt;code&gt;psql&lt;/code&gt;、&lt;code&gt;curl&lt;/code&gt;、Perl 脚本去落地——这是工程实现&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;而真正的 MCP 机制——tool 定义当文本塞 system prompt、LLM 靠语义理解决定调哪个、输出 tool call JSON——应该是不需要理论层那套向量嵌入模型。两层之间，Bruce 没有画出来连接线。这可能不是 bug，是 feature。&lt;/p&gt;</content:encoded></item></channel></rss>