这次我们来看一个可能改变 AI 应用开发格局的新动向:OpenAI 联合多家公司推出的 Agent 插件开放标准。这不是一个具体的代码库或模型,而是一套旨在统一 AI Agent 与外部工具交互方式的协议规范。简单来说,它想让不同的 AI 助手(Agent)能像电脑插上 USB 设备一样,即插即用地调用各种工具和服务,而无需为每个工具单独开发适配器。

这个标准的核心是 MCP(Model Context Protocol) 。它的目标很直接:解决当前 AI Agent 生态中工具集成混乱、开发重复、体验割裂的问题。对于开发者而言,这意味着未来为一个 Agent(比如 ChatGPT)开发的工具插件,理论上也能被 Claude、Gemini 或其他遵循 MCP 的 Agent 直接使用。对于用户,则有望获得更统一、更强大的 AI 助手体验。

本文不会涉及任何具体的模型部署或显存占用,因为 MCP 本身是一个协议层。我们将重点关注:这个标准是什么、解决了什么问题、它如何工作、以及作为开发者或技术爱好者,你现在可以如何开始了解和尝试它。我们会从协议的核心概念、工作流程、到如何搭建一个最简单的 MCP 服务器进行实操演示,帮助你快速判断其潜力和上手门槛。

1. 核心能力速览

能力项 说明
协议名称 Model Context Protocol (MCP)
核心目标 为 AI 应用(Agent/助手)与外部工具、数据源之间,建立统一、开放的通信标准。
主要参与方 OpenAI、Anthropic 等多家公司联合推动(根据网络信息)。
关键特性 工具与数据源抽象 :将工具调用和数据查询标准化。
双向通信 :支持 Server(工具提供方)与 Client(AI 应用)之间的实时交互。
传输层无关 :可在标准输入输出(stdio)、HTTP、SSE 等多种通道上运行。
开发语言无关 :可使用任何语言实现 MCP 服务器。
解决的问题 1. 消除重复开发 :避免为每个 AI 平台重复开发功能相同的插件。
2. 提升工具发现与集成效率 :Agent 能动态发现并安全调用可用工具。
3. 促进生态互联 :打破不同 AI 助手之间的工具壁垒。
当前状态 协议规范早期阶段,已有参考实现和开发工具包(SDK)。
适合场景 AI 应用开发者、工具服务提供商、希望研究下一代 AI 交互架构的技术人员。

2. 适用场景与使用边界

MCP 协议并非面向终端用户的即开即用产品,而是一套面向开发者和生态建设者的基础设施标准。理解其适用边界,能帮助你更准确地评估其价值。

它非常适合以下场景:

  • AI 应用(Agent)开发者 :如果你正在构建或维护一个 AI 助手类产品,MCP 提供了一种标准化集成海量第三方工具的能力,无需为每个工具编写定制代码,大幅降低集成复杂度。
  • 工具/数据服务提供商 :如果你拥有一个 API 服务、数据库或内部工具,希望被各类 AI Agent 便捷调用,实现一个 MCP 服务器是最高效的“一次开发,多处接入”方案。
  • 企业内 AI 平台建设 :企业内有大量内部系统(CRM、ERP、知识库)。通过 MCP 将这些系统封装成标准工具,可以快速构建一个能安全、可控访问内部数据的统一 AI 助手。
  • 技术研究与探索 :对于关注 AI 应用架构、Agent 能力边界、工具调用协议的技术人员,MCP 是目前最值得关注的开放标准之一,是理解未来 AI 交互模式的重要窗口。

它目前不适合或不直接解决:

  • 终端用户直接使用 :普通用户无法直接“运行”MCP,它需要嵌入在具体的 AI 应用(如未来的 ChatGPT 插件系统)中才能体现价值。
  • 替代现有的 API 调用 :对于简单的、一次性的 HTTP API 调用,直接使用 requests 库更简单。MCP 的优势在于复杂的、会话式的、需要动态发现和描述的交互场景。
  • 保证工具的功能或性能 :MCP 只定义通信协议,不保证工具本身的质量、速度或稳定性。一个设计拙劣的 MCP 服务器,其工具同样难用。
  • 处理敏感数据的自动授权 :MCP 协议包含权限和资源描述,但具体鉴权逻辑(如 OAuth)需要服务器自行实现。它不自动解决安全问题。

合规与安全边界: 任何通过 MCP 暴露的工具,都必须充分考虑:

  1. 权限最小化 :只暴露必要的操作接口,并明确声明所需权限。
  2. 输入验证与过滤 :防止 AI 生成的恶意或异常输入导致服务器端安全风险。
  3. 审计与日志 :记录所有的工具调用,便于追踪和复盘。
  4. 数据隐私 :确保通过 MCP 协议交换的数据符合相关法律法规(如 GDPR)和公司政策。

3. 环境准备与前置条件

由于 MCP 是一个协议,其“环境”更偏向于开发环境。我们将以使用官方 TypeScript/JavaScript SDK 为例,演示如何构建一个最简单的 MCP 服务器。

基础开发环境:

  • 操作系统 :Windows 10/11, macOS, 或 Linux 发行版(如 Ubuntu 20.04+)。协议本身是跨平台的。
  • Node.js 环境 :这是使用官方 JS SDK 的前提。建议安装 Node.js 18 或更高版本,以及配套的 npm yarn 包管理器。
  • 代码编辑器 :VS Code 或其他你熟悉的 IDE。
  • 网络 :能正常访问 npm 仓库以下载依赖。

环境检查清单: 在开始前,请打开终端(命令行),执行以下命令确认环境就绪:

# 检查 Node.js 和 npm 版本
node --version
npm --version

# 输出应类似:
# v18.17.0
# 9.6.7

如果未安装 Node.js,请前往其官网下载并安装 LTS(长期支持)版本。

概念准备: 理解 MCP 的两个核心角色:

  1. MCP 服务器 (Server) :工具的提供方。它向客户端宣告自己有哪些工具(或数据源),并处理客户端的调用请求。我们将要编写的就是一个 Server。
  2. MCP 客户端 (Client) :AI 应用本身,例如一个集成了 MCP 库的 AI 助手。它负责发现服务器提供的工具,并在需要时发起调用。本文暂不涉及 Client 的深度开发,但会演示如何测试 Server。

4. 安装部署与启动方式

我们将从零开始,创建一个提供“计算器”和“获取时间”工具的 MCP 服务器。

步骤 1:创建项目并初始化

# 创建一个新的项目目录
mkdir my-first-mcp-server
cd my-first-mcp-server

# 初始化 npm 项目(一路回车采用默认值即可)
npm init -y

# 安装 MCP 官方 SDK
npm install @modelcontextprotocol/sdk

步骤 2:编写服务器代码 在项目根目录下创建文件 server.js ,并输入以下内容:

// server.js
const { Server } = require("@modelcontextprotocol/sdk/server/index.js");
const { StdioServerTransport } = require("@modelcontextprotocol/sdk/server/stdio.js");

// 1. 创建 Server 实例,指定名称和版本
const server = new Server(
  {
    name: "my-tools-server",
    version: "1.0.0",
  },
  {
    capabilities: {
      // 声明本服务器支持“工具”功能
      tools: {},
    },
  }
);

// 2. 定义工具列表
const tools = [
  {
    name: "calculate",
    description: "执行简单的数学计算,支持加减乘除。",
    inputSchema: {
      type: "object",
      properties: {
        expression: {
          type: "string",
          description: "数学表达式,例如:'(5 + 3) * 2'",
        },
      },
      required: ["expression"],
    },
  },
  {
    name: "get_current_time",
    description: "获取服务器当前的日期和时间。",
    inputSchema: {
      type: "object",
      properties: {
        format: {
          type: "string",
          description: "时间格式,可选:'iso' (ISO 8601) 或 'human' (人类可读)。默认为 'iso'。",
          enum: ["iso", "human"],
          default: "iso",
        },
      },
      required: [],
    },
  },
];

// 3. 实现工具调用处理逻辑
server.setRequestHandler("tools/list", async () => {
  return { tools };
});

server.setRequestHandler("tools/call", async (request) => {
  const { name, arguments: args } = request.params;
  
  if (name === "calculate") {
    const expression = args.expression;
    // 警告:在实际生产中,应对表达式进行严格的安全检查和沙箱评估。
    // 此处为演示,使用 eval,存在严重安全风险,切勿用于生产环境!
    try {
      const result = eval(expression);
      return {
        content: [
          {
            type: "text",
            text: `计算表达式 "${expression}" 的结果是:${result}`,
          },
        ],
      };
    } catch (error) {
      return {
        content: [
          {
            type: "text",
            text: `计算失败:${error.message}`,
          },
        ],
        isError: true,
      };
    }
  } else if (name === "get_current_time") {
    const now = new Date();
    const format = args.format || "iso";
    let timeStr;
    if (format === "human") {
      timeStr = now.toLocaleString();
    } else {
      timeStr = now.toISOString();
    }
    return {
      content: [
        {
          type: "text",
          text: `当前服务器时间 (${format}): ${timeStr}`,
        },
      ],
    };
  } else {
    return {
      content: [
        {
          type: "text",
          text: `未知工具:${name}`,
        },
      ],
      isError: true,
    };
  }
});

// 4. 启动服务器,使用标准输入输出作为传输层
async function runServer() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error("MCP 服务器已启动,正在通过 stdio 监听...");
}

runServer().catch((error) => {
  console.error("服务器启动失败:", error);
  process.exit(1);
});

步骤 3:启动服务器 MCP 服务器通常不作为独立 Web 服务运行,而是通过标准输入输出(stdio)与客户端进程通信。这是一种常见的进程间通信(IPC)方式。 在终端中,直接运行我们的脚本:

node server.js

运行后,你会发现程序没有退出,也没有输出,只是在“等待”。这就对了!它正在通过 stdio 监听来自父进程(未来的 MCP 客户端)的请求。你可以按 Ctrl+C 终止它。

5. 功能测试与效果验证

如何测试这个“沉默”的服务器?我们需要一个 MCP 客户端来与它对话。这里我们使用一个简单的测试脚本,模拟客户端行为。

步骤 1:创建测试客户端脚本 在项目根目录下创建文件 test_client.js

// test_client.js - 一个极简的 MCP 客户端模拟器
const { spawn } = require('child_process');
const readline = require('readline');

// 启动我们的 MCP 服务器进程
const serverProcess = spawn('node', ['server.js'], {
  stdio: ['pipe', 'pipe', 'inherit'] // 继承 stderr 以便看错误
});

// 简单的 JSON-RPC 消息发送函数
function sendMessage(serverProcess, message) {
  const content = JSON.stringify(message);
  const header = `Content-Length: ${Buffer.byteLength(content, 'utf-8')}\r\n\r\n`;
  serverProcess.stdin.write(header + content);
}

// 设置读取服务器响应的接口
const rl = readline.createInterface({
  input: serverProcess.stdout,
  crlfDelay: Infinity
});

let buffer = '';
let contentLength = 0;

rl.on('line', (line) => {
  if (line.startsWith('Content-Length:')) {
    contentLength = parseInt(line.split(':')[1].trim(), 10);
    // 跳过空行
    rl.once('line', () => {});
  } else if (contentLength > 0) {
    // 这里简化处理,假设一行就是完整 JSON
    buffer = line;
    if (Buffer.byteLength(buffer, 'utf-8') >= contentLength) {
      try {
        const message = JSON.parse(buffer);
        console.log('<<< 收到服务器响应:', JSON.stringify(message, null, 2));
      } catch (e) {
        console.error('解析响应失败:', e);
      }
      buffer = '';
      contentLength = 0;
    }
  }
});

// 初始化握手
setTimeout(() => {
  console.log('>>> 发送初始化请求...');
  sendMessage(serverProcess, {
    jsonrpc: "2.0",
    id: 1,
    method: "initialize",
    params: {
      protocolVersion: "1.0",
      capabilities: {},
      clientInfo: { name: "test-client", version: "1.0" }
    }
  });

  // 请求工具列表
  setTimeout(() => {
    console.log('\n>>> 请求工具列表...');
    sendMessage(serverProcess, {
      jsonrpc: "2.0",
      id: 2,
      method: "tools/list",
      params: {}
    });
  }, 500);

  // 调用计算器工具
  setTimeout(() => {
    console.log('\n>>> 调用 calculate 工具...');
    sendMessage(serverProcess, {
      jsonrpc: "2.0",
      id: 3,
      method: "tools/call",
      params: {
        name: "calculate",
        arguments: { expression: "(12 + 8) * 3 / 2" }
      }
    });
  }, 1000);

  // 调用获取时间工具
  setTimeout(() => {
    console.log('\n>>> 调用 get_current_time 工具...');
    sendMessage(serverProcess, {
      jsonrpc: "2.0",
      id: 4,
      method: "tools/call",
      params: {
        name: "get_current_time",
        arguments: { format: "human" }
      }
    });
  }, 1500);

  // 5秒后退出
  setTimeout(() => {
    console.log('\n测试结束,退出进程。');
    serverProcess.kill();
    process.exit(0);
  }, 5000);

}, 100);

步骤 2:运行测试 打开一个新的终端,在项目目录下运行:

node test_client.js

步骤 3:观察预期结果 你应该能在终端看到类似以下的输出,这证明了 MCP 服务器正在正常工作:

>>> 发送初始化请求...
<<< 收到服务器响应: { "jsonrpc": "2.0", "id": 1, "result": { ... } }

>>> 请求工具列表...
<<< 收到服务器响应: { "jsonrpc": "2.0", "id": 2, "result": { "tools": [ ... ] } }

>>> 调用 calculate 工具...
<<< 收到服务器响应: { "jsonrpc": "2.0", "id": 3, "result": { "content": [ { "type": "text", "text": "计算表达式 \"(12 + 8) * 3 / 2\" 的结果是:30" } ] } }

>>> 调用 get_current_time 工具...
<<< 收到服务器响应: { "jsonrpc": "2.0", "id": 4, "result": { "content": [ { "type": "text", "text": "当前服务器时间 (human): 2024/5/27 下午3:30:15" } ] } }

测试结束,退出进程。

测试成功的关键判断:

  1. 握手成功 :收到 initialize 的响应,且没有错误。
  2. 工具列表正确 tools/list 响应中包含了我们在代码中定义的 calculate get_current_time 工具及其描述。
  3. 工具调用成功 tools/call 请求分别返回了正确的计算结果和当前时间。
  4. 协议通信正常 :整个交互基于 JSON-RPC 消息,通过 Content-Length 头分隔,流程符合 MCP 规范。

6. 接口 API 与批量任务

MCP 协议本身定义的是基于 JSON-RPC 的消息接口,而不是传统的 RESTful HTTP API。但我们可以通过不同的“传输层”来暴露它,例如 HTTP。官方 SDK 也提供了 HTTPServerTransport

将 MCP 服务器暴露为 HTTP 服务: 修改 server.js 的启动部分,使其成为一个 HTTP 服务器,方便使用 curl 或 Postman 测试。

首先,安装可选的 HTTP 传输层依赖(如果 SDK 未内置,可能需要查看官方文档确认)。这里我们假设使用一个简单的 HTTP 包装器。实际上,更常见的做法是使用 SSE(Server-Sent Events) WebSocket 来支持双向通信,因为 MCP 是会话式的。

概念:MCP 与批量任务 MCP 协议是面向会话和实时交互设计的,它本身不直接定义“批量任务”的语义。但是,你可以通过以下方式实现批量处理:

  1. 在工具层面实现批量 :例如,创建一个名为 batch_process_files 的工具,它接受一个文件列表作为参数,在服务器端循环处理。这要求服务器有足够的内存和处理能力。
  2. 客户端控制批量 :MCP 客户端(AI Agent)可以依次或并发调用同一个工具多次,实现批量效果。这更符合 MCP 的哲学——工具提供原子能力,由智能体来组织和规划任务。
  3. 异步通知 :MCP 支持服务器向客户端发送通知( notifications )。对于耗时的批量任务,工具调用可以立即返回一个任务ID,然后服务器在后台处理,完成后通过通知告知客户端。

一个模拟的“批量处理”工具示例: server.js tools 数组和 tools/call 处理器中添加:

// 在 tools 数组中添加
{
  name: "batch_greet",
  description: "向多个人发送问候。",
  inputSchema: {
    type: "object",
    properties: {
      names: {
        type: "array",
        items: { type: "string" },
        description: "人名列表",
      },
    },
    required: ["names"],
  },
}

// 在 tools/call 的 if-else 链中添加
else if (name === "batch_greet") {
  const names = args.names;
  if (!Array.isArray(names) || names.length === 0) {
    return {
      content: [{ type: "text", text: "请输入非空的人名列表。" }],
      isError: true,
    };
  }
  const greetings = names.map(name => `你好,${name}!`).join('\n');
  return {
    content: [
      {
        type: "text",
        text: `批量问候完成:\n${greetings}`,
      },
    ],
  };
}

测试时,客户端可以发送 {“names”: [“Alice”, “Bob”, “Charlie”]} 来触发这个“批量”操作。

7. 资源占用与性能观察

由于 MCP 服务器是你自己实现的程序,其资源占用(CPU、内存)完全取决于你工具的逻辑复杂度,与协议本身关系不大。一个只做简单字符串处理的服务器,可能只占用几 MB 内存;而一个集成了大语言模型或复杂数据库查询的服务器,则可能占用大量资源。

性能观察的关键点:

  1. 传输层开销 stdio 传输几乎没有开销,适合本地紧密集成的客户端-服务器。HTTP/SSE/WebSocket 会引入网络序列化和反序列化的开销,需要关注延迟。
  2. 工具调用延迟 :这是主要性能指标。你需要在服务器的工具处理函数中记录耗时。
  3. 并发处理能力 :如果你的服务器需要处理来自多个客户端的并发请求,需要考虑使用异步编程、连接池、请求队列等机制。Node.js 的异步 I/O 模型在这方面有天然优势。
  4. 内存泄漏 :长时间运行的服务器进程,需要确保没有内存泄漏。特别是工具函数中如果创建了大量临时对象或持有外部资源(如数据库连接),需要妥善管理生命周期。

简单的性能监控示例: 你可以在 tools/call 处理器开始时记录时间,结束时计算耗时并打印到 stderr (不影响协议通信):

server.setRequestHandler("tools/call", async (request) => {
  const startTime = Date.now();
  const { name, arguments: args } = request.params;
  let result;
  // ... 原有的工具判断和处理逻辑 ...
  const endTime = Date.now();
  console.error(`[性能] 工具 "${name}" 调用耗时: ${endTime - startTime}ms`);
  return result;
});

8. 常见问题与排查方法

在开发和运行 MCP 服务器时,你可能会遇到以下问题:

问题现象 可能原因 排查方式 解决方案
服务器启动后立即退出 1. 代码语法错误。
2. 依赖未安装。
3. server.connect() 失败。
1. 检查终端错误输出。
2. 运行 node -c server.js 检查语法。
3. 确保 npm install 已执行。
1. 根据错误信息修正代码。
2. 安装缺失依赖。
3. 检查传输层(如 StdioServerTransport )是否正确初始化。
客户端连接失败,收不到任何响应 1. 客户端未发送正确的初始化消息。
2. 传输层不匹配(如客户端用 HTTP,服务器用 stdio)。
3. JSON-RPC 消息格式错误。
1. 在服务器端 console.error 打印收到的原始消息。
2. 使用 test_client.js 这类简单客户端验证。
3. 检查消息是否包含正确的 Content-Length 头。
1. 确保客户端首先发送 initialize 请求。
2. 确保客户端和服务器使用同一种传输方式。
3. 严格按照 MCP 协议规范构建 JSON-RPC 消息。
tools/list 返回空列表或错误 1. 未正确设置 tools/list 的请求处理器。
2. tools 数组定义有误。
1. 检查 server.setRequestHandler(“tools/list”, ...) 是否被调用。
2. 检查 tools 数组的格式是否符合协议。
1. 确保在 server.connect() 前设置好所有请求处理器。
2. 参考官方 SDK 示例或协议文档,修正工具定义格式。
tools/call 返回 “未知工具” 错误 1. 客户端请求的工具名与注册的名称不匹配(大小写、拼写)。
2. 工具调用处理器中未处理该工具名。
1. 对比客户端发送的 name 和服务器 tools 数组中的 name
2. 在 tools/call 处理器中添加对应的 else if 分支。
1. 确保工具名完全一致。
2. 完善 tools/call 处理器的逻辑分支。
工具调用逻辑执行出错 1. 工具函数内部代码有 bug。
2. 参数解析错误。
3. 依赖的外部服务不可用。
1. 在工具函数内部添加 try-catch ,并通过 console.error 打印详细错误。
2. 验证客户端发送的参数格式是否符合 inputSchema
1. 修复工具函数内部的代码逻辑。
2. 加强参数验证和错误处理,返回友好的错误信息。
进程僵死或无响应 1. 工具函数中存在同步阻塞操作或死循环。
2. 未正确处理异步操作,导致 Promise 未返回。
1. 使用进程监控工具查看 CPU 占用。
2. 检查所有异步函数是否都正确使用了 async/await 或返回了 Promise。
1. 将耗时操作异步化或放入工作线程。
2. 确保所有请求处理器都返回一个 Promise。

9. 最佳实践与使用建议

基于当前对 MCP 协议的理解和开发经验,以下建议可以帮助你更好地构建和使用 MCP 服务器:

  1. 从简单工具开始 :先实现一个像“计算器”、“时间查询”这样的无状态、纯逻辑的工具,确保整个 MCP 通信链路跑通。然后再逐步集成数据库、外部 API 等复杂依赖。
  2. 严格定义工具 Schema inputSchema 是你的工具合约。要尽可能详细、准确地描述参数的类型、格式、是否必需、枚举值等。这能帮助 AI 客户端更好地理解如何使用你的工具。
  3. 实现全面的错误处理 :在 tools/call 处理器中,务必用 try-catch 包裹核心逻辑。返回错误时,使用 isError: true 标志,并在 content 中提供清晰的人类可读的错误信息,这有助于调试和用户体验。
  4. 安全性是第一要务
    • 绝不信任客户端输入 :对 arguments 中的任何数据都要进行验证、清理和转义。上面的 eval 示例是 极其危险 的,仅用于演示,生产环境必须使用安全的表达式求值库或自定义解析器。
    • 权限控制 :如果工具涉及敏感操作,需要在服务器端实现鉴权逻辑。MCP 协议本身不处理认证,这需要你自行设计(例如,在初始化阶段传递令牌)。
    • 资源隔离与限制 :为工具调用设置超时、内存限制和调用频率限制,防止恶意或错误的调用拖垮服务器。
  5. 考虑使用 TypeScript :官方 SDK 提供了 TypeScript 类型定义。使用 TypeScript 可以在编译时捕获许多与协议格式、工具定义相关的错误,提升开发效率和代码可靠性。
  6. 为工具编写清晰的描述 description 字段至关重要。AI 客户端(如未来的 ChatGPT)会依赖这些描述来决定在什么场景下调用你的工具。描述应简洁、准确,说明工具的功能、输入和输出。
  7. 探索“资源(Resources)” :MCP 不仅支持工具(Tools),还支持资源(Resources)。资源可以理解为可读的数据源(如数据库表、文件列表)。如果你的服务器主要是提供数据查询,考虑使用资源而不是工具。
  8. 关注官方动态 :MCP 协议仍在发展初期。密切关注 OpenAI 等官方渠道的更新,了解协议版本的变更、新的最佳实践以及官方工具集的发布。

10. 总结与下一步

OpenAI 联合推出的 Agent 插件开放标准 MCP,其核心价值在于 标准化和互联 。它试图为日益繁荣但各自为战的 AI Agent 工具生态,铺设一条通用的“高速公路”。虽然目前直接的应用案例还不多,但作为开发者,提前理解并尝试这一协议,有助于把握下一代 AI 应用集成模式的风向。

对于想要继续深入的同学,下一步可以:

  1. 阅读官方文档 :前往 MCP 的官方仓库或文档站,深入理解协议的所有细节,包括资源(Resources)、提示词模板(Prompts)等高级特性。
  2. 尝试连接真实客户端 :寻找已经支持 MCP 的早期 AI 客户端项目(例如一些开源的 AI 桌面应用),将你的服务器配置进去,体验真实的 AI 驱动调用。
  3. 封装真实服务 :将一个你常用的内部 API 或公共服务(如天气查询、汇率转换、公司内部知识库搜索)封装成 MCP 服务器。
  4. 探索复杂传输层 :尝试将你的服务器从 stdio 迁移到 HTTP with SSE ,使其能够被远程客户端调用。
  5. 参与社区 :在相关的开源社区或论坛分享你的实现,了解其他人的做法,共同探索 MCP 的最佳实践和潜在问题。

这个协议能否成功,取决于生态的采纳程度。但无论如何,它指出了一个明确的方向:AI 与工具之间的交互,需要更开放、更统一的标准。现在开始探索,正是时候。

更多推荐