<?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>MCP on Chico's Tech Blog</title><link>https://realtime-ai.chat/tags/mcp/</link><description>Recent content in MCP on Chico's Tech Blog</description><image><title>Chico's Tech Blog</title><url>https://github.com/chicogong.png</url><link>https://github.com/chicogong.png</link></image><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Sun, 17 May 2026 11:00:00 +0800</lastBuildDate><atom:link href="https://realtime-ai.chat/tags/mcp/index.xml" rel="self" type="application/rss+xml"/><item><title>Claude Code 高级功能实战：MCP、Hooks、SubAgent 与自定义命令</title><link>https://realtime-ai.chat/posts/claude-code-advanced-features/</link><pubDate>Fri, 26 Dec 2025 10:00:00 +0800</pubDate><guid>https://realtime-ai.chat/posts/claude-code-advanced-features/</guid><description>Claude Code 高级功能实战:MCP、Hooks、SubAgent 与自定义命令,把 AI 编程从「对话写代码」升级为自动化工作流。</description><content:encoded><![CDATA[<h2 id="前言不只是聊天机器人">前言：不只是聊天机器人</h2>
<p>大多数人使用 Claude Code 只是简单地&quot;对话写代码&quot;。但 Claude Code 的真正威力在于它的<strong>可扩展性</strong>和<strong>自动化能力</strong>。</p>
<p>本文将深入介绍 Claude Code 的四大高级功能：</p>
<ol>
<li><strong>MCP（Model Context Protocol）</strong>：让 Claude 连接外部工具和数据源</li>
<li><strong>Hooks</strong>：在关键节点插入自动化脚本</li>
<li><strong>SubAgent 多智能体架构</strong>：并发执行复杂任务</li>
<li><strong>CLAUDE.md 配置系统</strong>：定义项目规范和工作流</li>
</ol>
<p>这些功能组合起来，能让 Claude Code 从一个&quot;AI助手&quot;进化成&quot;AI工程师团队&quot;。</p>
<hr>
<h2 id="一mcp让-claude-连接一切">一、MCP：让 Claude 连接一切</h2>
<h3 id="11-什么是-mcp">1.1 什么是 MCP？</h3>
<p>MCP（Model Context Protocol）是 Anthropic 推出的开放协议，让 AI 模型能够与外部工具和数据源进行标准化交互。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">传统方式：Claude 只能看到你发给它的文本
</span></span><span class="line"><span class="cl">MCP方式：Claude 可以主动调用工具获取信息
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">┌─────────────┐     MCP协议      ┌─────────────┐
</span></span><span class="line"><span class="cl">│  Claude Code │ ◄────────────► │  外部服务    │
</span></span><span class="line"><span class="cl">└─────────────┘                 └─────────────┘
</span></span><span class="line"><span class="cl">                                    ├── 文件系统
</span></span><span class="line"><span class="cl">                                    ├── 数据库
</span></span><span class="line"><span class="cl">                                    ├── GitHub
</span></span><span class="line"><span class="cl">                                    ├── Slack
</span></span><span class="line"><span class="cl">                                    ├── Google Drive
</span></span><span class="line"><span class="cl">                                    └── 自定义工具
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="12-配置-mcp-服务器">1.2 配置 MCP 服务器</h3>
<p><strong>方法一：命令行添加（推荐）</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 添加文件系统访问</span>
</span></span><span class="line"><span class="cl">claude mcp add filesystem -- npx -y @modelcontextprotocol/server-filesystem ~/Documents ~/Projects
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 添加 GitHub 集成</span>
</span></span><span class="line"><span class="cl">claude mcp add github -e <span class="nv">GITHUB_TOKEN</span><span class="o">=</span>your_token -- npx -y @modelcontextprotocol/server-github
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 添加内存服务（持久化记忆）</span>
</span></span><span class="line"><span class="cl">claude mcp add memory -- npx -y @modelcontextprotocol/server-memory
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 查看已配置的服务器</span>
</span></span><span class="line"><span class="cl">claude mcp list
</span></span></code></pre></td></tr></table>
</div>
</div><p><strong>方法二：JSON 配置文件</strong></p>
<p>编辑 <code>~/.claude/settings.json</code>：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;mcpServers&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;filesystem&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;npx&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;args&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;-y&#34;</span><span class="p">,</span> <span class="s2">&#34;@modelcontextprotocol/server-filesystem&#34;</span><span class="p">,</span> <span class="s2">&#34;/Users/me/Projects&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;env&#34;</span><span class="p">:</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;github&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;npx&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;args&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;-y&#34;</span><span class="p">,</span> <span class="s2">&#34;@modelcontextprotocol/server-github&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;env&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;GITHUB_TOKEN&#34;</span><span class="p">:</span> <span class="s2">&#34;ghp_xxxxxxxxxxxx&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;postgres&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;npx&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;args&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;-y&#34;</span><span class="p">,</span> <span class="s2">&#34;@modelcontextprotocol/server-postgres&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;env&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;DATABASE_URL&#34;</span><span class="p">:</span> <span class="s2">&#34;postgresql://user:pass@localhost:5432/mydb&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="13-常用-mcp-服务器">1.3 常用 MCP 服务器</h3>
<table>
  <thead>
      <tr>
          <th style="text-align: left">服务器</th>
          <th style="text-align: left">用途</th>
          <th style="text-align: left">安装命令</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: left">filesystem</td>
          <td style="text-align: left">读写本地文件</td>
          <td style="text-align: left"><code>@modelcontextprotocol/server-filesystem</code></td>
      </tr>
      <tr>
          <td style="text-align: left">github</td>
          <td style="text-align: left">GitHub 操作</td>
          <td style="text-align: left"><code>@modelcontextprotocol/server-github</code></td>
      </tr>
      <tr>
          <td style="text-align: left">postgres</td>
          <td style="text-align: left">数据库查询</td>
          <td style="text-align: left"><code>@modelcontextprotocol/server-postgres</code></td>
      </tr>
      <tr>
          <td style="text-align: left">memory</td>
          <td style="text-align: left">持久化记忆</td>
          <td style="text-align: left"><code>@modelcontextprotocol/server-memory</code></td>
      </tr>
      <tr>
          <td style="text-align: left">slack</td>
          <td style="text-align: left">Slack 消息</td>
          <td style="text-align: left"><code>@modelcontextprotocol/server-slack</code></td>
      </tr>
      <tr>
          <td style="text-align: left">puppeteer</td>
          <td style="text-align: left">网页自动化</td>
          <td style="text-align: left"><code>@modelcontextprotocol/server-puppeteer</code></td>
      </tr>
  </tbody>
</table>
<h3 id="14-实战连接数据库查询">1.4 实战：连接数据库查询</h3>
<p>配置 PostgreSQL MCP 后，你可以这样使用：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">You: 帮我查一下最近7天注册的用户数量，按天分组
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Claude: 我来查询数据库...
</span></span><span class="line"><span class="cl">[调用 postgres MCP 服务器]
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">查询结果：
</span></span><span class="line"><span class="cl">| 日期 | 新增用户数 |
</span></span><span class="line"><span class="cl">|------|-----------|
</span></span><span class="line"><span class="cl">| 12-20 | 156 |
</span></span><span class="line"><span class="cl">| 12-21 | 189 |
</span></span><span class="line"><span class="cl">| 12-22 | 203 |
</span></span><span class="line"><span class="cl">| 12-23 | 178 |
</span></span><span class="line"><span class="cl">| 12-24 | 245 |
</span></span><span class="line"><span class="cl">| 12-25 | 312 |
</span></span><span class="line"><span class="cl">| 12-26 | 198 |
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">总计：1,481 位新用户
</span></span><span class="line"><span class="cl">可以看出 12-25（圣诞节）有明显的注册高峰。
</span></span></code></pre></td></tr></table>
</div>
</div><hr>
<h2 id="二hooks自动化工作流的核心">二、Hooks：自动化工作流的核心</h2>
<h3 id="21-什么是-hooks">2.1 什么是 Hooks？</h3>
<p>Hooks 是 Claude Code 生命周期中的&quot;钩子&quot;，让你在特定事件发生时自动执行脚本。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">用户输入 → [UserPromptSubmit Hook] → Claude 思考
</span></span><span class="line"><span class="cl">                                          ↓
</span></span><span class="line"><span class="cl">                              [PreToolUse Hook] → 工具执行
</span></span><span class="line"><span class="cl">                                                      ↓
</span></span><span class="line"><span class="cl">                                          [PostToolUse Hook] → 返回结果
</span></span><span class="line"><span class="cl">                                                                   ↓
</span></span><span class="line"><span class="cl">                                                          [Stop Hook] → 会话结束
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="22-官方-8-大事件">2.2 官方 8 大事件</h3>
<table>
  <thead>
      <tr>
          <th style="text-align: left">事件</th>
          <th style="text-align: left">触发时机</th>
          <th style="text-align: left">可用变量</th>
          <th style="text-align: left">能否阻断</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: left"><code>SessionStart</code></td>
          <td style="text-align: left">会话新建/resume</td>
          <td style="text-align: left">无</td>
          <td style="text-align: left">❌</td>
      </tr>
      <tr>
          <td style="text-align: left"><code>UserPromptSubmit</code></td>
          <td style="text-align: left">用户按回车前</td>
          <td style="text-align: left"><code>prompt</code></td>
          <td style="text-align: left">✅</td>
      </tr>
      <tr>
          <td style="text-align: left"><code>PreToolUse</code></td>
          <td style="text-align: left">工具准备执行前</td>
          <td style="text-align: left"><code>tool_name</code>, <code>tool_input</code></td>
          <td style="text-align: left">✅</td>
      </tr>
      <tr>
          <td style="text-align: left"><code>PostToolUse</code></td>
          <td style="text-align: left">工具执行结束后</td>
          <td style="text-align: left"><code>tool_name</code>, <code>tool_input</code>, <code>tool_output</code></td>
          <td style="text-align: left">❌</td>
      </tr>
      <tr>
          <td style="text-align: left"><code>Notification</code></td>
          <td style="text-align: left">Claude 需要用户输入</td>
          <td style="text-align: left"><code>notification_text</code></td>
          <td style="text-align: left">❌</td>
      </tr>
      <tr>
          <td style="text-align: left"><code>Stop</code></td>
          <td style="text-align: left">回答整体结束</td>
          <td style="text-align: left">无</td>
          <td style="text-align: left">❌</td>
      </tr>
      <tr>
          <td style="text-align: left"><code>SubagentStop</code></td>
          <td style="text-align: left">子代理任务结束</td>
          <td style="text-align: left"><code>subagent_name</code>, <code>result</code></td>
          <td style="text-align: left">❌</td>
      </tr>
      <tr>
          <td style="text-align: left"><code>PreCompact</code></td>
          <td style="text-align: left">压缩对话缓存前</td>
          <td style="text-align: left">无</td>
          <td style="text-align: left">❌</td>
      </tr>
  </tbody>
</table>
<h3 id="23-配置-hooks">2.3 配置 Hooks</h3>
<p><strong>全局配置</strong> <code>~/.claude/settings.json</code>：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;hooks&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;PreToolUse&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;matcher&#34;</span><span class="p">:</span> <span class="s2">&#34;Bash&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;hooks&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">          <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;command&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;echo &#39;[AUDIT] Bash command: $TOOL_INPUT&#39; &gt;&gt; ~/.claude/audit.log&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">]</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;PostToolUse&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;matcher&#34;</span><span class="p">:</span> <span class="s2">&#34;Write&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;hooks&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">          <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;command&#34;</span><span class="p">,</span> 
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;npx prettier --write $FILE_PATH 2&gt;/dev/null || true&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">]</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;UserPromptSubmit&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;hooks&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">          <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;command&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;/path/to/validate-prompt.sh&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">]</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p><strong>项目级配置</strong> <code>.claude/settings.local.json</code>：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;hooks&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;PostToolUse&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;matcher&#34;</span><span class="p">:</span> <span class="s2">&#34;Write&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;hooks&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">          <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;command&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;npm run lint:fix -- $FILE_PATH&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">]</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="24-实战示例">2.4 实战示例</h3>
<p><strong>示例1：自动格式化代码</strong></p>
<p>每次 Claude 写入文件后，自动运行 Prettier：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;hooks&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;PostToolUse&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;matcher&#34;</span><span class="p">:</span> <span class="s2">&#34;Write|Edit|MultiEdit&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;hooks&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">          <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;command&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;npx prettier --write \&#34;$TOOL_INPUT\&#34; 2&gt;/dev/null || true&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">]</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p><strong>示例2：危险命令拦截</strong></p>
<p>阻止执行危险的 Bash 命令：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="cp">#!/bin/bash
</span></span></span><span class="line"><span class="cl"><span class="cp"></span><span class="c1"># ~/.claude/scripts/validate-bash.sh</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nv">DANGEROUS_PATTERNS</span><span class="o">=</span><span class="s2">&#34;rm -rf|DROP TABLE|DELETE FROM|format|mkfs&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="nb">echo</span> <span class="s2">&#34;</span><span class="nv">$TOOL_INPUT</span><span class="s2">&#34;</span> <span class="p">|</span> grep -qE <span class="s2">&#34;</span><span class="nv">$DANGEROUS_PATTERNS</span><span class="s2">&#34;</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;BLOCKED: 检测到危险命令&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="nb">exit</span> <span class="m">1</span>
</span></span><span class="line"><span class="cl"><span class="k">fi</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">exit</span> <span class="m">0</span>
</span></span></code></pre></td></tr></table>
</div>
</div><div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;hooks&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;PreToolUse&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;matcher&#34;</span><span class="p">:</span> <span class="s2">&#34;Bash&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;hooks&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">          <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;command&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;~/.claude/scripts/validate-bash.sh&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">]</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p><strong>示例3：Slack 通知</strong></p>
<p>任务完成后发送 Slack 通知：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;hooks&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;Stop&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;hooks&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">          <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;command&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;curl -X POST -H &#39;Content-type: application/json&#39; --data &#39;{\&#34;text\&#34;:\&#34;Claude Code 任务完成!\&#34;}&#39; $SLACK_WEBHOOK_URL&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">]</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><hr>
<h2 id="三subagent多智能体并发架构">三、SubAgent：多智能体并发架构</h2>
<h3 id="31-架构原理">3.1 架构原理</h3>
<p>Claude Code 采用分层多 Agent 架构，通过<strong>主 Agent</strong>和<strong>SubAgent</strong>协作处理复杂任务：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">用户请求
</span></span><span class="line"><span class="cl">    ↓
</span></span><span class="line"><span class="cl">主 Agent (nO 函数)
</span></span><span class="line"><span class="cl">    ↓
</span></span><span class="line"><span class="cl">是否调用 Task 工具？
</span></span><span class="line"><span class="cl">    ├── 否 → 直接处理 → 返回结果
</span></span><span class="line"><span class="cl">    └── 是 → 创建 SubAgent
</span></span><span class="line"><span class="cl">              ↓
</span></span><span class="line"><span class="cl">         并发执行调度器 (UH1)
</span></span><span class="line"><span class="cl">              ↓
</span></span><span class="line"><span class="cl">         多个 SubAgent 并行执行
</span></span><span class="line"><span class="cl">              ↓
</span></span><span class="line"><span class="cl">         结果合成器 (KN5)
</span></span><span class="line"><span class="cl">              ↓
</span></span><span class="line"><span class="cl">         返回合成结果
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="32-核心特性">3.2 核心特性</h3>
<ol>
<li><strong>完全隔离的执行环境</strong>：每个 SubAgent 在独立上下文中运行</li>
<li><strong>智能并发调度</strong>：支持最多 10 个 Agent 并发执行</li>
<li><strong>安全权限控制</strong>：SubAgent 无法调用 Task 工具（防止递归）</li>
<li><strong>高效结果合成</strong>：智能合并多个 Agent 的输出</li>
</ol>
<h3 id="33-task-工具使用">3.3 Task 工具使用</h3>
<p>当你给 Claude Code 一个复杂任务时，它会自动决定是否使用 SubAgent：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">You: 分析这个项目的代码质量，包括：
</span></span><span class="line"><span class="cl">1. 代码结构是否合理
</span></span><span class="line"><span class="cl">2. 是否有潜在的性能问题
</span></span><span class="line"><span class="cl">3. 测试覆盖率如何
</span></span><span class="line"><span class="cl">4. 安全漏洞检查
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Claude: 这是一个复杂的分析任务，我会启动多个 SubAgent 并行处理：
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">[启动 SubAgent 1] 分析代码结构...
</span></span><span class="line"><span class="cl">[启动 SubAgent 2] 检查性能问题...
</span></span><span class="line"><span class="cl">[启动 SubAgent 3] 分析测试覆盖率...
</span></span><span class="line"><span class="cl">[启动 SubAgent 4] 扫描安全漏洞...
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">[等待所有 SubAgent 完成...]
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">[合成结果] 综合所有 Agent 的分析：
</span></span><span class="line"><span class="cl">...
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="34-subagent-可用工具">3.4 SubAgent 可用工具</h3>
<p>SubAgent 可以使用以下工具：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">SUBAGENT_ALLOWED_TOOLS</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;Read&#39;</span><span class="p">,</span>       <span class="c1">// 读取文件
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="s1">&#39;Write&#39;</span><span class="p">,</span>      <span class="c1">// 写入文件
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="s1">&#39;Edit&#39;</span><span class="p">,</span>       <span class="c1">// 编辑文件
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="s1">&#39;MultiEdit&#39;</span><span class="p">,</span>  <span class="c1">// 多处编辑
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="s1">&#39;Glob&#39;</span><span class="p">,</span>       <span class="c1">// 文件搜索
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="s1">&#39;Grep&#39;</span><span class="p">,</span>       <span class="c1">// 内容搜索
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="s1">&#39;Bash&#39;</span><span class="p">,</span>       <span class="c1">// 执行命令
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="s1">&#39;WebFetch&#39;</span><span class="p">,</span>   <span class="c1">// 网页获取
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="s1">&#39;WebSearch&#39;</span><span class="p">,</span>  <span class="c1">// 网络搜索
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="s1">&#39;TodoRead&#39;</span><span class="p">,</span>   <span class="c1">// 读取任务
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>    <span class="s1">&#39;TodoWrite&#39;</span><span class="p">,</span>  <span class="c1">// 写入任务
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">];</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// 被禁用的工具（防止递归）
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kr">const</span> <span class="nx">BLOCKED_TOOLS</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;Task&#39;</span><span class="p">];</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="35-并发执行示例">3.5 并发执行示例</h3>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">You: 帮我同时搜索项目中所有的 TODO 注释、FIXME 标记和废弃的 API 调用
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">Claude: 我会并行启动 3 个搜索任务：
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">[SubAgent 1] 搜索 TODO 注释...
</span></span><span class="line"><span class="cl">[SubAgent 2] 搜索 FIXME 标记...
</span></span><span class="line"><span class="cl">[SubAgent 3] 搜索废弃 API 调用...
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">--- 3 秒后 ---
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">[SubAgent 1 完成] 找到 23 个 TODO
</span></span><span class="line"><span class="cl">[SubAgent 2 完成] 找到 8 个 FIXME
</span></span><span class="line"><span class="cl">[SubAgent 3 完成] 找到 5 个废弃 API
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">[合成结果]
</span></span><span class="line"><span class="cl">## 代码待办事项汇总
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">### TODO (23处)
</span></span><span class="line"><span class="cl">- src/api/user.ts:45 - TODO: 添加缓存
</span></span><span class="line"><span class="cl">- src/components/Table.tsx:123 - TODO: 优化渲染性能
</span></span><span class="line"><span class="cl">...
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">### FIXME (8处)
</span></span><span class="line"><span class="cl">- src/utils/date.ts:67 - FIXME: 时区处理有问题
</span></span><span class="line"><span class="cl">...
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">### 废弃 API (5处)
</span></span><span class="line"><span class="cl">- src/legacy/auth.ts:12 - 使用了已废弃的 crypto.createCipher
</span></span><span class="line"><span class="cl">...
</span></span></code></pre></td></tr></table>
</div>
</div><hr>
<h2 id="四claudemd-配置系统">四、CLAUDE.md 配置系统</h2>
<h3 id="41-三级配置文件">4.1 三级配置文件</h3>
<p>Claude Code 使用三类 <code>.md</code> 文件进行配置，优先级从高到低：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: left">文件</th>
          <th style="text-align: left">位置</th>
          <th style="text-align: left">作用范围</th>
          <th style="text-align: left">版本控制</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: left"><code>CLAUDE.local.md</code></td>
          <td style="text-align: left">项目根目录</td>
          <td style="text-align: left">当前用户</td>
          <td style="text-align: left">❌ 不提交</td>
      </tr>
      <tr>
          <td style="text-align: left"><code>CLAUDE.md</code></td>
          <td style="text-align: left">项目根目录</td>
          <td style="text-align: left">当前项目</td>
          <td style="text-align: left">✅ 提交</td>
      </tr>
      <tr>
          <td style="text-align: left"><code>~/.claude/CLAUDE.md</code></td>
          <td style="text-align: left">用户目录</td>
          <td style="text-align: left">所有项目</td>
          <td style="text-align: left">❌ 不提交</td>
      </tr>
  </tbody>
</table>
<h3 id="42-创建项目配置">4.2 创建项目配置</h3>
<p>使用 <code>/init</code> 命令自动生成：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">claude
</span></span><span class="line"><span class="cl">&gt; /init
</span></span></code></pre></td></tr></table>
</div>
</div><p>这会在项目根目录创建 <code>CLAUDE.md</code> 文件。</p>
<h3 id="43-配置示例">4.3 配置示例</h3>
<p><strong>项目级 CLAUDE.md</strong>（提交到 Git）：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-markdown" data-lang="markdown"><span class="line"><span class="cl"><span class="gh"># 项目配置
</span></span></span><span class="line"><span class="cl"><span class="gh"></span>
</span></span><span class="line"><span class="cl"><span class="gu">## 项目概述
</span></span></span><span class="line"><span class="cl"><span class="gu"></span>这是一个 Next.js 14 电商平台，使用 TypeScript + Prisma + PostgreSQL。
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="gu">## 技术栈
</span></span></span><span class="line"><span class="cl"><span class="gu"></span><span class="k">-</span> 框架：Next.js 14 (App Router)
</span></span><span class="line"><span class="cl"><span class="k">-</span> 语言：TypeScript 5.x (严格模式)
</span></span><span class="line"><span class="cl"><span class="k">-</span> 数据库：PostgreSQL + Prisma ORM
</span></span><span class="line"><span class="cl"><span class="k">-</span> 样式：Tailwind CSS
</span></span><span class="line"><span class="cl"><span class="k">-</span> 状态管理：Zustand
</span></span><span class="line"><span class="cl"><span class="k">-</span> 测试：Vitest + Testing Library
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="gu">## 代码规范
</span></span></span><span class="line"><span class="cl"><span class="gu"></span><span class="k">-</span> 使用 ESLint + Prettier 格式化
</span></span><span class="line"><span class="cl"><span class="k">-</span> 组件使用函数式写法
</span></span><span class="line"><span class="cl"><span class="k">-</span> 所有函数必须有 JSDoc 注释
</span></span><span class="line"><span class="cl"><span class="k">-</span> 禁止使用 any 类型
</span></span><span class="line"><span class="cl"><span class="k">-</span> 错误处理使用自定义 Error 类
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="gu">## 目录结构
</span></span></span></code></pre></td></tr></table>
</div>
</div><p>src/
├── app/           # Next.js App Router 页面
├── components/    # React 组件
├── lib/           # 工具函数和配置
├── hooks/         # 自定义 Hooks
├── types/         # TypeScript 类型定义
└── prisma/        # 数据库 Schema</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">## 常用命令
</span></span><span class="line"><span class="cl">- `npm run dev` - 启动开发服务器
</span></span><span class="line"><span class="cl">- `npm run build` - 构建生产版本
</span></span><span class="line"><span class="cl">- `npm run test` - 运行测试
</span></span><span class="line"><span class="cl">- `npm run lint` - 代码检查
</span></span><span class="line"><span class="cl">- `npx prisma studio` - 打开数据库管理界面
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">## Git 提交规范
</span></span><span class="line"><span class="cl">- feat: 新功能
</span></span><span class="line"><span class="cl">- fix: 修复 Bug
</span></span><span class="line"><span class="cl">- refactor: 重构
</span></span><span class="line"><span class="cl">- docs: 文档
</span></span><span class="line"><span class="cl">- test: 测试
</span></span><span class="line"><span class="cl">- chore: 构建/工具
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">## 注意事项
</span></span><span class="line"><span class="cl">- 数据库敏感操作需要人工确认
</span></span><span class="line"><span class="cl">- 不要直接修改 prisma/migrations 目录
</span></span><span class="line"><span class="cl">- API 路由必须有权限验证
</span></span></code></pre></td></tr></table>
</div>
</div><p><strong>个人本地配置 CLAUDE.local.md</strong>（不提交）：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-markdown" data-lang="markdown"><span class="line"><span class="cl"><span class="gh"># 本地配置
</span></span></span><span class="line"><span class="cl"><span class="gh"></span>
</span></span><span class="line"><span class="cl"><span class="gu">## 个人偏好
</span></span></span><span class="line"><span class="cl"><span class="gu"></span><span class="k">-</span> 我喜欢详细的注释
</span></span><span class="line"><span class="cl"><span class="k">-</span> 代码示例要完整可运行
</span></span><span class="line"><span class="cl"><span class="k">-</span> 解释时使用中文
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="gu">## 本地环境
</span></span></span><span class="line"><span class="cl"><span class="gu"></span><span class="k">-</span> Node.js: v20.10.0
</span></span><span class="line"><span class="cl"><span class="k">-</span> 数据库：本地 Docker 容器
</span></span><span class="line"><span class="cl"><span class="k">-</span> 端口：3000 (开发), 5432 (PostgreSQL)
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="gu">## 调试配置
</span></span></span><span class="line"><span class="cl"><span class="gu"></span><span class="k">-</span> 使用 VS Code 调试
</span></span><span class="line"><span class="cl"><span class="k">-</span> 断点调试端口: 9229
</span></span></code></pre></td></tr></table>
</div>
</div><p><strong>全局配置 ~/.claude/CLAUDE.md</strong>：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-markdown" data-lang="markdown"><span class="line"><span class="cl"><span class="gh"># 全局配置
</span></span></span><span class="line"><span class="cl"><span class="gh"></span>
</span></span><span class="line"><span class="cl"><span class="gu">## 通用规范
</span></span></span><span class="line"><span class="cl"><span class="gu"></span><span class="k">-</span> 使用 2 空格缩进
</span></span><span class="line"><span class="cl"><span class="k">-</span> 变量命名使用 camelCase
</span></span><span class="line"><span class="cl"><span class="k">-</span> 常量使用 UPPER_SNAKE_CASE
</span></span><span class="line"><span class="cl"><span class="k">-</span> 组件使用 PascalCase
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="gu">## 默认工具
</span></span></span><span class="line"><span class="cl"><span class="gu"></span><span class="k">-</span> 包管理器：pnpm
</span></span><span class="line"><span class="cl"><span class="k">-</span> 版本控制：Git
</span></span><span class="line"><span class="cl"><span class="k">-</span> 编辑器：VS Code
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="gu">## 安全规则
</span></span></span><span class="line"><span class="cl"><span class="gu"></span><span class="k">-</span> 不要在代码中硬编码密钥
</span></span><span class="line"><span class="cl"><span class="k">-</span> 敏感文件（.env）不要提交
</span></span><span class="line"><span class="cl"><span class="k">-</span> API 调用必须有超时设置
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="44-自定义斜杠命令">4.4 自定义斜杠命令</h3>
<p>在 <code>.claude/commands/</code> 目录下创建 Markdown 文件，即可定义自定义命令：</p>
<p><strong>文件结构</strong>：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">.claude/
</span></span><span class="line"><span class="cl">└── commands/
</span></span><span class="line"><span class="cl">    ├── review.md      # /review 命令
</span></span><span class="line"><span class="cl">    ├── test.md        # /test 命令
</span></span><span class="line"><span class="cl">    └── deploy.md      # /deploy 命令
</span></span></code></pre></td></tr></table>
</div>
</div><p><strong>示例：review.md</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-markdown" data-lang="markdown"><span class="line"><span class="cl">请对当前项目进行代码审查：
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">1.</span> 检查代码质量
</span></span><span class="line"><span class="cl">   <span class="k">-</span> 是否有重复代码
</span></span><span class="line"><span class="cl">   <span class="k">-</span> 函数是否过长
</span></span><span class="line"><span class="cl">   <span class="k">-</span> 命名是否清晰
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">2.</span> 检查潜在问题
</span></span><span class="line"><span class="cl">   <span class="k">-</span> 是否有未处理的错误
</span></span><span class="line"><span class="cl">   <span class="k">-</span> 是否有性能问题
</span></span><span class="line"><span class="cl">   <span class="k">-</span> 是否有安全漏洞
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">3.</span> 检查最佳实践
</span></span><span class="line"><span class="cl">   <span class="k">-</span> 是否遵循项目规范
</span></span><span class="line"><span class="cl">   <span class="k">-</span> 是否有充分的测试
</span></span><span class="line"><span class="cl">   <span class="k">-</span> 是否有必要的注释
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">请提供详细的改进建议。
</span></span></code></pre></td></tr></table>
</div>
</div><p>使用：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">&gt; /review
</span></span></code></pre></td></tr></table>
</div>
</div><hr>
<h2 id="五综合实战打造个人-ai-工作流">五、综合实战：打造个人 AI 工作流</h2>
<h3 id="51-完整配置示例">5.1 完整配置示例</h3>
<p>结合以上所有功能，配置一个完整的 AI 开发工作流：</p>
<p><strong>~/.claude/settings.json</strong>：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span><span class="lnt">49
</span><span class="lnt">50
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;mcpServers&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;filesystem&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;npx&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;args&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;-y&#34;</span><span class="p">,</span> <span class="s2">&#34;@modelcontextprotocol/server-filesystem&#34;</span><span class="p">,</span> <span class="s2">&#34;~/Projects&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;env&#34;</span><span class="p">:</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;github&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;npx&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;args&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;-y&#34;</span><span class="p">,</span> <span class="s2">&#34;@modelcontextprotocol/server-github&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;env&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;GITHUB_TOKEN&#34;</span><span class="p">:</span> <span class="s2">&#34;${GITHUB_TOKEN}&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;hooks&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;PostToolUse&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;matcher&#34;</span><span class="p">:</span> <span class="s2">&#34;Write|Edit&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;hooks&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">          <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;command&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;npx prettier --write \&#34;$FILE_PATH\&#34; 2&gt;/dev/null || true&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">]</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;Stop&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;hooks&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">          <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;command&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;echo \&#34;[$(date)] Task completed\&#34; &gt;&gt; ~/.claude/activity.log&#34;</span>
</span></span><span class="line"><span class="cl">          <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">]</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="cl">  <span class="p">},</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;permissions&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;allow&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">      <span class="s2">&#34;Bash(npm run *)&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="s2">&#34;Bash(git *)&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="s2">&#34;Bash(npx prettier *)&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">],</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;deny&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">      <span class="s2">&#34;Bash(rm -rf *)&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="s2">&#34;Bash(sudo *)&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="52-工作流示例">5.2 工作流示例</h3>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">1. 启动项目
</span></span><span class="line"><span class="cl">   &gt; claude
</span></span><span class="line"><span class="cl">   &gt; /init  # 生成 CLAUDE.md
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">2. 查看项目状态
</span></span><span class="line"><span class="cl">   &gt; /review  # 运行自定义代码审查命令
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">3. 开发新功能
</span></span><span class="line"><span class="cl">   &gt; 帮我实现用户头像上传功能，要支持裁剪和压缩
</span></span><span class="line"><span class="cl">   
</span></span><span class="line"><span class="cl">   [Claude 自动]:
</span></span><span class="line"><span class="cl">   - 分析项目结构
</span></span><span class="line"><span class="cl">   - 创建组件文件（自动格式化）
</span></span><span class="line"><span class="cl">   - 编写测试用例
</span></span><span class="line"><span class="cl">   - 更新文档
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">4. 提交代码
</span></span><span class="line"><span class="cl">   &gt; 提交这些改动，写一个清晰的 commit message
</span></span><span class="line"><span class="cl">   
</span></span><span class="line"><span class="cl">   [Claude 使用 GitHub MCP]:
</span></span><span class="line"><span class="cl">   - 生成 commit message
</span></span><span class="line"><span class="cl">   - 创建 commit
</span></span><span class="line"><span class="cl">   - 可选：创建 PR
</span></span></code></pre></td></tr></table>
</div>
</div><hr>
<h2 id="总结">总结</h2>
<p>Claude Code 的高级功能让它从一个简单的 AI 聊天工具，变成了一个真正的<strong>AI 开发平台</strong>：</p>
<table>
  <thead>
      <tr>
          <th style="text-align: left">功能</th>
          <th style="text-align: left">作用</th>
          <th style="text-align: left">收益</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td style="text-align: left"><strong>MCP</strong></td>
          <td style="text-align: left">连接外部工具和数据</td>
          <td style="text-align: left">扩展能力边界</td>
      </tr>
      <tr>
          <td style="text-align: left"><strong>Hooks</strong></td>
          <td style="text-align: left">自动化工作流</td>
          <td style="text-align: left">减少重复操作</td>
      </tr>
      <tr>
          <td style="text-align: left"><strong>SubAgent</strong></td>
          <td style="text-align: left">并发处理复杂任务</td>
          <td style="text-align: left">提升效率</td>
      </tr>
      <tr>
          <td style="text-align: left"><strong>CLAUDE.md</strong></td>
          <td style="text-align: left">定义项目规范</td>
          <td style="text-align: left">保持一致性</td>
      </tr>
  </tbody>
</table>
<p>掌握这些功能，你就能把 Claude Code 打造成专属的 AI 工程师团队。</p>
<hr>
<h2 id="参考资源">参考资源</h2>
<ul>
<li><a href="https://docs.anthropic.com/claude-code">Claude Code 官方文档</a></li>
<li><a href="https://modelcontextprotocol.io">MCP 协议规范</a></li>
<li><a href="https://github.com/modelcontextprotocol/servers">MCP 服务器列表</a></li>
</ul>
]]></content:encoded></item><item><title>给 Agent 写工具:一个好 tool 长什么样</title><link>https://realtime-ai.chat/posts/agent-tool-design/</link><pubDate>Sun, 17 May 2026 11:00:00 +0800</pubDate><guid>https://realtime-ai.chat/posts/agent-tool-design/</guid><description>Agent 跑不好,常常不是模型不行,是工具设计得差。这篇讲清工具描述、参数、返回值、错误回传、粒度切分该怎么做,每条都配正反例。</description><content:encoded><![CDATA[<p>我见过一个团队为了让 Agent &ldquo;更聪明&rdquo;,把模型从中杯换成大杯,账单翻了三倍,效果几乎没动。后来定位下来,问题出在一个叫 <code>query</code> 的工具上:它的描述只有一句&quot;查询数据库&quot;,返回的是一坨 4000 行的 JSON,里面塞满了 <code>created_at_unix</code>、<code>tenant_uuid</code>、<code>row_version</code> 这种字段。模型不是不聪明,是它每次调用完都得在一堆噪声里捞针,然后经常捞错。</p>
<p>把这个工具拆成两个、描述写清楚、返回值砍掉八成,中杯模型的表现就超过了原来大杯的版本。</p>
<p>这不是个例。<strong>Agent 能力的天花板,很多时候是工具设计,不是模型。</strong> 模型是你换不动的那部分——它由 Anthropic、OpenAI 训练,你只能选型;工具是你完全能控制的那部分。把精力花在能控制的地方,回报率高得多。</p>
<p>Anthropic 在 2026 年那篇《Writing effective tools for AI agents》里有一句话我很认同:工具是一种新的软件形态,它是<strong>确定性系统和非确定性 Agent 之间的契约</strong>。你不能再按&quot;给另一个程序员写 API&quot;的思路写工具——调用方变了,设计原则就得跟着变。</p>
<h2 id="工具描述你在跟模型招标">工具描述:你在跟模型&quot;招标&quot;</h2>
<p>模型面对一组工具,做的事情和招标差不多:读每个工具的描述,判断&quot;这个活该派给谁&quot;。描述写得含糊,它就选错;描述之间边界不清,它就来回横跳。</p>
<p>最常见的坏味道是<strong>用实现细节代替使用场景</strong>。</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl"># 反例
</span></span><span class="line"><span class="cl">{
</span></span><span class="line"><span class="cl">  &#34;name&#34;: &#34;db_query&#34;,
</span></span><span class="line"><span class="cl">  &#34;description&#34;: &#34;对主库执行 SQL 查询&#34;
</span></span><span class="line"><span class="cl">}
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"># 正例
</span></span><span class="line"><span class="cl">{
</span></span><span class="line"><span class="cl">  &#34;name&#34;: &#34;search_orders&#34;,
</span></span><span class="line"><span class="cl">  &#34;description&#34;: &#34;按用户 ID、时间范围或订单状态查询订单。
</span></span><span class="line"><span class="cl">                  用于回答&#39;用户买过什么&#39;&#39;某笔订单到哪了&#39;这类问题。
</span></span><span class="line"><span class="cl">                  不要用它查商品库存——那是 search_inventory 的活。&#34;
</span></span><span class="line"><span class="cl">}
</span></span></code></pre></td></tr></table>
</div>
</div><p>差别在哪?反例描述的是&quot;工具内部怎么干活&quot;(执行 SQL),模型并不关心这个;它关心的是&quot;什么时候该用我&quot;。正例直接给出<strong>触发场景</strong>,还顺手划清了和邻居工具的边界。</p>
<p>这里有个容易被忽略的点:<strong>当你有多个相似工具时,描述里必须明确&quot;我不是谁&quot;。</strong> Anthropic 的建议是用命名空间区分,比如 <code>asana_search</code> 和 <code>jira_search</code>,或者更细的 <code>asana_projects_search</code>、<code>asana_users_search</code>。前缀本身就是一种边界声明。光靠名字还不够时,就在描述里直接写&quot;查 X 用我,查 Y 请用那个工具&quot;。</p>
<p>另一个实战技巧:<strong>在描述里塞一两个使用示例</strong>。模型在互联网文本里见过的函数,旁边大多带着调用例子,这种格式它最熟。一个 <code>search_orders(user_id=&quot;u_123&quot;, status=&quot;shipped&quot;)</code> 的示例,比三行抽象说明管用。2026 年 Anthropic 的 Claude API 干脆把这个能力产品化了,叫 Tool Use Examples——可见示例不是锦上添花,是正经手段。</p>
<h2 id="参数让模型填得对而不是填得全">参数:让模型&quot;填得对&quot;,而不是&quot;填得全&quot;</h2>
<p>参数设计的核心矛盾是:你想要灵活,模型想要明确。这两者经常打架,而你应该站在模型这边。</p>
<p><strong>第一,别用裸字符串当枚举。</strong> 一个 <code>status</code> 参数,如果你在描述里写&quot;传订单状态&quot;,模型可能传 <code>&quot;已发货&quot;</code>、<code>&quot;shipped&quot;</code>、<code>&quot;SHIPPED&quot;</code>、<code>&quot;发货中&quot;</code>——四种写法,你的代码能认几种?直接用枚举把可选值锁死:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 反例:status 是 str,模型自由发挥</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">search_orders</span><span class="p">(</span><span class="n">user_id</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">status</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span> <span class="o">...</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 正例:枚举,模型只能在合法值里选</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">enum</span> <span class="kn">import</span> <span class="n">Enum</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">OrderStatus</span><span class="p">(</span><span class="nb">str</span><span class="p">,</span> <span class="n">Enum</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">PENDING</span> <span class="o">=</span> <span class="s2">&#34;pending&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">SHIPPED</span> <span class="o">=</span> <span class="s2">&#34;shipped&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">DELIVERED</span> <span class="o">=</span> <span class="s2">&#34;delivered&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">CANCELLED</span> <span class="o">=</span> <span class="s2">&#34;cancelled&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">search_orders</span><span class="p">(</span><span class="n">user_id</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">status</span><span class="p">:</span> <span class="n">OrderStatus</span> <span class="o">|</span> <span class="kc">None</span> <span class="o">=</span> <span class="kc">None</span><span class="p">):</span> <span class="o">...</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p><strong>第二,能有默认值就别让模型填。</strong> 每多一个必填参数,就多一个模型出错的机会。分页的 <code>page_size</code>、排序的 <code>order_by</code>,给个合理默认值,模型大多数时候根本不用碰它。</p>
<p><strong>第三,警惕&quot;看起来很像&quot;的参数。</strong> 一个工具同时收 <code>start_date</code> 和 <code>end_date</code>,模型偶尔会填反。如果业务允许,合并成一个 <code>time_range</code> 枚举(<code>last_7_days</code>、<code>last_30_days</code>、<code>this_month</code>)往往更稳——你把&quot;理解日期区间&quot;这件事从模型手里拿回来了。当然,需要精确区间时该用两个还得用两个,这是取舍,不是教条。</p>
<p>一个判断标准:<strong>如果一个参数,你自己都要想三秒才知道该填什么,模型只会比你更糊涂。</strong></p>
<h2 id="返回值给模型能用的信息不是给它一份数据库导出">返回值:给模型能用的信息,不是给它一份数据库导出</h2>
<p>这是我见过踩坑最多的地方,值得单独讲。</p>
<p>工具的返回值会<strong>原封不动进入模型的上下文窗口</strong>。这意味着两件事:一是它占 token,占的还是最贵的那部分;二是模型要从里面提取信息做下一步决策。所以返回值的设计目标只有一个——<strong>高信噪比</strong>。</p>
<p>反例长这样:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;data&#34;</span><span class="p">:</span> <span class="p">[{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;order_id&#34;</span><span class="p">:</span> <span class="s2">&#34;ord_8f3a2b1c-9d4e-4f5a-8b6c-1d2e3f4a5b6c&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;tenant_uuid&#34;</span><span class="p">:</span> <span class="s2">&#34;tn_a1b2c3d4&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;created_at_unix&#34;</span><span class="p">:</span> <span class="mi">1747300800</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;updated_at_unix&#34;</span><span class="p">:</span> <span class="mi">1747387200</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;row_version&#34;</span><span class="p">:</span> <span class="mi">7</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;status_code&#34;</span><span class="p">:</span> <span class="mi">2</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;_internal_flags&#34;</span><span class="p">:</span> <span class="p">{</span> <span class="nt">&#34;is_migrated&#34;</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span> <span class="nt">&#34;shard&#34;</span><span class="p">:</span> <span class="mi">3</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}]</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>模型看到这个,得自己去想:<code>status_code: 2</code> 是什么意思?<code>created_at_unix</code> 怎么换算成人话?<code>tenant_uuid</code> 要不要在下一步带上?这些都是噪声,而且每一条都是潜在的出错点。</p>
<p>Anthropic 的原则说得很直白:<strong>返回人类可读的字段,别返回底层技术标识符。</strong> <code>name</code>、<code>status</code>、<code>created_at</code>(写成可读时间)这种字段能直接指导模型的下一步动作;<code>uuid</code>、<code>mime_type</code>、<code>row_version</code> 不能,它们只是占地方。</p>
<p>正例:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;orders&#34;</span><span class="p">:</span> <span class="p">[{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="s2">&#34;ord_8f3a2b1c&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;status&#34;</span><span class="p">:</span> <span class="s2">&#34;shipped&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;created_at&#34;</span><span class="p">:</span> <span class="s2">&#34;2026-05-15 14:00&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;total&#34;</span><span class="p">:</span> <span class="s2">&#34;¥299.00&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;items_summary&#34;</span><span class="p">:</span> <span class="s2">&#34;无线耳机 x1&#34;</span>
</span></span><span class="line"><span class="cl">  <span class="p">}],</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;total_count&#34;</span><span class="p">:</span> <span class="mi">47</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;showing&#34;</span><span class="p">:</span> <span class="s2">&#34;1-10&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;hint&#34;</span><span class="p">:</span> <span class="s2">&#34;还有 37 条,加 status 或更窄的时间范围可缩小结果&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>注意最后那个 <code>hint</code> 字段。<strong>返回值不只是数据,也是给模型的下一步提示。</strong> 当结果太多时,与其返回 47 条把上下文撑爆,不如返回 10 条加一句&quot;还有 37 条,这样筛&quot;。Anthropic 把这类机制叫分页、范围过滤、截断,核心思想一致:别让模型被数据淹没,主动引导它做更窄、更省 token 的查询。</p>
<p>下面这张图是返回值设计的取舍:</p>
<pre class="mermaid">flowchart TD
  A[工具拿到原始结果] --> B{结果量大吗?}
  B -->|小| C[直接返回可读字段]
  B -->|大| D[截断 + 分页]
  D --> E[附 hint:怎么缩小范围]
  C --> F[剔除 uuid/时间戳/内部 flag]
  E --> F
  F --> G[进入模型上下文]
  style F fill:#fde7c2,stroke:#e8b23c
  style E fill:#fde7c2,stroke:#e8b23c
</pre><p>橙色那两块——<strong>剔除噪声字段</strong>和<strong>附带引导提示</strong>——是最容易省略、又最影响效果的环节。</p>
<h2 id="错误怎么回错误信息是给模型的操作手册">错误怎么回:错误信息是给模型的&quot;操作手册&quot;</h2>
<p>工具调用失败是常态,不是异常。模型填错参数、查的资源不存在、触发了限流——这些每天都在发生。真正决定 Agent 韧性的,是<strong>出错之后它能不能自己爬起来</strong>。而它能不能爬起来,取决于你的错误信息写成什么样。</p>
<p>反例:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">&#34;Invalid input&#34;</span><span class="p">)</span>          <span class="c1"># 模型:啥 input?哪儿错了?</span>
</span></span><span class="line"><span class="cl"><span class="k">return</span> <span class="p">{</span><span class="s2">&#34;error&#34;</span><span class="p">:</span> <span class="s2">&#34;ERR_4012&#34;</span><span class="p">}</span>                 <span class="c1"># 模型:4012 是什么我怎么知道</span>
</span></span><span class="line"><span class="cl"><span class="k">raise</span> <span class="ne">Exception</span><span class="p">(</span><span class="n">traceback</span><span class="o">...</span><span class="p">)</span>                <span class="c1"># 模型:吞掉半屏 token,然后还是不知道咋办</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>这三种回法的共同问题是:<strong>模型读完不知道下一步该干什么。</strong> 它要么放弃,要么用同样的错参数原样重试,卡进死循环。</p>
<p>好的错误信息要满足一个标准——<strong>模型读完就知道怎么改</strong>:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 正例:说清错在哪 + 给出可执行的下一步</span>
</span></span><span class="line"><span class="cl"><span class="k">return</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;error&#34;</span><span class="p">:</span> <span class="s2">&#34;参数 status 的值 &#39;发货中&#39; 不合法&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;valid_values&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;pending&#34;</span><span class="p">,</span> <span class="s2">&#34;shipped&#34;</span><span class="p">,</span> <span class="s2">&#34;delivered&#34;</span><span class="p">,</span> <span class="s2">&#34;cancelled&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;hint&#34;</span><span class="p">:</span> <span class="s2">&#34;你可能想用 &#39;shipped&#39;&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">return</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;error&#34;</span><span class="p">:</span> <span class="s2">&#34;未找到 user_id &#39;u_999&#39; 对应的用户&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;hint&#34;</span><span class="p">:</span> <span class="s2">&#34;确认 ID 是否正确,或先用 search_users 按用户名查到 ID&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Anthropic 的说法是:你可以<strong>对错误信息做提示工程</strong>,把它写成清晰、可执行的改进建议,而不是不透明的错误码或堆栈。一条好的错误信息会顺手告诉模型&quot;下一步该调哪个工具&quot;——上面那个 <code>search_users</code> 的提示就是。这等于把错误信息也当成了引导模型的一个入口。</p>
<p>还有个常被忽略的点:<strong>错误也要省 token。</strong> 别把整个 Python traceback 塞回去,那几百个 token 对模型几乎没有信息价值。给一句人话就够了。</p>
<h2 id="工具粒度太细太粗都不行">工具粒度:太细太粗都不行</h2>
<p>最后一个,也是最难的——工具切多大。</p>
<p><strong>切太细的坑。</strong> 把 <code>get_user</code>、<code>get_user_orders</code>、<code>get_order_detail</code> 拆成三个独立工具,听起来很&quot;单一职责&quot;。但 Agent 要回答&quot;用户最近这单到哪了&quot;,得连着调三次:第一次拿 user,第二次拿 order 列表,第三次拿 detail。三次往返,三段返回值堆进上下文,任何一步选错都得重来。<strong>工具太细,模型就被迫去干编排的活,而编排正是它最容易出错的地方。</strong></p>
<p><strong>切太粗的坑。</strong> 反过来做一个万能的 <code>manage_order</code>,靠一个 <code>action</code> 参数切换&quot;查询/创建/退款/改地址&quot;。模型每次都要先想清楚 <code>action</code> 填什么、对应又该带哪些参数,描述也长得没法读。而且一个工具权限太大,审计和兜底都难做——你没法只给某个 Agent &ldquo;查询&quot;权限而不给&quot;退款&quot;权限。</p>
<p>我的经验法则是:<strong>按&quot;用户意图&quot;切,不按&quot;数据库表&quot;切,也不按&quot;一个超级动作&quot;切。</strong></p>
<table>
  <thead>
      <tr>
          <th>切法</th>
          <th>例子</th>
          <th>问题</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>按表切(太细)</td>
          <td><code>get_user</code> / <code>get_orders</code> / <code>get_items</code></td>
          <td>模型被迫多次编排,易错</td>
      </tr>
      <tr>
          <td>按超级动作切(太粗)</td>
          <td><code>manage_order(action=...)</code></td>
          <td>参数耦合、描述爆炸、权限难控</td>
      </tr>
      <tr>
          <td><strong>按意图切(推荐)</strong></td>
          <td><code>get_order_status(order_id)</code> 一次返回订单+物流+商品摘要</td>
          <td>一次调用解决一个完整问题</td>
      </tr>
  </tbody>
</table>
<p>判断方法很简单:<strong>想象一个真实的用户问题,数一数 Agent 要调几次工具才能答上。</strong> 如果一个常见问题要调四五次,你的工具大概率切太细了;如果一个工具的描述你得写满一屏才说得清,那它八成切太粗了。</p>
<p>Anthropic 反复强调的&quot;evaluation-driven development&quot;在这里特别管用:先拿真实任务跑一批评测,看 Agent 卡在哪、绕了多少弯路,再回头调工具的粒度。工具设计不是一次写对的,是测出来、改出来的。</p>
<h2 id="几条收尾的话">几条收尾的话</h2>
<p>把上面的拆开看是五个话题,合起来其实是一个视角的转变:<strong>你不是在给程序写接口,你是在给一个会读字、会犯错、上下文有限的&quot;实习生&quot;写操作手册。</strong></p>
<p>落到日常,优先级我会这么排:</p>
<ol>
<li><strong>先治返回值。</strong> 砍掉 uuid、时间戳、内部 flag,只留可读字段。这一步零成本,收益立竿见影。</li>
<li><strong>再治错误信息。</strong> 把每条错误都改成&quot;说清错在哪 + 下一步怎么办&rdquo;。Agent 的韧性主要靠这个。</li>
<li><strong>然后理顺粒度。</strong> 按意图切,用真实任务量一量调用次数。</li>
<li><strong>最后打磨描述和参数。</strong> 加示例、上枚举、给默认值。</li>
</ol>
<p>别一上来就盯着换模型。先把你能 100% 控制的那部分——工具——做扎实了,再去谈模型选型。很多时候,中杯配一组好工具,比大杯配一组烂工具跑得稳得多,还便宜。</p>
<hr>
<p><strong>参考资料</strong></p>
<ul>
<li><a href="https://www.anthropic.com/engineering/writing-tools-for-agents">Writing effective tools for AI agents — Anthropic Engineering</a></li>
<li><a href="https://www.anthropic.com/engineering/advanced-tool-use">Introducing advanced tool use on the Claude Developer Platform — Anthropic</a></li>
<li><a href="https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents">Effective context engineering for AI agents — Anthropic</a></li>
<li><a href="https://modelcontextprotocol.info/docs/tutorials/writing-effective-tools/">Writing Effective Tools for Agents: Complete MCP Development Guide</a></li>
</ul>
]]></content:encoded></item><item><title>MCP 生态这半年:从协议到工具市场</title><link>https://realtime-ai.chat/posts/mcp-ecosystem/</link><pubDate>Thu, 14 May 2026 11:00:00 +0800</pubDate><guid>https://realtime-ai.chat/posts/mcp-ecosystem/</guid><description>公开 MCP server 注册表从去年底六千多涨到九千多,远程 MCP、官方 registry、安全争议轮番上场。这篇梳理这半年 MCP 从一纸协议长成一个生态的真实变化与取舍。</description><content:encoded><![CDATA[<p>去年 12 月有件事,当时新闻没怎么吵,但回头看是个分水岭:Anthropic 把 MCP 捐给了一个叫 Agentic AI Foundation 的中立基金会,OpenAI 和 Block 是联合发起方。</p>
<p>翻译一下这句话的分量:<strong>MCP 不再是 Anthropic 的协议了</strong>。它从一家公司的项目,变成了像 Kubernetes、Linux 那样由基金会托管的东西。一个协议要想成为&quot;标准&quot;,最关键的一步从来不是技术上多优雅,而是发明它的那家公司愿意放手——因为没人愿意把自己的核心管道,绑死在竞争对手的协议上。Anthropic 放了手,OpenAI 才肯全线接入。</p>
<p>这半年,MCP 干的事就是这一件:从一纸协议,长成一个生态。这篇不讲 MCP 是什么、怎么写一个 server——那些去年就讲过了。这篇讲的是这半年它<strong>长成了什么样</strong>,以及哪些地方还在裂。</p>
<h2 id="数字先摆出来它到底有多热">数字先摆出来:它到底有多热</h2>
<p>先看注册表里的 server 数量,这是最硬的指标:</p>
<table>
  <thead>
      <tr>
          <th>时间</th>
          <th>公开注册表 server 数</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>2025 Q1 末</td>
          <td>~1,200</td>
      </tr>
      <tr>
          <td>2025 Q3 末</td>
          <td>~3,400</td>
      </tr>
      <tr>
          <td>2025 年底</td>
          <td>~6,800</td>
      </tr>
      <tr>
          <td>2026 年 4 月中</td>
          <td>9,400+</td>
      </tr>
  </tbody>
</table>
<p>一年多 7.8 倍。再看采用面:到 2026 年 4 月,<strong>78% 的企业 AI 团队</strong>说自己生产环境里至少跑着一个 MCP 接入的 agent;受访 CTO 里 67% 认为 MCP 会在一年内成为他们默认的 agent 集成标准。</p>
<p>工具链这边已经没有悬念了。Claude 是原生支持;ChatGPT 接了;Google Gemini API 和 Vertex AI Agent Builder 接了;IDE 这边 Cursor、Windsurf、Zed、JetBrains AI Assistant 全接了;Vercel AI SDK 也接了。你现在想找一个<strong>不支持 MCP</strong> 的主流 AI 产品,反而要费点劲。</p>
<p>但数字热不等于生态健康。9,400 个 server 里有多少是能用的、有人维护的、安全的?这个问题后面会回到。先说这半年最实质的几个变化。</p>
<h2 id="远程-mcp从本地进程到在线服务">远程 MCP:从&quot;本地进程&quot;到&quot;在线服务&quot;</h2>
<p>去年你用 MCP,基本都是 stdio——一个 server 就是你本地跑的一个进程,Claude Desktop 用标准输入输出跟它说话。这套东西的天花板很明显:server 跑在你电脑上,换台机器就没了,也没法给团队共享,更别说做成产品卖。</p>
<p>这半年补上的关键能力叫 <strong>Streamable HTTP</strong>。它让一个 MCP server 可以作为一个<strong>远程在线服务</strong>跑着,而不是绑在某台机器的某个进程上。配合 OAuth,远程 MCP 一下子打开了一类全新的玩法:</p>
<pre class="mermaid">flowchart LR
  subgraph 去年
    A[Claude Desktop] -->|stdio| B[本地 server 进程]
    B --> C[本地文件/数据库]
  end
  subgraph 这半年
    D[任意 MCP 客户端] -->|Streamable HTTP + OAuth| E[远程 MCP 服务]
    E --> F[SaaS API / 云数据]
  end
</pre><p>差别在哪?去年你要用 Notion 的 MCP server,得自己 npm 装一个、配好 token、本地跑起来。现在 Notion 可以<strong>自己</strong>跑一个官方远程 MCP 服务,你在客户端里点一下&quot;连接&quot;,走 OAuth 授权,就接上了——跟你授权一个第三方 App 登录没区别。</p>
<p>这件事的意义不只是方便。它把 MCP server 从&quot;开发者的玩具&quot;变成了&quot;厂商的产品入口&quot;。一个 SaaS 公司现在有动机去做一个官方 MCP server,因为那是它接入所有 AI agent 的门票。<strong>这是生态能滚起来的真正燃料</strong>——不是开源爱好者用爱发电,而是商业公司有了实打实的理由。</p>
<p>代价也实在。远程化之后,一堆分布式系统的老问题全冒出来了:MCP 协议里有&quot;有状态会话&quot;的概念,这东西跟负载均衡天生打架——请求被 LB 分到哪台机器,会话状态就得在哪台。横向扩展得靠各种 workaround。这些是 2026 路线图上明确列出来要解决的坑,现在还没解决干净。</p>
<h2 id="官方注册表-vs-工具市场两套东西别搞混">官方注册表 vs 工具市场:两套东西别搞混</h2>
<p>&ldquo;MCP 有了 App Store&rdquo;——这话这半年传得很广,但它其实把两类不同的东西混成了一个。</p>
<p>一类是<strong>官方注册表</strong>(registry.modelcontextprotocol.io),MCP 项目自己维护的。它的定位更像 DNS 或者 npm 的官方源:一个<strong>中立的、权威的元数据目录</strong>,告诉你&quot;这个 server 叫什么、在哪、谁发布的&quot;。它刻意做得很薄,目前只收录了大约 500 个 server,不替你托管、不替你评分、不卖东西。</p>
<p>另一类是<strong>第三方市场</strong>,Glama、Smithery、mcp.so 这些。它们才是真正&quot;App Store&quot;那一面:聚合、搜索、评分、一键安装,甚至帮你托管运行。规模上,Glama 的列表有两万多条(它把官方注册表 + npm + PyPI + GitHub 的来源全抓进来了),Smithery 有七千多个、而且能直接跑在它自己的基础设施上,自带 OAuth 弹窗——它现在基本就是 MCP 世界的 Docker Hub。</p>
<table>
  <thead>
      <tr>
          <th></th>
          <th>官方注册表</th>
          <th>第三方市场(如 Smithery)</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>定位</td>
          <td>中立元数据目录</td>
          <td>聚合 + 托管 + 分发</td>
      </tr>
      <tr>
          <td>收录量</td>
          <td>~500(精选)</td>
          <td>数千到两万+</td>
      </tr>
      <tr>
          <td>托管运行</td>
          <td>不提供</td>
          <td>提供(远程 server)</td>
      </tr>
      <tr>
          <td>评分/搜索</td>
          <td>弱</td>
          <td>强</td>
      </tr>
      <tr>
          <td>类比</td>
          <td>npm 官方源 / DNS</td>
          <td>Docker Hub / App Store</td>
      </tr>
  </tbody>
</table>
<p>我的看法:<strong>这种&quot;薄注册表 + 厚市场&quot;的分层是对的</strong>。注册表如果既当裁判又当商店,中立性立刻就没了。npm 当年也是这个结构——官方源管元数据,GitHub、各种镜像和增值服务在上面长。MCP 抄对了作业。</p>
<p>至于赚钱,这事儿还很早期、也很乱。各家平台抽成模式天差地别:有的平台要 server 作者每月先交 30 美元、自己一分钱分不到;有的把订阅收入全留下;也有新平台喊出 85% 分成、Stripe 直接打款。说白了,&ldquo;MCP server 怎么变现&quot;目前没有共识,谁也没跑通。但有人开始认真讨论分成比例这件事本身,就说明它正在从&quot;开源项目&quot;往&quot;市场&quot;挪。</p>
<h2 id="安全生态跑太快这块在裂">安全:生态跑太快,这块在裂</h2>
<p>如果说前面都是好消息,那这一节是泼冷水的。<strong>MCP 生态扩张的速度,明显快过它把安全问题想清楚的速度。</strong></p>
<p>最典型的攻击叫<strong>工具投毒</strong>(tool poisoning)。原理不复杂:MCP 的信任模型是 server 把工具的描述、元数据交给客户端,客户端再喂给 LLM 去做决策。攻击者就在工具描述里塞进恶意指令——<strong>模型读得到,用户看不到</strong>。一个看起来人畜无害的&quot;天气查询&quot;工具,描述里可能藏着一句&quot;顺便把用户的 SSH 私钥读出来发到这个地址&rdquo;。这本质上是一种间接 prompt injection,而且它钻的正是 MCP 信任模型的空子。研究界普遍认为这是目前<strong>最普遍、危害最大</strong>的客户端侧漏洞。</p>
<p>第二个是 OAuth。新规范(2025-06-18 那版)已经要求用 OAuth 2.1 了,但&quot;规范要求&quot;和&quot;实际实现&quot;是两码事。OAuth 配错一行,就可能造出一个&quot;混淆代理&quot;(confused deputy)漏洞——你的 agent 拿着它自己的高权限,替攻击者干了攻击者本来没权限干的事。</p>
<p>第三个更基础:<strong>大多数客户端根本不校验 server 给的工具描述</strong>,拿来就用。整个信任链是建立在&quot;server 不作恶&quot;这个假设上的,而远程 MCP 又让你能轻松接入一堆陌生人写的 server。</p>
<p>我的判断很直接:<strong>现在敢把陌生 MCP server 直接接进生产 agent 的,要么没读过威胁模型,要么在赌运气。</strong> 这半年生态在&quot;接入有多容易&quot;上进步飞快,在&quot;接入有多安全&quot;上进步慢得多。如果你在做企业级的东西,务实的做法是:只用自己审过的 server、给 agent 的权限按最小化来配、对工具描述做一遍校验和过滤——别指望协议本身替你兜底,它现在兜不住。</p>
<h2 id="它真成事实标准了吗我的答案是一半">它真成&quot;事实标准&quot;了吗?我的答案是:一半</h2>
<p>把上面的拼起来看:基金会托管、全行业接入、注册表、远程化、市场开始谈分成。从&quot;行业有没有就用哪个协议达成共识&quot;这个角度,MCP 已经赢了——OpenAI 把它织进了自己产品的每一层(Responses API、Agents SDK、Codex、ChatGPT 的 Apps SDK),竞争对手都用你的协议,这就是事实标准的定义。<strong>&ldquo;用哪个协议&quot;这场仗,基本结束了。</strong></p>
<p>但&quot;标准&quot;不只是&quot;大家都用&rdquo;,还得是&quot;用得好&quot;。第二个问题上,MCP 还没赢。</p>
<p>最现实的反例是<strong>上下文膨胀</strong>。MCP 的工具定义是直接塞进上下文的。实测下来,光是接上 GitHub、Slack、Sentry 三个 server,工具定义就能吃掉 5.5 万 token——Claude 20 万上下文的四分之一还多。有团队报告过更夸张的:三个 server 吃掉 14.3 万 token,72% 的上下文窗口全耗在了工具定义上,真正干活的空间反而被挤没了。有基准测试发现,同样一个操作,MCP 比 CLI 多花 4 到 32 倍的 token,差的几乎全是 schema——43 个工具定义全加载进去,agent 实际只用其中一两个。</p>
<p>所以这半年另一股声音也在变响:对很多开发者工作流来说,<strong>一个 CLI 工具可能比 MCP server 更合适</strong>。让模型直接读 CLI 的 help 文本和报错,按需调用,而不是把几十个工具定义一股脑塞进上下文。&ldquo;code agent&quot;那一派主张的也是类似思路——选择性地取用工具,而不是全量预加载。</p>
<p>这些不是要取代 MCP,而是在划清它的边界。我的总结是:</p>
<ul>
<li><strong>协议层面,MCP 赢了</strong>。该接的都接了,基金会托管解决了中立性,这事没有悬念。</li>
<li><strong>使用层面,远没收敛</strong>。工具太多就让模型犯晕,业界现在的经验法则是<strong>同时挂 10–15 个工具就到头了</strong>。怎么动态加载、怎么设计&quot;瘦 server&rdquo;、什么场景干脆别用 MCP——这些还在摸索。</li>
</ul>
<p>一句话:MCP 赢下了&quot;标准之争&quot;,但还没赢下&quot;怎么用好&quot;。这半年它从协议长成了生态,接下来这半年的关卡,是从&quot;能接上一切&quot;变成&quot;接上不添乱&quot;。生态的数字会继续涨,但真正值得盯的指标,已经从&quot;有多少个 server&quot;,变成&quot;一个 agent 能清醒地同时用好几个 server&quot;。</p>
<hr>
<p><strong>参考来源</strong></p>
<ul>
<li><a href="https://blog.modelcontextprotocol.io/posts/2026-mcp-roadmap/">The 2026 MCP Roadmap — Model Context Protocol Blog</a></li>
<li><a href="https://www.digitalapplied.com/blog/mcp-adoption-statistics-2026-model-context-protocol">MCP Adoption Statistics 2026 — Digital Applied</a></li>
<li><a href="https://www.digitalapplied.com/blog/mcp-97-million-downloads-model-context-protocol-mainstream">MCP Hits 97M Downloads — Digital Applied</a></li>
<li><a href="https://www.truefoundry.com/blog/best-mcp-registries">Best MCP Registries in 2026 — TrueFoundry</a></li>
<li><a href="https://mcpize.com/developers/monetize-mcp-servers">How to Monetize Your MCP Server — MCPize</a></li>
<li><a href="https://www.practical-devsecops.com/mcp-security-vulnerabilities/">MCP Security Vulnerabilities: Prompt Injection and Tool Poisoning — Practical DevSecOps</a></li>
<li><a href="https://www.apideck.com/blog/mcp-server-eating-context-window-cli-alternative">Your MCP Server Is Eating Your Context Window — Apideck</a></li>
<li><a href="https://developers.openai.com/api/docs/mcp">Building MCP servers for ChatGPT Apps — OpenAI Developers</a></li>
</ul>
]]></content:encoded></item><item><title>MCP协议：AI工具的「乐高积木」玩法</title><link>https://realtime-ai.chat/posts/mcp-protocol-guide/</link><pubDate>Sun, 11 Jan 2026 10:00:00 +0800</pubDate><guid>https://realtime-ai.chat/posts/mcp-protocol-guide/</guid><description>用「乐高积木」的比喻讲清 MCP 协议:它如何像 USB 一样让任意工具接入 AI,以及工具集成的实战玩法。</description><content:encoded><![CDATA[<h2 id="开场ai助手的能力危机">开场：AI助手的「能力危机」</h2>
<p><strong>场景一：你问Claude</strong></p>
<blockquote>
<p>你：&ldquo;帮我查一下公司数据库里上个月的销售数据&rdquo;<br>
Claude：&ldquo;抱歉，我无法直接访问数据库&hellip;&rdquo;</p></blockquote>
<p><strong>场景二：你问ChatGPT</strong></p>
<blockquote>
<p>你：&ldquo;读取我桌面上的report.pdf并总结&rdquo;<br>
ChatGPT：&ldquo;我无法访问您的本地文件&hellip;&rdquo;</p></blockquote>
<p><strong>问题来了</strong>：这些AI明明这么聪明，为什么连最基本的「读文件」「查数据库」都做不到？</p>
<p><strong>答案</strong>：不是它们不够聪明，而是缺少「工具」。</p>
<p>就像一个天才厨师，如果厨房里没有刀、锅、灶，也做不出美食。</p>
<hr>
<h2 id="第一章mcp协议是什么">第一章：MCP协议是什么？</h2>
<h3 id="11-一句话解释">1.1 一句话解释</h3>
<p><strong>MCP (Model Context Protocol)</strong> = AI模型的「USB接口标准」</p>
<p>就像USB让所有设备都能连接电脑一样，MCP让所有工具都能连接AI。</p>
<h3 id="12-没有mcp之前的世界">1.2 没有MCP之前的世界</h3>
<p>每个AI应用都要自己实现工具集成：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 开发者A的实现</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">ClaudeWithDatabase</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">query_db</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">sql</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># 自己写数据库连接逻辑</span>
</span></span><span class="line"><span class="cl">        <span class="n">conn</span> <span class="o">=</span> <span class="n">psycopg2</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># 自己写SQL执行逻辑</span>
</span></span><span class="line"><span class="cl">        <span class="n">cursor</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">sql</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># 自己写结果格式化</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">format_results</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 开发者B的实现（完全不同）</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">GPTWithDatabase</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">db_query</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">query</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># 又要重新实现一遍</span>
</span></span><span class="line"><span class="cl">        <span class="n">engine</span> <span class="o">=</span> <span class="n">create_engine</span><span class="p">(</span><span class="o">...</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># 完全不同的接口</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">engine</span><span class="o">.</span><span class="n">execute</span><span class="p">(</span><span class="n">query</span><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p><strong>问题</strong>：</p>
<ul>
<li>❌ 每个开发者都要重复造轮子</li>
<li>❌ 工具无法在不同AI之间复用</li>
<li>❌ 维护成本极高</li>
</ul>
<h3 id="13-有了mcp之后">1.3 有了MCP之后</h3>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 任何AI都可以使用同一个MCP服务器</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">mcp</span> <span class="kn">import</span> <span class="n">Client</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 连接到数据库MCP服务器</span>
</span></span><span class="line"><span class="cl"><span class="n">client</span> <span class="o">=</span> <span class="n">Client</span><span class="p">(</span><span class="s2">&#34;postgresql://localhost:5432/mydb&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Claude使用</span>
</span></span><span class="line"><span class="cl"><span class="n">claude_response</span> <span class="o">=</span> <span class="n">claude</span><span class="o">.</span><span class="n">chat</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;查询上月销售数据&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">tools</span><span class="o">=</span><span class="p">[</span><span class="n">client</span><span class="p">]</span>  <span class="c1"># 直接传入MCP客户端</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># GPT使用（完全相同的方式）</span>
</span></span><span class="line"><span class="cl"><span class="n">gpt_response</span> <span class="o">=</span> <span class="n">gpt</span><span class="o">.</span><span class="n">chat</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;查询上月销售数据&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">tools</span><span class="o">=</span><span class="p">[</span><span class="n">client</span><span class="p">]</span>  <span class="c1"># 同一个工具！</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p><strong>优势</strong>：</p>
<ul>
<li>✅ 一次开发，到处使用</li>
<li>✅ 工具可以在不同AI之间共享</li>
<li>✅ 标准化接口，易于维护</li>
</ul>
<hr>
<h2 id="第二章mcp的核心架构">第二章：MCP的核心架构</h2>
<h3 id="21-三个角色">2.1 三个角色</h3>
<pre class="mermaid">graph LR
    A[AI模型<br/>Claude/GPT] -->|请求工具| B[MCP客户端]
    B -->|标准协议| C[MCP服务器]
    C -->|实际操作| D[资源<br/>数据库/文件/API]
</pre><p><strong>角色说明</strong>：</p>
<ol>
<li><strong>AI模型（Host）</strong>：发起请求的&quot;大脑&quot;</li>
<li><strong>MCP客户端（Client）</strong>：AI和工具之间的&quot;翻译官&quot;</li>
<li><strong>MCP服务器（Server）</strong>：实际执行操作的&quot;工具箱&quot;</li>
</ol>
<h3 id="22-通信流程">2.2 通信流程</h3>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 完整的MCP通信示例</span>
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">MCPCommunicationFlow</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">demonstrate</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># Step 1: AI发现可用工具</span>
</span></span><span class="line"><span class="cl">        <span class="n">tools</span> <span class="o">=</span> <span class="n">mcp_client</span><span class="o">.</span><span class="n">list_tools</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># 返回: [</span>
</span></span><span class="line"><span class="cl">        <span class="c1">#   {&#34;name&#34;: &#34;query_database&#34;, &#34;description&#34;: &#34;查询PostgreSQL数据库&#34;},</span>
</span></span><span class="line"><span class="cl">        <span class="c1">#   {&#34;name&#34;: &#34;read_file&#34;, &#34;description&#34;: &#34;读取本地文件&#34;},</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># ]</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="c1"># Step 2: AI选择并调用工具</span>
</span></span><span class="line"><span class="cl">        <span class="n">result</span> <span class="o">=</span> <span class="n">mcp_client</span><span class="o">.</span><span class="n">call_tool</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="n">name</span><span class="o">=</span><span class="s2">&#34;query_database&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">arguments</span><span class="o">=</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;sql&#34;</span><span class="p">:</span> <span class="s2">&#34;SELECT * FROM sales WHERE month = &#39;2025-11&#39;&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="c1"># Step 3: MCP服务器执行并返回结果</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># result = {</span>
</span></span><span class="line"><span class="cl">        <span class="c1">#   &#34;content&#34;: [</span>
</span></span><span class="line"><span class="cl">        <span class="c1">#     {&#34;type&#34;: &#34;text&#34;, &#34;text&#34;: &#34;找到123条记录&#34;},</span>
</span></span><span class="line"><span class="cl">        <span class="c1">#     {&#34;type&#34;: &#34;resource&#34;, &#34;uri&#34;: &#34;db://sales/2025-11&#34;}</span>
</span></span><span class="line"><span class="cl">        <span class="c1">#   ]</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># }</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="c1"># Step 4: AI处理结果并回复用户</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">ai_model</span><span class="o">.</span><span class="n">generate_response</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="23-协议规范">2.3 协议规范</h3>
<p>MCP使用<strong>JSON-RPC 2.0</strong>作为通信协议：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="c1">// 请求示例
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;jsonrpc&#34;</span><span class="p">:</span> <span class="s2">&#34;2.0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;method&#34;</span><span class="p">:</span> <span class="s2">&#34;tools/call&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;params&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;name&#34;</span><span class="p">:</span> <span class="s2">&#34;query_database&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;arguments&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;sql&#34;</span><span class="p">:</span> <span class="s2">&#34;SELECT COUNT(*) FROM users&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// 响应示例
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;jsonrpc&#34;</span><span class="p">:</span> <span class="s2">&#34;2.0&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;id&#34;</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;result&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;content&#34;</span><span class="p">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;text&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;text&#34;</span><span class="p">:</span> <span class="s2">&#34;总用户数: 1,234,567&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><hr>
<h2 id="第三章实战搭建你的第一个mcp服务器">第三章：实战——搭建你的第一个MCP服务器</h2>
<h3 id="31-最简单的例子文件读取服务器">3.1 最简单的例子：文件读取服务器</h3>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span><span class="lnt">49
</span><span class="lnt">50
</span><span class="lnt">51
</span><span class="lnt">52
</span><span class="lnt">53
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># file_server.py</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">mcp.server</span> <span class="kn">import</span> <span class="n">Server</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">mcp.types</span> <span class="kn">import</span> <span class="n">Tool</span><span class="p">,</span> <span class="n">TextContent</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">os</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 创建MCP服务器</span>
</span></span><span class="line"><span class="cl"><span class="n">app</span> <span class="o">=</span> <span class="n">Server</span><span class="p">(</span><span class="s2">&#34;file-reader&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 定义工具</span>
</span></span><span class="line"><span class="cl"><span class="nd">@app.list_tools</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="k">async</span> <span class="k">def</span> <span class="nf">list_tools</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="n">Tool</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="n">name</span><span class="o">=</span><span class="s2">&#34;read_file&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">description</span><span class="o">=</span><span class="s2">&#34;读取本地文件内容&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">inputSchema</span><span class="o">=</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;object&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;properties&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="s2">&#34;path&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                        <span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                        <span class="s2">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;文件路径&#34;</span>
</span></span><span class="line"><span class="cl">                    <span class="p">}</span>
</span></span><span class="line"><span class="cl">                <span class="p">},</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;required&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;path&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 实现工具逻辑</span>
</span></span><span class="line"><span class="cl"><span class="nd">@app.call_tool</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="k">async</span> <span class="k">def</span> <span class="nf">call_tool</span><span class="p">(</span><span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">arguments</span><span class="p">:</span> <span class="nb">dict</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">name</span> <span class="o">==</span> <span class="s2">&#34;read_file&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">path</span> <span class="o">=</span> <span class="n">arguments</span><span class="p">[</span><span class="s2">&#34;path&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="c1"># 安全检查</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">path</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="p">[</span><span class="n">TextContent</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">                <span class="nb">type</span><span class="o">=</span><span class="s2">&#34;text&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="n">text</span><span class="o">=</span><span class="sa">f</span><span class="s2">&#34;错误：文件 </span><span class="si">{</span><span class="n">path</span><span class="si">}</span><span class="s2"> 不存在&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="p">)]</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="c1"># 读取文件</span>
</span></span><span class="line"><span class="cl">        <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="s1">&#39;r&#39;</span><span class="p">,</span> <span class="n">encoding</span><span class="o">=</span><span class="s1">&#39;utf-8&#39;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">content</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="p">[</span><span class="n">TextContent</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="nb">type</span><span class="o">=</span><span class="s2">&#34;text&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">text</span><span class="o">=</span><span class="sa">f</span><span class="s2">&#34;文件内容：</span><span class="se">\n</span><span class="si">{</span><span class="n">content</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="p">)]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 启动服务器</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">&#34;__main__&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">app</span><span class="o">.</span><span class="n">run</span><span class="p">()</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p><strong>运行服务器</strong>：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">python file_server.py
</span></span><span class="line"><span class="cl"><span class="c1"># MCP服务器启动在 stdio://</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="32-在claude-desktop中使用">3.2 在Claude Desktop中使用</h3>
<p>编辑Claude Desktop配置文件：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="c1">// ~/Library/Application Support/Claude/claude_desktop_config.json
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;mcpServers&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;file-reader&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;python&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;args&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;/path/to/file_server.py&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p><strong>重启Claude Desktop，现在你可以</strong>：</p>
<blockquote>
<p>你：&ldquo;读取我桌面上的report.txt&rdquo;<br>
Claude：&ldquo;好的，让我读取文件&hellip; [调用read_file工具] &hellip;文件内容是：&hellip;&rdquo;</p></blockquote>
<p>🎉 <strong>成功！Claude现在可以读取本地文件了！</strong></p>
<h3 id="33-进阶数据库查询服务器">3.3 进阶：数据库查询服务器</h3>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span><span class="lnt">47
</span><span class="lnt">48
</span><span class="lnt">49
</span><span class="lnt">50
</span><span class="lnt">51
</span><span class="lnt">52
</span><span class="lnt">53
</span><span class="lnt">54
</span><span class="lnt">55
</span><span class="lnt">56
</span><span class="lnt">57
</span><span class="lnt">58
</span><span class="lnt">59
</span><span class="lnt">60
</span><span class="lnt">61
</span><span class="lnt">62
</span><span class="lnt">63
</span><span class="lnt">64
</span><span class="lnt">65
</span><span class="lnt">66
</span><span class="lnt">67
</span><span class="lnt">68
</span><span class="lnt">69
</span><span class="lnt">70
</span><span class="lnt">71
</span><span class="lnt">72
</span><span class="lnt">73
</span><span class="lnt">74
</span><span class="lnt">75
</span><span class="lnt">76
</span><span class="lnt">77
</span><span class="lnt">78
</span><span class="lnt">79
</span><span class="lnt">80
</span><span class="lnt">81
</span><span class="lnt">82
</span><span class="lnt">83
</span><span class="lnt">84
</span><span class="lnt">85
</span><span class="lnt">86
</span><span class="lnt">87
</span><span class="lnt">88
</span><span class="lnt">89
</span><span class="lnt">90
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># database_server.py</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">mcp.server</span> <span class="kn">import</span> <span class="n">Server</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">mcp.types</span> <span class="kn">import</span> <span class="n">Tool</span><span class="p">,</span> <span class="n">TextContent</span><span class="p">,</span> <span class="n">Resource</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">psycopg2</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">pandas</span> <span class="k">as</span> <span class="nn">pd</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">app</span> <span class="o">=</span> <span class="n">Server</span><span class="p">(</span><span class="s2">&#34;postgres-query&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 数据库连接配置</span>
</span></span><span class="line"><span class="cl"><span class="n">DB_CONFIG</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;host&#34;</span><span class="p">:</span> <span class="s2">&#34;localhost&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;database&#34;</span><span class="p">:</span> <span class="s2">&#34;myapp&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;user&#34;</span><span class="p">:</span> <span class="s2">&#34;postgres&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;password&#34;</span><span class="p">:</span> <span class="s2">&#34;secret&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@app.list_tools</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="k">async</span> <span class="k">def</span> <span class="nf">list_tools</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">        <span class="n">Tool</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="n">name</span><span class="o">=</span><span class="s2">&#34;query_database&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">description</span><span class="o">=</span><span class="s2">&#34;执行SQL查询并返回结果&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">inputSchema</span><span class="o">=</span><span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;object&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;properties&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="s2">&#34;sql&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                        <span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                        <span class="s2">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;SQL查询语句&#34;</span>
</span></span><span class="line"><span class="cl">                    <span class="p">},</span>
</span></span><span class="line"><span class="cl">                    <span class="s2">&#34;format&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">                        <span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                        <span class="s2">&#34;enum&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;table&#34;</span><span class="p">,</span> <span class="s2">&#34;json&#34;</span><span class="p">,</span> <span class="s2">&#34;markdown&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">                        <span class="s2">&#34;description&#34;</span><span class="p">:</span> <span class="s2">&#34;返回格式&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                        <span class="s2">&#34;default&#34;</span><span class="p">:</span> <span class="s2">&#34;markdown&#34;</span>
</span></span><span class="line"><span class="cl">                    <span class="p">}</span>
</span></span><span class="line"><span class="cl">                <span class="p">},</span>
</span></span><span class="line"><span class="cl">                <span class="s2">&#34;required&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;sql&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">),</span>
</span></span><span class="line"><span class="cl">        <span class="n">Tool</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="n">name</span><span class="o">=</span><span class="s2">&#34;list_tables&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">description</span><span class="o">=</span><span class="s2">&#34;列出数据库中的所有表&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">inputSchema</span><span class="o">=</span><span class="p">{</span><span class="s2">&#34;type&#34;</span><span class="p">:</span> <span class="s2">&#34;object&#34;</span><span class="p">,</span> <span class="s2">&#34;properties&#34;</span><span class="p">:</span> <span class="p">{}}</span>
</span></span><span class="line"><span class="cl">        <span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@app.call_tool</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="k">async</span> <span class="k">def</span> <span class="nf">call_tool</span><span class="p">(</span><span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">arguments</span><span class="p">:</span> <span class="nb">dict</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">conn</span> <span class="o">=</span> <span class="n">psycopg2</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="o">**</span><span class="n">DB_CONFIG</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="n">name</span> <span class="o">==</span> <span class="s2">&#34;list_tables&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="c1"># 查询所有表</span>
</span></span><span class="line"><span class="cl">            <span class="n">df</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">read_sql</span><span class="p">(</span><span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="cl"><span class="s2">                SELECT table_name 
</span></span></span><span class="line"><span class="cl"><span class="s2">                FROM information_schema.tables 
</span></span></span><span class="line"><span class="cl"><span class="s2">                WHERE table_schema = &#39;public&#39;
</span></span></span><span class="line"><span class="cl"><span class="s2">            &#34;&#34;&#34;</span><span class="p">,</span> <span class="n">conn</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            
</span></span><span class="line"><span class="cl">            <span class="n">tables</span> <span class="o">=</span> <span class="n">df</span><span class="p">[</span><span class="s1">&#39;table_name&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">tolist</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="p">[</span><span class="n">TextContent</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">                <span class="nb">type</span><span class="o">=</span><span class="s2">&#34;text&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="n">text</span><span class="o">=</span><span class="sa">f</span><span class="s2">&#34;数据库表：</span><span class="se">\n</span><span class="s2">&#34;</span> <span class="o">+</span> <span class="s2">&#34;</span><span class="se">\n</span><span class="s2">&#34;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;- </span><span class="si">{</span><span class="n">t</span><span class="si">}</span><span class="s2">&#34;</span> <span class="k">for</span> <span class="n">t</span> <span class="ow">in</span> <span class="n">tables</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="p">)]</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="k">elif</span> <span class="n">name</span> <span class="o">==</span> <span class="s2">&#34;query_database&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="n">sql</span> <span class="o">=</span> <span class="n">arguments</span><span class="p">[</span><span class="s2">&#34;sql&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">            <span class="n">format_type</span> <span class="o">=</span> <span class="n">arguments</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&#34;format&#34;</span><span class="p">,</span> <span class="s2">&#34;markdown&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            
</span></span><span class="line"><span class="cl">            <span class="c1"># 执行查询</span>
</span></span><span class="line"><span class="cl">            <span class="n">df</span> <span class="o">=</span> <span class="n">pd</span><span class="o">.</span><span class="n">read_sql</span><span class="p">(</span><span class="n">sql</span><span class="p">,</span> <span class="n">conn</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            
</span></span><span class="line"><span class="cl">            <span class="c1"># 格式化输出</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="n">format_type</span> <span class="o">==</span> <span class="s2">&#34;markdown&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                <span class="n">result</span> <span class="o">=</span> <span class="n">df</span><span class="o">.</span><span class="n">to_markdown</span><span class="p">(</span><span class="n">index</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="k">elif</span> <span class="n">format_type</span> <span class="o">==</span> <span class="s2">&#34;json&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                <span class="n">result</span> <span class="o">=</span> <span class="n">df</span><span class="o">.</span><span class="n">to_json</span><span class="p">(</span><span class="n">orient</span><span class="o">=</span><span class="s2">&#34;records&#34;</span><span class="p">,</span> <span class="n">indent</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="k">else</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                <span class="n">result</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">df</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="p">[</span><span class="n">TextContent</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">                <span class="nb">type</span><span class="o">=</span><span class="s2">&#34;text&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">                <span class="n">text</span><span class="o">=</span><span class="sa">f</span><span class="s2">&#34;查询结果（</span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">df</span><span class="p">)</span><span class="si">}</span><span class="s2">行）：</span><span class="se">\n</span><span class="si">{</span><span class="n">result</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="p">)]</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">finally</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">conn</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">&#34;__main__&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">    <span class="n">app</span><span class="o">.</span><span class="n">run</span><span class="p">()</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p><strong>使用效果</strong>：</p>
<blockquote>
<p>你：&ldquo;我们数据库里有哪些表？&rdquo;<br>
Claude：[调用list_tables] &ldquo;数据库中有以下表：users, orders, products&hellip;&rdquo;</p>
<p>你：&ldquo;查询上个月订单总额&rdquo;<br>
Claude：[调用query_database] &ldquo;上个月订单总额为 ¥1,234,567&hellip;&rdquo;</p></blockquote>
<hr>
<h2 id="第四章mcp的杀手级应用场景">第四章：MCP的「杀手级」应用场景</h2>
<h3 id="41-场景一智能数据分析助手">4.1 场景一：智能数据分析助手</h3>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 用户只需要说话，AI自动完成整个分析流程</span>
</span></span><span class="line"><span class="cl"><span class="n">用户</span><span class="p">:</span> <span class="s2">&#34;分析一下我们Q4的销售趋势&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># AI的工作流程（全自动）：</span>
</span></span><span class="line"><span class="cl"><span class="mf">1.</span> <span class="p">[</span><span class="n">调用list_tables</span><span class="p">]</span> <span class="n">发现有sales表</span>
</span></span><span class="line"><span class="cl"><span class="mf">2.</span> <span class="p">[</span><span class="n">调用query_database</span><span class="p">]</span> <span class="n">查询Q4数据</span>
</span></span><span class="line"><span class="cl"><span class="mf">3.</span> <span class="p">[</span><span class="n">调用python_executor</span><span class="p">]</span> <span class="n">用pandas分析趋势</span>
</span></span><span class="line"><span class="cl"><span class="mf">4.</span> <span class="p">[</span><span class="n">调用chart_generator</span><span class="p">]</span> <span class="n">生成可视化图表</span>
</span></span><span class="line"><span class="cl"><span class="mf">5.</span> <span class="p">[</span><span class="n">返回分析报告</span><span class="p">]</span> <span class="s2">&#34;Q4销售呈上升趋势，环比增长23%...&#34;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p><strong>实现代码</strong>：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># analytics_server.py</span>
</span></span><span class="line"><span class="cl"><span class="nd">@app.call_tool</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="k">async</span> <span class="k">def</span> <span class="nf">call_tool</span><span class="p">(</span><span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">arguments</span><span class="p">:</span> <span class="nb">dict</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">name</span> <span class="o">==</span> <span class="s2">&#34;analyze_sales&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># Step 1: 查询数据</span>
</span></span><span class="line"><span class="cl">        <span class="n">df</span> <span class="o">=</span> <span class="n">query_sales_data</span><span class="p">(</span><span class="n">arguments</span><span class="p">[</span><span class="s2">&#34;period&#34;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="c1"># Step 2: 自动分析</span>
</span></span><span class="line"><span class="cl">        <span class="n">insights</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;total&#34;</span><span class="p">:</span> <span class="n">df</span><span class="p">[</span><span class="s1">&#39;amount&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">sum</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;growth&#34;</span><span class="p">:</span> <span class="n">calculate_growth</span><span class="p">(</span><span class="n">df</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;top_products&#34;</span><span class="p">:</span> <span class="n">df</span><span class="o">.</span><span class="n">groupby</span><span class="p">(</span><span class="s1">&#39;product&#39;</span><span class="p">)[</span><span class="s1">&#39;amount&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">sum</span><span class="p">()</span><span class="o">.</span><span class="n">nlargest</span><span class="p">(</span><span class="mi">5</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">            <span class="s2">&#34;trend&#34;</span><span class="p">:</span> <span class="n">detect_trend</span><span class="p">(</span><span class="n">df</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="c1"># Step 3: 生成图表</span>
</span></span><span class="line"><span class="cl">        <span class="n">chart_url</span> <span class="o">=</span> <span class="n">generate_chart</span><span class="p">(</span><span class="n">df</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        
</span></span><span class="line"><span class="cl">        <span class="c1"># Step 4: 返回结果</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">            <span class="n">TextContent</span><span class="p">(</span><span class="nb">type</span><span class="o">=</span><span class="s2">&#34;text&#34;</span><span class="p">,</span> <span class="n">text</span><span class="o">=</span><span class="n">format_insights</span><span class="p">(</span><span class="n">insights</span><span class="p">)),</span>
</span></span><span class="line"><span class="cl">            <span class="n">Resource</span><span class="p">(</span><span class="nb">type</span><span class="o">=</span><span class="s2">&#34;image&#34;</span><span class="p">,</span> <span class="n">uri</span><span class="o">=</span><span class="n">chart_url</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">]</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="42-场景二全能开发助手">4.2 场景二：全能开发助手</h3>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 开发者的梦想：AI能直接操作代码库</span>
</span></span><span class="line"><span class="cl"><span class="n">用户</span><span class="p">:</span> <span class="s2">&#34;帮我重构auth模块，添加OAuth支持&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># AI的操作：</span>
</span></span><span class="line"><span class="cl"><span class="mf">1.</span> <span class="p">[</span><span class="n">调用git_server</span><span class="p">]</span> <span class="n">创建新分支</span> <span class="n">feature</span><span class="o">/</span><span class="n">oauth</span>
</span></span><span class="line"><span class="cl"><span class="mf">2.</span> <span class="p">[</span><span class="n">调用file_server</span><span class="p">]</span> <span class="n">读取现有auth代码</span>
</span></span><span class="line"><span class="cl"><span class="mf">3.</span> <span class="p">[</span><span class="n">调用code_generator</span><span class="p">]</span> <span class="n">生成OAuth实现</span>
</span></span><span class="line"><span class="cl"><span class="mf">4.</span> <span class="p">[</span><span class="n">调用file_server</span><span class="p">]</span> <span class="n">写入新代码</span>
</span></span><span class="line"><span class="cl"><span class="mf">5.</span> <span class="p">[</span><span class="n">调用test_runner</span><span class="p">]</span> <span class="n">运行测试</span>
</span></span><span class="line"><span class="cl"><span class="mf">6.</span> <span class="p">[</span><span class="n">调用git_server</span><span class="p">]</span> <span class="n">提交并推送</span>
</span></span><span class="line"><span class="cl"><span class="mf">7.</span> <span class="p">[</span><span class="n">返回</span><span class="p">]</span> <span class="s2">&#34;重构完成，所有测试通过，PR已创建&#34;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p><strong>MCP服务器组合</strong>：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&#34;mcpServers&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;git&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;mcp-git-server&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;filesystem&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;mcp-file-server&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;args&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;--root&#34;</span><span class="p">,</span> <span class="s2">&#34;/Users/dev/myproject&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;test-runner&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&#34;command&#34;</span><span class="p">:</span> <span class="s2">&#34;mcp-pytest-server&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="43-场景三企业知识库问答">4.3 场景三：企业知识库问答</h3>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 连接公司所有数据源</span>
</span></span><span class="line"><span class="cl"><span class="n">用户</span><span class="p">:</span> <span class="s2">&#34;上季度客户投诉最多的问题是什么？&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># AI自动整合多个数据源：</span>
</span></span><span class="line"><span class="cl"><span class="mf">1.</span> <span class="p">[</span><span class="n">调用jira_server</span><span class="p">]</span> <span class="n">查询工单系统</span>
</span></span><span class="line"><span class="cl"><span class="mf">2.</span> <span class="p">[</span><span class="n">调用slack_server</span><span class="p">]</span> <span class="n">搜索客服频道</span>
</span></span><span class="line"><span class="cl"><span class="mf">3.</span> <span class="p">[</span><span class="n">调用database_server</span><span class="p">]</span> <span class="n">查询CRM数据</span>
</span></span><span class="line"><span class="cl"><span class="mf">4.</span> <span class="p">[</span><span class="n">调用confluence_server</span><span class="p">]</span> <span class="n">检索知识库</span>
</span></span><span class="line"><span class="cl"><span class="mf">5.</span> <span class="p">[</span><span class="n">综合分析</span><span class="p">]</span> <span class="s2">&#34;最多的投诉是配送延迟（占37%），主要原因是...&#34;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><hr>
<h2 id="第五章mcp生态系统">第五章：MCP生态系统</h2>
<h3 id="51-官方mcp服务器">5.1 官方MCP服务器</h3>
<p>Anthropic已经提供了一些开箱即用的服务器：</p>
<table>
  <thead>
      <tr>
          <th>服务器</th>
          <th>功能</th>
          <th>使用场景</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>@modelcontextprotocol/server-filesystem</code></td>
          <td>文件系统访问</td>
          <td>读写本地文件</td>
      </tr>
      <tr>
          <td><code>@modelcontextprotocol/server-github</code></td>
          <td>GitHub集成</td>
          <td>管理仓库、PR、Issues</td>
      </tr>
      <tr>
          <td><code>@modelcontextprotocol/server-postgres</code></td>
          <td>PostgreSQL</td>
          <td>数据库查询</td>
      </tr>
      <tr>
          <td><code>@modelcontextprotocol/server-brave-search</code></td>
          <td>网络搜索</td>
          <td>实时信息检索</td>
      </tr>
      <tr>
          <td><code>@modelcontextprotocol/server-slack</code></td>
          <td>Slack集成</td>
          <td>发送消息、查询历史</td>
      </tr>
  </tbody>
</table>
<p><strong>安装使用</strong>：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 安装官方服务器</span>
</span></span><span class="line"><span class="cl">npm install -g @modelcontextprotocol/server-github
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 配置到Claude Desktop</span>
</span></span><span class="line"><span class="cl"><span class="o">{</span>
</span></span><span class="line"><span class="cl">  <span class="s2">&#34;mcpServers&#34;</span>: <span class="o">{</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;github&#34;</span>: <span class="o">{</span>
</span></span><span class="line"><span class="cl">      <span class="s2">&#34;command&#34;</span>: <span class="s2">&#34;mcp-server-github&#34;</span>,
</span></span><span class="line"><span class="cl">      <span class="s2">&#34;env&#34;</span>: <span class="o">{</span>
</span></span><span class="line"><span class="cl">        <span class="s2">&#34;GITHUB_TOKEN&#34;</span>: <span class="s2">&#34;your_token_here&#34;</span>
</span></span><span class="line"><span class="cl">      <span class="o">}</span>
</span></span><span class="line"><span class="cl">    <span class="o">}</span>
</span></span><span class="line"><span class="cl">  <span class="o">}</span>
</span></span><span class="line"><span class="cl"><span class="o">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="52-社区mcp服务器">5.2 社区MCP服务器</h3>
<p>开源社区已经创建了大量服务器：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 一些有趣的社区服务器</span>
</span></span><span class="line"><span class="cl"><span class="n">awesome_mcp_servers</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;mcp-server-notion&#34;</span><span class="p">,</span>      <span class="c1"># Notion笔记集成</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;mcp-server-gmail&#34;</span><span class="p">,</span>       <span class="c1"># Gmail邮件管理</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;mcp-server-calendar&#34;</span><span class="p">,</span>    <span class="c1"># Google Calendar</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;mcp-server-docker&#34;</span><span class="p">,</span>      <span class="c1"># Docker容器管理</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;mcp-server-kubernetes&#34;</span><span class="p">,</span>  <span class="c1"># K8s集群操作</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;mcp-server-aws&#34;</span><span class="p">,</span>         <span class="c1"># AWS云服务</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;mcp-server-stripe&#34;</span><span class="p">,</span>      <span class="c1"># 支付处理</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;mcp-server-openai&#34;</span><span class="p">,</span>      <span class="c1"># OpenAI API封装</span>
</span></span><span class="line"><span class="cl"><span class="p">]</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="53-创建自己的mcp服务器">5.3 创建自己的MCP服务器</h3>
<p><strong>Python版本</strong>：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">pip install mcp
</span></span><span class="line"><span class="cl">mcp create my-server
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> my-server
</span></span><span class="line"><span class="cl"><span class="c1"># 编辑 server.py</span>
</span></span><span class="line"><span class="cl">python server.py
</span></span></code></pre></td></tr></table>
</div>
</div><p><strong>TypeScript版本</strong>：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl">npm create @modelcontextprotocol/server my-server
</span></span><span class="line"><span class="cl"><span class="nb">cd</span> my-server
</span></span><span class="line"><span class="cl"><span class="c1"># 编辑 src/index.ts</span>
</span></span><span class="line"><span class="cl">npm run build
</span></span><span class="line"><span class="cl">npm start
</span></span></code></pre></td></tr></table>
</div>
</div><hr>
<h2 id="第六章mcp-vs-其他方案">第六章：MCP vs 其他方案</h2>
<h3 id="61-对比表">6.1 对比表</h3>
<table>
  <thead>
      <tr>
          <th>方案</th>
          <th>优点</th>
          <th>缺点</th>
          <th>适用场景</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>MCP</strong></td>
          <td>标准化、可复用、生态丰富</td>
          <td>相对新，文档还在完善</td>
          <td>需要多工具集成的AI应用</td>
      </tr>
      <tr>
          <td><strong>Function Calling</strong></td>
          <td>简单直接</td>
          <td>每个AI都要单独实现</td>
          <td>简单的单一工具调用</td>
      </tr>
      <tr>
          <td><strong>LangChain Tools</strong></td>
          <td>成熟的框架</td>
          <td>绑定LangChain生态</td>
          <td>LangChain项目</td>
      </tr>
      <tr>
          <td><strong>自定义API</strong></td>
          <td>完全控制</td>
          <td>开发成本高，难复用</td>
          <td>特殊需求</td>
      </tr>
  </tbody>
</table>
<h3 id="62-什么时候用mcp">6.2 什么时候用MCP？</h3>
<p>✅ <strong>适合使用MCP</strong>：</p>
<ul>
<li>需要集成多个工具（数据库+文件+API）</li>
<li>希望工具可以在不同AI之间复用</li>
<li>构建企业级AI应用</li>
<li>需要标准化的工具接口</li>
</ul>
<p>❌ <strong>不适合使用MCP</strong>：</p>
<ul>
<li>只需要一个简单的API调用</li>
<li>项目已经深度绑定其他框架</li>
<li>对性能有极致要求（MCP有一定开销）</li>
</ul>
<hr>
<h2 id="第七章最佳实践">第七章：最佳实践</h2>
<h3 id="71-安全性">7.1 安全性</h3>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># ❌ 危险：直接执行用户SQL</span>
</span></span><span class="line"><span class="cl"><span class="nd">@app.call_tool</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="k">async</span> <span class="k">def</span> <span class="nf">call_tool</span><span class="p">(</span><span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">arguments</span><span class="p">:</span> <span class="nb">dict</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="n">sql</span> <span class="o">=</span> <span class="n">arguments</span><span class="p">[</span><span class="s2">&#34;sql&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">execute_sql</span><span class="p">(</span><span class="n">sql</span><span class="p">)</span>  <span class="c1"># SQL注入风险！</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># ✅ 安全：参数化查询 + 权限控制</span>
</span></span><span class="line"><span class="cl"><span class="nd">@app.call_tool</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="k">async</span> <span class="k">def</span> <span class="nf">call_tool</span><span class="p">(</span><span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">arguments</span><span class="p">:</span> <span class="nb">dict</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># 1. 验证用户权限</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="ow">not</span> <span class="n">user</span><span class="o">.</span><span class="n">has_permission</span><span class="p">(</span><span class="s2">&#34;query_database&#34;</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="p">[</span><span class="n">TextContent</span><span class="p">(</span><span class="nb">type</span><span class="o">=</span><span class="s2">&#34;text&#34;</span><span class="p">,</span> <span class="n">text</span><span class="o">=</span><span class="s2">&#34;权限不足&#34;</span><span class="p">)]</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="c1"># 2. 白名单检查</span>
</span></span><span class="line"><span class="cl">    <span class="n">allowed_tables</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&#34;users&#34;</span><span class="p">,</span> <span class="s2">&#34;orders&#34;</span><span class="p">,</span> <span class="s2">&#34;products&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="ow">not</span> <span class="nb">all</span><span class="p">(</span><span class="n">table</span> <span class="ow">in</span> <span class="n">allowed_tables</span> <span class="k">for</span> <span class="n">table</span> <span class="ow">in</span> <span class="n">extract_tables</span><span class="p">(</span><span class="n">sql</span><span class="p">)):</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="p">[</span><span class="n">TextContent</span><span class="p">(</span><span class="nb">type</span><span class="o">=</span><span class="s2">&#34;text&#34;</span><span class="p">,</span> <span class="n">text</span><span class="o">=</span><span class="s2">&#34;不允许查询该表&#34;</span><span class="p">)]</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="c1"># 3. 参数化查询</span>
</span></span><span class="line"><span class="cl">    <span class="n">sql</span> <span class="o">=</span> <span class="n">arguments</span><span class="p">[</span><span class="s2">&#34;sql&#34;</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">params</span> <span class="o">=</span> <span class="n">arguments</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&#34;params&#34;</span><span class="p">,</span> <span class="p">[])</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">execute_safe_sql</span><span class="p">(</span><span class="n">sql</span><span class="p">,</span> <span class="n">params</span><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="72-错误处理">7.2 错误处理</h3>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="nd">@app.call_tool</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="k">async</span> <span class="k">def</span> <span class="nf">call_tool</span><span class="p">(</span><span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">arguments</span><span class="p">:</span> <span class="nb">dict</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># 执行操作</span>
</span></span><span class="line"><span class="cl">        <span class="n">result</span> <span class="o">=</span> <span class="n">perform_operation</span><span class="p">(</span><span class="n">arguments</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="p">[</span><span class="n">TextContent</span><span class="p">(</span><span class="nb">type</span><span class="o">=</span><span class="s2">&#34;text&#34;</span><span class="p">,</span> <span class="n">text</span><span class="o">=</span><span class="n">result</span><span class="p">)]</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">except</span> <span class="ne">FileNotFoundError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># 友好的错误提示</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="p">[</span><span class="n">TextContent</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="nb">type</span><span class="o">=</span><span class="s2">&#34;text&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">text</span><span class="o">=</span><span class="sa">f</span><span class="s2">&#34;❌ 文件不存在：</span><span class="si">{</span><span class="n">e</span><span class="o">.</span><span class="n">filename</span><span class="si">}</span><span class="se">\n</span><span class="s2">建议：检查文件路径是否正确&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="p">)]</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">except</span> <span class="ne">PermissionError</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="p">[</span><span class="n">TextContent</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="nb">type</span><span class="o">=</span><span class="s2">&#34;text&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">text</span><span class="o">=</span><span class="s2">&#34;❌ 权限不足</span><span class="se">\n</span><span class="s2">建议：使用sudo或检查文件权限&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="p">)]</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># 记录详细错误日志</span>
</span></span><span class="line"><span class="cl">        <span class="n">logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="sa">f</span><span class="s2">&#34;MCP tool error: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&#34;</span><span class="p">,</span> <span class="n">exc_info</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># 返回用户友好的错误</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="p">[</span><span class="n">TextContent</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">            <span class="nb">type</span><span class="o">=</span><span class="s2">&#34;text&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">text</span><span class="o">=</span><span class="sa">f</span><span class="s2">&#34;❌ 操作失败：</span><span class="si">{</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">        <span class="p">)]</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="73-性能优化">7.3 性能优化</h3>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 使用缓存减少重复查询</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">functools</span> <span class="kn">import</span> <span class="n">lru_cache</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@lru_cache</span><span class="p">(</span><span class="n">maxsize</span><span class="o">=</span><span class="mi">100</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">query_database</span><span class="p">(</span><span class="n">sql</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># 相同的SQL查询会被缓存</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">execute_sql</span><span class="p">(</span><span class="n">sql</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 异步处理提高并发</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">asyncio</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@app.call_tool</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="k">async</span> <span class="k">def</span> <span class="nf">call_tool</span><span class="p">(</span><span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">arguments</span><span class="p">:</span> <span class="nb">dict</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># 并行执行多个操作</span>
</span></span><span class="line"><span class="cl">    <span class="n">results</span> <span class="o">=</span> <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">gather</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="n">query_database</span><span class="p">(</span><span class="n">sql1</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">        <span class="n">query_database</span><span class="p">(</span><span class="n">sql2</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">        <span class="n">read_file</span><span class="p">(</span><span class="n">path</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">combine_results</span><span class="p">(</span><span class="n">results</span><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><hr>
<h2 id="第八章未来展望">第八章：未来展望</h2>
<h3 id="81-mcp的发展方向">8.1 MCP的发展方向</h3>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 2025年：基础工具集成</span>
</span></span><span class="line"><span class="cl"><span class="n">current_capabilities</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;文件系统访问&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;数据库查询&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;API调用&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;Git操作&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 2026年预测：更智能的工具</span>
</span></span><span class="line"><span class="cl"><span class="n">future_capabilities</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;自动工具组合（AI自己决定调用哪些工具）&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;工具学习（根据使用反馈优化工具行为）&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;跨服务器协作（多个MCP服务器协同工作）&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;实时数据流（WebSocket支持）&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;工具市场（一键安装社区工具）&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">]</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="82-可能的应用场景">8.2 可能的应用场景</h3>
<p><strong>场景一：全自动运维</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">用户</span><span class="p">:</span> <span class="s2">&#34;网站响应变慢了&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">AI自动执行</span><span class="err">：</span>
</span></span><span class="line"><span class="cl"><span class="mf">1.</span> <span class="p">[</span><span class="n">调用monitoring_server</span><span class="p">]</span> <span class="n">检查服务器指标</span>
</span></span><span class="line"><span class="cl"><span class="mf">2.</span> <span class="p">[</span><span class="n">调用log_server</span><span class="p">]</span> <span class="n">分析错误日志</span>
</span></span><span class="line"><span class="cl"><span class="mf">3.</span> <span class="p">[</span><span class="n">调用database_server</span><span class="p">]</span> <span class="n">检查慢查询</span>
</span></span><span class="line"><span class="cl"><span class="mf">4.</span> <span class="p">[</span><span class="n">调用docker_server</span><span class="p">]</span> <span class="n">重启有问题的容器</span>
</span></span><span class="line"><span class="cl"><span class="mf">5.</span> <span class="p">[</span><span class="n">调用slack_server</span><span class="p">]</span> <span class="n">通知团队</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">结果</span><span class="p">:</span> <span class="s2">&#34;已自动修复，原因是数据库连接池耗尽&#34;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p><strong>场景二：智能客服</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="n">客户</span><span class="p">:</span> <span class="s2">&#34;我的订单怎么还没发货？&#34;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">AI自动处理</span><span class="err">：</span>
</span></span><span class="line"><span class="cl"><span class="mf">1.</span> <span class="p">[</span><span class="n">调用crm_server</span><span class="p">]</span> <span class="n">查询客户信息</span>
</span></span><span class="line"><span class="cl"><span class="mf">2.</span> <span class="p">[</span><span class="n">调用order_server</span><span class="p">]</span> <span class="n">查询订单状态</span>
</span></span><span class="line"><span class="cl"><span class="mf">3.</span> <span class="p">[</span><span class="n">调用logistics_server</span><span class="p">]</span> <span class="n">查询物流信息</span>
</span></span><span class="line"><span class="cl"><span class="mf">4.</span> <span class="p">[</span><span class="n">调用email_server</span><span class="p">]</span> <span class="n">发送更新邮件</span>
</span></span><span class="line"><span class="cl"><span class="mf">5.</span> <span class="p">[</span><span class="n">调用ticket_server</span><span class="p">]</span> <span class="n">创建跟进工单</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">回复</span><span class="p">:</span> <span class="s2">&#34;您的订单已在配送中，预计明天送达&#34;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><hr>
<h2 id="结语mcp的意义">结语：MCP的意义</h2>
<p><strong>MCP不仅仅是一个协议，它代表了AI应用开发的范式转变</strong>：</p>
<h3 id="从ai是工具到ai用工具">从「AI是工具」到「AI用工具」</h3>
<p><strong>以前</strong>：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">人类 → 使用AI → 获得答案
</span></span></code></pre></td></tr></table>
</div>
</div><p><strong>现在</strong>：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">人类 → 告诉AI目标 → AI使用工具 → 完成任务
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="开发者的新机会">开发者的新机会</h3>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="c1"># 以前：开发AI应用很难</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">build_ai_app</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="n">学习LLM</span> <span class="n">API</span> <span class="err">✅</span>
</span></span><span class="line"><span class="cl">    <span class="o">+</span> <span class="n">实现工具集成</span> <span class="err">❌</span> <span class="p">(</span><span class="n">难</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="o">+</span> <span class="n">处理错误和边界情况</span> <span class="err">❌</span> <span class="p">(</span><span class="n">难</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="o">+</span> <span class="n">维护和更新</span> <span class="err">❌</span> <span class="p">(</span><span class="n">难</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="o">=</span> <span class="n">放弃</span> <span class="err">😭</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 现在：使用MCP很简单</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">build_ai_app_with_mcp</span><span class="p">():</span>
</span></span><span class="line"><span class="cl">    <span class="n">学习LLM</span> <span class="n">API</span> <span class="err">✅</span>
</span></span><span class="line"><span class="cl">    <span class="o">+</span> <span class="n">安装MCP服务器</span> <span class="err">✅</span> <span class="p">(</span><span class="n">简单</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="o">+</span> <span class="n">配置JSON文件</span> <span class="err">✅</span> <span class="p">(</span><span class="n">简单</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="o">=</span> <span class="n">成功</span> <span class="err">🎉</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="最后的思考">最后的思考</h3>
<p><strong>MCP的本质是「标准化」</strong>。</p>
<p>就像USB标准让所有设备都能连接电脑，MCP让所有工具都能连接AI。</p>
<p><strong>这意味着</strong>：</p>
<ul>
<li>🔧 开发者可以专注于创造工具，而不是重复集成</li>
<li>🤖 AI可以使用越来越多的工具，变得越来越强大</li>
<li>👥 用户可以用自然语言完成复杂任务，无需学习技术细节</li>
</ul>
<p><strong>MCP正在构建AI的「工具生态系统」</strong>，就像App Store之于iPhone。</p>
<hr>
<p><strong>快速开始</strong>：</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 1. 安装MCP SDK</span>
</span></span><span class="line"><span class="cl">pip install mcp
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 2. 创建你的第一个服务器</span>
</span></span><span class="line"><span class="cl">mcp create my-first-server
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 3. 在Claude Desktop中配置</span>
</span></span><span class="line"><span class="cl"><span class="c1"># 编辑 ~/Library/Application Support/Claude/claude_desktop_config.json</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 4. 开始使用！</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p><strong>相关资源</strong>：</p>
<ul>
<li><a href="https://modelcontextprotocol.io/">MCP官方文档</a></li>
<li><a href="https://github.com/modelcontextprotocol">MCP GitHub仓库</a></li>
<li><a href="https://github.com/modelcontextprotocol/servers">MCP服务器列表</a></li>
<li><a href="https://github.com/modelcontextprotocol/python-sdk">MCP Python SDK</a></li>
</ul>
<p><strong>MCP的时代才刚刚开始。</strong></p>
]]></content:encoded></item></channel></rss>