资讯详情

x402 bazaar 扩展深度解析:用 HTTP 402 响应为端点与 MCP 工具构建可发现、可验证的资源目录

📅 2026/9/17 20:20:01 | 华诺云谱 👁 阅读
x402 bazaar 扩展深度解析:用 HTTP 402 响应为端点与 MCP 工具构建可发现、可验证的资源目录
x402 bazaar 扩展深度解析用 HTTP 402 响应为端点与 MCP 工具构建可发现、可验证的资源目录【免费下载链接】x402A payments protocol for the internet. Built on HTTP.项目地址: https://gitcode.com/GitHub_Trending/x4/x402bazaar是 x402 协议 v2 的官方扩展机制它让资源服务器在 402 Payment Required 响应中顺带“自描述”端点的调用方式HTTP 方法与参数、请求体或 MCP 工具名与参数 Schema从而使 Facilitator 能够自动编目和索引这些付费资源。本文基于规范文档 specs/extensions/bazaar.md结合仓库中 TypeScripttypescript/packages/extensions/src/bazaar/、Gogo/extensions/bazaar/、Pythonpython/x402/extensions/bazaar/三套 SDK 的真实实现完整讲解该扩展的线格式、字段语义、Schema 验证规则、动态路由的routeTemplate编目契约以及 Facilitator/Client 两侧的必做与可选行为。一、设计目标发现与编目Discovery and Cataloging在 x402 的世界里一次付费调用遵循如下链路客户端请求资源 → 服务器返回 402 与支付要求 → 客户端带着PaymentPayload交给 Facilitator 完成验证与结算。bazaar扩展在链路中注入了一条“元信息通道”资源服务器在 402 响应的extensions对象中声明bazaar扩展其中包含端点规格HTTP 方法或 MCP 工具名、输入参数示例、输出格式Facilitator收到携带该扩展的PaymentPayload后按随附的 JSON Schema 验证info再将其提取出来编目进发现服务数据库、发现 API 等存储方式属于实现细节规范不做强制客户端的职责很轻只需把 402 响应中的bazaar扩展原样回显echo到PaymentPayload中。若省略该扩展则不会发生任何编目。这种设计的关键在于发现数据不是由 Facilitator 猜测出来的而是由服务器主动声明、且携带自我验证能力的 JSON Schema。这使得编目过程既有数据可查、又有线上可校验的信任基础。二、PaymentRequired中的扩展结构bazaar扩展遵循 v2 扩展标准模式由两个字段组成info真正的发现数据——HTTP 方法与输入参数或 MCP 工具名与参数 Schema、输出格式schema一个 JSON SchemaDraft 2020-12用于验证info的结构合法性。info.input采用可辨识联合discriminated union由type字段区分input.type: http—— HTTP 端点再按method细分为“查询参数方法”GET/HEAD/DELETE与“请求体方法”POST/PUT/PATCH两类input.type: mcp—— MCPModel Context Protocol工具。2.1 GET 端点示例{ x402Version: 2, error: Payment required, resource: { url: https://api.example.com/weather, description: Weather data endpoint, mimeType: application/json }, accepts: [ ... ], extensions: { bazaar: { info: { input: { type: http, method: GET, queryParams: { city: San Francisco } }, output: { type: json, example: { city: San Francisco, weather: foggy, temperature: 60 } } }, schema: { $schema: https://json-schema.org/draft/2020-12/schema, type: object, properties: { input: { type: object, properties: { type: { type: string, const: http }, method: { type: string, enum: [GET, HEAD, DELETE] }, queryParams: { type: object, properties: { city: { type: string } }, required: [city] }, headers: { type: object, additionalProperties: { type: string } } }, required: [type, method], additionalProperties: false }, output: { type: object, properties: { type: { type: string }, example: { type: object } }, required: [type] } }, required: [input] } } } }注意示例中schema的method枚举是[GET, HEAD, DELETE]整组——这是声明期的宽枚举TypeScript SDK 的服务器扩展会在获得真实 HTTP 上下文后把method收窄为当前请求的实际方法见 server.ts 中enrichDeclaration的注释“在声明时使用宽枚举因为方法要等 HTTP 上下文可用才可知”从而让最终发出的 Schema 验证更精确。2.2 POST 端点示例{ x402Version: 2, error: Payment required, resource: { url: https://api.example.com/search, description: Search endpoint, mimeType: application/json }, accepts: [ ... ], extensions: { bazaar: { info: { input: { type: http, method: POST, bodyType: json, body: { query: example } }, output: { type: json, example: { results: [] } } }, schema: { $schema: https://json-schema.org/draft/2020-12/schema, type: object, properties: { input: { type: object, properties: { type: { type: string, const: http }, method: { type: string, enum: [POST, PUT, PATCH] }, bodyType: { type: string, enum: [json, form-data, text] }, body: { type: object }, queryParams: { type: object, additionalProperties: { type: string } }, headers: { type: object, additionalProperties: { type: string } } }, required: [type, method, bodyType, body], additionalProperties: false }, output: { type: object, properties: { type: { type: string }, example: { type: object } }, required: [type] } }, required: [input] } } } }2.3 MCP 工具示例{ x402Version: 2, error: Payment required, resource: { url: https://api.example.com/mcp, description: Advanced AI-powered financial tools, mimeType: application/json }, accepts: [ ... ], extensions: { bazaar: { info: { input: { type: mcp, tool: financial_analysis, description: Advanced AI-powered financial analysis, inputSchema: { type: object, properties: { ticker: { type: string }, analysis_type: { type: string, enum: [quick, deep] } }, required: [ticker] }, example: { ticker: AAPL, analysis_type: deep } }, output: { type: json, example: { summary: Strong fundamentals..., score: 8.5 } } }, schema: { $schema: https://json-schema.org/draft/2020-12/schema, type: object, properties: { input: { type: object, properties: { type: { type: string, const: mcp }, tool: { type: string }, description: { type: string }, transport: { type: string, enum: [streamable-http, sse] }, inputSchema: { type: object }, example: { type: object } }, required: [type, tool, inputSchema], additionalProperties: false }, output: { type: object, properties: { type: { type: string }, example: { type: object } }, required: [type] } }, required: [input] } } } }Go SDK 的包文档 doc.go 中给出了对应的服务端声明代码bazaar.DeclareMcpDiscoveryExtension(bazaar.DeclareMcpDiscoveryConfig{ ToolName: weather_lookup, ... })随后将返回的扩展放入PaymentRequired.Extensions[bazaar.BAZAAR.Key()]即可。三、发现信息结构Discovery Info Structure3.1 输入类型info.input描述“如何调用这个端点/工具”按判别分为三类。查询参数方法GET、HEAD、DELETE字段类型必填说明typestring是恒为httpmethodstring是GET、HEAD、DELETE之一queryParamsobject否查询参数示例headersobject否自定义请求头示例请求体方法POST、PUT、PATCH字段类型必填说明typestring是恒为httpmethodstring是POST、PUT、PATCH之一bodyTypestring是json、form-data、text之一bodyobject/string是请求体示例queryParamsobject否查询参数示例headersobject否自定义请求头示例MCP 工具字段类型必填说明typestring是恒为mcptoolstring是MCP 工具名即传给tools/call的名称descriptionstring否工具的人类可读描述inputSchemaobject是工具arguments的 JSON Schema遵循 MCPTool.inputSchema格式含type: object、properties、required的 JSON Schema 子集。服务器应直接复用其 MCP 工具已声明的同一份 Schematransportstring否MCP 传输协议streamable-http或sse。省略时默认streamable-httpexampleobject否示例arguments对象注意对于 MCP 工具唯一资源标识符是元组resource.url,input.tool。因为 MCP 在单个服务端点上复用多个工具resource.url单独并不唯一。Facilitator 在编目 MCP 工具时必须同时使用这两个字段。3.2 输出类型info.output可选描述预期响应格式字段类型必填说明typestring是响应内容类型如json、textformatstring否附加格式信息exampleany否响应示例值注意对于 MCP 工具如果省略outputFacilitator 应假定输出为任意文本内容MCP 的默认响应类型。3.3 输入类型判别器input.type是发现信息结构的判别字段input.type结构说明httpQueryDiscoveryInfoHTTP GET/HEAD/DELETE携带查询参数httpBodyDiscoveryInfoHTTP POST/PUT/PATCH携带请求体有bodyTypemcpMCPDiscoveryInfoMCP 工具调用Facilitator 应依据input.type决定应用哪组验证规则对 HTTP 输入bodyType的存在与否进一步区分查询方法与请求体方法。这一点在 TypeScript 实现中体现为显式的类型守卫 http/types.ts 中isQueryExtensionConfig/isBodyExtensionConfig以配置对象是否包含bodyType字段作为判别依据。四、Schema 验证规则schema字段是一个 JSON SchemaDraft 2020-12用于验证info的结构规范要求必须使用 JSON Schema Draft 2020-12必须定义input属性必填可定义output属性可选必须验证input.type等于httpHTTP 端点或mcpMCP 工具对 HTTP 端点必须按操作类型验证相应的method枚举对 MCP 工具必须要求tool和inputSchema字段。Facilitator 在编目前必须must用schema验证info。仓库中的 TypeScript 实现 validateDiscoveryExtension 正使用 Ajv 的 Draft 2020 实现ajv/dist/2020.js编译服务器随附的 Schema对extension.info直接做验证失败时返回instancePath: message形式的错误列表——这与规范“验证失败应可报告具体原因”的精神一致。五、Facilitator 行为与EXTENSION-RESPONSES响应头当 Facilitator 收到包含bazaar扩展的PaymentPayload时规范定义了两步必做动作Validate用提供的schema验证info字段Extract提取发现信息资源 URL、HTTP 方法或 MCP 工具名、输入/输出规格。Facilitator 如何存储、索引、对外暴露已发现资源数据库编目、发现 API、任意处理方式属于实现细节规范刻意不做强约束。5.1EXTENSION-RESPONSES头处理完PaymentPayload后Facilitator **可以MAY**在 verify 或 settlement 响应中追加EXTENSION-RESPONSESHTTP 头向客户端传达扩展处理结果头名EXTENSION-RESPONSES头值base64 编码的 JSON 对象键为扩展名bazaar键包含该扩展的响应字段类型必填说明bazaar.statusstring是success、processing、rejected之一bazaar.rejectedReasonstring否人类可读说明。仅当status为rejected时出现状态取值语义值含义success发现信息已通过验证并成功编目processing发现信息已接收正在异步编目rejected发现信息被拒绝如 Schema 验证失败。细节见rejectedReason成功示例EXTENSION-RESPONSES: eyJiYXphYXIiOnsic3RhdHVzIjoic3VjY2VzcyJ9fQ即{bazaar:{status:success}}的 base64拒绝示例EXTENSION-RESPONSES: eyJiYXphYXIiOnsic3RhdHVzIjoicmVqZWN0ZWQiLCJyZWplY3RlZFJlYXNvbiI6ImluZm8gZmFpbGVkIHNjaGVtYSB2YWxpZGF0aW9uIn19即{bazaar:{status:rejected,rejectedReason:info failed schema validation}}的 base64理解了bazaar扩展的客户端**应该SHOULD**读取该头的bazaar键以确认编目成功、并在调试时展示拒绝原因。六、Client 行为客户端只需把PaymentRequired响应中的bazaar扩展回显到PaymentPayload中即可。省略该扩展时不会发生发现编目。换言之编目链路的责任链是服务器声明 → 客户端回显 → Facilitator 验证并编目。七、动态路由与routeTemplateHTTP 端点常使用参数化路由如/users/[userId]。当路由含参数段时服务器扩展会为bazaar扩展追加两个字段info.input.pathParams—— 本次具体请求的参数值如{ userId: 123 }routeTemplate—— 采用:param语法的规范模板如/users/:userId。routeTemplate位于扩展对象顶层是服务器与 Facilitator 之间的编目键契约Facilitator 用它把/users/123、/users/456等所有具体请求映射到同一个规范编目条目。7.1routeTemplate线格式服务器内部使用[paramName]语法书写路由模式贴合路由框架惯例如 Next.js扩展对外交付routeTemplate时使用:paramName语法贴合 REST 惯例如 Express静态路由时该字段缺失Facilitator 必须MUST把缺失视为“直接使用具体 URL 路径”。动态路由的扩展增强示例{ info: { input: { type: http, method: GET, pathParams: { userId: 123 } } }, schema: { ... }, routeTemplate: /users/:userId }TypeScript SDK 的 extractDynamicRouteInfo 实现展示了这套转换同时支持[param]与:param两种输入语法输出恒为:param语法normalizeWildcardPattern 还会把*通配段自动改写为:var1、:var2以便编目归一化。7.2routeTemplate验证规则Facilitator 在使用routeTemplate作为编目键之前**必须MUST**验证它。预期格式为冒号前缀参数标识符如/users/:userId、/weather/:country/:city。规范明确要求三套 SDK 使用同一份验证逻辑isValidRouteTemplateTypeScript、Go与_is_valid_route_templatePython规则逐条如下规则原因必须是非空字符串空/缺失表示“无模板”必须以/开头防止相对路径与外部 URL必须匹配^/[a-zA-Z0-9_/:.\-~%]$只允许安全的 URL 路径字符与:param标识符不得包含..防止路径穿越/users/../admin不得包含://防止 URL 注入http://evil.com所有实现在做穿越检查与 scheme 检查之前都会先对值做百分号解码如%2e%2e→..。任何一条规则不满足该值即被丢弃Facilitator 回退为使用具体 URL 路径编目。规范还特别叮嘱 SDK 实现者若新增第四套 SDK必须原样复制这些验证规则包括百分号解码步骤——三份副本必须保持同步。从源码看这条规则背后的安全动机写得很直白isValidRouteTemplate 的注释指出 Facilitator 是信任边界——客户端控制支付负载可以在提交前篡改routeTemplate恶意值会让 Facilitator 把支付编目到任意 URL编目投毒catalog poisoning。因此在 extractDiscoveryInfo 中routeTemplate只有在通过isValidRouteTemplate校验后才被采纳为规范路径${url.origin}${routeTemplate}否则编目键退化为${url.origin}${url.pathname}查询串与 hash 段也会被剥离。Python 对应实现在 facilitator.py 中定义了_is_valid_route_template在提取路径中同样先校验再使用。八、三套 SDK 的落地方式规范定义的线格式在三套 SDK 中均有完整实现开发者可各取所需TypeScripttypescript/packages/extensions/src/bazaar/服务器侧统一入口declareDiscoveryExtension(config)resourceService.ts配置含toolName时走 MCP 构建器含bodyType时走 Body 构建器否则走 Query 构建器返回形如{ bazaar: extension }的对象bazaarResourceServerExtensionserver.ts在拿到 HTTP 上下文后完成 method 收窄、routeTemplate/pathParams注入且对 MCP 扩展input.type mcp跳过 HTTP 方法增强Facilitator 侧提供validateDiscoveryExtension、extractDiscoveryInfo、validateAndExtract等函数统一输出DiscoveredHTTPResource/DiscoveredMCPResource两类编目对象http/types.ts、mcp/types.ts。Gogo/extensions/bazaar/包文档 doc.go 给出服务器声明DeclareDiscoveryExtension/DeclareMcpDiscoveryExtension、Facilitator 提取ExtractDiscoveredResourceFromPaymentPayload、客户端 402 解析ExtractDiscoveredResourceFromPaymentRequired三类用法客户端提取在 v2 下检查PaymentRequired.Extensions并回退到Accepts[0]v1 下读取Accepts[0].OutputSchema。Pythonpython/x402/extensions/bazaar/与 TypeScript 结构对应的types.py、server.py、facilitator.py、resource_service.py、facilitator_client.py模块routeTemplate校验函数为_is_valid_route_template。三套实现的测试如 bazaar.test.ts、bazaar_test.go覆盖了声明、验证与提取链路可作为行为参考。九、向后兼容性从 v1 的outputSchema到 v2 的extensions.bazaarbazaar扩展在 x402 v2 中正式定型发现功能在 v1 中曾以非正式形式存在于outputSchema字段。规范明确Facilitator 不必支持 v1。若确有需求字段映射关系如下V1 位置V2 位置accepts[0].outputSchemaextensions.bazaaraccepts[0].resourceresource.urlaccepts[0].description顶层descriptionaccepts[0].mimeType顶层mimeTypev1 没有正式的 Schema 验证机制。值得注意的是TypeScript 的extractDiscoveryInfo实际上同时处理了 v1 与 v2v1 分支调用 v1/facilitator 中的extractDiscoveryInfoV1并自动把 v1 数据转换为 v2 的DiscoveryInfo结构对字段名做智能假设Go SDK 的两个提取函数同样自动兼容 v1 格式doc.go——也就是说规范层面“不要求”v1 支持而 SDK 层面“提供了”便利的 v1 转换能力两者并不矛盾规范定契约SDK 给便利。十、实践要点小结服务器在 402 响应中附带bazaar扩展info写清“怎么调用我”方法/工具名 参数示例schema写清“怎么验证它”Draft 2020-12动态路由的服务器依赖 SDK 的服务器扩展自动注入routeTemplate与pathParams。客户端把 402 中的bazaar扩展原样回显进PaymentPayload并读取 verify/settlement 响应中EXTENSION-RESPONSES头的bazaar键确认编目结果。Facilitator先验证info对schema、再验证routeTemplate含百分号解码后的..与://检查MCP 工具以resource.url,tool元组为编目键HTTP 动态路由以routeTemplate归一化所有具体请求。实现者新增 SDK 时逐字复制routeTemplate验证规则保持三份未来四份实现同步。【免费下载链接】x402A payments protocol for the internet. Built on HTTP.项目地址: https://gitcode.com/GitHub_Trending/x4/x402创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。