2.1 引言:协议是标准化的基石

在第一章中,我们理解了MCP的核心设计哲学——通过解耦和标准化来解决AI应用开发的“巴别塔”困境。而任何标准化的核心,都在于一套清晰、严谨、无歧义的协议(Protocol)。协议是通信双方必须共同遵守的“法律”,它规定了消息的格式、交互的流程以及能力的边界。

本章我们将深入MCP协议的内部,探究其技术实现的细节。我们将从其通信的基石——JSON-RPC 2.0讲起,然后详细剖析MCP定义的最核心、最通用的两组能力:文件系统(File System)工具执行(Tool Execution)。最后,我们将探讨在实现和使用MCP时必须时刻警惕的安全考量

理解协议规范,是掌握任何技术体系的必经之路。只有深入了解MCP的“语法”和“词汇”,我们才能在后续章节中游刃有余地构建出强大而可靠的MCP Server和Host。


2.2 通信基础:为何选择JSON-RPC 2.0?

MCP选择了JSON-RPC 2.0作为其底层的通信协议。这是一个深思熟虑的决定,背后有多重考量。JSON-RPC 2.0是一个轻量级、无状态的远程过程调用(RPC)协议,其简洁性和通用性使其成为MCP的理想选择。

2.2.1 JSON-RPC 2.0核心概念

JSON-RPC 2.0的规范非常简单,主要定义了三种消息类型:请求(Request)响应(Response)通知(Notification)

1. 请求对象 (Request Object)

当Client希望Server执行一个方法时,它会发送一个请求对象。一个标准的请求对象包含以下字段:

  • jsonrpc: 必须是字符串"2.0"
  • method: 必须是一个字符串,表示要调用的方法名。MCP的方法名有特定的命名空间,如fs/readFile
  • params: 可选的结构化值,表示方法的参数。可以是数组 [...] 或对象 {...}
  • id: 必须包含。一个由Client生成的唯一标识符,可以是字符串、数字或null。Server在响应时必须原样返回这个id,用于Client匹配请求和响应。

示例:读取一个文件

{
  "jsonrpc": "2.0",
  "id": "request-123",
  "method": "fs/readFile",
  "params": {
    "path": "/path/to/your/file.txt"
  }
}

2. 响应对象 (Response Object)

当Server处理完一个请求后,它必须返回一个响应对象。响应对象分为成功和失败两种。

  • 成功响应
    • jsonrpc: "2.0"
    • id: 与对应请求的id相同。
    • result: 方法调用的返回值。如果方法没有返回值,该字段也应该存在且值为null

示例:成功读取文件

{
  "jsonrpc": "2.0",
  "id": "request-123",
  "result": {
    "content": "SGVsbG8sIE1DUCE=",
    "encoding": "base64"
  }
}
  • 失败响应
    • jsonrpc: "2.0"
    • id: 与对应请求的id相同,如果无法确定请求ID(如解析错误),则为null
    • error: 一个包含错误信息的对象,必须包含code(整数)和message(字符串),可选data字段提供额外信息。

示例:文件未找到

{
  "jsonrpc": "2.0",
  "id": "request-123",
  "error": {
    "code": -32001,
    "message": "File not found",
    "data": {
      "path": "/path/to/your/file.txt"
    }
  }
}

3. 通知对象 (Notification Object)

通知是一个单向的消息,即Client向Server发送消息后,不期望收到任何响应。它与请求对象的区别在于没有id字段

MCP利用通知来实现事件推送,例如,当Server检测到其环境中的某个文件被修改时,可以主动向Client发送一个fs/didChange通知。

示例:文件内容变更通知

{
  "jsonrpc": "2.0",
  "method": "fs/didChange",
  "params": {
    "path": "/path/to/your/file.txt",
    "reason": "modified"
  }
}

2.2.2 选择JSON-RPC的优势

  • 简洁易懂:协议规范非常薄,易于学习和实现。
  • 人类可读:基于JSON,便于调试和日志记录。
  • 跨语言性:几乎所有主流编程语言都有成熟的JSON和RPC库支持。
  • 传输无关:JSON-RPC可以运行在任何双向通信信道之上,如TCP、WebSocket、HTTP,甚至是进程间的stdio,这为MCP的部署提供了极大的灵活性。
  • 支持异步:请求-响应模型天然支持异步通信,id字段使得乱序处理和并发请求成为可能。

2.3 核心能力(Capabilities):文件系统 (fs/)

MCP将不同的能力划分到不同的**命名空间(Namespace)**下,例如fs/代表文件系统,project/代表项目级工具。这种设计使得协议清晰、可扩展。

文件系统能力是MCP中最基础、最核心的能力之一,它为AI应用提供了观察和操作本地或远程文件环境的“眼睛”和“手”。

2.3.1 核心方法

以下是fs/命名空间下一些关键方法的定义(以简化的TypeScript接口形式表示):

1. fs/readFile

读取指定路径的文件内容。

  • 请求参数
    interface ReadFileParams {
      path: string; // 文件的绝对或相对路径
    }
    
  • 返回结果
    interface ReadFileResult {
      content: string; // 文件内容,使用base64编码
      encoding: 'base64';
    }
    
    选择Base64编码是为了确保可以安全地传输任何二进制文件,而不仅仅是文本文件。

2. fs/writeFile

向指定路径写入内容。如果文件不存在,则创建;如果文件存在,则覆盖。

  • 请求参数
    interface WriteFileParams {
      path: string;
      content: string; // 要写入的内容,同样使用base64编码
      encoding: 'base64';
    }
    
  • 返回结果null

3. fs/listDirectory

列出指定目录下的文件和子目录。

  • 请求参数
    interface ListDirectoryParams {
      path: string; // 目录路径
      recursive?: boolean; // 是否递归列出所有子目录,默认为false
    }
    
  • 返回结果
    interface DirectoryEntry {
      name: string; // 文件或目录名
      type: 'file' | 'directory' | 'symlink' | 'other';
    }
    
    type ListDirectoryResult = DirectoryEntry[];
    

4. fs/didChange (通知)

这是一个由Server主动发往Client的通知,用于告知文件系统发生了变化。

  • 通知参数
    interface DidChangeParams {
      path: string;
      reason: 'created' | 'modified' | 'deleted';
    }
    

2.3.2 设计考量

  • 路径表示:路径应使用正斜杠/作为分隔符,以实现跨平台兼容。Server负责将其翻译成特定操作系统的路径格式。
  • 原子性:协议本身不保证操作的原子性。例如,writeFile可能不是一个原子操作。更复杂的事务性文件操作超出了MCP核心协议的范围,但可以通过自定义工具实现。

2.4 核心能力(Capabilities):工具执行 (project/)

如果说fs/提供了通用的文件操作,那么project/命名空间则为执行特定于某个项目或环境的自定义工具提供了标准接口。这是MCP实现高度可扩展性的关键。

2.4.1 核心方法

1. project/listTools

查询当前Server支持哪些自定义工具。

  • 请求参数null
  • 返回结果
    interface ToolDefinition {
      name: string; // 工具的唯一名称,如 "project/countLines"
      description: string; // 对工具功能的自然语言描述,非常重要,用于AI理解工具用途
      parameters: any; // 参数的JSON Schema定义,用于AI理解如何调用工具
    }
    
    type ListToolsResult = ToolDefinition[];
    

2. project/executeTool

执行一个指定的自定义工具。

  • 请求参数
    interface ExecuteToolParams {
      name: string; // 要执行的工具名
      parameters: any; // 调用工具时传入的具体参数,必须符合该工具的JSON Schema
    }
    
  • 返回结果
    interface ExecuteToolResult {
      stdout?: string; // 工具的标准输出
      stderr?: string; // 工具的标准错误输出
      result?: any; // 工具返回的结构化数据
    }
    

2.4.2 “实践项目”的例子

在我们的教程大纲中,提到了一个“实践项目”——多源AI研究助理。让我们看看project/能力如何在这个场景中大放异彩:

  1. Host (AI助理) 首先调用project/listTools,可能会得到如下工具列表:

    [
      {
        "name": "project/queryLocalDB",
        "description": "Queries the local SQLite database of research papers.",
        "parameters": { "type": "object", "properties": { "sql": { "type": "string" } } }
      },
      {
        "name": "project/fetchFromArxiv",
        "description": "Fetches the latest papers from Arxiv.org based on a keyword.",
        "parameters": { "type": "object", "properties": { "keyword": { "type": "string" } } }
      }
    ]
    
  2. 当用户提问“帮我找找最近关于多模态大模型的论文”时,Host(或其背后的LLM)通过分析工具的description,决定调用project/fetchFromArxiv工具。

  3. Host向Server发送project/executeTool请求:

    {
      "jsonrpc": "2.0",
      "id": "tool-exec-1",
      "method": "project/executeTool",
      "params": {
        "name": "project/fetchFromArxiv",
        "parameters": {
          "keyword": "multimodal large language model"
        }
      }
    }
    
  4. Server收到请求后,执行内部的爬虫或API调用逻辑,并将结果返回给Host。

通过这种方式,任何复杂、专有的能力都可以被封装成一个标准的MCP工具,供AI应用按需调用。


2.5 安全考量:构建可信的交互边界

由于MCP赋予了AI应用强大的环境交互能力,安全性便成为设计的重中之重。MCP的架构本身就是为了安全而设计的,它通过在Server端建立一个可信的边界,来约束和审计AI的行为。

以下是在实现和部署MCP时必须考虑的关键安全策略:

  1. 最小权限原则:MCP Server应该只被授予完成其任务所必需的最小权限。例如,一个只提供文件读取能力的Server,其运行用户不应该有文件写入或删除的权限。

  2. 路径限制与沙箱化fs/相关的操作必须被严格限制在一个预先配置好的根目录(Workspace Root)下。任何试图访问该目录之外路径的请求(如../../etc/passwd)都必须被拒绝。使用操作系统的沙箱技术(如Docker容器)来运行MCP Server是一个非常好的实践。

  3. 工具执行的白名单project/executeTool是一个非常强大的能力,也可能是最危险的。Server必须维护一个严格的工具白名单,只允许执行预先定义和审查过的安全工具。绝不能允许执行任意的shell命令。

  4. 认证与授权:在Host和Server之间建立连接时,应进行双向认证(如mTLS),确保通信双方都是可信的。此外,可以实现更细粒度的授权机制,例如,不同的Host(或其代表的不同用户)连接到同一个Server时,可以拥有不同的工具访问权限。

  5. 审计日志:Server应该详细记录所有接收到的请求和执行的操作,包括请求来源、调用的方法、参数以及执行结果。这对于事后审计和异常行为分析至关重要。

2.6 总结

本章我们深入了MCP协议的内部构造。我们学习了它如何利用简洁而强大的JSON-RPC 2.0进行通信,并详细剖析了fs/project/这两个核心能力集的规范和设计思想。最后,我们强调了贯穿MCP设计始终的安全考量。

掌握了这些协议层面的知识,我们已经从一个MCP的“使用者”视角,开始转变为一个“构建者”视角。在下一章,我们将正式卷起袖子,利用官方提供的mcp-sdk,从零开始编写我们的第一个MCP Server。

Logo

更多推荐