本文从 Function Calling 出发,介绍 MCP 的核心架构,以及 Tools、Resources、Prompts 三类 Server 能力的发现与调用流程。

Function Calling

为什么需要Functioncalling

LLM本身只是根据上下文预测下一个 token的预测器,知识和能力有天然边界:它无法可靠获取实时信息、访问企业内部数据,也不能自行调用 API、读取数据库或执行代码。 真正去调用API、读数据库、执行代码的始终都是应用程序。Function Calling给“模型提出工具调用请求”提供了一套结构化、机器可解析、可进行 Schema 校验的交互协议,使模型能够通过应用程序提供的受控工具,间接访问外部系统并获取模型参数化知识之外的实时或私有数据。

Function Calling的核心流程:

  • 向模型声明可用能力:应用程序将可调用工具的名称、用途和参数 Schema 提供给模型,使模型知道当前有哪些能力可用。
  • 模型生成结构化调用意图:模型根据用户请求选择合适的工具,并输出符合约定格式的函数名和参数,由应用程序解析。
  • 应用程序执行工具并返回结果:后端负责鉴权、业务校验和实际执行;工具执行结果再作为上下文返回给模型。
  • 模型基于结果继续完成任务:模型可以据此生成最终回答,或根据需要继续发起后续工具调用。

以“查询北京今天天气”为例,一次典型的 LLM Tool Calling / Function Calling 流程如下图所示:

  • 1.应用程序会提前把可用工具及其说明提供给 LLM,例如有一个“天气查询工具”,可以根据城市查询天气。这里的工具列表通常通过 API 的 tools 参数传入,也可以在系统提示词中补充工具使用规则。
  • 2.用户输入:“查一下北京今天的天气。”
  • 3.LLM 看到用户的问题后,判断这需要实时天气信息,不能仅依赖模型已有知识。它再查看当前可用工具,发现有天气查询工具,因此决定调用该工具。
  • 4.LLM 不会自己直接访问天气 API,而是向系统返回类似下面的调用意图:
{  
   "name": "Weather_API",  
   "arguments": {  
      "city": "北京"  
   }  
}
  • 5.系统解析模型返回的函数名和参数,确认要调用 Weather_API,并以“北京”为参数,实际向外部天气服务发起 API 请求。
  • 6.天气 API 查询完成后,将结果返回给应用系统,例如:
{
   "status": "Success",
   "data": {
      "weather": "晴",
      "tempLow": 18,
      "tempHigh": 25,
      "city": "北京"
   }
}
  • 7.应用程序不会直接把原始 API 结果展示给用户,而是将该结果作为工具调用结果重新传给 LLM。
  • 8.LLM 读取工具返回的数据,将结构化信息组织成自然语言,例如:北京今天多云转晴,气温在 18 到 25 摄氏度之间
  • 9.用户得到经过 LLM 整理后的自然语言回复

tool-calling

总的来说,Function Calling 并不是让 LLM 获得了直接执行外部操作的权限,而是将“模型的语言理解与决策能力”和“外部系统的真实数据与执行能力”以标准化方式连接起来。

工具定义示例

一个标准的工具定义如下:

{
   "type": "function",
   "name": "get_order",
   "description": "根据订单号查询订单状态和物流信息。仅当用户询问订单状态、物流或发货情况时调用。",
   "parameters": {
      "type": "object",
      "properties": {
      "order_id": {
         "type": "string",
         "description": "订单编号,例如 A1001"
      },
      "include_tracking": {
         "type": "boolean",
         "description": "是否返回物流追踪信息"
      }
   },
   "required": ["order_id", "include_tracking"],
   "additionalProperties": false
   },
   "strict": true
}
  • type :固定为function,表示这是一个工具函数
  • name :工具的名字
  • description :工具描述,通常在这里写明此工具的功能以及适用情况
  • parameters :工具函数参数的 JSON Schema 定义
    • type :"object"
    • properties :参数属性
    • 字段名 :属性字段名
      • type :属性类型
      • description : 属性描述
    • required :数组,规定必须存在的参数属性的字段名
    • additionalProperties :是否允许对象中出现 properties 未声明的字段
  • strict :是否启用严格 Schema 约束。设为 true 时,函数调用参数会可靠地遵守 Schema;如果 Schema 不符合严格模式要求,请求会被拒绝。

当strict为true即在严格模式下时,

  • 1.parameters 中的每一个 object 都要写 "additionalProperties": false
  • 2.properties 中出现的每个字段,都必须列入 required
  • 3.若希望某个字段在业务语义上“可选”,仅仅将它从 required 中移除不够,应将它定义为可空类型。例如:
"parameters": {  
   "type": "object",  
   "properties": {  
      "include_tracking": {  
         "type": ["boolean", "null"],  
         "description": "是否返回物流追踪信息;用户未指定时传 null"  
      }  
   },  
   "required": ["include_tracking"],  
   "additionalProperties": false  
}

MCP

一次完整的 MCP 交互是如何发生的

用户提出任务
→ Host 将任务交给模型
→ 模型判断需要外部能力
→ Host / Client 从 MCP Server 获取可用 Tools、Resources、Prompts
→ 模型选择合适能力
→ Client 向 MCP Server 发起请求
→ MCP Server 调用真实系统并返回结果
→ Host 将结果加入模型上下文
→ 模型生成最终回答或继续调用其他能力

为什么需要MCP

Function Calling解决了LLM间接访问外部系统并获取模型参数化知识之外的实时或私有数据的核心问题:LLM可以输出一套结构化、机器可解析、可进行 Schema 校验的工具调用请求,但在实际应用中因为各家的数据格式,API调用方式等都不尽相同,每个 AI 应用都可能要为每个外部系统单独写一套接口,工具的集成成本太高,单打独斗是不可取的,因此 MCP 应运而生,它由 Anthropic 开源发布,现已被捐赠给 Linux Foundation,以更偏中立、社区驱动的方式治理和发展。

MCP是什么

MCP 是一套开放协议,不同客户端可以通过仅实现这一种协议从而连接文件、数据库、搜索、GitHub、Slack、内部业务系统等外部能力。它的核心仍旧基于Function Calling,但与Function Calling不同的是:

  • 工具定义来源:它的工具定义来源无需在 API 请求中手工传入,而是MCP Server 动态暴露给客户端。
  • 工具发现:MCP支持工具列表发现,Function Calling不支持。
  • 调用范围:MCP可跨不同 AI 客户端复用,而Function Calling通常只能在当前应用内的函数 / API内使用。
  • 资源访问:MCP原生有 resources 概念,Function Calling则取决于定义的工具。

MCP核心架构

mcp

1.MCP Host:承载用户交互的 AI 应用,例如Cursor、Claude Code、Codex,负责维护用户与模型的对话,管理用户权限和确认流程,创建 MCP Client,提供工具、资源等信息给模型,转发模型请求给 MCP Server
2.MCP Client:Host 内部负责与某个 MCP Server 通信的组件。一个 Host 可以连接多个 MCP Server,一个Client只能连接一个MCP Server。
3.MCP Server:本地进程或云端服务,它暴露三类核心能力:Tools、Resources、Prompts。它把真实系统能力包装成 MCP 标准接口,例如

订单系统 MCP Server
 ├── get_order(order_id)
 ├── get_tracking(order_id)
 ├── create_refund(order_id)
 └── search_orders(keyword)

MCP 连接生命周期

MCP 并不是 Client 一连上 Server 就可以直接调用 `tools/list`。  
一次连接通常经历三个阶段:  
  
1. 初始化(Initialization)  
- Client 发送 `initialize` 请求;  
- 双方协商协议版本;  
- Client 与 Server 分别声明自己支持的 capabilities;  
- 返回实现名称、版本等信息。  
  
2. 正常运行(Operation)  
- Client 与 Server 根据双方已经声明的能力,调用 Tools、Resources、Prompts、  
Sampling、Elicitation 等功能;  
- 双方也可以发送通知,例如工具列表或资源列表发生变化。  
  
3. 关闭(Shutdown)  
- 连接正常断开,相关会话状态被释放。

MCP Server 的核心能力

Tools

MCP 规范中,Tool 是带有名称、描述和输入 Schema 的可调用能力,可用于查询数据库、调用 API 或执行计算。MCP 的 tools/list 返回结果中的 tools 数组,就是由多个 Tool 对象组成的。一个完整的 MCP Tool 定义示例如下:

{
   "name": "get_order",
   "title": "订单查询",
   "description": "根据订单号查询订单状态、物流信息和预计送达时间。",
   "icons": [
   {
      "src": "https://example.com/icons/order.png",
      "mimeType": "image/png",
      "sizes": ["48x48", "96x96"],
      "theme": "light"
   }
   ],
   "inputSchema": {
      "$schema": "https://json-schema.org/draft/2020-12/schema",
      "type": "object",
      "properties": {
         "order_id": {
            "type": "string",
            "description": "订单编号,例如 A1001"
         },
         "include_tracking": {
            "type": "boolean",
            "description": "是否返回物流追踪详情"
         }
      },
      "required": ["order_id"],
      "additionalProperties": false
   },
   "outputSchema": {
      "$schema": "https://json-schema.org/draft/2020-12/schema",
      "type": "object",
      "properties": {
         "order_id": {
            "type": "string"
         },
         "status": {
            "type": "string",
            "enum": ["pending", "paid", "shipped", "delivered", "cancelled"]
         },
         "carrier": {
            "type": ["string", "null"]
         },
         "tracking_number": {
            "type": ["string", "null"]
         }
      },
      "required": ["order_id", "status"],
      "additionalProperties": false
  },
   "annotations": {
      "title": "查询订单",
      "readOnlyHint": true,
      "destructiveHint": false,
      "idempotentHint": true,
      "openWorldHint": false
   },
   "execution": {
      "taskSupport": "optional"
   },
   "_meta": {
      "internal_category": "order_service"
   }
}
  • name : 工具的名字
  • title : 给用户界面展示用的人类可读名称
  • description : 工具描述,通常在这里写明此工具的功能以及适用情况
  • icons : 图标数组
    • src : 图标 URI
    • mimeType : 图标 MIME 类型
    • sizes : 图标尺寸
    • theme :图标适配主题("light""dark"
  • inputSchema : 对应Function Calling 里的 parameters
    • $schema : JSON Schema所使用的语法版本
    • type : "object"
    • properties : 参数属性
      • 字段名 : 属性字段名
        • type : 属性类型
        • description : 属性描述
        • enum : 枚举候选值
      • required : 数组,规定必须存在的参数属性的字段名
      • additionalProperties :是否允许对象中出现 properties 未声明的字段
  • outputSchema : MCP Tool 对“工具返回结果”定义的期望的输出结构
  • annotations : 提供工具行为的“提示信息”
    • title : 人类可读名称
    • readOnlyHint : 工具是否只读,默认值为false表示可能修改外部环境
    • destructiveHint : 工具是否执行破坏性修改,默认值为true表示工具可能执行破坏性更新,如果为false表示工具只执行加法更新
    • idempotentHint : 相同参数重复调用不会产生额外副作用,默认值为false表示可能产生额外副作用
    • openWorldHint : 工具是否与开放外部世界交互,如互联网、外部用户、第三方服务,默认值为true表示可能与开放外部世界交互
  • execution : 描述执行相关属性
    • taskSupport : 工具是否支持任务增强执行。启用任务增强后,工具调用可以先被创建成一个可持续追踪的 Task,立即返回任务 ID 和状态,最终结果稍后再获取。主要为耗时任务、批处理、异步任务、需要等待外部系统的任务设计。值可取“forbidden ”(不支持任务增强),“optional ”(可能支持任务增强),“required ”(需要任务增强执行)。
  • _meta : 协议预留的元数据扩展字段。 对于无参数工具,应该写成:
{
   "inputSchema": {
      "type": "object",
      "additionalProperties": false
   }
}
Tools 的发现与调用流程

1.Server 声明支持 Tools:支持 Tools 的 MCP Server 在初始化时需要声明 tools 能力:

{ 
   "capabilities": { 
      "tools": { 
         "listChanged": true 
      } 
   } 
}
  • tools:表示该 Server 支持工具发现和调用。
  • listChanged:表示当可用工具列表发生变化时,Server 是否会向 Client 发送工具列表变更通知。 值得注意的是,若 MCP Server 支持将 tools/call 以任务增强方式执行,需要在初始化响应的 capabilities 中声明 tasks.requests.tools.calltasks.listtasks.cancel 则分别表示该 Server 是否额外支持列出和取消任务。
{
   "capabilities": {
      "tools": { 
         "listChanged": true 
      }, 
   "tasks": {
      "list": {}, 
      "cancel": {},
      "requests": {
         "tools": {
            "call": {}
         }
      }
   }
   }
}

当工具列表发生变化时,Server 可以发送:

{
   "jsonrpc": "2.0",
   "method": "notifications/tools/list_changed"
}

Client 收到该通知后,可以重新调用 tools/list 获取最新工具列表。

2.Client 发现工具:tools/list:Client 使用 tools/list 请求获取 Server 暴露的工具列表:

{ 
   "jsonrpc": "2.0", 
   "id": 1, 
   "method": "tools/list", 
   "params": { 
      "cursor": "optional-cursor-value" 
   } 
}
  • tools/list:返回结果中的 tools 字段是 Tool 对象数组。
  • cursor:可选的分页游标。 示例响应:
{ 
   "jsonrpc": "2.0", 
   "id": 1, 
   "result": { 
      "tools": [ 
      { 
         "name": "get_order", 
         "description": "根据订单号查询订单状态。", 
         "inputSchema": { 
            "type": "object", 
            "properties": { 
               "order_id": { 
                  "type": "string" 
               } 
            }, 
            "required": ["order_id"], 
            "additionalProperties": false
         } 
      } 
      ], 
      "nextCursor": "next-page-cursor" 
   } 
}

3.Client 调用工具:tools/call:当模型或 Host 决定调用工具时,Client 向 MCP Server 发送 tools/call 请求:

{ 
   "jsonrpc": "2.0", 
   "id": 2, 
   "method": "tools/call", 
   "params": { 
      "name": "get_order", 
      "arguments": { 
         "order_id": "A1001", 
         "include_tracking": true 
      } 
   } 
}
  • name:必填,要调用的 Tool 名称。
  • arguments:可选,工具输入参数,应符合该 Tool 的 inputSchema
  • task:可选,用于任务增强执行。
  • _meta:可选,扩展元数据。

4.工具调用结果:工具调用成功后,Server 返回 CallToolResult

{ 
   "jsonrpc": "2.0", 
   "id": 2, 
   "result": { 
      "content": [ 
      { 
         "type": "text", 
         "text": "订单 A1001 已发货,由 DHL 承运。" 
      } 
      ], 
      "structuredContent": { 
         "order_id": "A1001", 
         "status": "shipped", 
         "carrier": "DHL", 
         "tracking_number": "DHL-123456" 
      }, 
      "isError": false 
   } 
}
  • content:必填,非结构化结果内容数组。content 中可以返回多种内容类型:text(文本结果),image(Base64 编码图片),audio(Base64 编码音频),resource_link(资源链接),resource(嵌入式资源内容)
  • structuredContent:可选,结构化 JSON 结果。若 Tool 定义了 outputSchema,该字段应符合 outputSchema
  • isError:可选,表示工具是否执行失败;未设置时默认为 false
  • _meta:可选,扩展元数据。

5. 工具错误处理:MCP 将错误分为两类:

  • 1.协议错误
    例如未知工具名、JSON-RPC 请求格式错误、请求参数结构不合法等。这类错误使用 JSON-RPC 的 error 返回。
  • 2.工具执行错误 例如第三方 API 调用失败、日期格式错误、权限不足、业务规则不满足等。这类错误应通过工具结果返回,并设置isErrortrue

Resources

MCP 规范中,Resources是 Server 向 Client 提供的、可被读取的外部上下文数据。它们通常是文件、数据库 Schema、配置、知识库文档、代码文件、应用状态等。每个 Resource 都由一个 URI 唯一标识。Host 可以让用户手动选择资源、提供搜索和筛选 ,也可以根据规则或模型选择自动加入上下文。 一个完整的MCP Resource 定义示例如下:

{
   "uri": "file:///project/README.md",
   "name": "README.md",
   "title": "项目说明文档",
   "description": "项目的安装、运行和开发说明。",
   "mimeType": "text/markdown",
   "size": 12680,
   "icons": [
   {
      "src": "https://example.com/icons/markdown.png",
      "mimeType": "image/png",
      "sizes": ["48x48"],
      "theme": "light"
   }
   ],
   "annotations": {
      "audience": ["user", "assistant"],
      "priority": 0.8,
      "lastModified": "2025-01-12T15:00:58Z"
   },
   "_meta": {
      "source": "project-docs"
   }
}
  • uri:资源地址,不一定是网页 URL,也不一定对应真实文件系统路径。常见 URI Scheme:
       https://  网络资源
       file://   类文件系统资源
       git://    Git 版本控制资源
       自定义 Scheme
    
Resources 的发现与调用流程

Resources 的核心流程及对应的MCP协议关键操作:

Server 声明支持 Resources
→ Client 获取资源目录(resources/list)
→ 可选:获取动态资源模板(resources/templates/list)
→ Client 选择某个 URI
→ Client 读取资源内容(resources/read)
→ Host 决定是否将内容加入模型上下文
→ 可选:Client 订阅资源更新(resources/subscribe)

1.Server 声明支持 Resources 若 MCP Server 支持 Resources,需要在初始化响应中声明:

{
   "capabilities": {
      "resources": {
         "subscribe": true,
         "listChanged": true
      }
   }
}
  • resources : 表示 Server 支持资源能力
  • subscribe : Client 是否可以订阅单个资源的更新
  • listChanged : 资源目录变化时,Server 是否会通知 Client

2.发现资源:resources/list Client 使用 resources/list 获取当前 Server 可读取的资源目录:

{
   "jsonrpc": "2.0",
   "id": 1,
   "method": "resources/list",
   "params": {
      "cursor": "optional-cursor-value"
   }
}

Server 返回资源列表:

{
   "jsonrpc": "2.0",
   "id": 1,
   "result": {
      "resources": [
      {
         "uri": "company://policies/refund-policy",
         "name": "refund-policy",
         "title": "退款政策",
         "description": "公司当前退款规则。",
         "mimeType": "text/markdown"
      }
      ],
   "nextCursor": "next-page-cursor"
   }
}

3.读取资源:resources/read 当 Client 决定读取某个资源时,发送:

{
   "jsonrpc": "2.0",
   "id": 2,
   "method": "resources/read",
   "params": {
      "uri": "company://policies/refund-policy"
   }
}

Server 返回资源实际内容:

{
   "jsonrpc": "2.0",
   "id": 2,
   "result": {
      "contents": [
      {
         "uri": "company://policies/refund-policy",
         "mimeType": "text/markdown",
         "text": "# 退款政策\n\n订单签收后 7 天内可申请退款……"
      }
      ]
   }
}

Prompts

MCP 的 Prompts 是由 MCP Server 暴露给 Client 的、可复用的提示词模板 / 对话模板。 Prompts 的作用不是执行外部操作,也不是直接读取数据,而是由 Server 提供一组结构化的消息和指令。Client 或用户选择某个 Prompt 后,可以传入参数对模板进行定制,并将生成后的消息加入 LLM 上下文。

Prompts 通常是用户主动触发的能力。例如,Client 可以将 Prompt 展示为 Slash Command、按钮、菜单项或模板列表:

/code_review
/release_notes
/incident_review
/customer_reply
Prompt 定义示例

一个完整的 Prompt 定义通常如下:

{
   "name": "code_review",
   "title": "请求代码审查",
   "description": "让 LLM 分析代码质量、潜在问题和改进建议。",
   "arguments": [
   {
      "name": "code",
      "description": "需要审查的代码",
      "required": true
   },
   {
      "name": "language",
      "description": "编程语言,例如 Python、JavaScript",
      "required": false
   }
   ],
   "icons": [
   {
      "src": "https://example.com/review-icon.svg",
      "mimeType": "image/svg+xml",
      "sizes": ["any"]
   }
   ]
}
  • name:Prompt 的唯一标识。
  • title:用于用户界面展示的人类可读名称。
  • description:Prompt 的功能说明。
  • arguments:可选的模板参数列表。
    • name:参数名称。
    • description:参数说明。
    • required:是否为必填参数。
  • icons:用于 UI 展示的图标数组。

需要注意的是,Prompt 的 arguments 不像 Tool 的 inputSchema 一样使用完整 JSON Schema,而是使用较轻量的参数声明列表。

Prompts 的发现与调用流程

1.Server 声明支持 Prompts

支持 Prompts 的 MCP Server 需要在初始化响应中声明:

{
   "capabilities": {
      "prompts": {
      "listChanged": true
      }
   }
}
  • prompts:表示 Server 支持 Prompt 能力。
  • listChanged:表示 Prompt 列表发生变化时,Server 是否会发送变更通知。

当 Prompt 列表发生变化时,Server 可以发送:

{
   "jsonrpc": "2.0",
   "method": "notifications/prompts/list_changed"
}

Client 收到通知后,可以重新调用 prompts/list 获取最新 Prompt 列表。

2.Client 发现 Prompts:**prompts/list**

Client 使用 prompts/list 获取 Server 暴露的 Prompt 列表:

{
   "jsonrpc": "2.0",
   "id": 1,
   "method": "prompts/list",
   "params": {
      "cursor": "optional-cursor-value"
   }
}

Server 返回:

{
   "jsonrpc": "2.0",
   "id": 1,
   "result": {
      "prompts": [
      {
         "name": "code_review",
         "title": "请求代码审查",
         "description": "让 LLM 分析代码质量和改进建议。",
         "arguments": [
         {
            "name": "code",
            "description": "需要审查的代码",
            "required": true
         }
         ]
      }
      ],
      "nextCursor": "next-page-cursor"
   }
}
  • prompts:Prompt 对象数组。
  • cursor:可选的分页游标。
  • nextCursor:可选。存在时表示可能还有下一页 Prompt。

3.获取 Prompt 内容:**prompts/get**

当用户选择某个 Prompt 后,Client 调用 prompts/get,并传入所需参数:

{
   "jsonrpc": "2.0",
   "id": 2,
   "method": "prompts/get",
   "params": {
      "name": "code_review",
      "arguments": {
         "code": "def hello():\n    print('world')",
         "language": "Python"
      }
   }
}

Server 返回实际要加入模型上下文的消息:

{
   "jsonrpc": "2.0",
   "id": 2,
   "result": {
      "description": "代码审查 Prompt",
      "messages": [
      {
         "role": "user",
         "content": {
         "type": "text",
         "text": "请审查以下 Python 代码,指出 bug、可读性问题和改进建议:\n\ndef hello():\n    print('world')"
         }
      }
      ]
   }
}

Client 或 Host 将这些 messages 加入与 LLM 的对话上下文,LLM 再基于这些消息生成回答。

整个流程可以概括为:

用户选择 Prompt
→ Client 调用 prompts/get
→ Server 根据参数生成结构化消息
→ Client 将消息加入 LLM 上下文
→ LLM 生成结果

4.PromptMessage

prompts/get 返回结果中最重要的是 messages 字段。

每个 PromptMessage 包含:

  • role:角色,只能是 "user""assistant"
  • content:消息内容。

PromptMessage 的 content 支持以下类型:

text:文本内容
image:Base64 编码图片
audio:Base64 编码音频
resource:嵌入式资源内容

文本示例:

{
   "type": "text",
   "text": "请生成发布说明。"
}

图片示例:

{
   "type": "image",
   "data": "base64-encoded-image-data",
   "mimeType": "image/png"
}

音频示例:

{
   "type": "audio",
   "data": "base64-encoded-audio-data",
   "mimeType": "audio/wav"
}

嵌入式 Resource 示例:

{
   "type": "resource",
   "resource": {
      "uri": "company://policies/refund-policy",
      "mimeType": "text/markdown",
      "text": "# 退款政策\n..."
   }
}

嵌入式 Resource 使 Prompt 能够将 Server 管理的文档、代码样例或参考资料直接加入对话流程。

5.Prompts 的错误处理与安全要求

常见错误包括:

  • Prompt 名称不存在:JSON-RPC 错误码 -32602
  • 缺少必填参数:JSON-RPC 错误码 -32602
  • Server 内部错误:JSON-RPC 错误码 -32603

Server 应校验 Prompt 参数;同时,Prompt 的输入和输出也需要被谨慎处理,避免 Prompt Injection 或未经授权地访问敏感 Resource。