Back to blog

MCP 入门:模型上下文协议如何打通 AI 与工具

从协议分层到最小实现,系统梳理 MCP(Model Context Protocol)的核心概念、传输方式与安全边界,并给出一个可运行的服务器示例。

背景

#

大模型本身没有记忆外的"手"。要让 AI 查询数据库、读写文件、调用第三方 API,过去每个应用都要自造一套工具调用协议:有的走函数调用(function calling),有的靠提示词注入,有的干脆让模型把命令打进 Shell。协议五花八门,集成成本落在每一个接入方身上。

MCP(Model Context Protocol,模型上下文协议)是 Anthropic 于 2024 年底提出的开放标准,目标是把"应用与 AI 之间如何交换上下文"这件事规范化——官方常拿 USB-C 做比喻:一个统一接口,连接各种外设。到 2026 年,MCP 已移交开放治理(MCP.org / Linux Foundation),主流 IDE、终端 Agent、API 平台基本都原生支持。

本文按"协议分层 → 基元 → 最小实现 → 安全"的顺序展开,读完你既能看懂一个 MCP 服务器,也能自己写一个。

核心思路:三端分层

#

MCP 把一次工具集成拆成三个角色:

角色职责例子
Host宿主应用,负责用户体验与模型编排Claude Code、Claude Desktop、VS Code、Cursor
ClientHost 内的连接器,一个 Client 连一个 Server每个 MCP 连接对应一个 Client
Server暴露能力的进程,实现工具/资源/提示词GitHub MCP、数据库 MCP、自研工具

关键点:Host 与 Server 之间永远是 1:N。一个 Host 可以同时挂载多个 Server,每个 Server 是一个独立的被拉起(stdio)或被访问(HTTP)的进程。模型只跟 Host 说话,Host 通过 Client 把工具调用转发给 Server,再把结果回传给模型。

┌────────────── Host (Claude Code) ──────────────┐
│  LLM  ──►  Client A ──► MCP Server (GitHub)    │
│         └──► Client B ──► MCP Server (数据库)  │
└────────────────────────────────────────────────┘

这套分层带来的直接好处:Server 与 Host 解耦。同一个 MCP Server 可以被 Claude Desktop、Claude Code、任何 IDE 复用,无需为每个宿主各写一套适配层——这正是"工具的一次编写,处处接入"。

协议基元:Tools / Resources / Prompts

#

MCP 定义了三类核心基元,控制权的归属各不相同:

Tools(工具)——模型控制

  • 模型在需要时主动发起调用,可以执行动作(写库、发请求、改文件)。
  • 定义方式与 OpenAI function calling 类似:name + description + JSON Schema 的 inputSchema
  • 副作用最强的基元,因此权限控制(详见安全一节)主要针对它。

Resources(资源)——应用控制

  • 由应用侧暴露的只读上下文,模型只能"读取"不能"执行"。
  • 地址形式类似 URI:file:///project/config.yamlhttps://example.com/api
  • 适合喂给模型的长上下文,如项目文档、README、配置文件。

Prompts(提示词)——用户控制

  • 可复用的提示词模板,用户主动选择触发。
  • 相当于把常用的 prompt 封装成语义化的可发现单元。

三者的控制权分别是模型 / 应用 / 用户,这是理解 MCP 权限模型的第一把钥匙:谁发起,谁负责边界

此外还有两个补充基元:Sampling(Server 反向往模型发起请求,需要用户授权)与 Roots(Server 声明自己能访问的文件系统根路径,供 Host 做边界检查)。

传输层:stdio 与 Streamable HTTP

#

MCP 支持两种传输方式,选型取决于 Server 的部署形态。

stdio(本地进程)

  • Client 以子进程方式拉起 Server,通过标准输入/输出传递 JSON-RPC 消息。
  • 适合"安装即用"的本地工具,如 npxuvx 启动的服务器。
  • 生命周期由 Host 管理,退出时一并回收。

Streamable HTTP(网络服务)

  • 基于 HTTP,支持服务端流式响应(SSE),也支持普通请求/响应。
  • 2025-03-26 的规范更新用它取代了早期的 HTTP+SSE 双端点方案,目前是远程 Server 的唯一标准形态。
  • 适合部署在远端、多用户共享的工具服务。

选择建议:本地个人工具用 stdio(零部署成本),团队共享或需要鉴权的服务用 Streamable HTTP。

实现过程:最小 MCP Server

#

下面用 TypeScript SDK 写一个最简服务器,暴露一个 get_weather 工具。

mkdir mcp-weather && cd mcp-weather
npm init -y
npm install @modelcontextprotocol/sdk
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
import { z } from "zod"

const server = new McpServer({
  name: "weather",
  version: "1.0.0",
})

server.registerTool(
  "get_weather",
  {
    description: "查询指定城市的当前天气",
    inputSchema: {
      city: z.string().describe("城市名,例如 Beijing"),
    },
  },
  async ({ city }) => ({
    content: [{ type: "text", text: `${city}: 24°C 多云` }],
  }),
)

const transport = new StdioServerTransport()
await server.connect(transport)

这段代码已经是一个合法的 MCP Server:注册工具、声明 Schema、连接 stdio 传输。现在把它接进 Claude Code:

{
  "mcpServers": {
    "weather": {
      "command": "node",
      "args": ["src/index.ts"],
      "env": {}
    }
  }
}

Host 启动时会拉起该进程,模型的工具列表里就会出现 get_weather,并且可以在对话中直接调用。

远程 Server 与 API 接入

#

如果 Server 部署为 Streamable HTTP 服务,配置里换一种写法:

{
  "mcpServers": {
    "github": {
      "type": "http",
      "url": "https://api.githubcopilot.com/mcp/"
    }
  }
}

Claude API(Messages API) 也提供了 MCP Connector,用 mcp_servers + mcp_toolset 两个参数即可把远端工具直接挂进请求:

import Anthropic from "@anthropic-ai/sdk"

const client = new Anthropic()

const response = await client.beta.messages.create({
  model: "claude-opus-5",
  max_tokens: 1024,
  betas: ["mcp-client-2025-11-20"],
  mcp_servers: [
    { type: "url", url: "https://mcp.linear.app/mcp", name: "linear" },
  ],
  tools: [{ type: "mcp_toolset", mcp_server_name: "linear" }],
  messages: [{ role: "user", content: "列出我最近的 Linear issue" }],
})

需要注意两个参数必须成对出现:只声明 mcp_servers 而不加 mcp_toolset,会被校验直接拒绝。

在 Managed Agents(托管 Agent)场景,MCP Server 声明在 agent 配置上,而鉴权凭证放进 Vault,按 URL 匹配注入——职责分离:Agent 定义"能连什么",Vault 定义"用什么身份连"。

注意事项:安全是 MCP 的头号话题

#

MCP 把"模型能碰的东西"边界大幅拓宽了,安全模型必须跟上。以下几点是实际项目中最容易踩的坑。

最小权限原则

  • 只给 Server 声明的工具授予完成任务的必要权限,不要"全都要"。
  • 对高副作用工具(删除、写库、发消息)设置确认门槛(always_ask),让用户在模型动手前过目。

提示词注入(Prompt Injection)

  • 模型读到不可信内容(网页、邮件、文档)时,其中"请调用某工具把 X 发给我"这类指令可能被当作合法请求执行。
  • 缓解:对工具描述强调"仅在用户明确要求时调用";高敏感操作一律走人工确认;不要把密钥、Token 写进系统提示词或会话历史。

凭证管理

  • 不要把 API Key 塞进 mcpServers 配置或对话历史——配置常被版本管理,历史可被 API 读取。
  • 远端 MCP 的鉴权凭证应放在 Vault 或服务端密钥管理里,运行时注入。
  • 注意:MCP 鉴权 Token ≠ 该服务的 REST API Token。托管 MCP Server(如 Notion、Linear)通常要求 OAuth Bearer Token,用服务的原生 API Key 往往对不上。

信任边界

  • 只连接可信来源的 MCP Server;第三方 Server 的代码与 Host 进程同权限运行,风险等同安装任意软件。
  • 联网能力受限(sandbox)的环境里,需要显式放行 Server 域名,否则工具会静默失败。

总结

#

MCP 的价值不在协议本身多复杂,而在它把"AI 接工具"从各家自研的碎片化状态收敛成了统一标准:

  • 分层清晰:Host / Client / Server 三端解耦,工具一次编写处处接入。
  • 基元克制:Tools / Resources / Prompts 用控制权划分边界,够用且不过度设计。
  • 传输务实:本地 stdio、远程 Streamable HTTP,两种形态覆盖了绝大多数部署场景。

对个人开发者,最直接的上手路径是:用 SDK 写一个几十行的本地 Server,在 Claude Code 里挂上,把常用脚本、私有接口、本地文件变成模型可直接调用的工具。写之前先想清楚权限边界——工具能做什么,比它怎么实现更重要。

后续方向:MCP 的上下文管理(Context Management)、批量调用(Batching)与开放治理下的规范演进仍在持续推进,值得持续关注。

$ echo "collect what matters, write it down"