python-sdk 服务端資源開發指南:用 `@mcp.resource` 對應用程式公開資料

发布时间:2026/9/22 19:16:24

python-sdk 服务端資源開發指南:用 `@mcp.resource` 對應用程式公開資料 人工智能MCP 服务MCP Clients【免费下载链接】python-sdkThe official Python SDK for Model Context Protocol servers and clients项目地址https://gitcode.com/gh_mirrors/pythonsd/python-sdk点击查看免费下载資源Resource是 MCP 伺服器向應用程式公開、供其主動讀取的資料與「由模型決定呼叫」的工具形成互補。本文以 python-sdk 的MCPServer為主體完整講解靜態資源、資源範本、佔位符約定、回傳值序列化與 MIME 型別宣告並結合 src/mcp/server/mcpserver/server.py 的裝飾器原始碼說明底層驗證機制讓你能夠立即在自己的伺服器上公開設定檔、紀錄、文件與二進位內容。資源與工具的分界MCP 協定定義了三種基本元件工具、資源與提示詞。其中最容易混淆的就是工具與資源的區別但分界其實很清楚工具Tool是模型決定要呼叫的東西——模型在推理過程中主動發起tools/call資源Resource是應用程式決定要載入的東西——一個設定檔、一筆紀錄、一份文件由應用程式或使用者把它放到模型面前當作上下文。換句話說工具讓模型採取行動資源讓應用程式讀取。你只需要在一個普通的 Python 函式上加上mcp.resource(uri)就宣告了一個資源。第一個資源最簡單的資源範例如下完整範例見 docs_src/resources/tutorial001.pyfrom mcp.server import MCPServer mcp MCPServer(Bookshop) mcp.resource(config://app) def get_config() - str: The active shop configuration. return themedark\nlanguageen它的形狀和工具幾乎一樣只多了一樣東西URI。這是資源與工具最本質的差異——資源靠位址定位而不是靠名稱。用戶端要求的是config://app從來不是get_config。其餘的部分SDK 照樣從函式本身讀出來名稱就是函式名稱get_config用戶端看到的描述是 docstring內容就是你回傳的東西。用戶端眼中的資源清單在resources/list期間用戶端收到的清單項長這樣{ name: get_config, uri: config://app, description: The active shop configuration., mimeType: text/plain }對應的處理函式在 server.py 的_handle_list_resources中它直接呼叫list_resources()並返回ListResourcesResult不會執行任何資源函式。讀取資源當用戶端讀取config://app時你的函式才會被呼叫回傳值以文字形式送回result.contents # [TextResourceContents(uriconfig://app, mime_typetext/plain, textthemedark\nlanguageen)]列出是廉價的函式只在讀取時執行一個重要的效能特性列出資源的成本很低。函式在resources/list期間不會執行只有在resources/read時才會而且只針對用戶端要求的那個 URI。就算你公開了一千個資源也只會為有人打開的那幾個付出代價。從原始碼可以看到這正是FunctionResource的設計初衷——types.py 的註解明確寫著「函式只在資源被讀取時呼叫允許對可能昂貴的資料進行延遲載入」若函式是同步的SDK 會用anyio.to_thread.run_sync把它丟到執行緒池避免阻塞事件迴圈。試試看用 MCP Inspector 驗證用 MCP Inspector 執行伺服器uv run mcp dev server.py打開它印出的 URL切到Resources分頁。config://app會連同描述一起出現在清單裡。點一下Inspector 就會讀取它那兩行設定就在眼前。資源範本一筆紀錄一個 URI 行不通一筆紀錄一個 URI 沒有辦法擴展。當你有大量使用者、大量檔案、大量訂單時不可能為每一筆都寫一個裝飾器。解法是在 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.users://{user_id}/profile這個 URI 裡有{user_id}函式上有user_id: str。整個約定就是這樣佔位符名稱等於函式參數名稱。範本搬家了從 list 搬到 templates/list加了佔位符的資源就成了資源範本而且它會搬家離開resources/list改出現在resources/templates/list以「樣式pattern」而不是「位址address」的形式呈現{ 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——那是用戶端要求的具體URIusers://42/profile不是範本users://{user_id}/profile。佔位符與參數必須一致匯入時就拒絕佔位符和參數必須一致。如果你把函式參數改名為userURI 卻還寫著{user_id}裝飾器會在匯入時就拒絕任何用戶端都還來不及靠近ValueError: Mismatch between URI parameters {user_id} and function parameters {user}不一致只可能是 bug所以 SDK 讓帶著這種錯誤的伺服器根本啟動不了。從原始碼看這個檢查發生在 server.py 的resource()裝飾器內部它先用UriTemplate.parse(uri)解析 URI 並取出所有變數名稱再透過inspect.signature(fn)收集函式參數並用find_context_parameter排除被標記為Context的參數最後兩者做集合比較。值得注意的細節有兩點裝飾時即驗證UriTemplate.parse在裝飾階段就執行格式錯誤的範本malformed template會立刻以帶明確位置的錯誤拋出反方向的檢查同樣嚴格若 URI 不含任何變數靜態資源而函式卻宣告了參數同樣會拋出ValueError「Resource ... has no URI template variables, but the handler declares parameters ...」靜態資源甚至不允許宣告Context參數因為靜態資源函式無法參與多輪往返的輸入補齊流程。RFC 6570 佔位符語法與路徑安全佔位符語法遵循 RFC 6570{user_id}最簡單的單段變數{path}用於多段的值例如git://diff/{range}運算子不會把/編碼{?q,lang}用於選用的查詢參數query parameters用戶端可以省略{q,lang}連續的查詢參數接續運算子。一個由原始碼確認的實務細節查詢參數{?...}/{...}在線上傳輸時是可選的——用戶端不帶上它時match()會把它從提取參數中省略。因此 server.py 會強制要求綁定到查詢變數的函式參數必須帶有 Python 預設值否則在裝飾階段就拋出ValueError避免作者直到第一個省略該參數的請求進來才發現問題。SDK 預設也會對從範本提取出來的值做路徑安全檢查相關策略定義在 templates.py 的ResourceSecurity資料類別中reject_path_traversal: bool True拒絕包含..路徑元件的值reject_absolute_paths: bool True拒絕看起來像絕對檔案系統路徑的值reject_null_bytes: bool True拒絕含 NUL 字元\x00的值防止其繞過字串比較或在 C 擴充、子行程呼叫中被截斷exempt_params可指定跳過檢查的參數名稱例如當某個參數合法地包含..時from mcp.server.mcpserver.resources import ResourceSecurity mcp.resource( git://diff/{range}, securityResourceSecurity(exempt_params{range}), ) def git_diff(range: str) - str: ...這些檢查在UriTemplate.match提取並解碼參數值之後執行因此無論值在 URI 中以字面形式、%2F、%5C還是%2E%2E編碼都逃不過檢查。完整參考請見URI 範本與路徑安全。範本函式也能拿到 Contextget_user_profile也可以接受一個註記為Context的參數。SDK 會注入它而且絕不會把它當成 URI 參數它能提供什麼請求狀態、伺服器實例、輸入補齊的input_responses等Context頁面有說明。回傳什麼不限於 str資源函式的回傳值不限於str。你可以替每個資源指定mime_type回傳合適的東西即可完整範例見 docs_src/resources/tutorial003.pyimport 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所以原樣送出。這是最常見的情況catalog_stats回傳dict所以 SDK 會替你序列化成JSON 文字{ books: 1204, authors: 391 }placeholder_cover回傳bytes所以用戶端收到的是BlobResourceContents而不是TextResourceContents位元組以 base64 編碼後放在blob欄位裡。序列化規則的原始碼實現這個「str 原樣、bytes 原樣、其他轉 JSON」的規則在 types.py 的FunctionResource.read()中可以看到具體實現if isinstance(result, Resource): return await result.read() elif isinstance(result, bytes): return result elif isinstance(result, str): return result else: return pydantic_core.to_json(result, fallbackstr, indent2).decode()注意最後一行用的是pydantic_core.to_json帶fallbackstr所以同樣的規則適用於其他任何可序列化為 JSON 的東西list、Pydantic 模型、dataclass……只要不是str也不是bytes就會變成 JSON 文字縮排為 2 個空格。在傳輸層server.py 的_handle_read_resource會根據內容型別分派bytes→BlobResourceContentsblob欄位存放base64.b64encode(...)的結果其他 →TextResourceContentstext欄位存放內容。mime_type 是宣告出來的不是猜出來的mime_type由你宣告預設為text/plain。SDK從不會檢查回傳的內容來猜測它所以一個沒標示的dict資源仍然會以純文字對外宣告。從 base.py 的Resource基類可以看到mime_type欄位預設值就是text/plain。因此宣告資源時記得顯式指定合適的mime_type如application/json、text/markdown、image/gif這會直接影響用戶端如何呈現與處理內容。不想從函式推導name / title / description 與現成的 Resource 類別mcp.resource()也接受name、title和description當你不想從函式推導這些欄位時可以直接指定。從 server.py 的簽名可以看到裝飾器還支援更多參數def resource( self, uri: str, *, name: str | None None, title: str | None None, description: str | None None, mime_type: str | None None, icons: list[Icon] | None None, annotations: Annotations | None None, meta: dict[str, Any] | None None, security: ResourceSecurity | None None, ) - Callable[[_CallableT], _CallableT]:其中security的預設值來自伺服器層級的resource_security設定只作用於範本資源。沒有函式要寫用現成 Resource 類別如果根本沒有函式要寫mcp.server.mcpserver.resources裡有現成的Resource類別用mcp.add_resource(...)註冊即可見 server.py 的add_resource它會委派給內部的_resource_manager.add_resourceTextResource靜態文字內容直接指定textBinaryResource靜態二進位內容直接指定databytesFileResource讀取檔案系統中的檔案——未指定encoding時會依mime_type宣告的charset決定解碼方式文字型 MIME 如text/*、JSON、XML 預設utf-8-sig其餘為 None 表示以 bytes 送出見 types.py 的說明HttpResource抓取遠端 HTTP 內容DirectoryResource列舉目錄中的檔案清單以 JSON 形式回傳。例如直接註冊一個靜態文字資源from mcp.server.mcpserver.resources import TextResource mcp.add_resource( TextResource( uriinfo://version, nameversion, descriptionServer version information., textbookshop/1.0.0, ) )這些類別都繼承自 base.py 的Resource抽象基類統一具備uri、name未提供時會從 URI 推導、title、description、mime_type、icons、annotations、meta欄位並以抽象方法async def read() - str | bytes定義讀取行為。訂閱資源當資料變更時收到通知用戶端也可以訂閱資源在它變更時收到通知——例如設定檔被重新載入、目錄內容被修改時伺服器主動推送notifications/resources/updated讓用戶端不必輪詢。那是用戶端那一半的故事寫在用戶端裡。重點回顧在函式上加mcp.resource(uri)它就成了資源。URI 是位址回傳值是內容docstring 是描述URI 裡有{placeholder}就成了範本它列在resources/templates/list底下同一個函式服務所有符合的 URI佔位符名稱必須等於函式的參數名稱。弄錯的話匯入時就會知道不用等到正式環境函式在資源被讀取時執行而不是被列出時——列出一千個資源只會為被打開的那幾個付出代價str變成文字bytes變成 base64 blobBlobResourceContents其他的都變成 JSON 文字用mime_type來標示SDK 不會替你猜測範本參數預設啟用路徑安全檢查拒絕路徑穿越、絕對路徑與 NUL 字元可用ResourceSecurity精細控制工具讓模型採取行動資源讓應用程式讀取。第三種基本元件由人從選單裡挑選的那種是提示詞。赞分享人工智能MCP 服务MCP Clients【免费下载链接】python-sdkThe official Python SDK for Model Context Protocol servers and clients项目地址https://gitcode.com/gh_mirrors/pythonsd/python-sdk点击查看免费下载相关推荐FinceptTerminal 台灣股市資料連接器實戰指南以 TWSE/TPEX 行情、指數與公司資訊擴充開源終端FinceptTerminal 台灣股市資料連接器實戰指南以 TWSE/TPEX 行情、指數與公司資訊擴充開源終端 本指南圍繞 FinceptTerminal金融科技桌面应用AI 应用繁體中文教育語料新突破FineWeb-Edu-zhtw 資料集重磅發布推動中文AI教育應用發展在當前人工智能技術飛速發展的浪潮中高質量、領域專屬的語料資源已成為訓練先進語言模型的核心基礎。近日一項針對繁體中文教育領域的重要語料工程——FineWeb2025最強Android TV直播應用開發指南從安裝到源碼深度解析2025最強Android TV直播應用開發指南從安裝到源碼深度解析 還在為Android TV應用開發中的兼容性問題頭痛還在苦苦尋找穩定的直播源解決方案音视频直播上一篇使用 Three.js 和 JavaScript 创建程序化树木生成器从零到森林的艺术下一篇实用指南如何用GHelper高效管理华硕笔记本性能与续航创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/22 19:11:24

Cargo 为什么存在:从 `rustc` 到 Rust 包管理器的演进之路

开发工具包管理器CLI构建工具 【免费下载链接】cargo The Rust package manager 项目地址: https://gitcode.com/gh_mirrors/car/cargo 点击查看 免费下载 Cargo 是 Rust 的官方包管理器(package manager),本指南将带你理解它诞生…

2026/9/22 19:11:24

PS描边路径5大坑:从报错到修复的避坑指南

PS描边路径5大坑:从报错到修复的避坑指南 复制来的代码跑不通,报错信息一堆却不知从哪下手调?这种绝望感每个开发者都懂。今天这篇ps描边路径避坑指南,专治各种“看着对但跑不出结果”的疑难杂症。 坑一:路径坐标越界导致的静默失败 现象:…

2026/9/22 20:01:28

3个j3455性能优化陷阱:手写实现避坑指南

3个j3455性能优化陷阱:手写实现避坑指南 看了一堆教程还是不会写项目?别急,问题不在你笨,而在你没摸透底层逻辑。很多开发者卡在“j3455”这个概念上,以为它是某个特定框架或库,其实它是一个被过度神话的编码代号,常出现在老旧系统的性能优…

2026/9/22 20:01:28

苹果x电量监控手写实现:3步搞定环境配置痛点

苹果x电量监控手写实现:3步搞定环境配置痛点 配置环境就卡半天,是不是熟悉的感觉?很多刚入行的同学,想做个苹果x电量监控的小项目,结果卡在依赖安装、版本冲突或者API权限上,光折腾环境就花了一整天。别急,今天咱们不整那些虚的,直接上手,用…

2026/9/22 19:56:28

拒绝卡顿!2d网游帧率优化实战,从入门到精通

拒绝卡顿!2d网游帧率优化实战,从入门到精通 你是不是也遇到过这种情况:看了一堆教程,代码能跑通,Demo也做得花里胡哨,但一放到真机或者大地图场景里,帧率直接掉到20以下,玩家还没看清发生了什么就卡死了?这种“看了一堆教程还是不会写项目”…

2026/9/22 10:02:42

GAMP 5 基于风险的计算机化系统验证:软件分类与审计追踪实践

简介:《A Risk-Based Approach to Compliant GxP Computerized Systems》即业内熟知的GAMP 5指南,面向制药企业质量与IT合规人员、验证工程师及计算机化系统管理者,用于解决GxP法规环境下系统合规性难以科学落地的问题。文档以风险管理为主线…

2026/9/22 9:07:39

安全托管MSSP实战:从静态防御到人机协同的攻防运营与应急响应

简介:这份PPT围绕互联网业务安全托管服务展开,面向企业安全负责人、IT运维人员及关注MSSP/MSS选型的读者,重点回应传统安全过度依赖人工、碎片化静态防御难以对抗产业化攻击等痛点。资源共1个pptx文件,包体约30.63MB,以…

2026/9/22 0:04:49

输电线路在线监测高频面试题拆解 3秒抓住官方文档重点

输电线路在线监测高频面试题拆解 3秒抓住官方文档重点 官方文档几百页翻到头还是懵?面试问到 输电线路在线监测 的数据链路时,脑子一片空白?别慌,这种 高频面试题 我整理了10年,专门治各种“文档太长抓不住重点”的毛病。…

2026/9/22 0:04:49

中介房源管理系统重构避坑:3个关键步骤搞定API变更

中介房源管理系统重构避坑:3个关键步骤搞定API变更 版本升级后 API 全变了,这种痛只有真做过的人懂。 很多团队在接手老旧房产项目时,最崩溃的不是代码烂,而是底层框架升级后,原本熟悉的接口调用方式彻底失效。 这份 保姆级教程…

2026/9/22 0:04:49

3个坑点带你一文搞懂55gg小游戏源码

3个坑点带你一文搞懂55gg小游戏源码 盯着控制台满屏的红色报错,看着那一长串 StackTrace ,是不是脑子瞬间宕机?别急,这种时候最忌讳的就是盲目改代码。很多刚入行的前端同学,面对 55gg 小游戏这类轻量级 H5…

2026/9/22 16:34:32

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/22 20:01:30

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/22 13:25:41

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
咨询二维码