Skip to content

MCP — 外部能力扩展

上下文视角:MCP 工具的定义和返回值与内置工具一样进入上下文,LLM 不区分来源。

上一节的内置工具都在本地执行——读文件、跑命令,Agent 直接搞定。但如果你想让 Agent 抓网页、搜 Slack 消息、调公司内部 API 呢?

等 Agent 开发者更新?不现实。自己改源码?更不现实。

你需要一个标准接口,让任何外部能力都能接入 Agent。这就是 MCP(Model Context Protocol)。

MCP ARCHITECTURE Model Context Protocol // v1.0 stdio (Local) Streamable HTTP (Remote) AGENT Client Runtime UNIVERSAL INTERFACE LAYER JSON-RPC FILES Local FS PID:9021 SQL DB PostgreSQL BROWSER Firecrawl API JIRA/SLACK Remote API localhost:8080 TOOL DEFINITIONS INJECTION { "name": "read_file" } { "name": "query_db" } { "name": "jira_get" } LLM API "It's just a tool_call"
MCP ARCHITECTURE Model Context Protocol // v1.0 stdio (Local) Streamable HTTP (Remote) AGENT Client Runtime UNIVERSAL INTERFACE LAYER JSON-RPC FILES Local FS PID:9021 SQL DB PostgreSQL BROWSER Firecrawl API JIRA/SLACK Remote API localhost:8080 TOOL DEFINITIONS INJECTION { "name": "read_file" } { "name": "query_db" } { "name": "jira_get" } LLM API "It's just a tool_call"

什么是 MCP?

一句话:Agent 世界的 USB 接口。

MCP 是一个开放协议。它规定了一套标准,允许任何人为 Agent 开发工具,无需修改 Agent 本身的代码。就像 USB 设备不需要了解电脑内部构造,一个 MCP 工具不需要了解 Agent 的实现细节。

Agent 加载你预先配置好的这些外部工具。你只需要配一下,不需要写代码。

MCP in one picture: client, server, transport A diagram showing an agent-side MCP Client connecting to either a local MCP Server via stdio or a remote MCP Server via Streamable HTTP. Both expose tools that reach external systems. MCP in One Picture Same protocol, two transports: stdio (local) and Streamable HTTP (remote) INSIDE THE AGENT MCP Client Discovers servers, negotiates capabilities, calls tools. Wraps results as role: "tool" messages. tools[] schema tool_calls LLM sees a single tool interface (built-in and MCP tools look the same). MCP SERVER (LOCAL PROCESS) Transport: stdio Agent spawns and manages the process lifecycle. docs_search() postgres_query() MCP SERVER (REMOTE SERVICE) Transport: Streamable HTTP Suited for shared access and long-running services. search_jira() query_slack() EXTERNAL SYSTEMS SaaS, internal APIs, databases, web… J Jira S Slack API Internal API stdio Streamable HTTP A “Server” can be a local process or a remote service
MCP in one picture: client, server, transport A diagram showing an agent-side MCP Client connecting to either a local MCP Server via stdio or a remote MCP Server via Streamable HTTP. Both expose tools that reach external systems. MCP in One Picture Same protocol, two transports: stdio (local) and Streamable HTTP (remote) INSIDE THE AGENT MCP Client Discovers servers, negotiates capabilities, calls tools. Wraps results as role: "tool" messages. tools[] schema tool_calls LLM sees a single tool interface (built-in and MCP tools look the same). MCP SERVER (LOCAL PROCESS) Transport: stdio Agent spawns and manages the process lifecycle. docs_search() postgres_query() MCP SERVER (REMOTE SERVICE) Transport: Streamable HTTP Suited for shared access and long-running services. search_jira() query_slack() EXTERNAL SYSTEMS SaaS, internal APIs, databases, web… J Jira S Slack API Internal API stdio Streamable HTTP A “Server” can be a local process or a remote service

Server 与 Client

这两个词容易让人困惑。先澄清一个常见误解:MCP Server 不一定是远程服务器。

  • MCP Client:运行在 Agent 内部的组件,负责发现、连接和调用 MCP Server 上的工具。你通常不直接操作它。
  • MCP Server:提供工具的那一方。它可以是一个本地进程,也可以是一个远程 HTTP 服务。

你会遇到各种 MCP Server。举几个真实例子:Context7(文档查询)、Tavily/Exa(搜索引擎)、DeepWiki(代码仓库文档)、Firecrawl(网页抓取)、Grep.app(GitHub 代码搜索)。其中一部分通过 stdio 跑在你本地(如 Context7、Firecrawl),另一部分作为远程 HTTP 服务运行(如 Exa、DeepWiki、Tavily)。

两种传输方式

MCP 支持两种连接方式:

stdio(本地子进程):Agent 直接 spawn 一个子进程来运行 MCP Server,通信走 stdin/stdout。Agent 管理进程的整个生命周期——启动、通信、关闭。比如配置文件里写 command: "npx", args: ["-y", "@upstash/context7-mcp"],就能接入 Context7 文档查询服务。

Streamable HTTP(远程服务):MCP Server 作为独立的 HTTP 服务运行,Agent 通过 HTTP 请求连接。适合需要持久运行或多个 Agent 共享的场景。

对你来说,区别只在配置方式。对 LLM 来说,完全不知道也不关心。

两种方式的交互流程对比:

功能等价,来源不同

这是关键:对 LLM 来说,内置工具和 MCP 工具毫无区别

── 第 1 轮 ──

假设有一个通过 MCP 接入的 scrape_url 工具。用户提问时,Agent 把所有可用工具(内置 + MCP)的定义一起放进上下文:

json
// → REQUEST(agent → LLM API)
{
  "system": "你是一个项目助理...",
  "tools": [
    {
      "name": "read_file",
      "description": "读取文件内容",
      "input_schema": { "...": "..." }
    },
    {
      "name": "scrape_url",
      "description": "抓取指定 URL 的网页内容并返回 markdown",
      "input_schema": { "...": "..." }
    }
  ],
  "messages": [
    {
      "role": "user",
      "content": "帮我看一下 https://example.com/docs/api 这个页面写了什么"
    }
  ]
}

LLM 选择最合适的工具:

json
// ← RESPONSE(LLM API → agent,SSE 流)
{
  "role": "assistant",
  "content": "好的,正在抓取页面内容...",
  "tool_calls": [
    {
      "id": "call_xyz789",
      "name": "scrape_url",
      "arguments": { "url": "https://example.com/docs/api" }
    }
  ]
}

LLM 视角:和调用 read_file 完全一样,就是返回一个 tool_calls

Agent 视角:执行路径不同。

── 第 2 轮 ──

MCP Server 返回结果后,Agent 把它包装成 tool 角色消息,追加到对话历史。和内置工具的返回值格式一模一样:

json
// → REQUEST(agent → LLM API)
{
  "messages": [
    // ... 之前的消息
    {
      "role": "tool",
      "tool_call_id": "call_xyz789",
      "content": "# API Reference\n\n## Authentication\nAll requests require a Bearer token...\n\n## Endpoints\n- GET /users — List all users\n- POST /users — Create a new user\n..."
    }
  ]
}
json
// ← RESPONSE(LLM API → agent,SSE 流)
{
  "role": "assistant",
  "content": "这个页面是 API 文档,主要内容:\n1. 认证方式:Bearer token\n2. 两个端点:GET /users(获取用户列表)和 POST /users(创建用户)\n\n需要我看具体哪个端点的细节吗?"
}

LLM 只关心拿到了网页内容。它不知道也不需要知道这个结果来自本地还是远端。

一句话总结:LLM 层完全等价,Agent 执行层路径不同。

Context cost: tool schemas scale with MCP Two side-by-side profiles compare how tool definitions (static) can crowd out messages (dynamic) in the context window when many MCP servers/tools are enabled. Context Cost of MCP Tools Tool definitions are static context injected on every request. More tools → less room for messages. PROFILE A Lean (enable only what you need) Enabled servers: Search Docs Context window (same total budget): Instructions Messages + tool outputs Tool schemas (built-in + MCP) switch per task PROFILE B Everything enabled ("just in case") Enabled servers: Search Docs DB Internal API Context window (same total budget): tools[] Rule of thumb: keep MCP off by default; enable by profile when needed.
Context cost: tool schemas scale with MCP Two side-by-side profiles compare how tool definitions (static) can crowd out messages (dynamic) in the context window when many MCP servers/tools are enabled. Context Cost of MCP Tools Tool definitions are static context injected on every request. More tools → less room for messages. PROFILE A Lean (enable only what you need) Enabled servers: Search Docs Context window (same total budget): Instructions Messages + tool outputs Tool schemas (built-in + MCP) switch per task PROFILE B Everything enabled ("just in case") Enabled servers: Search Docs DB Internal API Context window (same total budget): tools[] Rule of thumb: keep MCP off by default; enable by profile when needed.

灵活性好理解。代价呢?每接入一个 MCP Server,它所有的工具定义都会注入到每一轮请求里。同时挂十个 Server,几十个工具定义永久占着上下文窗口——挤掉的是你的指令、对话历史和工具返回值的空间。

实操建议:按任务类型建不同的 MCP 配置——写代码用一套,跑数据用另一套。默认关闭,需要时再开。

为什么重要

MCP 解决的问题很直接——你不再需要等 Agent 开发者给你加工具

  • 不等官方更新:想接搜索引擎?装个 MCP Server 就行,不需要等 Agent 下个版本。
  • 快接内部系统:公司内部 API 大概率不会被 Agent 官方支持,但你可以自己写(或找现成的)MCP Server。
  • 跨 Agent 复用:一个 MCP Server 理论上能被任何支持该协议的 Agent 使用——不绑定特定工具。

本节小结

  • 上下文流动:MCP 工具定义在每次请求时注入上下文(静态),返回值在执行后追加(动态)。和内置工具走同一条上下文通道——LLM 感知不到区别。
  • 风险:MCP 的信任问题比内置工具更尖锐。恶意 MCP Server 可能返回虚假数据污染上下文,或记录你的敏感请求。装 MCP Server 和装浏览器插件一样——来源可信吗?权限合理吗?
  • 可审计性:Agent 与 MCP Server 之间的每次交互都应该被记录——请求了什么、返回了什么、耗时多少。出了问题,这就是你的排查线索。

下一节看 Slash Commands——如何把常用操作打包成一键触发的快捷方式。