MCP 一文搞懂:从 Host、Client 到 Server,FastMCP 手把手跑通

发布时间:2026/10/8 17:52:22
MCP 一文搞懂:从 Host、Client 到 Server,FastMCP 手把手跑通 1. 从一次 Agent 工具接入的崩溃说起如果你正在做 Agent 或者 AI 应用大概率经历过这样的场景一开始只让模型调一个天气接口注册个 Function Calling 就完事了。后来需求像滚雪球一样加进来——查 MySQL、搜 Elasticsearch、操作 GitHub、读本地文件、调内部订单系统。这时候你会发现代码里开始出现一堆if model openai ... elif model anthropic ...和if tool mysql ... elif tool github ...的分支判断模型越多、工具越多集成复杂度呈乘法增长。MCPModel Context Protocol就是来解决这个问题的。它给 AI 应用和外部工具之间定义了一套统一协议你可以把它理解成 AI 世界里的 USB-CAgent 不再直连各种 SDK而是通过 MCP Client 连到 MCP ServerServer 后面接数据库、浏览器、GitHub 还是公司内部 APIAgent 完全不用关心。同样Server 也不关心前面是 GPT、Claude 还是 Gemini。这篇文章面向初次接触 MCP 的开发者用 Host、Client、Server 三个角色把协议全貌拆开然后以 FastMCP 为例手把手跑通一条最小可运行链路写一个同时包含 Tool、Resource、Prompt 的 Server配好 Host 侧的mcp_config.json用 Client 发一次真实请求最后把常见的报错逐条排掉。全程本地可复现不需要任何远程服务。我试过把 MCP 当成又一个 Function Calling 封装来理解结果卡了很久。真正想通的关键是Function Calling 是模型怎么表达我要调用工具MCP 是 Host 怎么标准化地找到并调用这个工具。前者靠近 LLM后者靠近工具生态两者是上下游关系不是替代关系。2. Host、Client、Server 三个角色到底谁管什么很多人第一次看 MCP 架构最容易混淆的就是 Host 和 Client 的区别。实际上 MCP 的核心可以拆成三个角色职责边界非常清晰。2.1 Host真正的大脑和总调度中心Host 是承载 LLM、用户会话、Agent Loop 和 MCP Client 的应用程序。一个 AI IDE、桌面助手或者你自己写的 Agent都可以成为 Host。它负责接收用户 Query、保存聊天上下文、调用 LLM、把 MCP Server 暴露的 Tool 转换成模型能理解的 Tool Schema、判断模型返回的是普通文本还是工具调用、调用对应的 MCP Client、把 Tool Result 再交还给 LLM同时还要管权限、确认弹窗、安全策略和多个 Server 的生命周期。所以千万别把 Host 理解成一个简单转发器。真正的 Agent Loop 发生在 Host用户问题进来Host 交给 LLMLLM 决定是否调用工具如果调用就走 MCP Client → MCP Server → Tool Result再回到 LLM 生成最终答案。这个循环里 Host 是唯一的调度者。2.2 ClientHost 与某个 Server 之间的协议适配层Client 的职责更底层。它负责建立与 MCP Server 的连接、处理传输层、发送 MCP 请求、接收 Response、做 JSON-RPC 编解码、做 Tool/Resource/Prompt 能力发现以及调用tools/call、resources/read、prompts/get还要管理超时和连接关闭。一个 Host 通常不是只有一个 MCP Client而是一个 Server 对应一个逻辑 Client Connection。比如 Host 下面挂着 filesystem client、mysql client、github client各自连各自的 Server。这种一对一的映射关系是理解 MCP 连接模型的关键。2.3 Server真正提供能力的一侧MCP Server 是把已有系统能力包装成 MCP 标准接口的适配器。它可以连接数据库、REST API、RPC、文件系统、浏览器、Shell、企业知识库、Git、Kubernetes、云平台、内部微服务。Server 不需要知道用户是谁也不必知道前面具体用哪个 LLM它只需要遵守协议你问我有哪些工具我返回tools/list你调用某个工具我处理tools/call你读取资源我处理resources/read。2.4 三种原语的职责划分Server 最值得先掌握的是三种核心原语FastMCP 里对应mcp.tool、mcp.resource、mcp.prompt。它们的职责划分如下原语谁主要控制用来干什么ToolModel执行动作比如查天气、创建订单、发邮件ResourceApplication提供上下文数据比如读配置、读文件、读数据库 schemaPromptUser提供可复用提示模板比如代码审查、写测试Tool 是 ActionResource 是读取Prompt 是模板这三个概念一定不要混。Tool 由模型决定调用Resource 由应用读取并放进上下文Prompt 更接近用户主动选择的模板。3. 用 FastMCP 写一个最小可运行 Server理论看得再多不如自己写一次。这一节我们用 FastMCP 写一个同时包含 Tool、Resource、Prompt 的 Server然后配好 Host 侧的mcp_config.json把整条链路跑起来。3.1 环境准备建议用 Python 3.10 配合 uv。创建项目mkdir mcp-demo cd mcp-demo uv init uv add fastmcp如果不用 uv直接pip install fastmcp也可以。项目结构很简单一个server.py加一个pyproject.toml就够了。3.2 完整 Server 代码新建server.py把三种原语都写进去from fastmcp import FastMCP mcp FastMCP(DemoServer) mcp.tool def add(a: int, b: int) - int: 计算两个整数之和 return a b mcp.resource(config://app) def get_app_config() - str: 读取应用配置 return {app_name:MCP Demo,env:dev} mcp.resource(users://{user_id}) def get_user(user_id: str) - str: 根据用户 ID 获取用户信息 return fuser_id{user_id}, nameuser_{user_id} mcp.prompt def code_review(code: str) - str: 生成代码审查提示词 return f请检查以下代码的 Bug、安全和性能问题\n\n{code} if __name__ __main__: mcp.run()mcp.tool会把普通 Python 函数注册成 MCP ToolFastMCP 根据函数名、类型注解、Docstring 和参数默认值自动生成 Tool Schema。mcp.resource(users://{user_id})是一个 Resource TemplateClient 通过resources/templates/list发现它然后读取users://10001这样的具体 URI。mcp.prompt不执行外部动作只生成一段参数化的 Prompt。3.3 Host 侧配置mcp_config.jsonServer 写完以后Host 怎么知道有哪些 MCP Server这就是 Host Configuration 要解决的问题。需要强调mcp_config.json并不是 MCP Core Protocol 强制规定的唯一格式不同 Host 的文件名和字段可能不同但{mcpServers: {}}这个结构已经成为非常常见的工程约定。最基础的 Python 启动方式{ mcpServers: { demo: { command: python, args: [/absolute/path/mcp-demo/server.py] } } }实际项目里更推荐用 uv因为一个 MCP Server 通常有自己独立的 Python 版本、依赖和启动命令uv 能把这些环境问题封装起来{ mcpServers: { demo: { command: uv, args: [ run, --directory, /absolute/path/mcp-demo, python, server.py ], env: { LOG_LEVEL: INFO } } } }这里有个经常踩的坑不要想当然地认为 stdio 子进程一定继承 Host 的全部环境变量。stdio 子进程使用受控的环境变量集合需要的敏感变量应明确通过env传入。比如 Server 要访问外部天气 API就得在配置里写WEATHER_API_KEY: ${WEATHER_API_KEY}Server 里用os.environ[WEATHER_API_KEY]读取。3.4 三件套对照Base URL、Key、Model ID如果你打算把 MCP Server 接到远程模型服务上配置里必须写全三件套Base URL、API Key、Model ID。以 TaoToken 为例Base URL 用https://taotoken.net/apiKey 在控制台的 API Keys 页面生成Model ID 按你实际要用的模型填。这三者缺一不可少任何一个都会在请求阶段报错。很多新手只填了 Key 忘了 Base URL结果请求打到默认地址上报 401 或者连接失败排查半天才发现是配置漏项。4. 验证请求从 tools/list 到 tools/call 的完整链路Server 和配置都就绪了接下来要验证它真的能用。开发阶段不建议手敲 JSON-RPC直接用 FastMCP Client 最省事。4.1 用 Client 列出工具并调用新建client_demo.pyimport asyncio from fastmcp import Client async def main(): client Client(server.py) async with client: tools await client.list_tools() print(tools:, tools) resources await client.list_resources() print(resources:, resources) prompts await client.list_prompts() print(prompts:, prompts) result await client.call_tool(add, {a: 100, b: 200}) print(result:, result) asyncio.run(main())运行uv run python client_demo.py预期能看到add工具、config://app资源、code_review提示词以及工具调用结果300。FastMCP Client 会自动处理 Server 连接和 MCP 协议细节业务代码只需要调list_tools()、list_resources()、list_prompts()和call_tool()。4.2 底层 JSON-RPC 长什么样如果你想理解协议本身可以看看 Client 背后实际发的是什么。能力发现阶段Client 发{ jsonrpc: 2.0, id: 2, method: tools/list }Server 返回{ jsonrpc: 2.0, id: 2, result: { tools: [ { name: add, description: 计算两个整数之和, inputSchema: { type: object, properties: { a: {type: integer}, b: {type: integer} }, required: [a, b] } } ] } }调用阶段Client 发{ jsonrpc: 2.0, id: 3, method: tools/call, params: { name: add, arguments: {a: 1024, b: 2048} } }Server 执行函数后返回结果。注意这里有个关键点模型层返回的 Tool Call 还不是 MCP JSON-RPCHost 拿到模型的{name: add, arguments: {a: 1024, b: 2048}}之后找到这个工具属于哪个 Server再通过 MCP Client 发出上面的tools/call。这个翻译动作发生在 Host/Agent 与 MCP Client 这一层。4.3 经典工作流与 2026 新规范的区别你在大量项目源码里会看到这样的流程initialize→notifications/initialized→tools/list→resources/list→resources/templates/list→prompts/list→tools/call。这是经典的 MCP Session 工作流initialize用于协议版本协商、Client Capability 告知和身份信息交换notifications/initialized是通知没有 id不需要 Response表示初始化完成。但从 2026-07-28 规范开始MCP 进一步无状态化删除了initialize和notifications/initialized握手每次请求自己携带protocolVersion、clientCapabilities、clientInfo等元数据并增加server/discover用于能力发现。为什么这么改因为传统建立连接 → initialize → 保存 Session State → 后续请求依赖 Session的模式对 Serverless、多实例、Load Balancer、Kubernetes 横向扩展并不友好。无状态以后每个请求自描述Server 更容易扩展。所以你现在看到旧项目用 initialize、新规范用 per-request metadata两种实现同时存在完全正常。5. 常见报错逐条排查跑通链路的过程中最容易卡在几个典型报错上。这一节把真实遇到的错误和排查动作列出来。5.1 401 Unauthorized这个报错通常出现在远程模型服务调用阶段。原因一般是 API Key 没填、填错或者 Base URL 和 Key 不匹配。排查动作先确认mcp_config.json或环境变量里的 Key 是否正确再确认 Base URL 是不是https://taotoken.net/api最后确认 Model ID 是否在服务端支持列表里。三件套任何一项缺失都会导致 401。如果 Key 是从环境变量读的检查env字段有没有正确传入stdio 子进程不会自动继承 Host 的全部环境变量。5.2 local proxy failed / connection refused这个报错一般出现在 Client 连 Server 的阶段。常见原因Server 进程没启动、command路径写错、args里的绝对路径不对。排查动作先在终端手动执行配置里的command和args看能不能正常启动。如果手动能跑但 Host 里报错多半是路径问题——mcp_config.json里的路径必须是绝对路径相对路径在不同工作目录下会失效。另外检查uv run --directory后面的目录是否存在。5.3 reading choices / 返回结构解析失败这个报错通常出现在模型返回结果解析阶段。原因可能是模型返回的 JSON 结构不符合预期或者 Tool Result 的格式和 Host 期望的不一致。排查动作先打印原始返回内容确认choices字段是否存在。如果是自定义 Server 返回的 Tool Result检查是否符合 MCP 规范——成功时外层是result失败时如果是业务错误应该用result加isError: true而不是直接返回 JSON-RPCerror。5.4 OAuth / 认证流程报错如果 Server 需要 OAuth 认证报错通常出现在 token 获取或刷新阶段。排查动作确认 OAuth 配置的 client_id、client_secret、redirect_uri 是否和提供方一致确认 token 是否过期。远程 HTTP Server 必须考虑认证这是生产环境的基本要求。5.5 两类错误的本质区别MCP 最容易被忽视的一点是Protocol Error 不等于 Tool Execution Error。前者表示这次 MCP 调用本身就不成立比如 tool 不存在、JSON-RPC 格式错误、request schema 不合法、协议版本不支持这类错误通常由 Client/Host 优先处理记录日志、判断 Server 是否失效、决定是否重连LLM 通常无需直接感知。后者表示工具已经正常进入执行阶段但业务执行失败比如外部 API 超时、参数业务校验失败这类错误通过{result: {content: [...], isError: true}}返回给 LLM让模型根据错误信息修正参数、重试或询问用户。一个推荐的 Server 错误写法是让信息具备可操作性。不要只返回error或failed而是返回Order 10001 does not exist.或Upstream API timed out after 5 seconds. Retry is allowed.或start_date must be earlier than end_date.。因为这个错误最终很可能进入 LLM Context错误信息越明确Agent 自愈能力越强。6. 把 MCP 接入你的日常开发流跑通最小链路之后下一步就是把它用起来。如果你主要做长期编码或者 Agent 开发建议直接上 Coding Plan把 MCP Server 的配置和模型调用统一管理起来省得每次手动改mcp_config.json。配置入口在 https://taotoken.net/api-keys 接入文档在 https://taotoken.net/doc 模型对话调试可以用 https://taotoken.net/chat Coding Plan 在 https://taotoken.net/coding-plan 。生产环境还有几件事必须补上所有外部调用设置 Timeout只对幂等可恢复错误做 Retry接 OpenTelemetry 做链路追踪远程 HTTP 必须做 Auth加 Rate Limit 防止 Tool 被高频调用服务端做 Input Validation 和 Output Validation高风险操作要求用户确认Secret 和代码配置文件解耦Tool Description 写清楚输入输出和副作用。永远不要因为参数来自 LLM 就跳过服务端校验Tool 是真正进入业务系统的边界它和传统 Web API 一样需要鉴权、校验、限流、审计、超时和异常处理。把 Server 写出来、配置配好、请求验证通过这三件事亲手做完MCP 基本就从看懂了变成真正会用了。它本身并不神秘真正做的事情就是在快速膨胀的 Agent 世界里给模型如何连接外部能力规定一套大家都能说的语言。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询