MCP 教程:MCP Server,MCP Client,AI模型之间的关系

0. 本篇目标

这篇专门解决 3 个问题:

  1. MCP ServerMCP ClientAI 模型 到底是谁负责什么。
  2. Server 部署好以后,应该怎么“被调用”。
  3. 给出一个可以直接抄的 MCP Client 示例(代码 + 调用链)。

1. 先把三者关系讲清楚

1.1 三个角色的职责

角色 本质 负责什么 不负责什么
MCP Server 能力提供方 暴露 tools/resources/prompts,执行具体动作并返回结果 不直接决定“何时调用”
MCP Client 协议执行方 连接 Server、完成握手、发起 tools/call、回传结果、做权限/超时控制 不做业务推理
AI 模型 推理决策方 根据用户意图和工具描述,决定“要不要调用哪个工具” 不直接连你的数据库/系统(要经 Client)

一句话:
模型做决策,Client 执行协议,Server 提供能力。

1.2 实际调用链(最常见)

用户提问
  -> Host 应用把上下文交给 AI 模型
  -> 模型决定调用某个 MCP Tool
  -> Host 内的 MCP Client 发起 tools/call
  -> MCP Server 执行并返回结果
  -> MCP Client 把结果回给模型
  -> 模型生成最终答案给用户

重点:

  • 模型本身通常不会“直接连”你的 MCP Server。
  • 真正发请求的是 Host 应用里的 MCP Client(例如 Codex/IDE/你自己写的 Agent)。

2. “是 AI 调用吗?”的准确答案

是,也不是:

  1. 是 AI 调用:
    模型决定要调用哪个工具(决策层)。

  2. 不是 AI 直接调用:
    真正发起网络/进程调用的是 MCP Client(执行层)。

你可以把它理解为:

  • AI 是“调度员”
  • Client 是“执行员”
  • Server 是“能力工位”

3. MCP Client 需要掌握的核心知识

3.1 连接与生命周期

  • 建连后先 initialize
  • 然后发送 notifications/initialized
  • 再进行 tools/listresources/listtools/call

3.2 两种常见传输

  • stdio:本机子进程方式,延迟低,适合本地插件化。
  • streamable-http:远程 URL 方式,适合多客户端复用和服务化部署。

3.3 Client 的工程职责(生产环境)

  • 工具发现缓存:定期刷新 tools/list
  • 参数校验:按 JSON Schema 组装参数。
  • 超时/重试/取消:避免工具调用卡死。
  • 权限控制:高风险工具加人工确认或策略拦截。
  • 观测性:记录 request_id、耗时、错误码、工具名。

3.4 自动调用 vs 强制调用

  • 自动调用:模型自己决定何时调用工具。
  • 强制调用:你在代码里直接调用 tools/call(不等模型决策)。

建议:
默认用自动调用提升自然交互;关键路径(例如固定流水线任务)用强制调用更可控。


4. 示例 A:把 Codex 当 MCP Client(配置式)

如果你已经有一个 HTTP MCP Server,例如:

  • http://127.0.0.1:8000/mcp

可在 ~/.codex/config.toml 中配置:

[mcp_servers.my_mcp]
url = "http://127.0.0.1:8000/mcp"

或使用 stdio 类型服务:

[mcp_servers.my_local_stdio]
command = "python"
args = ["C:/workspace_2/MediaCrawler/path/to/server.py"]

然后你在对话里说:
请调用 my_mcp 的 xxx 工具做 ...

背后发生的事:

  1. Codex 作为 Host,读取 MCP 配置。
  2. 内置 MCP Client 建连并发现工具。
  3. 模型决策调用工具。
  4. Client 执行调用并把结果回传给模型。

5. 示例 B:自建一个最小 MCP HTTP Client(Python)

下面例子展示“你自己写 Client”如何直接调用 MCP Server。

# mcp_http_client_demo.py
import requests


class MCPHttpClient:
    def __init__(self, url: str, timeout: int = 30):
        self.url = url
        self.timeout = timeout
        self._id = 0
        self._session = requests.Session()

    def _next_id(self) -> int:
        self._id += 1
        return self._id

    def request(self, method: str, params: dict | None = None):
        payload = {
            "jsonrpc": "2.0",
            "id": self._next_id(),
            "method": method,
        }
        if params is not None:
            payload["params"] = params

        resp = self._session.post(self.url, json=payload, timeout=self.timeout)
        resp.raise_for_status()
        data = resp.json()

        if "error" in data:
            raise RuntimeError(f"MCP error: {data['error']}")
        return data.get("result")

    def notify(self, method: str, params: dict | None = None):
        payload = {
            "jsonrpc": "2.0",
            "method": method,
        }
        if params is not None:
            payload["params"] = params

        resp = self._session.post(self.url, json=payload, timeout=self.timeout)
        resp.raise_for_status()


if __name__ == "__main__":
    client = MCPHttpClient("http://127.0.0.1:8000/mcp")

    # 1) initialize
    init_result = client.request(
        "initialize",
        {
            "protocolVersion": "2025-06-18",
            "clientInfo": {"name": "demo-client", "version": "0.1.0"},
            "capabilities": {},
        },
    )
    print("initialize:", init_result)

    # 2) initialized notification
    client.notify("notifications/initialized")

    # 3) tools/list
    tools = client.request("tools/list")
    print("tools/list:", tools)

    # 4) tools/call(示例:调用 add)
    result = client.request(
        "tools/call",
        {
            "name": "add",
            "arguments": {"a": 2, "b": 3},
        },
    )
    print("tools/call:", result)

运行:

pip install requests
python mcp_http_client_demo.py

说明:

  • 这是“强制调用”路径,不依赖模型决策。
  • 如果你的 Server 是有状态会话模式,需要按服务端要求保存并回传会话标识。

6. 把 AI 模型接进来(自动调用工具)

当你要“让模型自动决定是否调用工具”时,Client 循环通常是:

1) MCP Client 获取 tools/list
2) 把工具 schema 转成模型可识别的 tool 定义
3) 把用户问题 + tools 发送给模型
4) 若模型返回 tool call:
   -> MCP Client 执行 tools/call
   -> 把 tool result 回填给模型
5) 循环直到模型返回最终自然语言答案

关键点:

  • 模型负责“决策与编排”。
  • Client 负责“协议与执行闭环”。
  • Server 负责“能力与结果”。

7. 生产实践建议(MCP Client 侧)

  1. 超时分级:connect timeouttool timeout 分开配置。
  2. 重试策略:只对幂等工具重试,非幂等工具要谨慎。
  3. 并发治理:限制同一工具并发,避免把下游打崩。
  4. 熔断降级:Server 不可用时给模型明确 fallback 文本。
  5. 审计日志:记录 user_intent -> tool_name -> arguments -> result_summary
  6. 权限分层:读操作默认放行,写操作加审批。
  7. 版本治理:工具 schema 变更要做向后兼容或版本号隔离。

8. 常见误区

误区 1:Server 部署好就会自动被模型调用
更正:必须有 Client 连接并把工具暴露给模型,模型才有机会调用。

误区 2:模型可以直接访问你的内网系统
更正:模型通常通过 Client 间接调用,不应直连生产系统。

误区 3:只要 tools/call 能跑就算完成
更正:还需要超时、权限、日志、错误恢复,才能生产可用。


9. 一页结论

  1. MCP Server 提供能力。
  2. MCP Client 连接和执行协议。
  3. AI 模型 负责决策与编排。
  4. “AI 调用工具”本质是:模型做决定,Client 去执行。

这就是你部署 MCP 后真正的调用方式。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐