找回密码
 立即注册
首页 业界区 业界 深入理解MCP:AI 应用与外部世界的桥梁

深入理解MCP:AI 应用与外部世界的桥梁

姘轻拎 4 小时前
在构建由大型语言模型(LLM)驱动的智能应用时,如何让 AI 不仅仅停留在文本生成,而是能够与外部世界的数据和工具进行交互,是一个核心挑战。Anthropic 推出的 Model Context Protocol (MCP) 正是为了解决这一问题,它提供了一个标准化的框架,让 AI 应用能够安全、高效地获取上下文信息并调用外部功能。
本文将深入探讨 MCP 的核心概念、三大组件、完整实现、使用流程与传统插件机制的区别。
一、 什么是MCP?

MCP (Model Context Protocol) 是一个开源标准和框架,由Anthropic 在2024年11月份提出,旨在连接 AI 应用程序与外部系统。它为 AI 助手提供了一种标准化的方式,使其能够无缝地与外部数据源(如内容管理系统、数据库、企业应用程序等)和各种工具进行集成。
简单来说,MCP 使得 LLM 应用程序能够:

  • 获取实时或领域特定的上下文信息,超越其训练数据的限制。
  • 执行外部操作,例如搜索网页、查询数据库、发送邮件等。
它解决了 AI 助手在与外部世界交互时,如何安全、高效、标准化地获取和利用上下文信息的问题。
二、 MCP 的三大核心组件

MCP 架构由三个关键角色组成,它们协同工作,共同实现了 AI 应用与外部世界的连接:
1. Host (AI 应用本体)


  • 角色: 承载 AI 核心逻辑的应用程序,例如 Cursor、Claude Desktop、Dify、Gptbots等或者您自己开发的 AI应用。
  • 核心功能:

    • 管理用户界面 (UI) 和对话历史: 提供用户交互界面,并维护与用户的对话记录。
    • 调用 LLM: 负责与底层的大型语言模型(如 OpenAI 的 GPT 系列、Anthropic 的 Claude 系列等)进行交互,发送提示并接收响应。
    • 挂载 MCP Client: 在其内部集成 MCP Client,将 MCP Server 暴露的工具映射成 LLM 可以理解和调用的 tools (Function Calling)。
    • 处理 tool_calls: 当 LLM 决定调用某个工具时,Host 会将模型生成的 tool_calls 请求,转发给 MCP Client,进而触发对 MCP Server 的实际调用。

2. Client (MCP Client,Host 内的一层运行时)


  • 角色: 位于 Host 内部的运行时层,负责实现 MCP 协议并管理与 MCP Server 的连接。
  • 核心功能:

    • 协议实现者 + 进程/连接管理者:

      • 本地 stdio 模式: 负责启动本地的 MCP Server 进程(例如通过 uvx mcp-server-time 或 python mcp_server.py 命令),并通过标准输入/输出 (stdin/stdout) 使用 MCP JSON-RPC 协议进行通信。
      • 示例:获取当前时间的 MCP Server
        比如使用 https://mcp.so 提供的一个获取当前时间的 mcp-server,其配置如下:
        1. {
        2.   "mcpServers": {
        3.     "time": {
        4.       "command": "uvx",
        5.       "args": [
        6.         "mcp-server-time",
        7.         "--local-timezone=America/New_York"
        8.       ]
        9.     }
        10.   }
        11. }
        复制代码
        执行原理:

        • 先判断命令 Host 会从 PyPI 上下载 mcp-server-time 这个包。
          这块需要强调下协议本身不限制 command 是什么,Host 就是 spawn(command, args) 开子进程;所以你可以内置任意多种:python、uvx、node、npx、docker、自家 CLI……都行,但是host端必须存在对应工具,比如mcp是docker命令执行一个镜像,那host端必须安装了docker,否则启动进程会报错。

        • 找到它在 pyproject.toml 里声明的 console_scripts,例如
          [project.scripts]
          mcp-server-time = "mcp-server-time.server:main"
        • Host 的 MCP Client 会启动一个新进程,执行 my_mcp_demo.server:main()。
        • 在这个 main() 函数内部,会调用 server.run_stdio(),从而使这个新进程成为一个 MCP Server。
        • 这个 mcp-server-time 服务内部都是基于标准 MCP 协议开发的,例如包含 list_tools、call_tool 等方法。

      • 远程 HTTP/SSE 模式: 建立与远程 MCP Server 的 HTTP(S) + SSE(Server-Sent Events)长连接,将 MCP JSON-RPC 消息封装在事件流中发送。


3. Server (MCP Server)


  • 角色: 真正定义“有哪些工具”以及如何执行这些工具的一方。
  • 核心功能:

    • 实现 MCP 协议规定的方法: 响应 initialize、tools/list、tools/call 等协议方法。
    • 内部注册工具: 注册具体的工具函数,例如 get_current_time (获取当前时间)、web_search (网页搜索) 等,并为每个工具提供其参数的 JSON Schema 定义。
    • 返回工具元数据: 当收到 tools/list 请求时,返回所有注册工具的元数据(包括工具名 name、描述 description 和参数 parameters)。
    • 执行工具: 当收到 tools/call 请求时,根据工具名和参数执行相应的内部工具,并将执行结果返回。
      外部工具,工具方内部已经实现server了我们直接用即可,内部工具需要我们自己去写server。


三、 MCP 的案例完整实现(可直接使用)

安装完包直接启动mcp_host即可。
项目地址gitee:mcp-test
项目目录
1.png

项目依赖
  1. [project]
  2. name = "mcp-test"
  3. version = "0.1.0"
  4. description = "Add your description here"
  5. readme = "README.md"
  6. requires-python = ">=3.11"
  7. dependencies = [
  8.     "dotenv>=0.9.9",
  9.     "openai>=1.0.0",
  10.     "mcp>=0.1.0",
  11. ]
复制代码
mcp_client.py
  1. import asyncio
  2. from typing import Any, Dict, List
  3. from mcp import ClientSession
  4. from mcp.client.stdio import StdioServerParameters, stdio_client
  5. class SDKMCPClient:
  6.     """
  7.     当前实现仅支持 stdio 模式(command + args 启动本地进程),
  8.     如果要支持 URL/HTTP 形式,可以在此基础上再用 SDK 的 HTTP Transport 拓展。
  9.     """
  10.     def __init__(self, command: str, args: List[str]) -> None:
  11.         self._command = command
  12.         self._args = args
  13.     async def _run_with_session(self, coro):
  14.         server_params = StdioServerParameters(command=self._command, args=self._args)
  15.         async with stdio_client(server_params) as (read, write):
  16.             async with ClientSession(read, write) as session:
  17.                 await session.initialize()
  18.                 return await coro(session)
  19.     def list_tools(self) -> List[Dict[str, Any]]:
  20.         async def _list(session: ClientSession):
  21.             tools = await session.list_tools()
  22.             # SDK 返回的是 Tool 对象列表,这里简单转成 dict 方便和方案二统一
  23.             tools_meta: List[Dict[str, Any]] = []
  24.             for t in tools.tools:
  25.                 tools_meta.append(
  26.                     {
  27.                         "name": t.name,
  28.                         "description": t.description or "",
  29.                         "parameters": t.inputSchema or {},  # type: ignore[attr-defined]
  30.                     }
  31.                 )
  32.             return tools_meta
  33.         return asyncio.run(self._run_with_session(_list))
  34.     def call_tool(self, name: str, arguments: Dict[str, Any]) -> Any:
  35.         async def _call(session: ClientSession):
  36.             result = await session.call_tool(name, arguments)
  37.             # result.content 里通常是 TextContent / JsonContent,这里简单返回原始结构
  38.             return [c.model_dump() for c in result.content]
  39.         return asyncio.run(self._run_with_session(_call))
  40.     def close(self) -> None:
  41.         # SDK 客户端使用 async context,每次调用都会创建/关闭连接,这里无需额外清理
  42.         return None
  43. __all__ = ["SDKMCPClient"]
复制代码
mcp_host.py
  1. import json
  2. import os
  3. import sys
  4. from typing import Any, Dict, List, Tuple
  5. from dotenv import load_dotenv
  6. from openai import OpenAI
  7. from mcp_sdk_client import SDKMCPClient
  8. def build_openai_tools_from_mcp(
  9.     server_name: str, tools_meta: List[Dict[str, Any]]
  10. ) -> Tuple[List[Dict[str, Any]], Dict[str, str]]:
  11.     """
  12.     把某个 MCP Server 返回的工具描述,转换成 OpenAI Chat Completions 的 tools 结构。
  13.     同时返回 tool_name -> server_name 的映射。
  14.     """
  15.     tools_for_openai: List[Dict[str, Any]] = []
  16.     tool_to_server: Dict[str, str] = {}
  17.     for t in tools_meta:
  18.         name = t["name"]
  19.         tool_to_server[name] = server_name
  20.         tools_for_openai.append(
  21.             {
  22.                 "type": "function",
  23.                 "function": {
  24.                     "name": name,
  25.                     "description": t.get("description", ""),
  26.                     "parameters": t.get(
  27.                         "parameters",
  28.                         {"type": "object", "properties": {}, "required": []},
  29.                     ),
  30.                 },
  31.             }
  32.         )
  33.     return tools_for_openai, tool_to_server
  34. def load_mcp_servers_from_files() -> Dict[str, Dict[str, Any]]:
  35.     """
  36.     从两个地方聚合 MCP Server 配置:
  37.     1. mcp_multi.json (可选,需要维护)
  38.     2. 自定义mcp工具
  39.     只保留带 command/args 的本地进程型 MCP server。
  40.     """
  41.     servers: Dict[str, Dict[str, Any]] = {}
  42.     def merge_from_mcpservers_obj(obj: Any, src: str) -> None:
  43.         """从一个可能包含 mcpServers 字段的对象里合并配置。"""
  44.         if not isinstance(obj, dict):
  45.             return
  46.         servers_cfg = obj.get("mcpServers") or {}
  47.         if not isinstance(servers_cfg, dict):
  48.             print(f"[Console-Host] 跳过 {src}:mcpServers 必须是对象。")
  49.             return
  50.         for name, cfg in servers_cfg.items():
  51.             if not isinstance(cfg, dict):
  52.                 continue
  53.             command = cfg.get("command")
  54.             args = cfg.get("args", [])
  55.             if not command or not isinstance(args, list):
  56.                 continue
  57.             servers[name] = {
  58.                 "command": str(command),
  59.                 "args": [str(a) for a in args],
  60.             }
  61.     def load_from_path(path: str) -> None:
  62.         """
  63.         从JSON 文件里合并 MCP Server 配置。[ {"mcpServers": {...}}, {"mcpServers": {...}}, ... ]
  64.         """
  65.         if not os.path.exists(path):
  66.             return
  67.         try:
  68.             with open(path, "r", encoding="utf-8") as f:
  69.                 data = json.load(f)
  70.             for idx, item in enumerate(data):
  71.                 merge_from_mcpservers_obj(item, f"{path}[{idx}]")
  72.         except Exception as exc:
  73.             print(f"[Console-Host] 读取 {path} 失败: {exc}")
  74.     # 1) 本地项目内的配置
  75.     load_from_path(os.path.join(os.path.dirname(__file__), "mcp_multi.json"))
  76.     # 2) 内置两个 demo MCP Server(始终可用)
  77.     base_dir = os.path.dirname(__file__)
  78.     servers.setdefault(
  79.         "demo-math",
  80.         {
  81.             "command": sys.executable,
  82.             "args": [os.path.join(base_dir, "demo_math_server.py")],
  83.         },
  84.     )
  85.     servers.setdefault(
  86.         "demo-text",
  87.         {
  88.             "command": sys.executable,
  89.             "args": [os.path.join(base_dir, "demo_text_server.py")],
  90.         },
  91.     )
  92.     return servers
  93. def main() -> None:
  94.     """
  95.     - 从 ./mcp_multi.json 聚合所有本地自定义 MCP server
  96.     - 对每个 server 通过 SDKMCPClient.list_tools() 拉取工具
  97.     - 聚合所有工具为一个大 tools 列表
  98.     - 控制台循环读入用户输入,让 OpenAI 模型按需调用这些工具
  99.     """
  100.     load_dotenv("dev.env")
  101.     api_key = os.getenv("OPENAI_API_KEY")
  102.     if not api_key:
  103.         print("请先设置环境变量 OPENAI_API_KEY,例如:")
  104.         print("  set OPENAI_API_KEY=你的key   (PowerShell: $env:OPENAI_API_KEY="...")")
  105.         return
  106.     model = os.getenv("OPENAI_MODEL", "gpt-4o-mini")
  107.     oa_client = OpenAI(api_key=api_key)
  108.     servers = load_mcp_servers_from_files()
  109.     if not servers:
  110.         print("[Console-Host] 没有找到任何 MCP Server 配置。")
  111.         print("你可以在 mcp_multi.json 中配置 mcpServers。")
  112.         return
  113.     print(f"[Console-Host] 已加载 MCP Server 配置: {list(servers.keys())}")
  114.     # 启动所有 MCP server,聚合 tools
  115.     clients: Dict[str, SDKMCPClient] = {}
  116.     server_tools: Dict[str, List[Dict[str, Any]]] = {}
  117.     tools_for_openai: List[Dict[str, Any]] = []
  118.     tool_to_server: Dict[str, str] = {}
  119.     for name, cfg in servers.items():
  120.         command = cfg["command"]
  121.         args = cfg["args"]
  122.         print(f"[Console-Host] 连接 MCP Server '{name}',命令: {[command] + args}")
  123.         try:
  124.             client = SDKMCPClient(command=command, args=args)  # 启动server进程
  125.             tools_meta = client.list_tools()
  126.         except Exception as exc:  # noqa: BLE001
  127.             print(f"[Console-Host] 连接 '{name}' 失败: {exc}")
  128.             continue
  129.         clients[name] = client
  130.         server_tools[name] = tools_meta
  131.         part_tools, mapping = build_openai_tools_from_mcp(name, tools_meta)
  132.         tools_for_openai.extend(part_tools)
  133.         tool_to_server.update(mapping)
  134.         print(f"[Console-Host] Server '{name}' 工具: {[t['name'] for t in tools_meta]}")
  135.     if not clients:
  136.         print("[Console-Host] 所有 MCP Server 都连接失败,退出。")
  137.         return
  138.     print(f"[Console-Host] 最终聚合工具数: {len(tools_for_openai)}")
  139.     print("现在可以开始对话了,输入 exit / quit 结束。")
  140.     messages: List[Dict[str, Any]] = []
  141.     while True:
  142.         try:
  143.             user_input = input("你:").strip()
  144.         except (EOFError, KeyboardInterrupt):
  145.             print()
  146.             break
  147.         if not user_input:
  148.             continue
  149.         if user_input.lower() in {"exit", "quit"}:
  150.             break
  151.         messages.append({"role": "user", "content": user_input})
  152.         try:
  153.             response = oa_client.chat.completions.create(
  154.                 model=model,
  155.                 messages=messages,
  156.                 tools=tools_for_openai,
  157.                 tool_choice="auto",
  158.             )
  159.         except Exception as exc:  # noqa: BLE001
  160.             print(f"[Console-Host] 调用 OpenAI 出错: {exc}")
  161.             messages = []
  162.             continue
  163.         msg = response.choices[0].message
  164.         tool_calls = msg.tool_calls or []
  165.         if tool_calls:
  166.             print("[Console-Host] 模型决定调用 MCP 工具:")
  167.             assistant_tool_calls_payload: List[Dict[str, Any]] = []
  168.             for tc in tool_calls:
  169.                 print(
  170.                     f"  - 工具名: {tc.function.name}, "
  171.                     f"arguments: {tc.function.arguments}"
  172.                 )
  173.                 assistant_tool_calls_payload.append(
  174.                     {
  175.                         "id": tc.id,
  176.                         "type": "function",
  177.                         "function": {
  178.                             "name": tc.function.name,
  179.                             "arguments": tc.function.arguments,
  180.                         },
  181.                     }
  182.                 )
  183.             messages.append(
  184.                 {
  185.                     "role": "assistant",
  186.                     "tool_calls": assistant_tool_calls_payload,
  187.                     "content": None,
  188.                 }
  189.             )
  190.             # 路由到对应的 MCP Server
  191.             for tc in tool_calls:
  192.                 args = json.loads(tc.function.arguments or "{}")
  193.                 tool_name = tc.function.name
  194.                 server_name = tool_to_server.get(tool_name)
  195.                 client = clients.get(server_name) if server_name else None
  196.                 if not client:
  197.                     print(
  198.                         f"[Console-Host] 找不到处理工具 '{tool_name}' 的 MCP Server(映射缺失)。"
  199.                     )
  200.                     continue
  201.                 print(
  202.                     f"[Console-Host] 调用 MCP Server '{server_name}' 工具 '{tool_name}',参数: {args}"
  203.                 )
  204.                 try:
  205.                     tool_result = client.call_tool(tool_name, args)
  206.                 except Exception as exc:  # noqa: BLE001
  207.                     print(
  208.                         f"[Console-Host] 调用 MCP Server '{server_name}' 工具 '{tool_name}' 失败: {exc}"
  209.                     )
  210.                     continue
  211.                 print(
  212.                     f"[Console-Host] 工具 '{tool_name}' 返回结果: {tool_result}"
  213.                 )
  214.                 messages.append(
  215.                     {
  216.                         "role": "tool",
  217.                         "tool_call_id": tc.id,
  218.                         "content": json.dumps(tool_result, ensure_ascii=False),
  219.                     }
  220.                 )
  221.             try:
  222.                 response = oa_client.chat.completions.create(
  223.                     model=model,
  224.                     messages=messages,
  225.                 )
  226.             except Exception as exc:  # noqa: BLE001
  227.                 print(f"[Console-Host] 第二次调用 OpenAI 出错: {exc}")
  228.                 continue
  229.             final_msg = response.choices[0].message
  230.             answer = final_msg.content or ""
  231.         else:
  232.             answer = msg.content or ""
  233.         print(f"助手:{answer}")
  234.         messages.append({"role": "assistant", "content": answer})
  235. if __name__ == "__main__":
  236.     main()
复制代码
mcp_multi.json
  1. [
  2.   {
  3.     "mcpServers": {
  4.       "context7": {
  5.         "command": "npx",
  6.         "args": [
  7.           "-y",
  8.           "@upstash/context7-mcp",
  9.           "--api-key",
  10.           "ctx7sk-9db997d9-9eeb-4c4b-9b0d-7b4f2656a8db"
  11.         ]
  12.       }
  13.     }
  14.   },
  15.   {
  16.     "mcpServers": {
  17.       "time": {
  18.         "command": "uvx",
  19.         "args": [
  20.           "mcp-server-time",
  21.           "--local-timezone=America/New_York"
  22.         ]
  23.       }
  24.     }
  25.   },
  26.   {
  27.     "mcpServers": {
  28.       "howtocook-mcp": {
  29.         "command": "npx",
  30.         "args": [
  31.           "-y",
  32.           "howtocook-mcp"
  33.         ]
  34.       }
  35.     }
  36.   }
  37. ]
复制代码
可以自行去mcp.so官网找一些可以启本地进程的mcp
demo_math_server.py
  1. import asyncio
  2. import random
  3. from typing import Annotated
  4. from mcp.server.fastmcp import FastMCP
  5. mcp = FastMCP("demo-math")
  6. @mcp.tool()
  7. async def add(
  8.     a: Annotated[float, "第一个数字"],
  9.     b: Annotated[float, "第二个数字"],
  10. ) -> Annotated[float, "a + b 的结果"]:
  11.     """把两个数字相加。"""
  12.     await asyncio.sleep(0)  # 协程占位
  13.     return a + b
  14. @mcp.tool()
  15. async def random_int(
  16.     minimum: Annotated[int, "最小整数(包含)"],
  17.     maximum: Annotated[int, "最大整数(包含)"],
  18. ) -> Annotated[int, "生成的随机整数"]:
  19.     """在给定区间内生成一个随机整数。"""
  20.     await asyncio.sleep(0)
  21.     if minimum > maximum:
  22.         minimum, maximum = maximum, minimum
  23.     return random.randint(minimum, maximum)
  24. def main() -> None:
  25.     """
  26.     demo 数学 MCP Server:
  27.     - 工具 add(a, b)
  28.     - 工具 random_int(minimum, maximum)
  29.     通过 stdio 运行,满足 MCP 协议,可被 SDK 客户端连接。
  30.     """
  31.     mcp.run()
  32. if __name__ == "__main__":
  33.     main()
复制代码
demo_text_server.py
  1. import asyncio
  2. from typing import Annotated
  3. from mcp.server.fastmcp import FastMCP
  4. mcp = FastMCP("demo-text")
  5. @mcp.tool()
  6. async def upper(
  7.     text: Annotated[str, "要转换为大写的字符串"],
  8. ) -> Annotated[str, "大写结果"]:
  9.     """把字符串转成大写。"""
  10.     await asyncio.sleep(0)
  11.     return text.upper()
  12. @mcp.tool()
  13. async def word_count(
  14.     text: Annotated[str, "要统计的文本"],
  15. ) -> Annotated[int, "按空格分词后的词数"]:
  16.     """统计一句话里有多少个词(按空格粗略切分)。"""
  17.     await asyncio.sleep(0)
  18.     return len(text.split())
  19. def main() -> None:
  20.     """
  21.     demo 文本 MCP Server:
  22.     - 工具 upper(text)
  23.     - 工具 word_count(text)
  24.     通过 stdio 运行,满足 MCP 协议,可被 SDK 客户端连接。
  25.     """
  26.     mcp.run()
  27. if __name__ == "__main__":
  28.     main()
复制代码
随便写了两个内置工具,可以自行修改测试
dev.env
  1. OPENAI_API_KEY=sk-proj-xxxx
  2. OPENAI_MODEL=gpt-4o
复制代码
四、 典型的 MCP 使用流程


  • 用户配置 MCP Server 信息: 用户在 AI 应用(Host)的配置中(例如一个 mcp.json 文件)定义了有哪些 MCP Server,以及如何连接它们(是本地进程 stdio 模式还是远程 URL+SSE 模式)。
  • Host 建立连接并获取工具列表:

    • Host 读取配置后,通过其内部的 MCP Client 建立与 MCP Server 的连接(启动本地进程或连接远程 URL)。
    • Client 按照 MCP 协议向 Server 发送 tools/list 请求。
    • MCP Server 响应请求,返回其内部注册的所有工具的列表,包括每个工具的名称、描述和参数的 JSON Schema。

  • Host 映射工具为 LLM 可调用格式: Host 接收到 MCP Server 返回的工具列表后,将这些工具的元数据转换成 LLM(如 OpenAI 的 Function Calling 机制)可以理解和调用的 tools 格式。这相当于“将 MCP 世界的工具安装进模型的插件系统”。
  • 用户对话,LLM 判断是否需要工具:

    • 用户与 AI 应用进行对话。
    • Host 将用户输入和已映射的工具定义一同发送给 LLM(通过 chat.completions API 调用,并带上 tools 参数)。
    • LLM 根据对话内容和工具定义,判断是否需要调用某个工具来完成任务。如果需要,模型会返回一个 tool_calls 响应,指明它“想用 MCP 里的某个工具”以及相应的参数。

  • Host 用 MCP Client 调 tools/call 真正执行工具:

    • 当 Host 收到 LLM 返回的 tool_calls 时,它会通过 MCP Client 再次向 MCP Server 发送 tools/call 请求,真正执行模型指定的工具,并传入模型生成的参数。
    • MCP Server 执行相应的内部工具,并将执行结果返回给 MCP Client。

  • Host 把结果塞回对话,再让 LLM 给最终回答:

    • Host 收到工具执行结果后,将这个结果作为新的上下文信息,再次塞回给 LLM(作为 tool_outputs)。
    • LLM 结合之前的对话历史和工具执行结果,生成最终的回答并返回给用户。

举例来说:
用户在 Cursor(Host)中配置了一个新的 MCP Server。Cursor 内置的 MCP Client 会立即启动这个 MCP 进程(如果是本地模式)或建立远程连接。Host 随后通过 Client 拉取 MCP Server 暴露的所有工具,并将它们转换为 OpenAI 的 tools 格式。当用户提问时,模型可能会决定调用一个 MCP 工具(例如 web_search),Host 通过 tools/call 将请求转发给 MCP Server。Server 执行搜索并返回结果,Host 再将搜索结果提供给模型,让模型生成最终的最终回答。
五、 MCP 与传统插件机制的区别

mcp实际就是提供了一种标准化的访问外部数据源的方式,他能做的插件也能做,但是插件与模型厂商挂钩,协议格式各不相同,对接复杂,mcp简化了这种流程,且更加开放 标准了 别人写好了mcp工具我们直接就能用。
在构建基于大型语言模型(LLM)的应用时,理解 function_call 和 Model Context Protocol (MCP) 这两个概念至关重要。它们虽然都与工具集成相关,但作用的“层级”和解决的问题截然不同。
1. function_call 是“LLM API 级别”的能力

function_call(或类似的工具调用机制,如 Anthropic 的 tool_use)是 LLM 提供商在其 API 中内置的一种能力。它解决的核心问题是:“这个模型如何在一次 API 调用里请求某个函数、传参,并让调用者拿到结果?”
对于开发者来说,使用 function_call 时,你需要自己搞定以下这些“手工工作”:

  • 工具发现: 去哪里找到这些可供 LLM 调用的函数(工具)?多个 server、几十上百个工具,怎么声明、分类、动态启用/禁用?
  • 工具传输和生命周期: 这些函数(工具)是本地运行的、需要通过远程 HTTP API 调用的,还是通过命令行接口(CLI)执行的?连接、心跳、长任务、cancel、错误码处理?
  • 服务厂商差异化处理: 如果有多个工具服务提供商,它们的 API schema/鉴权/错误码可能各不相同,如何统一处理?
因此,在没有 MCP 这样的协议层时,你的 AI 应用(Host)里,实际上做了很多繁琐且定制化的工作:

  • 从 JSON 配置文件或特定的 MCP Server 拉取工具元数据。
  • 把它们“翻译”成 OpenAI 或其他 LLM 平台所要求的 tools(Function Calling)格式。
  • 收到 tool_calls 再自己路由到不同的 server 去执行。
2. MCP 是“工具/Agent 生态层”的协议

Model Context Protocol (MCP) 则是一个更高层级的协议,它旨在解决更宏观的问题:“世界上所有想给 LLM 用的工具/Agent,要用什么统一的方式把自己挂出来,让任何 AI 应用都能方便地发现和使用?”
MCP 协议提供了一套标准化的机制,包括:

  • 外部工具能力标准化(发现 + 传输)

    • 工具发现:mcpServers 配置 + tools/list → Host 不需要为每个服务商自定义“列出我有哪些能力”的协议。
    • tools/call + JSON‑RPC over stdio/HTTP/SSE → 不同传输方式下,语义和报文结构是一致的。

  • 工具协议处理(鉴权 / 请求 / 响应 / 错误码)

    • 各家服务商在自己的 MCP Server 里,把乱七八糟的内部 API(鉴权、数据结构、错误码)统统“翻译”为统一的 MCP 形状;
    • Host 只跟 MCP Server 说话,看到的是统一的:

      • initialize / tools/list / tools/call
      • 标准 JSON‑RPC 报文
      • 标准 error.code / error.message / error.data。


  • 多端复用

    • 同一个 MCP Server,可以被不同的 AI 应用(Host),如 Cursor、Claude Desktop 或你自己的自定义 Host,直接连接并复用,极大地提高了工具的生态复用性。

对于 AI 应用(Host)来说,有了 MCP 这一层协议之后,其工作变得更加简化和标准化:

  • 通过client按照mcp协议连上 mcp-server;
  • host连接client获取server的所有工具挂到 llm-function_call 里;
  • 按规范把 tools.call 转发出去就行,不用管每家怎么实现。
可以这么说:在“能不能让模型调工具”这件事上,function_call 理论上都能做到 MCP 能做的事,但两者不在一个层级,MCP 是把一整层东西“标准化 + 外包”了。
总结,function_call 是 LLM 本身具备的“调用函数”的能力,而 MCP 则是一套“如何标准化地组织、发现和调用这些函数”的协议和生态系统。MCP 极大地简化了 Host(AI应用) 在工具集成方面的工作,将复杂性下沉到 Client 和 Server 层,从而促进了 AI 工具生态的繁荣和互操作性。

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

您需要登录后才可以回帖 登录 | 立即注册