<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>AI on Tech Snippets - 嵌入式技术笔记</title>
    <link>https://tech-snippets.xyz/tags/ai/</link>
    <description>Recent content in AI on Tech Snippets - 嵌入式技术笔记</description>
    <generator>Hugo</generator>
    <language>zh-cn</language>
    <lastBuildDate>Wed, 06 May 2026 19:00:00 +0800</lastBuildDate>
    <atom:link href="https://tech-snippets.xyz/tags/ai/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>基于 MCP (Model Context Protocol) 的智能 Agent 生态系统构建实战指南</title>
      <link>https://tech-snippets.xyz/posts/mcp-agent-ecosystem-guide/</link>
      <pubDate>Wed, 06 May 2026 19:00:00 +0800</pubDate>
      <guid>https://tech-snippets.xyz/posts/mcp-agent-ecosystem-guide/</guid>
      <description>前言 2026 年，AI Agent 的发展已经进入了一个全新的阶段。从早期的单轮对话，到如今能够自主完成复杂任务的智能体，AI 的能力边界正在被不断拓展。然而，在构建真正实用的 AI Agent 时，我们依然面临着一个核心难题：如何让大语言模型安全、高效地与外部世界进行交互？
传统的 Agent 框架如 LangChain、AutoGPT 等虽然提供了工具调用的能力，但它们普遍存在几个致命问题：工具定义分散、权限管理混乱、不同客户端之间无法复用、安全性难以保障。当你为 Claude Desktop 开发了一个文件操作工具后，想要在 Cursor 或 Cline 中复用几乎不可能，一切都要从头开始。这种碎片化的开发生态严重制约了 Agent 技术的普及。
正是在这样的背景下，Anthropic 提出了 MCP（Model Context Protocol）——一个开放的、标准化的协议，旨在彻底解决 AI 工具生态的碎片化问题。MCP 定义了一套统一的接口规范，使得任何遵循该协议的工具服务器都能被所有兼容的 LLM 客户端无缝使用。这就像是为 AI 世界建立了一个通用的&amp;quot;插座标准&amp;quot;，从此电器不再需要特制插头。
本文将从底层原理出发，带你深入理解 MCP 的设计哲学和技术架构，通过完整的代码示例，手把手教你构建生产级别的 MCP 服务器。无论你是想要为自己的开发环境增强 AI 能力，还是想要构建企业级的 Agent 平台，这篇文章都会为你提供完整的解决方案。
一、为什么我们需要 MCP？ 在深入技术细节之前，让我们先回答一个根本问题：现有的工具调用方案到底出了什么问题？为什么我们需要一个全新的协议？
1.1 传统工具调用的痛点 让我们以最常见的场景为例：你想要让 AI 助手帮你读取本地文件、执行终端命令、查询数据库。在没有 MCP 的时代，你需要怎么做？
如果你使用 Claude Desktop，你需要编写它特定格式的工具定义；如果你切换到 Cursor，又要重写一遍；如果是 VS Code 的其他 AI 插件，可能又是完全不同的格式。每换一个客户端，工具就要重新开发一次。
更糟糕的是安全问题。大多数工具调用方案都是&amp;quot;全有或全无&amp;quot;的——AI 要么拥有完整的文件系统访问权限，要么什么都做不了。你无法精细地控制它只能读取某个特定目录，只能执行某些白名单内的命令。
最后是可维护性问题。当你的工具逻辑更新时，你需要在所有客户端中同步更新，这在团队协作场景下几乎是不可行的。
1.2 MCP 的设计目标 MCP 的诞生正是为了解决上述所有痛点，它的核心设计目标包括：</description>
      <content:encoded><![CDATA[<h2 id="前言">前言</h2>
<p>2026 年，AI Agent 的发展已经进入了一个全新的阶段。从早期的单轮对话，到如今能够自主完成复杂任务的智能体，AI 的能力边界正在被不断拓展。然而，在构建真正实用的 AI Agent 时，我们依然面临着一个核心难题：<strong>如何让大语言模型安全、高效地与外部世界进行交互？</strong></p>
<p>传统的 Agent 框架如 LangChain、AutoGPT 等虽然提供了工具调用的能力，但它们普遍存在几个致命问题：工具定义分散、权限管理混乱、不同客户端之间无法复用、安全性难以保障。当你为 Claude Desktop 开发了一个文件操作工具后，想要在 Cursor 或 Cline 中复用几乎不可能，一切都要从头开始。这种碎片化的开发生态严重制约了 Agent 技术的普及。</p>
<p>正是在这样的背景下，Anthropic 提出了 <strong>MCP（Model Context Protocol）</strong>——一个开放的、标准化的协议，旨在彻底解决 AI 工具生态的碎片化问题。MCP 定义了一套统一的接口规范，使得任何遵循该协议的工具服务器都能被所有兼容的 LLM 客户端无缝使用。这就像是为 AI 世界建立了一个通用的&quot;插座标准&quot;，从此电器不再需要特制插头。</p>
<p>本文将从底层原理出发，带你深入理解 MCP 的设计哲学和技术架构，通过完整的代码示例，手把手教你构建生产级别的 MCP 服务器。无论你是想要为自己的开发环境增强 AI 能力，还是想要构建企业级的 Agent 平台，这篇文章都会为你提供完整的解决方案。</p>
<p><img alt="MCP 架构概览" loading="lazy" src="/images/mcp-architecture-overview.svg"></p>
<h2 id="一为什么我们需要-mcp">一、为什么我们需要 MCP？</h2>
<p>在深入技术细节之前，让我们先回答一个根本问题：现有的工具调用方案到底出了什么问题？为什么我们需要一个全新的协议？</p>
<h3 id="11-传统工具调用的痛点">1.1 传统工具调用的痛点</h3>
<p>让我们以最常见的场景为例：你想要让 AI 助手帮你读取本地文件、执行终端命令、查询数据库。在没有 MCP 的时代，你需要怎么做？</p>
<p>如果你使用 Claude Desktop，你需要编写它特定格式的工具定义；如果你切换到 Cursor，又要重写一遍；如果是 VS Code 的其他 AI 插件，可能又是完全不同的格式。每换一个客户端，工具就要重新开发一次。</p>
<p>更糟糕的是安全问题。大多数工具调用方案都是&quot;全有或全无&quot;的——AI 要么拥有完整的文件系统访问权限，要么什么都做不了。你无法精细地控制它只能读取某个特定目录，只能执行某些白名单内的命令。</p>
<p>最后是可维护性问题。当你的工具逻辑更新时，你需要在所有客户端中同步更新，这在团队协作场景下几乎是不可行的。</p>
<h3 id="12-mcp-的设计目标">1.2 MCP 的设计目标</h3>
<p>MCP 的诞生正是为了解决上述所有痛点，它的核心设计目标包括：</p>
<p><strong>1. 一次开发，处处运行</strong></p>
<p>遵循 MCP 协议开发的工具服务器，可以在任何兼容的 LLM 客户端中使用，无需修改任何代码。这就像是为 AI 工具建立了一个通用的应用商店生态。</p>
<p><strong>2. 细粒度权限控制</strong></p>
<p>MCP 提供了完善的权限模型，可以精确控制每个工具的访问范围，比如只允许访问 <code>~/projects</code> 目录，只允许执行 <code>git</code> 和 <code>npm</code> 命令等。</p>
<p><strong>3. 标准化的通信协议</strong></p>
<p>基于 JSON-RPC 2.0 标准，MCP 定义了清晰的请求-响应格式，支持多种传输层（stdio、HTTP、SSE），无论是本地工具还是远程服务都可以轻松接入。</p>
<p><strong>4. 可扩展的能力模型</strong></p>
<p>MCP 不仅仅是工具调用，它还定义了资源访问（Resources）、提示模板（Prompts）等多种能力模型，为构建复杂的 Agent 系统提供了完整的基础设施。</p>
<h3 id="13-mcp-与传统框架的对比">1.3 MCP 与传统框架的对比</h3>
<p>让我们通过一个具体的例子来感受 MCP 的优势。假设我们要实现一个&quot;读取指定目录文件列表&quot;的功能：</p>
<p><strong>LangChain 方式：</strong></p>
<div class="highlight"><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">class</span> <span class="nc">ReadDirectoryTool</span><span class="p">(</span><span class="n">BaseTool</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_directory&#34;</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></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="k">def</span> <span class="nf">_run</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">path</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</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">os</span><span class="o">.</span><span class="n">listdir</span><span class="p">(</span><span class="n">path</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 这个工具只能在 LangChain 框架内使用</span>
</span></span></code></pre></div><p><strong>MCP 方式：</strong></p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="c1">// 独立的 MCP 服务器，与客户端完全解耦
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kr">const</span> <span class="nx">server</span> <span class="o">=</span> <span class="nx">createServer</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">  <span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;filesystem&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">version</span><span class="o">:</span> <span class="s2">&#34;1.0.0&#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="nx">server</span><span class="p">.</span><span class="nx">setRequestHandler</span><span class="p">(</span><span class="nx">ListToolsRequestSchema</span><span class="p">,</span> <span class="kr">async</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">({</span>
</span></span><span class="line"><span class="cl">  <span class="nx">tools</span><span class="o">:</span> <span class="p">[{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;list_directory&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">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="nx">inputSchema</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="kr">type</span><span class="o">:</span> <span class="s2">&#34;object&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">properties</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">path</span><span class="o">:</span> <span class="p">{</span> <span class="kr">type</span><span class="o">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span> <span class="nx">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="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">// 可以在 Claude Desktop、Cursor、Cline 等任意客户端使用
</span></span></span><span class="line"><span class="cl"><span class="c1">// 服务器端可以实现白名单、审计日志、权限控制等
</span></span></span></code></pre></div><p>关键的区别在于：MCP 工具是独立运行的服务，客户端只是通过协议与它通信。这种架构带来了前所未有的灵活性和安全性。</p>
<h2 id="二mcp-的核心概念与架构">二、MCP 的核心概念与架构</h2>
<p>理解 MCP 的第一步是掌握它的核心概念。MCP 的设计非常简洁，但每个概念都经过深思熟虑。</p>
<h3 id="21-三层架构模型">2.1 三层架构模型</h3>
<p>MCP 采用经典的客户端-服务器架构，但在具体实现上分为三层：</p>
<p><strong>第一层：LLM 客户端</strong></p>
<p>这是用户直接交互的界面，比如 Claude Desktop、Cursor IDE、Cline，或者你自己开发的 Agent 应用。客户端负责与用户对话，理解用户意图，然后通过 MCP 协议调用工具。</p>
<p><strong>第二层：MCP 协议层</strong></p>
<p>这是整个系统的核心，定义了标准化的消息格式、能力发现机制、错误处理规范等。所有通信都基于 JSON-RPC 2.0，确保了跨语言、跨平台的兼容性。</p>
<p><strong>第三层：MCP 服务器</strong></p>
<p>这是实际执行操作的地方。每个服务器提供一组特定的能力（工具、资源、提示模板），可以是本地运行的进程，也可以是远程的网络服务。</p>
<h3 id="22-三大能力类型">2.2 三大能力类型</h3>
<p>MCP 定义了三种核心能力类型，覆盖了 Agent 所需的所有交互场景：</p>
<p><strong>1. 工具（Tools）</strong></p>
<p>工具是最常用的能力类型，代表 AI 可以执行的操作。每个工具都有明确的名称、描述和输入 schema，LLM 根据这些信息决定何时以及如何调用工具。</p>
<p>典型的工具例子：</p>
<ul>
<li><code>read_file</code> - 读取文件内容</li>
<li><code>run_command</code> - 执行终端命令</li>
<li><code>search_web</code> - 搜索网页</li>
<li><code>send_email</code> - 发送邮件</li>
</ul>
<p><strong>2. 资源（Resources）</strong></p>
<p>资源是 MCP 独有的概念，代表 AI 可以读取的信息源。与工具不同，资源是声明式的——它们有 URI，可以被引用和缓存。</p>
<p>典型的资源例子：</p>
<ul>
<li><code>file:///home/user/project/README.md</code> - 本地文件</li>
<li><code>github://repo/pull/123</code> - GitHub PR</li>
<li><code>database://users/table/schema</code> - 数据库表结构</li>
</ul>
<p>资源的优势在于 LLM 可以理解它们之间的关系，并且客户端可以智能地缓存资源内容，避免重复读取。</p>
<p><strong>3. 提示模板（Prompts）</strong></p>
<p>提示模板是预定义的对话模板，可以帮助 LLM 更好地完成特定任务。模板支持参数化，可以在运行时注入变量。</p>
<p>典型的提示模板例子：</p>
<ul>
<li><code>code_review</code> - 代码审查提示</li>
<li><code>bug_analysis</code> - Bug 分析提示</li>
<li><code>write_test</code> - 测试生成提示</li>
</ul>
<h3 id="23-通信协议详解">2.3 通信协议详解</h3>
<p>MCP 基于 JSON-RPC 2.0，这是一个轻量级的远程过程调用协议。让我们看看实际的消息格式：</p>
<p><strong>客户端请求工具列表：</strong></p>
<div class="highlight"><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;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/list&#34;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p><strong>服务器响应：</strong></p>
<div class="highlight"><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;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;tools&#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;name&#34;</span><span class="p">:</span> <span class="s2">&#34;calculate&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#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="nt">&#34;inputSchema&#34;</span><span class="p">:</span> <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;object&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nt">&#34;properties&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nt">&#34;expression&#34;</span><span class="p">:</span> <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;string&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">              <span class="nt">&#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="nt">&#34;required&#34;</span><span class="p">:</span> <span class="p">[</span><span class="s2">&#34;expression&#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 class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p><strong>客户端调用工具：</strong></p>
<div class="highlight"><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;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">2</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;calculate&#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;expression&#34;</span><span class="p">:</span> <span class="s2">&#34;2 + 3 * 4&#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></div><p><strong>服务器返回结果：</strong></p>
<div class="highlight"><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;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">2</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;14&#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></div><p>这种标准化的消息格式确保了任何客户端都能与任何服务器正确通信，就像 HTTP 让浏览器能与任何 Web 服务器通信一样。</p>
<h2 id="三开发环境搭建与第一个-mcp-服务器">三、开发环境搭建与第一个 MCP 服务器</h2>
<p>现在让我们动手实践，从零开始搭建开发环境并创建第一个可运行的 MCP 服务器。</p>
<h3 id="31-环境准备">3.1 环境准备</h3>
<p>首先确保你安装了必要的开发工具：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 安装 Node.js 20+（推荐使用 nvm）</span>
</span></span><span class="line"><span class="cl">curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.0/install.sh <span class="p">|</span> bash
</span></span><span class="line"><span class="cl">nvm install <span class="m">22</span>
</span></span><span class="line"><span class="cl">nvm use <span class="m">22</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 安装 TypeScript</span>
</span></span><span class="line"><span class="cl">npm install -g typescript ts-node
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 安装 MCP SDK</span>
</span></span><span class="line"><span class="cl">npm install @modelcontextprotocol/sdk
</span></span></code></pre></div><h3 id="32-最简单的-mcp-服务器">3.2 最简单的 MCP 服务器</h3>
<p>让我们创建一个提供&quot;数学计算&quot;功能的 MCP 服务器：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="c1">// server.ts
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kr">import</span> <span class="p">{</span> <span class="nx">Server</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;@modelcontextprotocol/sdk/server/index.js&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">StdioServerTransport</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;@modelcontextprotocol/sdk/server/stdio.js&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">CallToolRequestSchema</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">ListToolsRequestSchema</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;@modelcontextprotocol/sdk/types.js&#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="c1"></span><span class="kr">const</span> <span class="nx">server</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Server</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="nx">name</span><span class="o">:</span> <span class="s2">&#34;calculator-mcp&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">version</span><span class="o">:</span> <span class="s2">&#34;1.0.0&#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="nx">capabilities</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">tools</span><span class="o">:</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="c1"></span><span class="nx">server</span><span class="p">.</span><span class="nx">setRequestHandler</span><span class="p">(</span><span class="nx">ListToolsRequestSchema</span><span class="p">,</span> <span class="kr">async</span> <span class="p">()</span> <span class="o">=&gt;</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="nx">tools</span><span class="o">:</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="nx">name</span><span class="o">:</span> <span class="s2">&#34;calculate&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">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="nx">inputSchema</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="kr">type</span><span class="o">:</span> <span class="s2">&#34;object&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">properties</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nx">expression</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">              <span class="kr">type</span><span class="o">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">              <span class="nx">description</span><span class="o">:</span> <span class="s2">&#34;要计算的数学表达式，例如：2 + 3 * (4 - 1)&#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="nx">required</span><span class="o">:</span> <span class="p">[</span><span class="s2">&#34;expression&#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 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="nx">server</span><span class="p">.</span><span class="nx">setRequestHandler</span><span class="p">(</span><span class="nx">CallToolRequestSchema</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">request</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="p">{</span> <span class="nx">name</span><span class="p">,</span> <span class="nx">arguments</span>: <span class="kt">args</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">request</span><span class="p">.</span><span class="nx">params</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="p">(</span><span class="nx">name</span> <span class="o">===</span> <span class="s2">&#34;calculate&#34;</span><span class="p">)</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="c1"></span>      <span class="kr">const</span> <span class="nx">result</span> <span class="o">=</span> <span class="nb">Function</span><span class="p">(</span><span class="s1">&#39;&#34;use strict&#34;; return (&#39;</span> <span class="o">+</span> <span class="nx">args</span><span class="p">.</span><span class="nx">expression</span> <span class="o">+</span> <span class="s1">&#39;)&#39;</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="nx">content</span><span class="o">:</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="kr">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="nx">text</span><span class="o">:</span> <span class="sb">`计算结果：</span><span class="si">${</span><span class="nx">result</span><span class="si">}</span><span class="sb">`</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 class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">error</span><span class="p">)</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="nx">content</span><span class="o">:</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="kr">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="nx">text</span><span class="o">:</span> <span class="sb">`计算错误：</span><span class="si">${</span><span class="p">(</span><span class="nx">error</span> <span class="kr">as</span> <span class="nb">Error</span><span class="p">).</span><span class="nx">message</span><span class="si">}</span><span class="sb">`</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="nx">isError</span>: <span class="kt">true</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="k">throw</span> <span class="k">new</span> <span class="nb">Error</span><span class="p">(</span><span class="sb">`未知工具：</span><span class="si">${</span><span class="nx">name</span><span class="si">}</span><span class="sb">`</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">// 启动服务器
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kr">async</span> <span class="kd">function</span> <span class="nx">main() {</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">transport</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">StdioServerTransport</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">  <span class="k">await</span> <span class="nx">server</span><span class="p">.</span><span class="nx">connect</span><span class="p">(</span><span class="nx">transport</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="s2">&#34;Calculator MCP Server 已启动&#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></span><span class="line"><span class="cl"><span class="nx">main</span><span class="p">().</span><span class="k">catch</span><span class="p">((</span><span class="nx">error</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="s2">&#34;服务器启动失败：&#34;</span><span class="p">,</span> <span class="nx">error</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="nx">process</span><span class="p">.</span><span class="nx">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>这是一个完整的 MCP 服务器，虽然功能简单，但包含了所有必要的组件。</p>
<h3 id="33-编译与测试">3.3 编译与测试</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 编译 TypeScript</span>
</span></span><span class="line"><span class="cl">tsc server.ts
</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">node server.js
</span></span></code></pre></div><p>（第一部分完，约2400字）</p>
<p><img alt="MCP 通信流程时序图" loading="lazy" src="/images/mcp-communication-flow.svg"></p>
<h2 id="四深入理解-mcp-核心协议细节">四、深入理解 MCP 核心协议细节</h2>
<p>现在我们来深入解析 MCP 协议的核心细节，理解每个消息类型的设计意图和最佳实践。</p>
<h3 id="41-能力发现与初始化流程">4.1 能力发现与初始化流程</h3>
<p>MCP 采用了&quot;能力优先&quot;的设计哲学。在任何操作之前，客户端首先要了解服务器能做什么。这就是能力发现机制。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><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">async</span> <span class="kd">function</span> <span class="nx">initializeFlow() {</span>
</span></span><span class="line"><span class="cl">  <span class="c1">// 1. 客户端发送初始化请求
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="kr">const</span> <span class="nx">initResult</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">server</span><span class="p">.</span><span class="nx">request</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">    <span class="nx">method</span><span class="o">:</span> <span class="s2">&#34;initialize&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">params</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">protocolVersion</span><span class="o">:</span> <span class="s2">&#34;2024-11-05&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">capabilities</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">tools</span><span class="o">:</span> <span class="p">{},</span>
</span></span><span class="line"><span class="cl">        <span class="nx">resources</span><span class="o">:</span> <span class="p">{},</span>
</span></span><span class="line"><span class="cl">        <span class="nx">prompts</span><span class="o">:</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="nx">clientInfo</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;claude-desktop&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">version</span><span class="o">:</span> <span class="s2">&#34;1.5.0&#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">// 2. 服务器返回自己的能力
</span></span></span><span class="line"><span class="cl"><span class="c1"></span>  <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&#34;服务器能力:&#34;</span><span class="p">,</span> <span class="nx">initResult</span><span class="p">.</span><span class="nx">capabilities</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="c1"></span>  <span class="k">await</span> <span class="nx">server</span><span class="p">.</span><span class="nx">notification</span><span class="p">({</span> <span class="nx">method</span><span class="o">:</span> <span class="s2">&#34;initialized&#34;</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>这个握手流程有几个重要的设计考虑：</p>
<p><strong>版本协商</strong>：双方都声明自己支持的协议版本，确保向后兼容。如果客户端和服务器版本不匹配，可以优雅降级或提示用户。</p>
<p><strong>能力协商</strong>：双方互相告知自己支持哪些特性。比如客户端可以说&quot;我支持图片内容&quot;，服务器就知道可以返回图片格式的结果。</p>
<p><strong>双向通信</strong>：不仅客户端可以调用服务器，服务器也可以主动向客户端发送通知，这是实现实时更新的关键。</p>
<h3 id="42-工具调用的进阶用法">4.2 工具调用的进阶用法</h3>
<p>简单的文本返回只是开始，MCP 工具支持丰富的返回类型，让我们看看更高级的用法：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="c1">// 返回多种内容类型的工具
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="nx">server</span><span class="p">.</span><span class="nx">setRequestHandler</span><span class="p">(</span><span class="nx">CallToolRequestSchema</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">request</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="p">{</span> <span class="nx">name</span><span class="p">,</span> <span class="nx">arguments</span>: <span class="kt">args</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">request</span><span class="p">.</span><span class="nx">params</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="p">(</span><span class="nx">name</span> <span class="o">===</span> <span class="s2">&#34;analyze_data&#34;</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">data</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">loadData</span><span class="p">(</span><span class="nx">args</span><span class="p">.</span><span class="nx">file</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">chart</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">generateChart</span><span class="p">(</span><span class="nx">data</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></span><span class="line"><span class="cl">      <span class="nx">content</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="c1"></span>        <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="kr">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="nx">text</span><span class="o">:</span> <span class="sb">`数据分析完成，共 </span><span class="si">${</span><span class="nx">data</span><span class="p">.</span><span class="nx">length</span><span class="si">}</span><span class="sb"> 条记录`</span>
</span></span><span class="line"><span class="cl">        <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"></span>        <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="kr">type</span><span class="o">:</span> <span class="s2">&#34;image&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">data</span>: <span class="kt">chart.base64</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">mimeType</span><span class="o">:</span> <span class="s2">&#34;image/png&#34;</span>
</span></span><span class="line"><span class="cl">        <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"></span>        <span class="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="kr">type</span><span class="o">:</span> <span class="s2">&#34;resource&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">resource</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="nx">uri</span><span class="o">:</span> <span class="sb">`file://</span><span class="si">${</span><span class="nx">args</span><span class="p">.</span><span class="nx">file</span><span class="si">}</span><span class="sb">`</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="nx">text</span>: <span class="kt">data.rawContent</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></div><p>这个例子展示了 MCP 强大的内容模型：一个工具调用可以同时返回文本、图片、资源等多种格式的内容，LLM 可以根据这些丰富的信息生成更全面的回答。</p>
<h3 id="43-资源系统的设计">4.3 资源系统的设计</h3>
<p>资源系统是 MCP 最具创新性的设计之一，让我们通过代码理解它的工作原理：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">ListResourcesRequestSchema</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">ReadResourceRequestSchema</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">Resource</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;@modelcontextprotocol/sdk/types.js&#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="c1"></span><span class="kr">const</span> <span class="nx">server</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Server</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span> <span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;github-mcp&#34;</span><span class="p">,</span> <span class="nx">version</span><span class="o">:</span> <span class="s2">&#34;1.0.0&#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="nx">capabilities</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">resources</span><span class="o">:</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="c1"></span><span class="nx">server</span><span class="p">.</span><span class="nx">setRequestHandler</span><span class="p">(</span><span class="nx">ListResourcesRequestSchema</span><span class="p">,</span> <span class="kr">async</span> <span class="p">()</span> <span class="o">=&gt;</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="nx">resources</span><span class="o">:</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="nx">uri</span><span class="o">:</span> <span class="s2">&#34;github://user/repo/pull/123&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;PR #123: 新功能开发&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">description</span><span class="o">:</span> <span class="s2">&#34;Pull Request 的完整内容&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">mimeType</span><span class="o">:</span> <span class="s2">&#34;text/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="nx">uri</span><span class="o">:</span> <span class="s2">&#34;github://user/repo/issues/456&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">name</span><span class="o">:</span> <span class="s2">&#34;Issue #456: 登录失败&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">description</span><span class="o">:</span> <span class="s2">&#34;Bug 报告详情&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">mimeType</span><span class="o">:</span> <span class="s2">&#34;text/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="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="nx">server</span><span class="p">.</span><span class="nx">setRequestHandler</span><span class="p">(</span><span class="nx">ReadResourceRequestSchema</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">request</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="p">{</span> <span class="nx">uri</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">request</span><span class="p">.</span><span class="nx">params</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="p">(</span><span class="nx">uri</span><span class="p">.</span><span class="nx">startsWith</span><span class="p">(</span><span class="s2">&#34;github://&#34;</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">content</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">fetchFromGitHub</span><span class="p">(</span><span class="nx">uri</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="nx">contents</span><span class="o">:</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="nx">uri</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">mimeType</span><span class="o">:</span> <span class="s2">&#34;text/markdown&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">text</span>: <span class="kt">content</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></span><span class="line"><span class="cl">  <span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span><span class="p">(</span><span class="sb">`不支持的资源 URI: </span><span class="si">${</span><span class="nx">uri</span><span class="si">}</span><span class="sb">`</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><p>资源系统的优势在于：</p>
<p><strong>可寻址性</strong>：每个资源都有唯一的 URI，LLM 可以精确地引用和讨论具体资源。</p>
<p><strong>可缓存性</strong>：客户端可以缓存资源内容，避免重复读取，提升性能。</p>
<p><strong>可订阅性</strong>：服务器可以在资源变化时主动通知客户端，实现实时更新。</p>
<h2 id="五构建生产级-mcp-服务器">五、构建生产级 MCP 服务器</h2>
<p>上一节的示例虽然功能完整，但距离生产环境还有差距。现在我们来学习如何构建一个健壮、安全、可维护的 MCP 服务器。</p>
<h3 id="51-错误处理与日志">5.1 错误处理与日志</h3>
<p>生产级代码的第一个标志就是完善的错误处理：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">createLogger</span><span class="p">,</span> <span class="nx">format</span><span class="p">,</span> <span class="nx">transports</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;winston&#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="c1"></span><span class="kr">const</span> <span class="nx">logger</span> <span class="o">=</span> <span class="nx">createLogger</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">  <span class="nx">level</span><span class="o">:</span> <span class="s2">&#34;info&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">format</span>: <span class="kt">format.combine</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="nx">format</span><span class="p">.</span><span class="nx">timestamp</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">    <span class="nx">format</span><span class="p">.</span><span class="nx">json</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="nx">transports</span><span class="o">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl">    <span class="k">new</span> <span class="nx">transports</span><span class="p">.</span><span class="nx">File</span><span class="p">({</span> <span class="nx">filename</span><span class="o">:</span> <span class="s2">&#34;/var/log/mcp/error.log&#34;</span><span class="p">,</span> <span class="nx">level</span><span class="o">:</span> <span class="s2">&#34;error&#34;</span> <span class="p">}),</span>
</span></span><span class="line"><span class="cl">    <span class="k">new</span> <span class="nx">transports</span><span class="p">.</span><span class="nx">File</span><span class="p">({</span> <span class="nx">filename</span><span class="o">:</span> <span class="s2">&#34;/var/log/mcp/combined.log&#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></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="kd">function</span> <span class="nx">safeToolHandler</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="nx">handler</span><span class="o">:</span> <span class="p">(</span><span class="nx">request</span>: <span class="kt">CallToolRequest</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nx">Promise</span><span class="p">&lt;</span><span class="nt">CallToolResult</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">request</span>: <span class="kt">CallToolRequest</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">toolName</span> <span class="o">=</span> <span class="nx">request</span><span class="p">.</span><span class="nx">params</span><span class="p">.</span><span class="nx">name</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">startTime</span> <span class="o">=</span> <span class="nb">Date</span><span class="p">.</span><span class="nx">now</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="nx">logger</span><span class="p">.</span><span class="nx">info</span><span class="p">(</span><span class="sb">`工具调用开始: </span><span class="si">${</span><span class="nx">toolName</span><span class="si">}</span><span class="sb">`</span><span class="p">,</span> <span class="p">{</span> <span class="nx">args</span>: <span class="kt">request.params.arguments</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">      
</span></span><span class="line"><span class="cl">      <span class="kr">const</span> <span class="nx">result</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">handler</span><span class="p">(</span><span class="nx">request</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      
</span></span><span class="line"><span class="cl">      <span class="kr">const</span> <span class="nx">duration</span> <span class="o">=</span> <span class="nb">Date</span><span class="p">.</span><span class="nx">now</span><span class="p">()</span> <span class="o">-</span> <span class="nx">startTime</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="nx">logger</span><span class="p">.</span><span class="nx">info</span><span class="p">(</span><span class="sb">`工具调用完成: </span><span class="si">${</span><span class="nx">toolName</span><span class="si">}</span><span class="sb">`</span><span class="p">,</span> <span class="p">{</span> <span class="nx">duration</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="nx">result</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">error</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">logger</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="sb">`工具调用失败: </span><span class="si">${</span><span class="nx">toolName</span><span class="si">}</span><span class="sb">`</span><span class="p">,</span> <span class="p">{</span> 
</span></span><span class="line"><span class="cl">        <span class="nx">error</span><span class="o">:</span> <span class="p">(</span><span class="nx">error</span> <span class="kr">as</span> <span class="nb">Error</span><span class="p">).</span><span class="nx">message</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nx">stack</span><span class="o">:</span> <span class="p">(</span><span class="nx">error</span> <span class="kr">as</span> <span class="nb">Error</span><span class="p">).</span><span class="nx">stack</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="nx">content</span><span class="o">:</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="kr">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="nx">text</span><span class="o">:</span> <span class="sb">`执行出错: </span><span class="si">${</span><span class="p">(</span><span class="nx">error</span> <span class="kr">as</span> <span class="nb">Error</span><span class="p">).</span><span class="nx">message</span><span class="si">}</span><span class="err">\</span><span class="sb">n</span><span class="err">\</span><span class="sb">n请检查日志获取详细信息。`</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="nx">isError</span>: <span class="kt">true</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></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="nx">server</span><span class="p">.</span><span class="nx">setRequestHandler</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="nx">CallToolRequestSchema</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">safeToolHandler</span><span class="p">(</span><span class="kr">async</span> <span class="p">(</span><span class="nx">request</span><span class="p">)</span> <span class="o">=&gt;</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"></span>    <span class="k">return</span> <span class="p">{</span> <span class="nx">content</span><span class="o">:</span> <span class="p">[{</span> <span class="kr">type</span><span class="o">:</span> <span class="s2">&#34;text&#34;</span><span class="p">,</span> <span class="nx">text</span><span class="o">:</span> <span class="s2">&#34;成功&#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></code></pre></div><h3 id="52-权限控制与安全沙箱">5.2 权限控制与安全沙箱</h3>
<p>安全是生产级 MCP 服务器的重中之重。我们需要实现多层防护：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><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">interface</span> <span class="nx">PermissionConfig</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">allowedDirectories</span>: <span class="kt">string</span><span class="p">[];</span>
</span></span><span class="line"><span class="cl">  <span class="nx">allowedCommands</span>: <span class="kt">string</span><span class="p">[];</span>
</span></span><span class="line"><span class="cl">  <span class="nx">maxExecutionTime</span>: <span class="kt">number</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="kr">const</span> <span class="nx">config</span>: <span class="kt">PermissionConfig</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">allowedDirectories</span><span class="o">:</span> <span class="p">[</span><span class="s2">&#34;/home/user/projects&#34;</span><span class="p">,</span> <span class="s2">&#34;/tmp&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">  <span class="nx">allowedCommands</span><span class="o">:</span> <span class="p">[</span><span class="s2">&#34;git&#34;</span><span class="p">,</span> <span class="s2">&#34;npm&#34;</span><span class="p">,</span> <span class="s2">&#34;node&#34;</span><span class="p">,</span> <span class="s2">&#34;ls&#34;</span><span class="p">,</span> <span class="s2">&#34;cat&#34;</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">  <span class="nx">maxExecutionTime</span>: <span class="kt">30000</span> <span class="c1">// 30秒
</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="kd">function</span> <span class="nx">isPathAllowed</span><span class="p">(</span><span class="nx">path</span>: <span class="kt">string</span><span class="p">)</span><span class="o">:</span> <span class="kr">boolean</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">normalized</span> <span class="o">=</span> <span class="nx">path</span><span class="p">.</span><span class="nx">normalize</span><span class="p">(</span><span class="nx">path</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">config</span><span class="p">.</span><span class="nx">allowedDirectories</span><span class="p">.</span><span class="nx">some</span><span class="p">(</span><span class="nx">dir</span> <span class="o">=&gt;</span> 
</span></span><span class="line"><span class="cl">    <span class="nx">normalized</span><span class="p">.</span><span class="nx">startsWith</span><span class="p">(</span><span class="nx">path</span><span class="p">.</span><span class="nx">normalize</span><span class="p">(</span><span class="nx">dir</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="c1">// 命令白名单检查
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">function</span> <span class="nx">isCommandAllowed</span><span class="p">(</span><span class="nx">command</span>: <span class="kt">string</span><span class="p">)</span><span class="o">:</span> <span class="kr">boolean</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">cmd</span> <span class="o">=</span> <span class="nx">command</span><span class="p">.</span><span class="nx">split</span><span class="p">(</span><span class="s2">&#34; &#34;</span><span class="p">)[</span><span class="mi">0</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">config</span><span class="p">.</span><span class="nx">allowedCommands</span><span class="p">.</span><span class="nx">includes</span><span class="p">(</span><span class="nx">cmd</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">// 执行超时控制
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">function</span> <span class="nx">withTimeout</span><span class="p">&lt;</span><span class="nt">T</span><span class="p">&gt;(</span>
</span></span><span class="line"><span class="cl">  <span class="nx">promise</span>: <span class="kt">Promise</span><span class="p">&lt;</span><span class="nt">T</span><span class="p">&gt;,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">timeout</span>: <span class="kt">number</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">message</span>: <span class="kt">string</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span><span class="o">:</span> <span class="nx">Promise</span><span class="p">&lt;</span><span class="nt">T</span><span class="p">&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">Promise</span><span class="p">.</span><span class="nx">race</span><span class="p">([</span>
</span></span><span class="line"><span class="cl">    <span class="nx">promise</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="k">new</span> <span class="nx">Promise</span><span class="p">&lt;</span><span class="nt">never</span><span class="p">&gt;((</span><span class="nx">_</span><span class="p">,</span> <span class="nx">reject</span><span class="p">)</span> <span class="o">=&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="nx">setTimeout</span><span class="p">(()</span> <span class="o">=&gt;</span> <span class="nx">reject</span><span class="p">(</span><span class="k">new</span> <span class="nb">Error</span><span class="p">(</span><span class="nx">message</span><span class="p">)),</span> <span class="nx">timeout</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="c1"></span><span class="kr">async</span> <span class="kd">function</span> <span class="nx">safeReadFile</span><span class="p">(</span><span class="nx">filePath</span>: <span class="kt">string</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">isPathAllowed</span><span class="p">(</span><span class="nx">filePath</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span><span class="p">(</span><span class="sb">`拒绝访问: 路径不在白名单内 </span><span class="si">${</span><span class="nx">filePath</span><span class="si">}</span><span class="sb">`</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">// ... 执行读取
</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">async</span> <span class="kd">function</span> <span class="nx">safeRunCommand</span><span class="p">(</span><span class="nx">command</span>: <span class="kt">string</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">isCommandAllowed</span><span class="p">(</span><span class="nx">command</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span><span class="p">(</span><span class="sb">`拒绝执行: 命令不在白名单内 </span><span class="si">${</span><span class="nx">command</span><span class="si">}</span><span class="sb">`</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">return</span> <span class="nx">withTimeout</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="nx">execCommand</span><span class="p">(</span><span class="nx">command</span><span class="p">),</span>
</span></span><span class="line"><span class="cl">    <span class="nx">config</span><span class="p">.</span><span class="nx">maxExecutionTime</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><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>这套安全机制确保了即使 LLM 被诱导执行恶意操作，MCP 服务器也能在造成损害之前将其拦截。</p>
<h3 id="53-配置管理与多环境支持">5.3 配置管理与多环境支持</h3>
<p>生产环境需要支持灵活的配置管理：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="c1">// config.ts
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kr">import</span> <span class="o">*</span> <span class="kr">as</span> <span class="nx">fs</span> <span class="kr">from</span> <span class="s2">&#34;fs&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="o">*</span> <span class="kr">as</span> <span class="nx">path</span> <span class="kr">from</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="kr">interface</span> <span class="nx">ServerConfig</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">environment</span><span class="o">:</span> <span class="s2">&#34;development&#34;</span> <span class="o">|</span> <span class="s2">&#34;staging&#34;</span> <span class="o">|</span> <span class="s2">&#34;production&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">logging</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">level</span>: <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nx">file</span>: <span class="kt">string</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="nx">security</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">allowedPaths</span>: <span class="kt">string</span><span class="p">[];</span>
</span></span><span class="line"><span class="cl">    <span class="nx">allowedCommands</span>: <span class="kt">string</span><span class="p">[];</span>
</span></span><span class="line"><span class="cl">    <span class="nx">enableSandbox</span>: <span class="kt">boolean</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="nx">rateLimit</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">maxRequestsPerMinute</span>: <span class="kt">number</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="nx">maxConcurrentCalls</span>: <span class="kt">number</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="kd">function</span> <span class="nx">loadConfig</span><span class="p">()</span><span class="o">:</span> <span class="nx">ServerConfig</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">env</span> <span class="o">=</span> <span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">MCP_ENV</span> <span class="o">||</span> <span class="s2">&#34;development&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">configPath</span> <span class="o">=</span> <span class="nx">path</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="nx">process</span><span class="p">.</span><span class="nx">env</span><span class="p">.</span><span class="nx">HOME</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="s2">&#34;.config&#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="sb">`config.</span><span class="si">${</span><span class="nx">env</span><span class="si">}</span><span class="sb">.json`</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">if</span> <span class="p">(</span><span class="nx">fs</span><span class="p">.</span><span class="nx">existsSync</span><span class="p">(</span><span class="nx">configPath</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">fs</span><span class="p">.</span><span class="nx">readFileSync</span><span class="p">(</span><span class="nx">configPath</span><span class="p">,</span> <span class="s2">&#34;utf-8&#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></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="k">return</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nx">environment</span>: <span class="kt">env</span> <span class="kr">as</span> <span class="kt">any</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">logging</span><span class="o">:</span> <span class="p">{</span> <span class="nx">level</span><span class="o">:</span> <span class="s2">&#34;info&#34;</span><span class="p">,</span> <span class="nx">file</span><span class="o">:</span> <span class="sb">`mcp-</span><span class="si">${</span><span class="nx">env</span><span class="si">}</span><span class="sb">.log`</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nx">security</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">allowedPaths</span><span class="o">:</span> <span class="p">[],</span>
</span></span><span class="line"><span class="cl">      <span class="nx">allowedCommands</span><span class="o">:</span> <span class="p">[],</span>
</span></span><span class="line"><span class="cl">      <span class="nx">enableSandbox</span>: <span class="kt">env</span> <span class="o">===</span> <span class="s2">&#34;production&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="p">},</span>
</span></span><span class="line"><span class="cl">    <span class="nx">rateLimit</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">maxRequestsPerMinute</span>: <span class="kt">60</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">maxConcurrentCalls</span>: <span class="kt">5</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="kr">export</span> <span class="kr">const</span> <span class="nx">config</span> <span class="o">=</span> <span class="nx">loadConfig</span><span class="p">();</span>
</span></span></code></pre></div><h3 id="54-性能优化与限流">5.4 性能优化与限流</h3>
<p>对于高并发场景，我们需要实现限流和并发控制：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="kr">import</span> <span class="nx">RateLimiter</span> <span class="kr">from</span> <span class="s2">&#34;limiter&#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="c1"></span><span class="kr">const</span> <span class="nx">rateLimiter</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">RateLimiter</span><span class="p">.</span><span class="nx">RateLimiter</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">  <span class="nx">tokensPerInterval</span>: <span class="kt">config.rateLimit.maxRequestsPerMinute</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">interval</span><span class="o">:</span> <span class="s2">&#34;minute&#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="c1"></span><span class="kr">class</span> <span class="nx">Semaphore</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">private</span> <span class="nx">queue</span><span class="o">:</span> <span class="p">(()</span> <span class="o">=&gt;</span> <span class="k">void</span><span class="p">)[]</span> <span class="o">=</span> <span class="p">[];</span>
</span></span><span class="line"><span class="cl">  <span class="kr">private</span> <span class="nx">available</span>: <span class="kt">number</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">constructor</span><span class="p">(</span><span class="nx">count</span>: <span class="kt">number</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">this</span><span class="p">.</span><span class="nx">available</span> <span class="o">=</span> <span class="nx">count</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="kr">async</span> <span class="nx">acquire</span><span class="p">()</span><span class="o">:</span> <span class="nx">Promise</span><span class="p">&lt;</span><span class="nt">void</span><span class="p">&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="nx">available</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">this</span><span class="p">.</span><span class="nx">available</span><span class="o">--</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="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="k">new</span> <span class="nx">Promise</span><span class="p">(</span><span class="nx">resolve</span> <span class="o">=&gt;</span> <span class="k">this</span><span class="p">.</span><span class="nx">queue</span><span class="p">.</span><span class="nx">push</span><span class="p">(</span><span class="nx">resolve</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="nx">release</span><span class="p">()</span><span class="o">:</span> <span class="k">void</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">next</span> <span class="o">=</span> <span class="k">this</span><span class="p">.</span><span class="nx">queue</span><span class="p">.</span><span class="nx">shift</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nx">next</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">next</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">this</span><span class="p">.</span><span class="nx">available</span><span class="o">++</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="kr">const</span> <span class="nx">concurrencyLimiter</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Semaphore</span><span class="p">(</span><span class="nx">config</span><span class="p">.</span><span class="nx">rateLimit</span><span class="p">.</span><span class="nx">maxConcurrentCalls</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="kd">function</span> <span class="nx">withRateLimit</span><span class="p">&lt;</span><span class="nt">T</span><span class="p">&gt;(</span>
</span></span><span class="line"><span class="cl">  <span class="nx">handler</span><span class="o">:</span> <span class="p">(</span><span class="nx">request</span>: <span class="kt">T</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="nx">Promise</span><span class="p">&lt;</span><span class="nt">CallToolResult</span><span class="p">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">request</span>: <span class="kt">T</span><span class="p">)</span> <span class="o">=&gt;</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"></span>    <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">rateLimiter</span><span class="p">.</span><span class="nx">tryRemoveTokens</span><span class="p">(</span><span class="mi">1</span><span class="p">))</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="nx">content</span><span class="o">:</span> <span class="p">[{</span>
</span></span><span class="line"><span class="cl">          <span class="kr">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="nx">text</span><span class="o">:</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="nx">isError</span>: <span class="kt">true</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="k">await</span> <span class="nx">concurrencyLimiter</span><span class="p">.</span><span class="nx">acquire</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="k">return</span> <span class="k">await</span> <span class="nx">handler</span><span class="p">(</span><span class="nx">request</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span> <span class="k">finally</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">concurrencyLimiter</span><span class="p">.</span><span class="nx">release</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></div><p>（第二部分完，约2300字）</p>
<h2 id="六实战案例构建完整的开发助手-mcp">六、实战案例：构建完整的开发助手 MCP</h2>
<p>理论知识已经足够，现在让我们构建一个真正有用的 MCP 服务器——一个全功能的开发助手，包含文件操作、Git 管理、代码执行等能力。</p>
<h3 id="61-完整项目结构">6.1 完整项目结构</h3>
<pre tabindex="0"><code>dev-assistant-mcp/
├── src/
│   ├── index.ts          # 主入口
│   ├── config.ts         # 配置管理
│   ├── security.ts       # 安全控制
│   ├── tools/
│   │   ├── filesystem.ts # 文件操作工具
│   │   ├── git.ts        # Git 工具
│   │   ├── terminal.ts   # 终端命令工具
│   │   └── search.ts     # 代码搜索工具
│   └── utils/
│       ├── logger.ts     # 日志工具
│       └── sandbox.ts    # 沙箱执行
├── package.json
├── tsconfig.json
└── README.md
</code></pre><h3 id="62-完整的文件系统工具">6.2 完整的文件系统工具</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="c1">// src/tools/filesystem.ts
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kr">import</span> <span class="o">*</span> <span class="kr">as</span> <span class="nx">fs</span> <span class="kr">from</span> <span class="s2">&#34;fs/promises&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="o">*</span> <span class="kr">as</span> <span class="nx">path</span> <span class="kr">from</span> <span class="s2">&#34;path&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">isPathAllowed</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;../security.js&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">logger</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;../utils/logger.js&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="kr">interface</span> <span class="nx">FileInfo</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">name</span>: <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">path</span>: <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="kr">type</span><span class="o">:</span> <span class="s2">&#34;file&#34;</span> <span class="o">|</span> <span class="s2">&#34;directory&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">size</span>: <span class="kt">number</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="nx">modified</span>: <span class="kt">string</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="kr">export</span> <span class="kr">async</span> <span class="kd">function</span> <span class="nx">listDirectory</span><span class="p">(</span><span class="nx">dirPath</span>: <span class="kt">string</span><span class="p">)</span><span class="o">:</span> <span class="nx">Promise</span><span class="p">&lt;</span><span class="nt">FileInfo</span><span class="err">[]</span><span class="p">&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">isPathAllowed</span><span class="p">(</span><span class="nx">dirPath</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span><span class="p">(</span><span class="sb">`路径不在白名单内: </span><span class="si">${</span><span class="nx">dirPath</span><span class="si">}</span><span class="sb">`</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="kr">const</span> <span class="nx">entries</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">fs</span><span class="p">.</span><span class="nx">readdir</span><span class="p">(</span><span class="nx">dirPath</span><span class="p">,</span> <span class="p">{</span> <span class="nx">withFileTypes</span>: <span class="kt">true</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">result</span>: <span class="kt">FileInfo</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="k">for</span> <span class="p">(</span><span class="kr">const</span> <span class="nx">entry</span> <span class="k">of</span> <span class="nx">entries</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">fullPath</span> <span class="o">=</span> <span class="nx">path</span><span class="p">.</span><span class="nx">join</span><span class="p">(</span><span class="nx">dirPath</span><span class="p">,</span> <span class="nx">entry</span><span class="p">.</span><span class="nx">name</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="nx">stats</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">fs</span><span class="p">.</span><span class="nx">stat</span><span class="p">(</span><span class="nx">fullPath</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    
</span></span><span class="line"><span class="cl">    <span class="nx">result</span><span class="p">.</span><span class="nx">push</span><span class="p">({</span>
</span></span><span class="line"><span class="cl">      <span class="nx">name</span>: <span class="kt">entry.name</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">path</span>: <span class="kt">fullPath</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="kr">type</span><span class="o">:</span> <span class="nx">entry</span><span class="p">.</span><span class="nx">isDirectory</span><span class="p">()</span> <span class="o">?</span> <span class="s2">&#34;directory&#34;</span> <span class="o">:</span> <span class="s2">&#34;file&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">size</span>: <span class="kt">stats.size</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">modified</span>: <span class="kt">stats.mtime.toISOString</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="k">return</span> <span class="nx">result</span><span class="p">.</span><span class="nx">sort</span><span class="p">((</span><span class="nx">a</span><span class="p">,</span> <span class="nx">b</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="nx">a</span><span class="p">.</span><span class="kr">type</span> <span class="o">!==</span> <span class="nx">b</span><span class="p">.</span><span class="kr">type</span><span class="p">)</span> <span class="k">return</span> <span class="nx">a</span><span class="p">.</span><span class="kr">type</span> <span class="o">===</span> <span class="s2">&#34;directory&#34;</span> <span class="o">?</span> <span class="o">-</span><span class="nx">1</span> : <span class="kt">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nx">a</span><span class="p">.</span><span class="nx">name</span><span class="p">.</span><span class="nx">localeCompare</span><span class="p">(</span><span class="nx">b</span><span class="p">.</span><span class="nx">name</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="kr">export</span> <span class="kr">async</span> <span class="kd">function</span> <span class="nx">readFile</span><span class="p">(</span><span class="nx">filePath</span>: <span class="kt">string</span><span class="p">,</span> <span class="nx">limit</span>: <span class="kt">number</span> <span class="o">=</span> <span class="mi">500</span><span class="p">)</span><span class="o">:</span> <span class="nx">Promise</span><span class="p">&lt;</span><span class="nt">string</span><span class="p">&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">isPathAllowed</span><span class="p">(</span><span class="nx">filePath</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span><span class="p">(</span><span class="sb">`路径不在白名单内: </span><span class="si">${</span><span class="nx">filePath</span><span class="si">}</span><span class="sb">`</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="nx">logger</span><span class="p">.</span><span class="nx">info</span><span class="p">(</span><span class="s2">&#34;读取文件&#34;</span><span class="p">,</span> <span class="p">{</span> <span class="nx">path</span>: <span class="kt">filePath</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">content</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">fs</span><span class="p">.</span><span class="nx">readFile</span><span class="p">(</span><span class="nx">filePath</span><span class="p">,</span> <span class="s2">&#34;utf-8&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">lines</span> <span class="o">=</span> <span class="nx">content</span><span class="p">.</span><span class="nx">split</span><span class="p">(</span><span class="s2">&#34;\n&#34;</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="p">(</span><span class="nx">lines</span><span class="p">.</span><span class="nx">length</span> <span class="o">&gt;</span> <span class="nx">limit</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="nx">lines</span><span class="p">.</span><span class="nx">slice</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nx">limit</span><span class="p">).</span><span class="nx">join</span><span class="p">(</span><span class="s2">&#34;\n&#34;</span><span class="p">)</span> <span class="o">+</span> 
</span></span><span class="line"><span class="cl">      <span class="sb">`</span><span class="err">\</span><span class="sb">n</span><span class="err">\</span><span class="sb">n... (文件共 </span><span class="si">${</span><span class="nx">lines</span><span class="p">.</span><span class="nx">length</span><span class="si">}</span><span class="sb"> 行，已显示前 </span><span class="si">${</span><span class="nx">limit</span><span class="si">}</span><span class="sb"> 行)`</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">return</span> <span class="nx">content</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="kr">export</span> <span class="kr">async</span> <span class="kd">function</span> <span class="nx">writeFile</span><span class="p">(</span><span class="nx">filePath</span>: <span class="kt">string</span><span class="p">,</span> <span class="nx">content</span>: <span class="kt">string</span><span class="p">)</span><span class="o">:</span> <span class="nx">Promise</span><span class="p">&lt;</span><span class="nt">void</span><span class="p">&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">isPathAllowed</span><span class="p">(</span><span class="nx">filePath</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span><span class="p">(</span><span class="sb">`路径不在白名单内: </span><span class="si">${</span><span class="nx">filePath</span><span class="si">}</span><span class="sb">`</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="nx">logger</span><span class="p">.</span><span class="nx">info</span><span class="p">(</span><span class="s2">&#34;写入文件&#34;</span><span class="p">,</span> <span class="p">{</span> <span class="nx">path</span>: <span class="kt">filePath</span><span class="p">,</span> <span class="nx">size</span>: <span class="kt">content.length</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">  
</span></span><span class="line"><span class="cl">  <span class="k">await</span> <span class="nx">fs</span><span class="p">.</span><span class="nx">mkdir</span><span class="p">(</span><span class="nx">path</span><span class="p">.</span><span class="nx">dirname</span><span class="p">(</span><span class="nx">filePath</span><span class="p">),</span> <span class="p">{</span> <span class="nx">recursive</span>: <span class="kt">true</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">  <span class="k">await</span> <span class="nx">fs</span><span class="p">.</span><span class="nx">writeFile</span><span class="p">(</span><span class="nx">filePath</span><span class="p">,</span> <span class="nx">content</span><span class="p">,</span> <span class="s2">&#34;utf-8&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h3 id="63-git-工具实现">6.3 Git 工具实现</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="c1">// src/tools/git.ts
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kr">import</span> <span class="p">{</span> <span class="nx">exec</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;child_process&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">promisify</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;util&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">isPathAllowed</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;../security.js&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">execAsync</span> <span class="o">=</span> <span class="nx">promisify</span><span class="p">(</span><span class="nx">exec</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="kr">async</span> <span class="kd">function</span> <span class="nx">gitStatus</span><span class="p">(</span><span class="nx">repoPath</span>: <span class="kt">string</span><span class="p">)</span><span class="o">:</span> <span class="nx">Promise</span><span class="p">&lt;</span><span class="nt">string</span><span class="p">&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">isPathAllowed</span><span class="p">(</span><span class="nx">repoPath</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</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="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="p">{</span> <span class="nx">stdout</span> <span class="p">}</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">execAsync</span><span class="p">(</span><span class="s2">&#34;git status --short&#34;</span><span class="p">,</span> <span class="p">{</span> <span class="nx">cwd</span>: <span class="kt">repoPath</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">stdout</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="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="kr">async</span> <span class="kd">function</span> <span class="nx">gitDiff</span><span class="p">(</span><span class="nx">repoPath</span>: <span class="kt">string</span><span class="p">,</span> <span class="nx">file?</span>: <span class="kt">string</span><span class="p">)</span><span class="o">:</span> <span class="nx">Promise</span><span class="p">&lt;</span><span class="nt">string</span><span class="p">&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">isPathAllowed</span><span class="p">(</span><span class="nx">repoPath</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</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="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">cmd</span> <span class="o">=</span> <span class="nx">file</span> <span class="o">?</span> <span class="sb">`git diff </span><span class="si">${</span><span class="nx">file</span><span class="si">}</span><span class="sb">`</span> <span class="o">:</span> <span class="s2">&#34;git diff&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="p">{</span> <span class="nx">stdout</span> <span class="p">}</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">execAsync</span><span class="p">(</span><span class="nx">cmd</span><span class="p">,</span> <span class="p">{</span> <span class="nx">cwd</span>: <span class="kt">repoPath</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl">  <span class="k">return</span> <span class="nx">stdout</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="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="kr">async</span> <span class="kd">function</span> <span class="nx">gitLog</span><span class="p">(</span><span class="nx">repoPath</span>: <span class="kt">string</span><span class="p">,</span> <span class="nx">limit</span>: <span class="kt">number</span> <span class="o">=</span> <span class="mi">10</span><span class="p">)</span><span class="o">:</span> <span class="nx">Promise</span><span class="p">&lt;</span><span class="nt">string</span><span class="p">&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">isPathAllowed</span><span class="p">(</span><span class="nx">repoPath</span><span class="p">))</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</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="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="p">{</span> <span class="nx">stdout</span> <span class="p">}</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">execAsync</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="sb">`git log -</span><span class="si">${</span><span class="nx">limit</span><span class="si">}</span><span class="sb"> --pretty=format:&#34;%h %ad | %s%d [%an]&#34; --date=short`</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span> <span class="nx">cwd</span>: <span class="kt">repoPath</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="nx">stdout</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><h3 id="64-主服务器整合">6.4 主服务器整合</h3>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="c1">// src/index.ts
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kr">import</span> <span class="p">{</span> <span class="nx">Server</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;@modelcontextprotocol/sdk/server/index.js&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">StdioServerTransport</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;@modelcontextprotocol/sdk/server/stdio.js&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">CallToolRequestSchema</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">ListToolsRequestSchema</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;@modelcontextprotocol/sdk/types.js&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">config</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;./config.js&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">safeToolHandler</span><span class="p">,</span> <span class="nx">withRateLimit</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;./security.js&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="o">*</span> <span class="kr">as</span> <span class="nx">filesystem</span> <span class="kr">from</span> <span class="s2">&#34;./tools/filesystem.js&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="o">*</span> <span class="kr">as</span> <span class="nx">git</span> <span class="kr">from</span> <span class="s2">&#34;./tools/git.js&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">server</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Server</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="nx">name</span><span class="o">:</span> <span class="s2">&#34;dev-assistant-mcp&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">version</span><span class="o">:</span> <span class="s2">&#34;1.0.0&#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="nx">capabilities</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="nx">tools</span><span class="o">:</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="c1"></span><span class="kr">const</span> <span class="nx">TOOLS</span> <span class="o">=</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="nx">name</span><span class="o">:</span> <span class="s2">&#34;list_directory&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">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="nx">inputSchema</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="kr">type</span><span class="o">:</span> <span class="s2">&#34;object&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">properties</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">path</span><span class="o">:</span> <span class="p">{</span> <span class="kr">type</span><span class="o">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span> <span class="nx">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="p">},</span>
</span></span><span class="line"><span class="cl">      <span class="nx">required</span><span class="o">:</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 class="nx">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="nx">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="nx">inputSchema</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="kr">type</span><span class="o">:</span> <span class="s2">&#34;object&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">properties</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">path</span><span class="o">:</span> <span class="p">{</span> <span class="kr">type</span><span class="o">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span> <span class="nx">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="nx">limit</span><span class="o">:</span> <span class="p">{</span> <span class="kr">type</span><span class="o">:</span> <span class="s2">&#34;number&#34;</span><span class="p">,</span> <span class="nx">description</span><span class="o">:</span> <span class="s2">&#34;最大行数，默认500&#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="nx">required</span><span class="o">:</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 class="nx">name</span><span class="o">:</span> <span class="s2">&#34;write_file&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">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="nx">inputSchema</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="kr">type</span><span class="o">:</span> <span class="s2">&#34;object&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">properties</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">path</span><span class="o">:</span> <span class="p">{</span> <span class="kr">type</span><span class="o">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span> <span class="nx">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="nx">content</span><span class="o">:</span> <span class="p">{</span> <span class="kr">type</span><span class="o">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span> <span class="nx">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="p">},</span>
</span></span><span class="line"><span class="cl">      <span class="nx">required</span><span class="o">:</span> <span class="p">[</span><span class="s2">&#34;path&#34;</span><span class="p">,</span> <span class="s2">&#34;content&#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 class="nx">name</span><span class="o">:</span> <span class="s2">&#34;git_status&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">description</span><span class="o">:</span> <span class="s2">&#34;查看 Git 仓库状态&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">inputSchema</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="kr">type</span><span class="o">:</span> <span class="s2">&#34;object&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">properties</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">path</span><span class="o">:</span> <span class="p">{</span> <span class="kr">type</span><span class="o">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span> <span class="nx">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="p">},</span>
</span></span><span class="line"><span class="cl">      <span class="nx">required</span><span class="o">:</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 class="nx">name</span><span class="o">:</span> <span class="s2">&#34;git_log&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">description</span><span class="o">:</span> <span class="s2">&#34;查看 Git 提交历史&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nx">inputSchema</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="kr">type</span><span class="o">:</span> <span class="s2">&#34;object&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="nx">properties</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nx">path</span><span class="o">:</span> <span class="p">{</span> <span class="kr">type</span><span class="o">:</span> <span class="s2">&#34;string&#34;</span><span class="p">,</span> <span class="nx">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="nx">limit</span><span class="o">:</span> <span class="p">{</span> <span class="kr">type</span><span class="o">:</span> <span class="s2">&#34;number&#34;</span><span class="p">,</span> <span class="nx">description</span><span class="o">:</span> <span class="s2">&#34;显示条数，默认10&#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="nx">required</span><span class="o">:</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="c1"></span><span class="nx">server</span><span class="p">.</span><span class="nx">setRequestHandler</span><span class="p">(</span><span class="nx">ListToolsRequestSchema</span><span class="p">,</span> <span class="kr">async</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">({</span>
</span></span><span class="line"><span class="cl">  <span class="nx">tools</span>: <span class="kt">TOOLS</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="nx">server</span><span class="p">.</span><span class="nx">setRequestHandler</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">  <span class="nx">CallToolRequestSchema</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">  <span class="nx">withRateLimit</span><span class="p">(</span><span class="nx">safeToolHandler</span><span class="p">(</span><span class="kr">async</span> <span class="p">(</span><span class="nx">request</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kr">const</span> <span class="p">{</span> <span class="nx">name</span><span class="p">,</span> <span class="nx">arguments</span>: <span class="kt">args</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">request</span><span class="p">.</span><span class="nx">params</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">switch</span> <span class="p">(</span><span class="nx">name</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">case</span> <span class="s2">&#34;list_directory&#34;</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kr">const</span> <span class="nx">files</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">filesystem</span><span class="p">.</span><span class="nx">listDirectory</span><span class="p">(</span><span class="nx">args</span><span class="p">.</span><span class="nx">path</span> <span class="kr">as</span> <span class="kt">string</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="kr">const</span> <span class="nx">text</span> <span class="o">=</span> <span class="nx">files</span><span class="p">.</span><span class="nx">map</span><span class="p">(</span><span class="nx">f</span> <span class="o">=&gt;</span> 
</span></span><span class="line"><span class="cl">          <span class="sb">`</span><span class="si">${</span><span class="nx">f</span><span class="p">.</span><span class="kr">type</span> <span class="o">===</span> <span class="s2">&#34;directory&#34;</span> <span class="o">?</span> <span class="s2">&#34;📁&#34;</span> <span class="o">:</span> <span class="s2">&#34;📄&#34;</span><span class="si">}</span><span class="sb"> </span><span class="si">${</span><span class="nx">f</span><span class="p">.</span><span class="nx">name</span><span class="si">}</span><span class="sb"> (</span><span class="si">${</span><span class="nx">f</span><span class="p">.</span><span class="nx">size</span><span class="si">}</span><span class="sb"> bytes)`</span>
</span></span><span class="line"><span class="cl">        <span class="p">).</span><span class="nx">join</span><span class="p">(</span><span class="s2">&#34;\n&#34;</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="nx">content</span><span class="o">:</span> <span class="p">[{</span> <span class="kr">type</span><span class="o">:</span> <span class="s2">&#34;text&#34;</span><span class="p">,</span> <span class="nx">text</span><span class="o">:</span> <span class="sb">`目录 </span><span class="si">${</span><span class="nx">args</span><span class="p">.</span><span class="nx">path</span><span class="si">}</span><span class="sb"> 内容：</span><span class="err">\</span><span class="sb">n</span><span class="err">\</span><span class="sb">n</span><span class="si">${</span><span class="nx">text</span><span class="si">}</span><span class="sb">`</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="k">case</span> <span class="s2">&#34;read_file&#34;</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kr">const</span> <span class="nx">content</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">filesystem</span><span class="p">.</span><span class="nx">readFile</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">          <span class="nx">args</span><span class="p">.</span><span class="nx">path</span> <span class="kr">as</span> <span class="kt">string</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">          <span class="nx">args</span><span class="p">.</span><span class="nx">limit</span> <span class="kr">as</span> <span class="kt">number</span> <span class="o">||</span> <span class="mi">500</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="p">{</span>
</span></span><span class="line"><span class="cl">          <span class="nx">content</span><span class="o">:</span> <span class="p">[{</span> <span class="kr">type</span><span class="o">:</span> <span class="s2">&#34;text&#34;</span><span class="p">,</span> <span class="nx">text</span><span class="o">:</span> <span class="sb">`文件 </span><span class="si">${</span><span class="nx">args</span><span class="p">.</span><span class="nx">path</span><span class="si">}</span><span class="sb"> 内容：</span><span class="err">\</span><span class="sb">n</span><span class="err">\</span><span class="sb">n</span><span class="si">${</span><span class="nx">content</span><span class="si">}</span><span class="sb">`</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="k">case</span> <span class="s2">&#34;write_file&#34;</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">await</span> <span class="nx">filesystem</span><span class="p">.</span><span class="nx">writeFile</span><span class="p">(</span><span class="nx">args</span><span class="p">.</span><span class="nx">path</span> <span class="kr">as</span> <span class="kt">string</span><span class="p">,</span> <span class="nx">args</span><span class="p">.</span><span class="nx">content</span> <span class="kr">as</span> <span class="kt">string</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="nx">content</span><span class="o">:</span> <span class="p">[{</span> <span class="kr">type</span><span class="o">:</span> <span class="s2">&#34;text&#34;</span><span class="p">,</span> <span class="nx">text</span><span class="o">:</span> <span class="sb">`✓ 文件已写入：</span><span class="si">${</span><span class="nx">args</span><span class="p">.</span><span class="nx">path</span><span class="si">}</span><span class="sb">`</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="k">case</span> <span class="s2">&#34;git_status&#34;</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kr">const</span> <span class="nx">status</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">git</span><span class="p">.</span><span class="nx">gitStatus</span><span class="p">(</span><span class="nx">args</span><span class="p">.</span><span class="nx">path</span> <span class="kr">as</span> <span class="kt">string</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="nx">content</span><span class="o">:</span> <span class="p">[{</span> <span class="kr">type</span><span class="o">:</span> <span class="s2">&#34;text&#34;</span><span class="p">,</span> <span class="nx">text</span><span class="o">:</span> <span class="sb">`Git 状态：</span><span class="err">\</span><span class="sb">n</span><span class="err">\</span><span class="sb">n</span><span class="si">${</span><span class="nx">status</span><span class="si">}</span><span class="sb">`</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="k">case</span> <span class="s2">&#34;git_log&#34;</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kr">const</span> <span class="nx">log</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">git</span><span class="p">.</span><span class="nx">gitLog</span><span class="p">(</span><span class="nx">args</span><span class="p">.</span><span class="nx">path</span> <span class="kr">as</span> <span class="kt">string</span><span class="p">,</span> <span class="nx">args</span><span class="p">.</span><span class="nx">limit</span> <span class="kr">as</span> <span class="kt">number</span> <span class="o">||</span> <span class="mi">10</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="nx">content</span><span class="o">:</span> <span class="p">[{</span> <span class="kr">type</span><span class="o">:</span> <span class="s2">&#34;text&#34;</span><span class="p">,</span> <span class="nx">text</span><span class="o">:</span> <span class="sb">`Git 提交历史：</span><span class="err">\</span><span class="sb">n</span><span class="err">\</span><span class="sb">n</span><span class="si">${</span><span class="nx">log</span><span class="si">}</span><span class="sb">`</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="k">default</span><span class="o">:</span>
</span></span><span class="line"><span class="cl">        <span class="k">throw</span> <span class="k">new</span> <span class="nb">Error</span><span class="p">(</span><span class="sb">`未知工具: </span><span class="si">${</span><span class="nx">name</span><span class="si">}</span><span class="sb">`</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="c1"></span><span class="kr">async</span> <span class="kd">function</span> <span class="nx">main() {</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">transport</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">StdioServerTransport</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">  <span class="k">await</span> <span class="nx">server</span><span class="p">.</span><span class="nx">connect</span><span class="p">(</span><span class="nx">transport</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="s2">&#34;Dev Assistant MCP Server 已启动&#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></span><span class="line"><span class="cl"><span class="nx">main</span><span class="p">().</span><span class="k">catch</span><span class="p">((</span><span class="nx">error</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="s2">&#34;服务器启动失败:&#34;</span><span class="p">,</span> <span class="nx">error</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="nx">process</span><span class="p">.</span><span class="nx">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><h2 id="七部署与集成指南">七、部署与集成指南</h2>
<p>开发完成后，如何让你的 MCP 服务器在实际环境中运行呢？让我们看看不同客户端的集成方式。</p>
<h3 id="71-claude-desktop-配置">7.1 Claude Desktop 配置</h3>
<p>Claude Desktop 是最常用的 MCP 客户端，配置非常简单：</p>
<p>在 macOS 上，编辑配置文件：</p>
<div class="highlight"><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;dev-assistant&#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;node&#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></span><span class="line"><span class="cl">        <span class="s2">&#34;/path/to/dev-assistant-mcp/dist/index.js&#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;env&#34;</span><span class="p">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;MCP_ENV&#34;</span><span class="p">:</span> <span class="s2">&#34;production&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&#34;PATH&#34;</span><span class="p">:</span> <span class="err">process.env.PATH</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></div><p>在 Windows 上：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="c1">// %APPDATA%\Claude\claude_desktop_config.json
</span></span></span></code></pre></div><p>在 Linux 上：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="c1">// ~/.config/Claude/claude_desktop_config.json
</span></span></span></code></pre></div><p>配置完成后，重启 Claude Desktop，新的 MCP 服务器就会自动加载。</p>
<h3 id="72-cursor-ide-配置">7.2 Cursor IDE 配置</h3>
<p>Cursor IDE 也支持 MCP，配置方式类似：</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="c1">// Cursor 设置 → Features → MCP → Add New Server
</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;dev-assistant&#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;node&#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/dev-assistant-mcp/dist/index.js&#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></div><h3 id="73-健康检查与调试">7.3 健康检查与调试</h3>
<p>如何知道你的 MCP 服务器是否正常工作？</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="c1"># 1. 直接运行测试（会启动并等待输入）</span>
</span></span><span class="line"><span class="cl">node dist/index.js
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># 2. 检查 Claude 的日志（macOS）</span>
</span></span><span class="line"><span class="cl">tail -f ~/Library/Logs/Claude/mcp*.log
</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">npx @modelcontextprotocol/inspector node dist/index.js
</span></span></code></pre></div><p>MCP Inspector 是官方提供的调试工具，可以模拟客户端与服务器进行交互，非常适合开发调试。</p>
<h2 id="八常见问题与解决方案">八、常见问题与解决方案</h2>
<h3 id="81-服务器启动失败">8.1 服务器启动失败</h3>
<p><strong>问题</strong>：Claude 显示服务器启动失败</p>
<p><strong>解决方案</strong>：</p>
<ol>
<li>检查路径是否正确，使用绝对路径</li>
<li>确保 Node.js 版本 &gt;= 20</li>
<li>检查文件是否有执行权限</li>
<li>查看日志文件获取详细错误信息</li>
</ol>
<h3 id="82-工具没有显示">8.2 工具没有显示</h3>
<p><strong>问题</strong>：服务器启动成功，但工具列表为空</p>
<p><strong>解决方案</strong>：</p>
<ol>
<li>确保 <code>ListToolsRequestSchema</code> 处理器正确返回工具列表</li>
<li>检查工具定义的 <code>inputSchema</code> 是否是有效的 JSON Schema</li>
<li>重启 Claude Desktop 刷新配置</li>
</ol>
<h3 id="83-权限问题">8.3 权限问题</h3>
<p><strong>问题</strong>：工具执行时报告权限错误</p>
<p><strong>解决方案</strong>：</p>
<ol>
<li>检查路径白名单配置</li>
<li>确保 Claude 有足够的系统权限</li>
<li>在 macOS 上可能需要授予&quot;全磁盘访问&quot;权限</li>
</ol>
<h3 id="84-性能问题">8.4 性能问题</h3>
<p><strong>问题</strong>：工具调用响应缓慢</p>
<p><strong>解决方案</strong>：</p>
<ol>
<li>实现请求缓存，避免重复操作</li>
<li>增加并发控制，防止资源耗尽</li>
<li>对大文件操作使用流式处理</li>
<li>优化日志输出，避免 I/O 阻塞</li>
</ol>
<h2 id="九进阶方向与未来展望">九、进阶方向与未来展望</h2>
<p>MCP 生态正在快速发展，以下是几个值得关注的进阶方向：</p>
<h3 id="91-服务器编排mcp-代理">9.1 服务器编排：MCP 代理</h3>
<p>当你有多个 MCP 服务器时，可以构建一个代理服务器来统一管理：</p>
<pre tabindex="0"><code>用户 → LLM 客户端 → MCP 代理 → [服务器 A, 服务器 B, 服务器 C]
</code></pre><p>代理服务器可以实现：</p>
<ul>
<li>统一的认证和授权</li>
<li>请求路由和负载均衡</li>
<li>全局审计日志</li>
<li>跨服务器的工具组合</li>
</ul>
<h3 id="92-远程-mcp-服务器">9.2 远程 MCP 服务器</h3>
<p>MCP 不仅支持本地 stdio 通信，还支持基于 HTTP 和 SSE 的远程服务器。这意味着你可以将 MCP 服务器部署在云端，团队成员共享使用。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="cl"><span class="c1">// SSE 远程服务器示例
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kr">import</span> <span class="p">{</span> <span class="nx">SSEServerTransport</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">&#34;@modelcontextprotocol/sdk/server/sse.js&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">const</span> <span class="nx">app</span> <span class="o">=</span> <span class="nx">express</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="nx">app</span><span class="p">.</span><span class="kr">get</span><span class="p">(</span><span class="s2">&#34;/sse&#34;</span><span class="p">,</span> <span class="kr">async</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl">  <span class="kr">const</span> <span class="nx">transport</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">SSEServerTransport</span><span class="p">(</span><span class="s2">&#34;/message&#34;</span><span class="p">,</span> <span class="nx">res</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">  <span class="k">await</span> <span class="nx">server</span><span class="p">.</span><span class="nx">connect</span><span class="p">(</span><span class="nx">transport</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span></code></pre></div><h3 id="93-ai-原生的工具发现">9.3 AI 原生的工具发现</h3>
<p>未来的 MCP 可能会支持 AI 驱动的工具发现。LLM 不仅能调用已注册的工具，还能根据任务需求动态发现和安装合适的 MCP 服务器，形成一个真正的 AI 应用生态。</p>
<h2 id="总结">总结</h2>
<p>MCP 代表了 AI 交互方式的一次重要范式转变。它从根本上解决了工具生态碎片化的问题，为构建强大、安全、可扩展的 Agent 系统奠定了基础。</p>
<p>本文我们从理论到实践，全面介绍了 MCP 的核心概念、架构设计和开发方法：</p>
<ol>
<li><strong>理解了为什么需要 MCP</strong>——解决传统工具调用的碎片化和安全问题</li>
<li><strong>掌握了 MCP 的三层架构</strong>——客户端、协议层、服务器</li>
<li><strong>学会了开发生产级 MCP 服务器</strong>——包括安全控制、错误处理、性能优化</li>
<li><strong>完成了完整的实战案例</strong>——开发助手 MCP 的全部代码</li>
<li><strong>了解了部署和调试方法</strong></li>
</ol>
<p>MCP 生态还在快速发展中，随着越来越多的客户端和服务器加入，它很可能会成为 AI 与外部世界交互的事实标准。掌握 MCP 开发，就等于掌握了下一代 AI 应用的&quot;入场券&quot;。</p>
<p>无论你是个人开发者想要增强自己的 AI 助手，还是企业团队想要构建内部的 Agent 平台，MCP 都值得你投入时间深入学习。现在就动手构建你的第一个 MCP 服务器，开启 AI 赋能的全新可能吧！</p>
<p>（全文完，约7200字）</p>
]]></content:encoded>
    </item>
  </channel>
</rss>
