拓冰建站拓冰建站
首页 / 资讯中心 / 正文

在 MCP Python SDK 中定义 Resources:从静态 URI、资源模板到多类型返回值的完整实战指南

人工智能MCP 服务MCP Clients【免费下载链接】python-sdkThe official Python SDK for Model Context Protocol servers and clients项目地址https://gitcode.com/gh_mirrors/pythonsd/python-sdk点击查看免费下载本篇指南以 Model Context ProtocolMCP官方 Python SDK 的 Resources 能力为主题结合仓库内docs_src/resources/三个教程示例与src/mcp/server/mcpserver/的源码实现讲解如何在服务端声明资源Resource、用 URI 寻址、通过{placeholder}构建可扩展的资源模板以及str/bytes/dict等不同返回值如何被客户端消费。读完你可以独立写出配置读取、用户档案、目录统计这类被应用程序主动加载的数据源并用 MCP Inspector 立即验证。资源是什么与工具的本质区别在 MCP 中资源resource是服务端暴露出来、供应用程序application读取的数据。官方文档i18n/es/pages/servers/resources.md给出了一个非常清晰的划分工具Tool由**模型model**决定何时调用用于让模型做动作资源Resource由**应用程序application**决定何时加载一个配置文件、一条记录、一份文档加载后作为上下文摆到模型面前。这决定了资源的地址语义资源按URI 寻址而不是按名字寻址。客户端请求的是config://app而不是get_config——名字只是元数据URI 才是身份。声明一个资源的方式极其简单在普通 Python 函数上放一个mcp.resource(uri)装饰器即可。下面我们从第一个例子开始。你的第一个资源教程 docs_src/resources/tutorial001.py 展示了最小可用的资源定义from mcp.server import MCPServer mcp MCPServer(Bookshop) mcp.resource(config://app) def get_config() - str: The active shop configuration. return themedark\nlanguageen它和工具的形态几乎一样唯一的加料就是那个URI。SDK 依然从函数身上读取其余信息元数据来源取值名称name函数名get_config描述description函数 docstringThe active shop configuration.内容content函数返回值themedark\nlanguageen当客户端发起resources/list时它拿到的是这样一条元数据记录{ name: get_config, uri: config://app, description: The active shop configuration., mimeType: text/plain }而客户端真正去读config://app时你的函数才会执行返回值以文本形式返回result.contents # [TextResourceContents(uriconfig://app, mime_typetext/plain, textthemedark\nlanguageen)]关键机制列表廉价读取才执行提示列出list是廉价的。你的函数在resources/list期间不会被调用只在resources/read期间被调用而且只为被请求的那个 URI 调用。哪怕你暴露一千个资源也只为被打开的那几个买单。这一点被测试 tests/docs_src/test_resources.py 明确固化test_function_becomes_a_listed_resource验证URI、函数名和 docstring 构成了完整的列表条目而test_read_returns_the_return_value_as_text验证读取 URI 才运行函数并把str包装成TextResourceContents。这意味着你可以放心注册大量资源无需担心启动或列出的性能开销。用 MCP Inspector 试一下用 MCP 官方 Inspector 启动这个服务器uv run mcp dev server.py打开它打印出的 URL切到Resources标签页config://app带着它的描述出现在列表里。点击它Inspector 会执行读取——那两行配置themedark与languageen就展示在眼前。资源模板一个 URI 模式服务无数条记录一条记录一个 URI无法扩展。解决方案是把占位符placeholder放进 URI并在函数上放一个同名参数。见 docs_src/resources/tutorial002.pyfrom mcp.server import MCPServer mcp MCPServer(Bookshop) mcp.resource(config://app) def get_config() - str: The active shop configuration. return themedark\nlanguageen mcp.resource(users://{user_id}/profile) def get_user_profile(user_id: str) - str: A customers profile. return fUser {user_id}: 12 orders since 2021.{user_id}出现在 URI 里user_id: str出现在函数签名里——这就是全部契约。模板会搬家从 list 到 templates/list一旦 URI 含占位符它就不再是一个静态资源而是一个资源模板resource template并随之搬家离开resources/list出现在resources/templates/list中以模式而非地址的形式呈现{ name: get_user_profile, uriTemplate: users://{user_id}/profile, description: A customers profile., mimeType: text/plain }客户端填充占位符后读取具体 URIusers://42/profile、users://ada/profile…… 一个函数服务所有匹配的 URI匹配到的值以user_id参数传入result.contents # [TextResourceContents(uriusers://42/profile, textUser 42: 12 orders since 2021.)]注意返回结果里的uri——它是客户端请求的那个具体URI而不是模板本身。占位符与参数必须一致导入期即拦截校验占位符和函数参数必须严格对齐。如果你把函数参数改成user而 URI 里仍是{user_id}装饰器会在**导入时import time**直接拒绝任何客户端都靠不近这个服务器ValueError: Mismatch between URI parameters {user_id} and function parameters {user}这种不一致只可能是 bug因此 SDK 让带着不一致启动服务器成为不可能。对应测试test_uri_params_must_match_function_params见 tests/docs_src/test_resources.py正是验证这一行为。把错误提前到导入期而不是留到生产环境的某个读取请求上是这类框架该有的防御姿态。模板占位符语法RFC 6570 与路径安全占位符语法遵循RFC 6570URI Template{path}匹配多段路径值{?q,lang}可选的查询参数以及更多 RFC 6570 定义的表达式形式。默认情况下SDK 还会对抽取出来的值应用路径安全检查path-safety checks。完整参考请见 Plantillas de URI y seguridad de rutasURI 模板与路径安全英文原版位于 docs/servers/uri-templates.md。模板函数也能注入 Contextget_user_profile这类模板函数还可以声明一个类型为Context的参数。SDK 会把它作为依赖注入处理绝不会把它当作 URI 参数去匹配。Context能给你什么请求状态、会话信息等见 The Context上下文。返回值不限于 strmime_type 与三种内容形态资源函数完全可以返回别的类型。诀窍是给每个资源声明mime_type然后返回与之匹配的值。教程 docs_src/resources/tutorial003.py 一口气展示了三种import base64 from mcp.server import MCPServer mcp MCPServer(Bookshop) mcp.resource(docs://readme, mime_typetext/markdown) def readme() - str: How to use this server. return # Bookshop\n\nSearch the catalog with the search_books tool. mcp.resource(stats://catalog, mime_typeapplication/json) def catalog_stats() - dict[str, int]: Live counts for the catalog. return {books: 1204, authors: 391} mcp.resource(covers://placeholder, mime_typeimage/gif) def placeholder_cover() - bytes: A 1x1 transparent GIF, shown when a book has no cover. return base64.b64decode(R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)三种返回值各有归属readme返回str原样发送。这是最常见的情形mime_type标为text/markdowncatalog_stats返回dictSDK 自动帮你序列化为JSON 文本{ books: 1204, authors: 391 }placeholder_cover返回bytes客户端收到的将不再是TextResourceContents而是BlobResourceContents你的字节被base64 编码后放进它的blob字段mime_type为image/gif。规则可以推广到任何 JSON 可序列化的东西列表、Pydantic 模型、dataclass……只要既不是str也不是bytes就会被转成 JSON。测试文件中的test_str_return_is_sent_as_is、test_dict_return_becomes_json_text、test_bytes_return_becomes_a_blob分别锁定了这三种行为。mime_type 是你声明的不是猜出来的mime_type由你声明默认值是text/plain。SDK 从不偷看返回值去猜类型——所以一个没打标签的dict资源在列表里依然会被宣告为纯文本。想被正确消费就主动mime_type标注。这从源码也能印证在 src/mcp/server/mcpserver/resources/base.py 中Resource基类的字段定义是mime_type: str Field(defaulttext/plain, ...)且装饰器签名resource(uri, *, nameNone, titleNone, descriptionNone, mime_typeNone, ...)见 src/mcp/server/mcpserver/server.py把mime_type作为显式参数暴露。源码视角装饰器、基类与内置 Resource 类从源码看mcp.resource(...)的实际签名src/mcp/server/mcpserver/server.py除了uri之外还支持这些关键字参数name、title、description当你不希望从函数名 / 函数本身派生时直接覆盖mime_type如上文所述标注内容类型icons、annotations、meta资源元数据与展示信息security模板资源抽取参数的路径安全策略默认继承服务器的resource_security设置仅对模板资源生效。同时URI 是否含{...}参数决定了注册路径含参数注册为模板资源否则注册为静态资源静态 URI 上声明函数参数会直接报错。装饰器接受同步函数也接受async def异步函数。当根本没有函数可写时比如资源内容就是固定的文本、文件、远程 HTTP 地址可以直接用mcp.server.mcpserver.resources模块里现成的Resource类TextResource从一个字符串读取字段textBinaryResource从字节读取字段dataFileResource从文件读取支持encoding解码为文本或按字节读取HttpResource从一个 HTTP 端点抓取内容字段urlDirectoryResource列出目录中的文件字段path。这些类继承自 Resource 基类基类统一承载uri、name、title、description、mime_type、icons、annotations、meta字段并通过抽象方法read()定义读取契约。注册方式同样简单mcp.add_resource(...)对应 server.py 中的add_resource。注意这些内置类的具体行为属于实现细节实际用法可结合该类源码确认。资源的另一半客户端订阅与通知资源的故事不只在服务端。客户端还可以**订阅subscribe**一个资源在它发生变化时收到通知——这是属于客户端的另一半故事详见 The Client客户端 文档。订阅机制让应用程序把最新上下文摆在模型面前成为可能服务端资源一变客户端立刻得知无需反复轮询。小结在函数上放mcp.resource(uri)即可把它变成资源URI 是地址返回值是内容docstring 是描述。URI 中的{placeholder}让它成为模板列在resources/templates/list下一个函数服务所有匹配的 URI。占位符名必须等于函数参数名写错了会在导入期报错而不是生产环境。函数只在资源被**读取read**时执行列表list阶段绝不执行。str变成文本bytes变成 base64 blob其他一切变成 JSON 文本用mime_type给内容打标签。工具是给模型行动的资源是给应用程序读取的。三种原语里资源面向应用上下文让人从菜单里选择的那一种是Prompts提示词那是下一个值得深入的主题。赞分享人工智能MCP 服务MCP Clients【免费下载链接】python-sdkThe official Python SDK for Model Context Protocol servers and clients项目地址https://gitcode.com/gh_mirrors/pythonsd/python-sdk点击查看免费下载相关推荐Python MCP SDK 服务端资源Resources开发指南从静态 URI 到模板化资源Python MCP SDK 服务端资源Resources开发指南从静态 URI 到模板化资源 导读 在 Model Context ProtocolM人工智能MCP 服务MCP ClientsMCP Python SDK Resources 实战用 mcp.resource() 暴露静态资源与 RFC 6570 模板资源MCP Python SDK Resources 实战用 mcp.resource 暴露静态资源与 RFC 6570 模板资源 资源Resources是人工智能MCP 服务MCP ClientsModel Context Protocol TypeScript SDK 服务端 Resources 完整实战指南从静态资源到模板订阅Model Context Protocol TypeScript SDK 服务端 Resources 完整实战指南从静态资源到模板订阅 导读 Resourc人工智能MCP 服务MCP Clients上一篇InterpretML终极可视化指南如何创建交互式模型解释仪表板下一篇Obtainium单元测试模拟Mockito框架实践创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门