news 2026/9/6 2:02:00

MCP 入门:从普通函数到可运行的 MCP Server 与 Client

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MCP 入门:从普通函数到可运行的 MCP Server 与 Client

本文面向了解 Python 基础、希望理解 AI 工具调用的读者。全文用“查询订单状态”作为例子,先解释 MCP 解决什么问题,再拆解架构、能力类型和调用流程,最后用 Python 完成一个可以本地运行的 MCP Server 与 Client。示例使用模拟数据,不需要数据库、模型密钥或网络服务。

一、先从一个普通函数开始

假设用户对 AI 说:

帮我查一下订单 A1024 发货了吗?

大模型能够理解这句话,但它并不知道你的订单数据。订单状态可能保存在数据库、订单 API 或企业内部系统中。要回答真实结果,AI 应用必须调用程序,而不是让模型根据常识猜测。

最简单的查询逻辑可以只是一个 Python 函数:

orders = { "A1024": "已发货", "A1025": "待发货", } def get_order_status(order_id: str) -> str: if order_id not in orders: raise ValueError("订单不存在") return orders[order_id] print(get_order_status("A1024")) # 已发货

这个函数本身没有问题。问题出在“连接”上:

  • AI 应用怎样知道这个函数存在?
  • 模型怎样知道参数叫order_id,并且它是字符串?
  • 应用怎样启动或连接这个程序?
  • 调用结果怎样返回给模型?
  • 订单不存在、权限不足或调用超时时,谁负责处理?

当然可以为每个系统单独设计接口。但当一个 AI 应用要连接订单、日历、知识库和文件系统时,开发者就要重复处理工具描述、连接管理、参数传递和错误返回。MCP 试图把这些通用的连接规则标准化。

二、MCP 到底是什么

MCP 是Model Context Protocol的缩写,中文通常译为“模型上下文协议”。它是一套让 AI 应用与外部数据、工具和提示模板进行标准化交互的协议。

可以把它理解为 AI 应用和外部能力之间的一种通用插座:

AI 应用 <--统一协议--> MCP Server <--业务代码--> 数据库 / API / 文件 / 系统

这个类比只强调“连接方式统一”,不代表插上以后就自动拥有权限,也不代表所有业务系统都能零配置兼容。认证、授权、数据校验、业务规则和部署方式,仍然需要开发者设计。

MCP 也不等于以下概念:

  • 它不是大模型。模型负责理解问题、决定是否需要调用工具并组织回答。
  • 它不是业务系统。真正的订单查询、库存扣减或文件读取仍由业务代码执行。
  • 它不是 Agent。Agent 是一种应用形态,MCP 只是其中可能使用的连接协议。
  • 它不是安全边界。是否允许调用、能读到哪些数据,最终仍由 Host 和 Server 的权限控制决定。

MCP 的核心价值,是让“能力如何被发现、描述、调用和返回”有一套共同语言。

三、五个角色:用户、模型、Host、Client 和 Server

实际理解 MCP 时,最容易混淆的是角色。可以按下面的关系来记:

角色主要职责订单示例
用户提出目标,必要时确认敏感操作“查询 A1024”
模型理解自然语言,选择是否调用以及调用哪个工具识别出订单号并选择查询工具
HostAI 应用本身,协调模型、用户界面、权限和多个连接聊天应用或企业 AI 助手
ClientHost 中负责连接某个 MCP Server 的组件订单连接器
Server暴露工具、资源和提示模板,并执行对应代码订单 MCP Server

一个 Host 可以同时包含多个 Client,每个 Client 连接一个或多个 MCP Server。Server 可以是本机进程,也可以是远程服务;这里的“Server”指协议中的服务端角色,不一定意味着单独购买一台服务器。

订单查询的结构大致如下:

用户 │ ▼ Host(AI 应用) <------> 大模型 │ └── Client │ MCP 请求与响应 ▼ 订单 MCP Server │ ▼ 订单 API / 数据库

关键点是:模型通常不会直接连接数据库。模型提出结构化的调用意图,Host 决定是否允许,Client 负责协议通信,Server 执行业务逻辑。

四、Server 能提供什么

MCP Server 最常见的三类能力是 Tools、Resources 和 Prompts。它们都可以被发现和读取,但用途不同。

能力解决的问题订单示例是否通常会产生副作用
Tool 工具“我可以执行什么操作?”查询订单、取消订单可能有,也可能没有
Resource 资源“我可以读取什么上下文?”订单状态说明、配置文档通常是读取
Prompt 提示模板“这类任务可以使用什么指令模板?”生成订单客服回复的模板本身不执行业务操作

1. Tool:可调用的操作

Tool 是最接近函数的能力。它一般有名称、说明、参数结构和执行结果。例如:

工具名:get_order_status 说明:根据订单编号查询订单状态,仅查询,不修改订单 参数:order_id,字符串,必填

模型可以根据工具说明生成调用参数,但应用仍应检查参数和权限。工具描述写得越清晰,模型越容易正确使用;不过清晰的描述不能代替服务端校验。

2. Resource:可读取的上下文

Resource 用来提供模型或应用可以读取的资料。它通常由 URI 标识,例如order://status-guide。这里的 URI 是资源名称,不一定是网页地址,也不代表一定要通过浏览器访问。

订单状态说明适合放在 Resource 中,因为它是供应用参考的知识:

待发货:尚未交给物流。 已发货:已交给物流,但不代表已经签收。

Resource 不应被简单理解为“只读工具”。它们的发现、读取和呈现方式不同,具体行为取决于 Host 的实现。

3. Prompt:可复用的提示模板

Prompt 是一段结构化、可复用的交互模板。例如客服场景可能需要:

请先查询订单的真实状态,再用简洁中文回复客户。 如果查询失败,请明确说明无法确认,不要猜测发货情况。

读取 Prompt 只会得到提示内容,不会自动调用订单工具,也不会自动生成最终答案。Host 可以把它展示给用户,也可以将它纳入后续对话流程。

五、一个最小可运行的 MCP Server

下面使用 Python MCP SDK 中常见的FastMCP接口。为了让示例容易复现,订单数据仍然放在内存字典中。

将代码保存为order_server.py

from mcp.server.fastmcp import FastMCP mcp = FastMCP("订单助手") orders = { "A1024": "已发货", "A1025": "待发货", } @mcp.tool() def get_order_status(order_id: str) -> str: """根据订单编号查询订单状态,仅查询,不修改订单。""" status = orders.get(order_id) if status is None: raise ValueError(f"订单不存在:{order_id}") return status @mcp.resource("order://status-guide") def status_guide() -> str: """提供订单状态的含义说明。""" return "待发货:尚未交给物流;已发货:已交给物流,但不代表已签收。" @mcp.prompt() def reply_to_customer(order_id: str) -> str: """生成订单客服回复前的提示模板。""" return ( f"请先查询订单 {order_id} 的真实状态,再用简洁中文回复客户。" "如果查询失败,请说明无法确认,不要猜测发货情况。" ) if __name__ == "__main__": mcp.run(transport="stdio")

逐段看这份代码:

  1. FastMCP("订单助手")创建一个 MCP Server 实例。
  2. @mcp.tool()将普通 Python 函数注册成工具。函数名、文档字符串和类型标注会帮助 SDK 生成工具描述和参数信息。
  3. @mcp.resource(...)注册一个可读取的资源,并为它指定资源标识。
  4. @mcp.prompt()注册一个提示模板。它只返回文本,不会自己执行查询。
  5. mcp.run(transport="stdio")让 Server 通过标准输入输出与 Host 通信。协议消息会经过标准输入输出传递,因此服务端不要用print()输出普通日志;调试日志应写入标准错误或日志文件。

这里的get_order_status()仍然是业务函数。将来接入真实系统时,可以把字典替换为数据库查询或 HTTP API 调用,而对 Host 暴露的工具名称和参数保持稳定。

六、MCP 是怎样完成一次调用的

用户说“查询 A1024”后,一次典型的工具调用可以拆成下面几步:

  1. Host 启动或连接订单 MCP Server,并完成必要的初始化和授权。
  2. Client 向 Server 询问可用工具,获得工具名称、说明和输入参数结构。
  3. Host 把这些工具信息转换成模型能理解的工具定义。
  4. 模型判断需要调用get_order_status,并生成参数{"order_id": "A1024"}
  5. Host 检查工具是否允许当前用户调用,必要时向用户请求确认。
  6. Client 将工具名称和参数发给 Server。
  7. Server 执行 Python 函数,把成功结果或错误返回给 Client。
  8. Host 将结果放回对话上下文,模型根据真实结果生成最终回答。

可以用伪代码表示 Host 的核心协调逻辑:

# 这是流程示意,不是某个模型厂商的完整 API。 tools = await client.list_tools() tool_call = await model.choose_tool(user_message, tools) if application_allows(tool_call): result = await client.call_tool( tool_call.name, tool_call.arguments, ) answer = await model.answer_with_tool_result(result) else: answer = "当前操作未获准执行。"

这段流程体现了一个重要边界:

模型:提出调用意图 Host:决定是否允许 Client:传输协议消息 Server:执行实际代码 模型:解释返回结果

因此,模型说“请调用取消订单”并不等于订单已经取消。是否真正执行,取决于 Host 的审批逻辑以及 Server 的权限和业务校验。

七、用 Python Client 调用 Server

1. 创建虚拟环境并安装依赖

建议使用 Python 3.10 或更高版本,并在单独的示例目录中创建虚拟环境:

python -m venv .venv .\.venv\Scripts\python.exe -m pip install mcp

macOS 或 Linux 可以使用:

python3 -m venv .venv ./.venv/bin/python -m pip install mcp

本文不固定 SDK 的小版本号,因为 SDK 会持续演进。若你要写教程或生产项目,建议在项目的依赖文件中锁定经过验证的版本,并以该版本的 API 为准。

2. 编写 Client

为了聚焦“发现和调用”这件事,下面的 Client 通过 stdio 启动 Server 子进程。这种方式更接近许多本地 AI Host 的连接方式。

将代码保存为demo_client.py

import asyncio from mcp import ClientSession from mcp.client.stdio import StdioServerParameters, stdio_client async def main() -> None: server_params = StdioServerParameters( command=".venv\Scripts\python.exe", args=["order_server.py"], ) async with stdio_client(server_params) as (read, write): async with ClientSession(read, write) as session: await session.initialize() tools = await session.list_tools() print("可用工具:", [tool.name for tool in tools.tools]) result = await session.call_tool( "get_order_status", arguments={"order_id": "A1024"}, ) if result.isError: print("查询失败:", result.content) return print("查询结果:", result.content) if __name__ == "__main__": asyncio.run(main())

这个 Client 做了四件事:启动 Server 子进程、建立标准输入输出连接、初始化会话、发现并调用工具。它没有接入大模型,所以订单号和工具名称由代码直接指定;真实 Host 才会把工具列表交给模型,并把模型生成的调用请求交给 Client。

如果你的系统环境不是 Windows,需要把command改成虚拟环境中的 Python 路径,例如./.venv/bin/python。也可以根据 SDK 版本提供的传输方式,改用其他 Client 连接方式。

3. 运行示例

在两个文件所在的目录执行:

.\.venv\Scripts\python.exe demo_client.py

预期能看到类似输出:

可用工具: ['get_order_status'] 查询结果: [TextContent(type='text', text='已发货', ...)]

你可以把A1024改成A1025,观察“待发货”结果;也可以改成不存在的订单号,观察错误如何返回。这个实验比直接看装饰器更重要,因为它展示了 MCP 的三个关键动作:发现能力、按结构化参数调用、接收结构化结果。

八、MCP、业务 API 和 Function Calling 的区别

这三个概念经常一起出现,但处在不同层次:

概念解决的问题订单例子
业务 API业务系统怎样提供能力订单服务返回发货状态
Function Calling / Tool Calling模型怎样表达结构化调用意图模型选择查询工具并给出订单号
MCPAI 应用怎样统一发现和调用外部能力Client 发现工具并请求 Server 执行

可以把一次调用看成一条链:

模型的调用意图 ↓ Host 的工具调用接口 ↓ MCP Client / MCP Server ↓ 业务 API 或数据库

MCP 不会自动替代订单 API。一个 MCP Tool 的内部实现完全可以调用现有 API,也可以直接访问数据库。MCP 主要减少的是每个 AI 应用分别适配每个系统的工作量。

如果应用只连接一个固定函数,直接使用 Function Calling 可能已经足够;如果需要让多个 AI 应用以统一方式接入多个外部系统,MCP 的标准化价值会更明显。

九、如何判断一个能力是否适合做成 Tool

并不是把所有函数都暴露给模型就好。一个适合暴露的工具通常具有以下特征:

  • 目标明确:工具名称和说明能准确表达用途。
  • 参数有限:模型可以从对话中可靠地获得参数,或知道缺什么信息。
  • 结果可解释:返回结果结构清楚,模型能够据此回答用户。
  • 权限可控制:服务端可以判断当前用户能否执行。
  • 失败可处理:不存在、超时、权限不足等情况都有明确错误。

例如,“查询订单状态”通常适合做成只读工具;“取消订单”虽然也可以做成工具,但应额外考虑用户确认、幂等性、订单状态校验和审计记录。工具说明中的“仅查询”只是给模型的提示,真正的只读保证必须由业务代码实现。

十、安全与生产实践

本文的订单数据是公开的模拟数据,因此省略了许多生产问题。真实 MCP Server 至少需要考虑:

身份与权限

只知道订单号不代表用户有权查看订单。Server 应从可信的会话身份中获得用户信息,并检查订单归属、组织范围或角色权限,不能只相信模型传入的参数。

输入校验

对订单号做格式校验,对分页、日期范围和数量限制设置上限。不要因为参数已经由模型生成,就跳过普通 API 的校验。

敏感操作确认

查询、修改、删除、退款的风险不同。取消订单、发起退款等操作应由 Host 明确展示影响,并在执行前要求用户确认。对于高风险场景,还可以要求二次认证或人工审批。

数据最小化

工具只返回完成任务所需的数据。查询订单状态不必把收货地址、手机号和完整支付信息一起返回。需要展示给模型的内容越少,泄露和误用的风险越低。

错误与审计

区分“订单不存在”“无权访问”“系统超时”和“服务暂时不可用”。同时记录调用者、工具名、参数摘要、结果状态和时间,便于排查问题;日志中不要直接写入不必要的敏感信息。

传输与部署

本地 stdio 适合个人工具和开发环境。远程部署还需要处理身份认证、加密传输、连接生命周期、并发、限流和版本兼容。协议本身不会替你完成这些运维工作。

十一、常见误解

“用了 MCP,模型就能访问所有数据”

不是。模型只能看到 Host 提供给它的工具和资源,Server 也应该只暴露允许访问的能力。

“Tool 一定是写操作,Resource 一定是读操作”

不是。Tool 可以是只读查询,Resource 也不仅仅是普通文件。两者的核心差异是交互定位和协议语义,而不是简单的读写标签。

“MCP Server 就是数据库代理”

不一定。Server 可以连接数据库、HTTP API、本地文件、命令行程序或其他服务,也可以只提供静态提示模板。

“模型决定调用,就已经执行成功”

不是。模型的调用请求只是意图。Host 的审批、Client 的通信、Server 的校验和业务系统的最终响应都可能使调用被拒绝或失败。

十二、总结

从普通 Python 函数到 MCP Server,业务能力本身没有神奇变化。变化的是:这个能力拥有了标准化的描述、发现、调用和结果返回方式。

理解 MCP,可以先记住下面这条链:

用户提出目标 → 模型选择工具 → Host 检查权限与确认 → Client 按 MCP 发起调用 → Server 执行业务代码 → 结果返回模型 → 模型生成回答

一句话概括:MCP 不是让模型凭空获得能力,而是让 AI 应用用统一方式接入已有的数据与工具。

本文示例没有连接真实模型,也没有实现生产级认证、授权和远程部署。它的目标是先把协议角色和一次工具调用的完整路径建立起来;掌握这条路径后,再接入真实订单 API、模型和权限系统,会更容易判断每一层应该负责什么。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/6 1:59:26

AI Skills 7步工作法:让团队AI编程从个人试水到全员落地

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/6 1:58:50

PyTorch深度学习实战:从环境搭建到模型部署完整指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/6 1:56:36

LLM工程化:提示工程、RAG、Agent与结构化输出实战

# LLM工程化&#xff1a;提示工程、RAG、Agent与结构化输出实战## 1. 背景&#xff1a;从“聊天”到“生产级组件”的鸿沟2024年以来&#xff0c;GPT-4o、Claude 3.5 Sonnet等模型在对话、代码生成上表现出众&#xff0c;但当开发人员试图将LLM集成到生产系统时&#xff0c;很快…

作者头像 李华
网站建设 2026/9/6 1:55:44

普通BM和验证BM到底有什么区别?Facebook广告投放必看的资产避坑指南

做Facebook投放的朋友&#xff0c;应该都听过两个词&#xff1a;普通BM、验证BM。很多人对它们的理解特别简单——普通BM就是没验证的&#xff0c;验证BM就是验证过的。这话没错&#xff0c;但如果你真的在做Facebook投放&#xff0c;光知道这个还不够。因为不少人会进一步认为…

作者头像 李华
网站建设 2026/9/6 1:55:35

CEH v12认证备考全攻略:从资料筛选到靶场实战一次讲透

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华