Python MCP SDK 工具开发指南:用 `@mcp.tool()` 声明模型可调用的函数
Python MCP SDK 工具开发指南用mcp.tool()声明模型可调用的函数【免费下载链接】python-sdkThe official Python SDK for Model Context Protocol servers and clients项目地址: https://gitcode.com/gh_mirrors/pythonsd/python-sdk在 Model Context ProtocolMCP中工具tool就是模型可以调用的函数。本文基于 pythonsd/python-sdk 官方仓库的文档与源码完整讲解如何用mcp.tool()装饰器把一个普通 Python 函数变成 MCP 工具从函数名、docstring、类型提示自动推导出工具名称、描述与 JSON Schema 输入契约再到可选参数、Field约束、Pydantic 模型参数、async def异步工具以及title与ToolAnnotations行为提示。读完本文你将能独立编写一个可被任意 MCP 客户端发现并调用的工具服务并用 MCP Inspector 完成端到端验证。你的第一个工具在 MCP 中声明一个工具的 API 极其简洁把mcp.tool()装饰器贴在一个普通 Python 函数上即可。没有手写 schema、没有 JSON、没有协议细节只有函数本身。以下代码摘自仓库教程 docs_src/tools/tutorial001.pyfrom mcp.server import MCPServer mcp MCPServer(Bookshop) mcp.tool() def search_books(query: str, limit: int) - str: Search the catalog by title or author. return fFound 3 books matching {query!r} (showing up to {limit}).SDK 从这段函数中读取三样东西工具的名称来自函数名search_books模型看到的描述来自 docstringSearch the catalog by title or author.模型可以传入的参数来自类型提示query: str与limit: int。输入 schemaThe input schemaSDK 会根据类型提示生成 JSON Schema并在tools/list握手阶段发送给客户端。上面函数的输入 schema 如下{ type: object, properties: { query: {title: Query, type: string}, limit: {title: Limit, type: integer} }, required: [query, limit], title: search_booksArguments }两个参数都没有默认值所以都出现在required中这个马上就会改掉。其中的title键是 Pydantic 生成的附带产物真正构成“契约”的是属性、属性类型与required列表。另外注意这里没有$schema键。MCP 把不带该键的 schema 一律视为JSON Schema 2020-12而 Pydantic 生成的正是这一方言所以在 低级 Server 上手工编写 schema 之前你不需要做任何选择。!!! tip 在这里类型提示不是文档而是契约本身。如果客户端发送limit: tenSDK 会在你的函数运行之前就拒绝该请求。从源码看MCPServer的add_tool方法见 src/mcp/server/mcpserver/server.py会把函数连同name、title、description、annotations、icons、meta、structured_output等配置一并交给ToolManager注册schema 的生成与参数校验正是发生在这一注册与后续调用链路上。模型拿回什么用{query: dune, limit: 5}调用该工具结果由两部分组成result.content # [TextContent(textFound 3 books matching dune (showing up to 5).)] result.structured_content # {result: Found 3 books matching dune (showing up to 5).}content是模型读取的文本structured_content是提供给客户端应用程序的类型化数据——它之所以存在是因为你把返回类型声明为- str。现在不必深究structured_content只要工具返回真实的 Python 对象SDK 就会自动做正确的事。这个主题在结构化输出页面有完整讲解。动手试一试Try it用 MCP Inspector 启动服务器uv run mcp dev server.py打开命令打印出的 URL进入Tools标签页然后调用search_books。Inspector 会根据你的类型提示渲染一个表单必填的query文本字段 必填的limit数字字段。所有其他 MCP 客户端都会做同样的事情——表单本身就是从类型提示推导出来的。可选参数Optional arguments给参数一个默认值它就不再是必填项。仅此而已这就是普通 Python 语义。代码见 docs_src/tools/tutorial002.pyfrom mcp.server import MCPServer mcp MCPServer(Bookshop) mcp.tool() def search_books(query: str, limit: int 10) - str: Search the catalog by title or author. return fFound 3 books matching {query!r} (showing up to {limit}).生成的 schema 也随之变化{ type: object, properties: { query: {title: Query, type: string}, limit: {default: 10, title: Limit, type: integer} }, required: [query], title: search_booksArguments }limit从required中移出同时新增了default: 10。省略该参数的客户端拿到的就是10与 Python 默认参数行为完全一致。用Field构建更丰富的 schema类型提示能做的事情很多但有时你希望对参数做描述或约束。把类型包进Annotated再加一个 PydanticField即可。代码见 docs_src/tools/tutorial003.pyfrom typing import Annotated, Literal from pydantic import Field from mcp.server import MCPServer mcp MCPServer(Bookshop) mcp.tool() def search_books( query: Annotated[str, Field(descriptionTitle or author to search for.)], limit: Annotated[int, Field(ge1, le50, descriptionMaximum number of results.)] 10, genre: Literal[fiction, non-fiction, poetry] | None None, ) - str: Search the catalog by title or author. where f in {genre} if genre else return fFound 3 books matching {query!r}{where} (showing up to {limit}).这里出现了三样新东西全部作用在参数上Field(description...)针对单个参数的描述模型会连同 docstring 一起阅读Field(ge1, le50)数值范围约束会落入 schema 的minimum: 1, maximum: 50Literal[fiction, non-fiction, poetry]枚举类型模型只能从中选一个。!!! check 约束不是装饰品。用limit999调用工具SDK 会在函数执行之前就返回一个工具错误text Input should be less than or equal to 50 这个错误会作为工具结果回到模型那里模型读到错误后会换一个合法值重试。你只写了一次 le50就免费得到了一个会自我纠正的 Agent。!!! info 如果你用过 FastAPI 或 Pydantic这些你都已了然于胸同一个Field、同一个Annotated、同一套校验。这里没有任何 MCP 特有的新知识。用模型作为参数A model as a parameter当工具的参数超过两三个时把它们打包进一个 Pydantic 模型。代码见 docs_src/tools/tutorial004.pyfrom pydantic import BaseModel, Field from mcp.server import MCPServer mcp MCPServer(Bookshop) class Book(BaseModel): title: str author: str year: int Field(ge1450, descriptionYear of first publication.) mcp.tool() def add_book(book: Book) - str: Add a book to the catalog. return fAdded {book.title!r} by {book.author} ({book.year}).Book的 schema 会以$defs引用的形式嵌套进工具的输入 schema模型在调用时把该位置填成一个 JSON 对象而你的函数收到的是一个已经完成校验的真实Book实例可以直接访问.title、.author、.year属性。组合方式非常自由普通参数与模型参数并列、模型嵌套模型、接收模型列表全部可行——自底向上都是 Pydantic。async def异步工具如果工具要做 I/O调用 API、读文件、查询数据库就把它声明为async def并在函数内部使用await。SDK 会负责 await 它mcp.tool() async def fetch_price(symbol: str) - str: price await market_api.get(symbol) # 异步 I/O return f{symbol}: {price}普通的def工具同样可以工作SDK 会在线程中运行它因此不会阻塞服务器的事件循环。这里没有任何额外配置项仅此而已。从 src/mcp/server/mcpserver/server.py 的装饰器实现看同步与异步函数都走同一条注册路径调用时由 SDK 统一调度执行。名称、标题与注解Names, titles, and annotationsSDK 推断出来的一切都可以在装饰器中覆盖。代码见 docs_src/tools/tutorial005.pyfrom mcp.server import MCPServer from mcp.types import ToolAnnotations mcp MCPServer(Bookshop) mcp.tool( titleSearch the catalog, annotationsToolAnnotations(read_only_hintTrue, open_world_hintFalse), ) def search_books(query: str) - str: Search the catalog by title or author. return fFound 3 books matching {query!r}.title面向 UI 的人性化名称。客户端会显示Search the catalog而不是search_booksannotations面向客户端的行为提示hintsread_only_hintTrue该工具不会修改任何东西open_world_hintFalse它作用于一个封闭集合这个书目而非开放网络另外两个destructive_hint与idempotent_hint描述的是写入型工具它是否可能删除某些内容调用两次与调用一次结果是否相同规范只为非只读工具定义这两个字段因此把它们挂在search_books上没有任何意义。在仓库的 src/mcp-types/mcp_types/_types.py 中ToolAnnotations共定义了五个可选字段title、read_only_hint默认false、destructive_hint仅在read_only_hint false时有意义默认true、idempotent_hint同样仅对非只读工具有意义默认false、open_world_hint默认true。其源码注释明确强调这些属性都是提示hints并不保证对工具行为的忠实描述客户端不应基于来自不受信任服务器的ToolAnnotations做工具使用决策。一个行为良好的客户端会依据这些提示做出判断例如运行这个工具之前需要先询问用户吗。但它们只是提示不是安全机制——永远不要指望客户端会遵守它们。!!! tip 如果你不想从函数名和 docstring 推导mcp.tool()也接受name与description参数。大多数时候直接用默认推导即可。回顾Recap给函数加mcp.tool()装饰器它就成了工具名称取自函数名描述取自 docstring类型提示就是输入 schema有默认值的参数自动变为可选Annotated[..., Field(...)]添加描述与约束Literal添加枚举Pydantic 模型参数是接收结构化请求体的方式非法参数会被自动拒绝并返回一个模型能读懂、能自我恢复的错误I/O 用async def其余情况用普通def。关于return返回值的去向请继续阅读结构化输出一文。【免费下载链接】python-sdkThe official Python SDK for Model Context Protocol servers and clients项目地址: https://gitcode.com/gh_mirrors/pythonsd/python-sdk创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

Lightweight Charts™ iOS 集成指南:借助 iOS wrapper 在原生应用中渲染高性能 HTML5 图表

Lightweight Charts™ iOS 集成指南:借助 iOS wrapper 在原生应用中渲染高性能 HTML5 图表

前端图表库金融科技数据可视化 【免费下载链接】lightweight-charts Performant financial charts built with HTML5 canvas 项目地址: https://gitcode.com/gh_mirrors/li/lightweight-charts 点击查看 免费下载 Lightweight Charts™ 是一款基于 HTML5 canvas 的…

2026/9/23 14:53:02 阅读更多 →
3步调通FreePascal源码解析 解决代码复制报错难题

3步调通FreePascal源码解析 解决代码复制报错难题

3步调通FreePascal源码解析 解决代码复制报错难题 复制来的 FreePascal 代码,是不是经常一跑就红屏?明明逻辑看着没问题,编译器却报出一堆 E2003 或 F2004 错误。这种“看着懂,跑不通”的绝望感,每个写过…

2026/9/24 7:48:48 阅读更多 →
C#从零实现CAN ASC文件解析器:报文提取与性能优化实战

C#从零实现CAN ASC文件解析器:报文提取与性能优化实战

1. CAN ASC文件到底长什么样:先看懂再动手搞汽车电子或者工业控制的朋友,对CAN总线肯定不陌生。但真正让人头疼的往往不是CAN通信本身,而是拿到一个.asc文件之后怎么把它里面的数据干干净净地提取出来。ASC是Vector工具链定义的一种文本格式&…

2026/9/24 3:55:31 阅读更多 →

最新新闻

Apache Beam RC 测试指南:用 Python、Java、Go 三种 SDK 对发布候选版本做下游验证

Apache Beam RC 测试指南:用 Python、Java、Go 三种 SDK 对发布候选版本做下游验证

大数据批处理流处理数据工程 【免费下载链接】beam Apache Beam is a unified programming model for Batch and Streaming data processing. 项目地址: https://gitcode.com/gh_mirrors/beam4/beam 点击查看 免费下载 Apache Beam(下称 Beam&#xff0…

2026/9/25 6:07:49 阅读更多 →
医院信息系统Word导入方案解析:三条路线与POI实战避坑

医院信息系统Word导入方案解析:三条路线与POI实战避坑

被一个三甲医院信息科的哥们找过来时,我第一反应是这活儿简单:把临床科室积累了好几年的Word文档——病历、检验报告、制度文件、科研方案——导入他们新上的HIS系统。结果真正动手才发现,"医院信息系统需要哪种Word导入方案"这个问…

2026/9/25 6:07:49 阅读更多 →
32位单片机选型指南:STM32与国产芯片的深度对比

32位单片机选型指南:STM32与国产芯片的深度对比

不开篇说废话了,直接进入正题。作为一个从8位机一路玩到Cortex-M7、这几年又把国产单片机翻来覆去折腾过的人,我想认真聊聊32位单片机的选型这件事。现在网上聊32位单片机绕不开两个关键词:一个是统治了教科书和毕业设计多年的STM32&#xff…

2026/9/25 6:07:49 阅读更多 →
Flex:ai是什么?一文看懂开源XPU虚拟化与AI训推智能调度的终极解析

Flex:ai是什么?一文看懂开源XPU虚拟化与AI训推智能调度的终极解析

Flex:ai是什么?一文看懂开源XPU虚拟化与AI训推智能调度的终极解析 【免费下载链接】flexai Flex:ai是一个面向AI容器场景的开源项目,其核心能力包含两大部分,分别是XPU虚拟化和多级智能调度。其中XPU虚拟化分为本地XPU虚拟化和跨节点拉远虚拟…

2026/9/25 6:07:49 阅读更多 →
从0到1理解零信任:边界为何失灵、身份如何接管防线(纵深防御落地指南)

从0到1理解零信任:边界为何失灵、身份如何接管防线(纵深防御落地指南)

从0到1理解零信任:边界为何失灵、身份如何接管防线(纵深防御落地指南) 【免费下载链接】Security-101 8 Lessons, Kick-start Your Cybersecurity Learning. 项目地址: https://gitcode.com/GitHub_Trending/se/Security-101 还在靠&q…

2026/9/25 6:07:49 阅读更多 →
x86汇编实战指南:高频指令、寻址方式与栈帧调试

x86汇编实战指南:高频指令、寻址方式与栈帧调试

1. 为什么还要啃x86汇编这块硬骨头很多人第一次接触汇编,脑子里冒出来的画面大概是黑底白字、满屏寄存器名、看一眼就想关掉。尤其是现在高级语言和框架已经把底层包得严严实实,写业务代码根本碰不到eax、ebp这些东西。但只要你做过逆向分析、性能调优、…

2026/9/25 6:06:48 阅读更多 →

日新闻

AI元人文:从工具使用到思维重构的深度探索

AI元人文:从工具使用到思维重构的深度探索

最近半年我一直在琢磨一件事:AI元人文到底是什么?说白了,就是“用元视角重新审视人与AI的关系”,也在“探索AI如何反向逼着我们发现自己的思考边界”。标题里的“元探索”,在我看就是一层套一层的追问——当你用AI解决…

2026/9/25 0:00:41 阅读更多 →
Python+CNN车牌识别实战:从数据预处理到模型训练与部署

Python+CNN车牌识别实战:从数据预处理到模型训练与部署

简介:基于Python与卷积神经网络的车牌识别项目,面向计算机视觉初学者及智能交通开发者,目标是帮助用户掌握从数据预处理、模型构建到实际部署的完整流程。压缩包共25个文件,包含jpg/png图像样本、py训练脚本、md说明文档、dat数据…

2026/9/25 0:00:41 阅读更多 →
Vim基础操作全攻略:保存退出、模式切换与高频命令实战

Vim基础操作全攻略:保存退出、模式切换与高频命令实战

1. 项目概述1.1 核心需求解析今天聊聊Vim。写这个题目的原因是:几乎每个后端开发者、运维人员、数据工程师某天都会遇到一个场景——深夜加班,服务器登录界面只有黑底白字,编辑器只有vi/vim,你必须在五分钟内完成一次配置修改并保…

2026/9/25 0:00:41 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/24 14:34:13 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/24 9:10:42 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/24 14:33:56 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/24 12:50:34 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/24 14:33:48 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/24 12:49:17 阅读更多 →