[{"data":1,"prerenderedAt":4597},["ShallowReactive",2],{"note:\u002Fagent\u002F02-mcp协议":3},{"id":4,"title":5,"body":6,"date":4577,"description":4578,"draft":4579,"extension":4580,"featured":140,"kind":4581,"lastmod":4577,"meta":4582,"navigation":140,"path":4586,"planned":4587,"section":4588,"seo":4589,"source":4590,"stem":4591,"tags":4592,"toc":140,"weight":195,"__hash__":4596},"notes\u002Fagent\u002F02-MCP协议.md","MCP 协议：给大模型的工具装一个「Type-C 接口」",{"type":7,"value":8,"toc":4558},"minimark",[9,16,21,26,29,36,39,64,211,219,229,232,236,243,248,256,261,267,367,378,381,469,475,479,548,720,730,734,740,743,763,766,769,774,778,850,869,872,877,897,902,919,923,992,1003,1014,1017,1087,1098,1103,1111,1183,1188,1193,1208,1256,1261,1269,1323,1328,1336,1368,1373,1378,1386,1390,1393,1398,1426,1463,1498,1503,1532,1570,1602,1607,1627,1662,1694,1699,1837,1848,1937,1946,1950,1957,2032,2131,2150,2155,2163,2177,2181,2215,2219,2226,2239,2244,2254,2262,2519,2525,2591,2595,2602,2665,2696,2727,2734,2900,2904,2977,2980,2986,2990,3016,3023,3375,3379,3461,3463,3469,3473,3480,3499,3503,3521,3528,3633,3637,3640,3647,3740,3744,3768,3773,3821,3825,3834,3986,4003,4007,4014,4029,4054,4058,4061,4068,4157,4161,4168,4258,4262,4361,4365,4400,4405,4502,4514,4518,4554],[10,11,12],"blockquote",{},[13,14,15],"p",{},"一句话总结：Function Call 解决的是“模型怎么表达要调用工具”，MCP 解决的是“工具怎么被统一暴露和调用”——前者是模型层的能力，后者是工具层的协议。MCP 想做的，是 AI 世界的 Type-C。",[17,18,20],"h2",{"id":19},"_1-背景","1. 背景",[22,23,25],"h3",{"id":24},"_11-从一个生活场景说起","1.1 从一个生活场景说起",[13,27,28],{},"出差住酒店，你把手机、手表、耳机往床头一放，桌上却只有一种接口可用——Type-C 解决了\"接口不统一\"这件事。在它出现之前，每家厂商都有自己的方案：Micro-USB、Lightning、Mini-USB……出门得带三根线再加一个转接头，借个充电宝还得先看口子对不对得上。",[13,30,31,35],{},[32,33,34],"strong",{},"大模型调用工具也经历了类似的\"接口混乱\"阶段","。",[13,37,38],{},"在前面的 Function Call 例子中，工具的描述（函数名、参数格式、说明文字）都是由应用开发者手写的。这就带来两个现实问题：",[40,41,42,58],"ul",{},[43,44,45,48,49,53,54,57],"li",{},[32,46,47],{},"描述质量参差不齐","：同一个能力，不同开发者写法不同——有的叫\"查询排队人数\"，有的叫\"获取门店等候时长\"；参数有的用 ",[50,51,52],"code",{},"store","，有的用 ",[50,55,56],{},"shop_id","。模型该按哪一份来调？调用稳定性自然无法保证。",[43,59,60,63],{},[32,61,62],{},"重复劳动严重","：你封装好了一个门店排队查询工具，隔壁团队也想用——但他们得照文档重写一遍描述、重新调试参数格式。工具越多，这种重复越夸张。",[65,66,71],"pre",{"className":67,"code":68,"language":69,"meta":70,"style":70},"language-mermaid shiki shiki-themes github-light github-dark","flowchart LR\n    subgraph Before[\"❌ 没有 MCP 之前：每个工具\u002F服务描述格式各异\"]\n        B1[\"REST API\u003Cbr\u002F>GET \u002Fapi\u002Fstore\u002Fqueue?shop=望京店 → JSON\"]\n        B2[\"CLI 命令\u003Cbr\u002F>python store_cli.py --shop 望京店 --date 2026-09-14\"]\n        B3[\"SDK 函数\u003Cbr\u002F>store_sdk.queue_length(shop=望京店)\"]\n        B4[\"LLM 需要为每种格式写不同的对接代码\"]\n        B1 --> B4\n        B2 --> B4\n        B3 --> B4\n    end\n\n    subgraph After[\"✅ 使用 MCP 之后：所有工具统一描述\"]\n        A1[\"统一的 MCP 工具描述\u003Cbr\u002F>name = get_queue_length\u003Cbr\u002F>description = 查询门店排队时长\u003Cbr\u002F>inputSchema = store \u002F string\"]\n        A2[\"LLM 只认一种格式，新增工具零改动\"]\n        A1 --> A2\n    end\n\n    Before -->|MCP| After\n\n    style Before fill:#FEF2F2,stroke:#DC2626,stroke-width:2px\n    style After fill:#ECFDF5,stroke:#059669,stroke-width:2px\n    style B4 fill:#FFFFFF,stroke:#DC2626\n    style A2 fill:#FFFFFF,stroke:#059669\n","mermaid","",[50,72,73,81,87,93,99,105,111,117,123,129,135,142,148,154,160,166,171,176,182,187,193,199,205],{"__ignoreMap":70},[74,75,78],"span",{"class":76,"line":77},"line",1,[74,79,80],{},"flowchart LR\n",[74,82,84],{"class":76,"line":83},2,[74,85,86],{},"    subgraph Before[\"❌ 没有 MCP 之前：每个工具\u002F服务描述格式各异\"]\n",[74,88,90],{"class":76,"line":89},3,[74,91,92],{},"        B1[\"REST API\u003Cbr\u002F>GET \u002Fapi\u002Fstore\u002Fqueue?shop=望京店 → JSON\"]\n",[74,94,96],{"class":76,"line":95},4,[74,97,98],{},"        B2[\"CLI 命令\u003Cbr\u002F>python store_cli.py --shop 望京店 --date 2026-09-14\"]\n",[74,100,102],{"class":76,"line":101},5,[74,103,104],{},"        B3[\"SDK 函数\u003Cbr\u002F>store_sdk.queue_length(shop=望京店)\"]\n",[74,106,108],{"class":76,"line":107},6,[74,109,110],{},"        B4[\"LLM 需要为每种格式写不同的对接代码\"]\n",[74,112,114],{"class":76,"line":113},7,[74,115,116],{},"        B1 --> B4\n",[74,118,120],{"class":76,"line":119},8,[74,121,122],{},"        B2 --> B4\n",[74,124,126],{"class":76,"line":125},9,[74,127,128],{},"        B3 --> B4\n",[74,130,132],{"class":76,"line":131},10,[74,133,134],{},"    end\n",[74,136,138],{"class":76,"line":137},11,[74,139,141],{"emptyLinePlaceholder":140},true,"\n",[74,143,145],{"class":76,"line":144},12,[74,146,147],{},"    subgraph After[\"✅ 使用 MCP 之后：所有工具统一描述\"]\n",[74,149,151],{"class":76,"line":150},13,[74,152,153],{},"        A1[\"统一的 MCP 工具描述\u003Cbr\u002F>name = get_queue_length\u003Cbr\u002F>description = 查询门店排队时长\u003Cbr\u002F>inputSchema = store \u002F string\"]\n",[74,155,157],{"class":76,"line":156},14,[74,158,159],{},"        A2[\"LLM 只认一种格式，新增工具零改动\"]\n",[74,161,163],{"class":76,"line":162},15,[74,164,165],{},"        A1 --> A2\n",[74,167,169],{"class":76,"line":168},16,[74,170,134],{},[74,172,174],{"class":76,"line":173},17,[74,175,141],{"emptyLinePlaceholder":140},[74,177,179],{"class":76,"line":178},18,[74,180,181],{},"    Before -->|MCP| After\n",[74,183,185],{"class":76,"line":184},19,[74,186,141],{"emptyLinePlaceholder":140},[74,188,190],{"class":76,"line":189},20,[74,191,192],{},"    style Before fill:#FEF2F2,stroke:#DC2626,stroke-width:2px\n",[74,194,196],{"class":76,"line":195},21,[74,197,198],{},"    style After fill:#ECFDF5,stroke:#059669,stroke-width:2px\n",[74,200,202],{"class":76,"line":201},22,[74,203,204],{},"    style B4 fill:#FFFFFF,stroke:#DC2626\n",[74,206,208],{"class":76,"line":207},23,[74,209,210],{},"    style A2 fill:#FFFFFF,stroke:#059669\n",[10,212,213],{},[13,214,215,218],{},[32,216,217],{},"图示解读："," 左边是三种形态各异的工具接入方式——HTTP 接口、命令行脚本、SDK 函数，每一种都要 LLM 侧单独写对接代码；MCP 把这三种形态统一收敛成一份\"名字 + 描述 + 参数 Schema\"的声明，模型只认这一种格式。这就是 MCP 被称为\"工具世界 USB 接口\"的原因。",[13,220,221,224,225,228],{},[32,222,223],{},"核心矛盾在于","：工具的描述应该由",[32,226,227],{},"最了解工具的人","（工具开发者）来完成，而不是由调用者（应用开发者）去猜。如果工具能\"自我介绍\"——清晰地描述自己有什么能力、需要什么参数——就能实现\"一次编写，到处调用\"。",[13,230,231],{},"这就是 MCP 要解决的问题。",[22,233,235],{"id":234},"_12-有了-mcp-之前-vs-有了-mcp-之后","1.2 有了 MCP 之前 vs 有了 MCP 之后",[13,237,238,239,242],{},"为了更直观地理解 MCP 的价值，先看一个",[32,240,241],{},"真实开发场景的对比","：假设你的团队要开发一个门店经营助手，需要接入排队时长查询、原料库存查询、员工排班查询三个外部工具。",[13,244,245],{},[32,246,247],{},"有了 MCP 之前（Function Call 手工集成）：",[65,249,254],{"className":250,"code":252,"language":253,"meta":70},[251],"language-text","应用开发者视角：\n1. 打开排队系统 API 文档 → 手写 JSON Schema 描述（函数名、参数、返回值）\n2. 打开库存系统 API 文档 → 手写 JSON Schema 描述\n3. 打开排班系统 API 文档 → 手写 JSON Schema 描述\n4. 编写胶水代码：拼接 HTTP 请求 → 解析响应 → 转换格式\n5. 每个 API 的认证方式不同（API Key \u002F OAuth \u002F Cookie），分别处理\n6. 如果换一个 LLM 平台，以上全部重写一遍\n","text",[50,255,252],{"__ignoreMap":70},[13,257,258],{},[32,259,260],{},"有了 MCP 之后：",[65,262,265],{"className":263,"code":264,"language":253,"meta":70},[251],"应用开发者视角：\n1. 连接 MCP Server（一个 URL 搞定）\n2. 自动获取工具列表（Server 自己描述自己）\n3. 直接用，认证\u002F格式\u002F错误处理全由 MCP Server 负责\n",[50,266,264],{"__ignoreMap":70},[65,268,270],{"className":67,"code":269,"language":69,"meta":70,"style":70},"flowchart LR\n    subgraph NoMCP[\"❌ 没有 MCP（手工 Function Call）\"]\n        N1[\"LLM\"] --> N2[\"手写胶水代码（每个 API 单独处理）\u003Cbr\u002F>1. 读文档 → 手写 JSON Schema 描述\u003Cbr\u002F>2. 编写 HTTP 请求拼接 + 响应解析\u003Cbr\u002F>3. 分别处理不同认证方式 Key\u002FOAuth\u002FCookie\"]\n        N2 --> N3[\"排队系统 API\"]\n        N2 --> N4[\"库存系统 API\"]\n        N2 --> N5[\"排班系统 API\"]\n        N6[\"痛点：每接一个 API 需要半天到一天\u003Cbr\u002F>描述质量参差不齐\u003Cbr\u002F>换 LLM 平台需要全部重写\u003Cbr\u002F>各团队重复造轮子\"]\n    end\n\n    subgraph HasMCP[\"✅ 有了 MCP\"]\n        H1[\"LLM\"] -->|FC| H2[\"MCP Client\"]\n        H2 -->|一个 URL| H3[\"MCP Server（统一接入）\"]\n        H3 --> H4[\"排队工具\"]\n        H3 --> H5[\"库存工具\"]\n        H3 --> H6[\"排班工具\"]\n        H7[\"优势：工具自描述，自动发现，几分钟接入\u003Cbr\u002F>工具升级自动同步，客户端无感\u003Cbr\u002F>一次编写，所有 MCP 兼容 LLM 都能用\u003Cbr\u002F>社区生态共享，拿来即用\"]\n    end\n\n    style NoMCP fill:#FEF2F2,stroke:#DC2626,stroke-width:2px\n    style HasMCP fill:#ECFDF5,stroke:#059669,stroke-width:2px\n",[50,271,272,276,281,286,291,296,301,306,310,314,319,324,329,334,339,344,349,353,357,362],{"__ignoreMap":70},[74,273,274],{"class":76,"line":77},[74,275,80],{},[74,277,278],{"class":76,"line":83},[74,279,280],{},"    subgraph NoMCP[\"❌ 没有 MCP（手工 Function Call）\"]\n",[74,282,283],{"class":76,"line":89},[74,284,285],{},"        N1[\"LLM\"] --> N2[\"手写胶水代码（每个 API 单独处理）\u003Cbr\u002F>1. 读文档 → 手写 JSON Schema 描述\u003Cbr\u002F>2. 编写 HTTP 请求拼接 + 响应解析\u003Cbr\u002F>3. 分别处理不同认证方式 Key\u002FOAuth\u002FCookie\"]\n",[74,287,288],{"class":76,"line":95},[74,289,290],{},"        N2 --> N3[\"排队系统 API\"]\n",[74,292,293],{"class":76,"line":101},[74,294,295],{},"        N2 --> N4[\"库存系统 API\"]\n",[74,297,298],{"class":76,"line":107},[74,299,300],{},"        N2 --> N5[\"排班系统 API\"]\n",[74,302,303],{"class":76,"line":113},[74,304,305],{},"        N6[\"痛点：每接一个 API 需要半天到一天\u003Cbr\u002F>描述质量参差不齐\u003Cbr\u002F>换 LLM 平台需要全部重写\u003Cbr\u002F>各团队重复造轮子\"]\n",[74,307,308],{"class":76,"line":119},[74,309,134],{},[74,311,312],{"class":76,"line":125},[74,313,141],{"emptyLinePlaceholder":140},[74,315,316],{"class":76,"line":131},[74,317,318],{},"    subgraph HasMCP[\"✅ 有了 MCP\"]\n",[74,320,321],{"class":76,"line":137},[74,322,323],{},"        H1[\"LLM\"] -->|FC| H2[\"MCP Client\"]\n",[74,325,326],{"class":76,"line":144},[74,327,328],{},"        H2 -->|一个 URL| H3[\"MCP Server（统一接入）\"]\n",[74,330,331],{"class":76,"line":150},[74,332,333],{},"        H3 --> H4[\"排队工具\"]\n",[74,335,336],{"class":76,"line":156},[74,337,338],{},"        H3 --> H5[\"库存工具\"]\n",[74,340,341],{"class":76,"line":162},[74,342,343],{},"        H3 --> H6[\"排班工具\"]\n",[74,345,346],{"class":76,"line":168},[74,347,348],{},"        H7[\"优势：工具自描述，自动发现，几分钟接入\u003Cbr\u002F>工具升级自动同步，客户端无感\u003Cbr\u002F>一次编写，所有 MCP 兼容 LLM 都能用\u003Cbr\u002F>社区生态共享，拿来即用\"]\n",[74,350,351],{"class":76,"line":173},[74,352,134],{},[74,354,355],{"class":76,"line":178},[74,356,141],{"emptyLinePlaceholder":140},[74,358,359],{"class":76,"line":184},[74,360,361],{},"    style NoMCP fill:#FEF2F2,stroke:#DC2626,stroke-width:2px\n",[74,363,364],{"class":76,"line":189},[74,365,366],{},"    style HasMCP fill:#ECFDF5,stroke:#059669,stroke-width:2px\n",[10,368,369],{},[13,370,371,373,374,377],{},[32,372,217],{}," 左图是\"星型直连\"——LLM 通过一堆手写胶水代码分别对接 N 个 API，每加一个工具就多一份维护成本。右图把胶水代码换成了 ",[32,375,376],{},"MCP Server（统一接入）","：LLM 只经 Function Call 与 MCP Client 打交道，Client 再通过一个 URL 连上 Server，由 Server 内部去适配底下的三类工具。接入成本从\"每个 API 半天\"变成\"一次配置\"。",[13,379,380],{},"下面用一张对比表把差异说清楚：",[382,383,384,400],"table",{},[385,386,387],"thead",{},[388,389,390,394,397],"tr",{},[391,392,393],"th",{},"对比维度",[391,395,396],{},"没有 MCP（手工 Function Call）",[391,398,399],{},"有了 MCP",[401,402,403,417,430,443,456],"tbody",{},[388,404,405,411,414],{},[406,407,408],"td",{},[32,409,410],{},"工具描述谁写",[406,412,413],{},"应用开发者手写（经常不准确）",[406,415,416],{},"工具开发者自己写（最准确）",[388,418,419,424,427],{},[406,420,421],{},[32,422,423],{},"接入一个新工具",[406,425,426],{},"读文档 → 写 Schema → 写胶水代码 → 测试，通常半天到一天",[406,428,429],{},"配置 MCP Server 地址 → 自动发现工具，几分钟",[388,431,432,437,440],{},[406,433,434],{},[32,435,436],{},"工具升级",[406,438,439],{},"应用侧也要同步改 Schema 和胶水代码",[406,441,442],{},"Server 侧更新即可，客户端自动获取最新描述",[388,444,445,450,453],{},[406,446,447],{},[32,448,449],{},"跨 LLM 复用",[406,451,452],{},"每个 LLM 平台的 Schema 格式不同，需要分别适配",[406,454,455],{},"MCP 是统一协议，一次编写，所有支持 MCP 的 LLM 都能用",[388,457,458,463,466],{},[406,459,460],{},[32,461,462],{},"生态共享",[406,464,465],{},"各团队各自造轮子，同一个 API 被不同团队重复集成",[406,467,468],{},"MCP 社区提供标准化工具服务，拿来即用",[13,470,471,474],{},[32,472,473],{},"一句话总结","：MCP 之前，每个应用开发者都在\"手工接线\"；MCP 之后，工具自己\"插上就能用\"——就像 Type-C 统一了充电口一样。",[22,476,478],{"id":477},"_13-更多场景mcp-在真实业务中的价值","1.3 更多场景：MCP 在真实业务中的价值",[382,480,481,494],{},[385,482,483],{},[388,484,485,488,491],{},[391,486,487],{},"场景",[391,489,490],{},"没有 MCP 的痛点",[391,492,493],{},"有了 MCP 的解法",[401,495,496,509,522,535],{},[388,497,498,503,506],{},[406,499,500],{},[32,501,502],{},"企业内部知识库",[406,504,505],{},"每个 AI 应用都要单独写一套 RAG 接入代码，不同团队各搞一套",[406,507,508],{},"知识库团队发布一个 MCP Server，所有 AI 应用统一接入，查询\u002F权限\u002F缓存全由 Server 管理",[388,510,511,516,519],{},[406,512,513],{},[32,514,515],{},"数据库查询",[406,517,518],{},"开发者在提示词里拼 SQL，既不安全也不可控",[406,520,521],{},"DBA 发布 MCP Server，只暴露安全的查询工具，参数化查询防止注入，权限由 Server 统一管控",[388,523,524,529,532],{},[406,525,526],{},[32,527,528],{},"第三方 SaaS 集成",[406,530,531],{},"每接一个 SaaS（如飞书、钉钉、企业微信）都要写一套集成代码",[406,533,534],{},"社区已有大量现成的 MCP Server，配置 URL 即可使用",[388,536,537,542,545],{},[406,538,539],{},[32,540,541],{},"多模型切换",[406,543,544],{},"从 GPT 切到 Claude 切到通义千问，工具集成代码要重写三遍",[406,546,547],{},"MCP 工具定义与模型无关，切换模型不影响工具层",[65,549,551],{"className":67,"code":550,"language":69,"meta":70,"style":70},"flowchart TB\n    subgraph S1[\"场景一：企业内部知识库\"]\n        S1A[\"❌ 没有 MCP：每个 AI 应用单独写 RAG 接入代码\u003Cbr\u002F>不同团队各搞一套，重复劳动\u003Cbr\u002F>App A \u002F App B \u002F App C 各写一套\"]\n        S1B[\"✅ 有了 MCP：知识库团队发布 1 个 MCP Server\u003Cbr\u002F>所有 AI 应用统一接入\u003Cbr\u002F>App A\u002FB\u002FC → 同一个 MCP Server\"]\n        S1C[\"收益：一次构建，全公司复用；权限\u002F缓存由 Server 统一管理\"]\n        S1A --> S1B --> S1C\n    end\n\n    subgraph S2[\"场景二：数据库查询\"]\n        S2A[\"❌ 没有 MCP：开发者在提示词里拼 SQL\u003Cbr\u002F>不安全、不可控、有注入风险\u003Cbr\u002F>LLM → SELECT * FROM ...\"]\n        S2B[\"✅ 有了 MCP：DBA 发布 MCP Server\u003Cbr\u002F>参数化查询，权限由 Server 管控\u003Cbr\u002F>LLM → MCP → 安全的参数化 SQL\"]\n        S2C[\"收益：参数化查询防注入，DBA 统一管控权限\"]\n        S2A --> S2B --> S2C\n    end\n\n    subgraph S3[\"场景三：第三方 SaaS 集成\"]\n        S3A[\"❌ 没有 MCP：每接一个 SaaS 写一套集成代码\u003Cbr\u002F>飞书\u002F钉钉\u002F企业微信各搞各的\u003Cbr\u002F>API Key\u002FOAuth\u002FREST 各不相同\"]\n        S3B[\"✅ 有了 MCP：社区已有大量现成 MCP Server\u003Cbr\u002F>配置 URL 即可使用\u003Cbr\u002F>飞书 MCP \u002F 钉钉 MCP \u002F 企业微信 MCP\"]\n        S3C[\"收益：社区生态即插即用，零集成成本\"]\n        S3A --> S3B --> S3C\n    end\n\n    subgraph S4[\"场景四：多模型切换\"]\n        S4A[\"❌ 没有 MCP：从 GPT 切到 Claude 切到通义\u003Cbr\u002F>工具集成代码要重写三遍\u003Cbr\u002F>每个 LLM 平台 Schema 格式不同\"]\n        S4B[\"✅ 有了 MCP：工具定义与模型无关\u003Cbr\u002F>切换模型不影响工具层\u003Cbr\u002F>MCP Server = 统一标准接口\"]\n        S4C[\"收益：工具层与模型解耦，切换零成本\"]\n        S4A --> S4B --> S4C\n    end\n\n    style S1 fill:#ECFDF5,stroke:#059669,stroke-width:2px\n    style S2 fill:#EFF6FF,stroke:#2563EB,stroke-width:2px\n    style S3 fill:#F5F3FF,stroke:#7C3AED,stroke-width:2px\n    style S4 fill:#FFF7ED,stroke:#EA580C,stroke-width:2px\n",[50,552,553,558,563,568,573,578,583,587,591,596,601,606,611,616,620,624,629,634,639,644,649,653,657,662,668,674,680,686,691,696,702,708,714],{"__ignoreMap":70},[74,554,555],{"class":76,"line":77},[74,556,557],{},"flowchart TB\n",[74,559,560],{"class":76,"line":83},[74,561,562],{},"    subgraph S1[\"场景一：企业内部知识库\"]\n",[74,564,565],{"class":76,"line":89},[74,566,567],{},"        S1A[\"❌ 没有 MCP：每个 AI 应用单独写 RAG 接入代码\u003Cbr\u002F>不同团队各搞一套，重复劳动\u003Cbr\u002F>App A \u002F App B \u002F App C 各写一套\"]\n",[74,569,570],{"class":76,"line":95},[74,571,572],{},"        S1B[\"✅ 有了 MCP：知识库团队发布 1 个 MCP Server\u003Cbr\u002F>所有 AI 应用统一接入\u003Cbr\u002F>App A\u002FB\u002FC → 同一个 MCP Server\"]\n",[74,574,575],{"class":76,"line":101},[74,576,577],{},"        S1C[\"收益：一次构建，全公司复用；权限\u002F缓存由 Server 统一管理\"]\n",[74,579,580],{"class":76,"line":107},[74,581,582],{},"        S1A --> S1B --> S1C\n",[74,584,585],{"class":76,"line":113},[74,586,134],{},[74,588,589],{"class":76,"line":119},[74,590,141],{"emptyLinePlaceholder":140},[74,592,593],{"class":76,"line":125},[74,594,595],{},"    subgraph S2[\"场景二：数据库查询\"]\n",[74,597,598],{"class":76,"line":131},[74,599,600],{},"        S2A[\"❌ 没有 MCP：开发者在提示词里拼 SQL\u003Cbr\u002F>不安全、不可控、有注入风险\u003Cbr\u002F>LLM → SELECT * FROM ...\"]\n",[74,602,603],{"class":76,"line":137},[74,604,605],{},"        S2B[\"✅ 有了 MCP：DBA 发布 MCP Server\u003Cbr\u002F>参数化查询，权限由 Server 管控\u003Cbr\u002F>LLM → MCP → 安全的参数化 SQL\"]\n",[74,607,608],{"class":76,"line":144},[74,609,610],{},"        S2C[\"收益：参数化查询防注入，DBA 统一管控权限\"]\n",[74,612,613],{"class":76,"line":150},[74,614,615],{},"        S2A --> S2B --> S2C\n",[74,617,618],{"class":76,"line":156},[74,619,134],{},[74,621,622],{"class":76,"line":162},[74,623,141],{"emptyLinePlaceholder":140},[74,625,626],{"class":76,"line":168},[74,627,628],{},"    subgraph S3[\"场景三：第三方 SaaS 集成\"]\n",[74,630,631],{"class":76,"line":173},[74,632,633],{},"        S3A[\"❌ 没有 MCP：每接一个 SaaS 写一套集成代码\u003Cbr\u002F>飞书\u002F钉钉\u002F企业微信各搞各的\u003Cbr\u002F>API Key\u002FOAuth\u002FREST 各不相同\"]\n",[74,635,636],{"class":76,"line":178},[74,637,638],{},"        S3B[\"✅ 有了 MCP：社区已有大量现成 MCP Server\u003Cbr\u002F>配置 URL 即可使用\u003Cbr\u002F>飞书 MCP \u002F 钉钉 MCP \u002F 企业微信 MCP\"]\n",[74,640,641],{"class":76,"line":184},[74,642,643],{},"        S3C[\"收益：社区生态即插即用，零集成成本\"]\n",[74,645,646],{"class":76,"line":189},[74,647,648],{},"        S3A --> S3B --> S3C\n",[74,650,651],{"class":76,"line":195},[74,652,134],{},[74,654,655],{"class":76,"line":201},[74,656,141],{"emptyLinePlaceholder":140},[74,658,659],{"class":76,"line":207},[74,660,661],{},"    subgraph S4[\"场景四：多模型切换\"]\n",[74,663,665],{"class":76,"line":664},24,[74,666,667],{},"        S4A[\"❌ 没有 MCP：从 GPT 切到 Claude 切到通义\u003Cbr\u002F>工具集成代码要重写三遍\u003Cbr\u002F>每个 LLM 平台 Schema 格式不同\"]\n",[74,669,671],{"class":76,"line":670},25,[74,672,673],{},"        S4B[\"✅ 有了 MCP：工具定义与模型无关\u003Cbr\u002F>切换模型不影响工具层\u003Cbr\u002F>MCP Server = 统一标准接口\"]\n",[74,675,677],{"class":76,"line":676},26,[74,678,679],{},"        S4C[\"收益：工具层与模型解耦，切换零成本\"]\n",[74,681,683],{"class":76,"line":682},27,[74,684,685],{},"        S4A --> S4B --> S4C\n",[74,687,689],{"class":76,"line":688},28,[74,690,134],{},[74,692,694],{"class":76,"line":693},29,[74,695,141],{"emptyLinePlaceholder":140},[74,697,699],{"class":76,"line":698},30,[74,700,701],{},"    style S1 fill:#ECFDF5,stroke:#059669,stroke-width:2px\n",[74,703,705],{"class":76,"line":704},31,[74,706,707],{},"    style S2 fill:#EFF6FF,stroke:#2563EB,stroke-width:2px\n",[74,709,711],{"class":76,"line":710},32,[74,712,713],{},"    style S3 fill:#F5F3FF,stroke:#7C3AED,stroke-width:2px\n",[74,715,717],{"class":76,"line":716},33,[74,718,719],{},"    style S4 fill:#FFF7ED,stroke:#EA580C,stroke-width:2px\n",[10,721,722],{},[13,723,724,726,727],{},[32,725,217],{}," 四个场景的共性都是\"从 N 份重复实现收敛到 1 个统一出口\"：知识库把接入代码收敛到一个 Server、数据库把 SQL 拼接收敛到参数化查询、SaaS 把集成代码收敛到社区现成的 Server、多模型把平台适配收敛到与模型无关的工具层。",[32,728,729],{},"MCP 的核心价值就是工具自描述 + 统一标准 + 生态共享，最终落到\"一次编写，到处调用\"。",[17,731,733],{"id":732},"_2-什么是-mcp-协议","2. 什么是 MCP 协议",[13,735,736,739],{},[32,737,738],{},"一个生活类比","：把 LLM 想象成图书馆里的读者，MCP 就是服务台的馆员。读者（LLM）知道自己想借什么书（意图），却进不去书库（没有数据访问能力）。馆员（MCP Server）清楚馆藏目录上有什么（工具列表），能替读者去书库找书（执行工具），再把书递到手上（返回结果）。读者不需要知道书库在几楼、书按什么规则上架——只要说\"我要《三体》\"，馆员就搞定一切。",[13,741,742],{},"在这个类比中：",[40,744,745,751,757],{},[43,746,747,750],{},[32,748,749],{},"MCP 服务端（Server）"," = 馆员 + 书库接口：把本地函数包装成标准接口暴露出去",[43,752,753,756],{},[32,754,755],{},"MCP 客户端（Client）"," = 服务台的借阅终端：连接服务端、查询馆藏目录（工具列表）并按需取书（调用工具）",[43,758,759,762],{},[32,760,761],{},"MCP 主机（Host）"," = 图书馆本身：发起请求的 LLM 应用，MCP 客户端是主机程序内部的一个对象",[13,764,765],{},"MCP（Model Context Protocol，模型上下文协议）是由 Anthropic 提出的一套开放协议，旨在实现大型语言模型（LLM）与外部数据源和工具的无缝集成，用来在大模型和数据源之间建立安全双向的链接。",[13,767,768],{},"Anthropic 的愿景，是希望把 MCP 协议打造成 AI 世界的\"Type-C\"接口，可以通过 MCP 协议把工具、数据链接起来，达到类似 HTTP 协议的那种通用程度。",[10,770,771],{},[13,772,773],{},"协议（Protocol）是一种约定或标准，用于定义不同系统、设备或软件之间如何通信和交换数据。它确保各方使用相同的\"语言\"和规则，避免混乱。例如，HTTP 协议定义了浏览器与服务器的交互方式，USB 协议标准化了设备连接。",[22,775,777],{"id":776},"_21-mcp-核心架构","2.1 MCP 核心架构",[65,779,781],{"className":67,"code":780,"language":69,"meta":70,"style":70},"flowchart TB\n    H[\"🏠 Host（宿主应用）\u003Cbr\u002F>运行大模型的应用程序，如 AI 助手、IDE 插件\u003Cbr\u002F>内置 LLM 大语言模型\"]\n    C[\"🔌 MCP Client（客户端）\u003Cbr\u002F>每个工具对应一个 Client，负责与 Server 一对一通信\u003Cbr\u002F>Client A \u002F Client B \u002F Client C\"]\n    S[\"🧰 MCP Server（服务端）\u003Cbr\u002F>每个工具\u002F服务一个 Server，向 Client 暴露标准化的工具接口\u003Cbr\u002F>排队服务 \u002F 库存服务 \u002F 排班服务\"]\n    T[\"🗄 外部工具与数据源\u003Cbr\u002F>MySQL 订单库 · 门店排队系统 · 库存中心接口 · RAG 知识库\"]\n\n    H --> C\n    C --> S\n    S --> T\n\n    style H fill:#F8FAFC,stroke:#64748B,stroke-width:2px\n    style C fill:#EFF6FF,stroke:#2563EB,stroke-width:2px\n    style S fill:#ECFDF5,stroke:#059669,stroke-width:2px\n    style T fill:#FFF7ED,stroke:#EA580C,stroke-width:2px\n",[50,782,783,787,792,797,802,807,811,816,821,826,830,835,840,845],{"__ignoreMap":70},[74,784,785],{"class":76,"line":77},[74,786,557],{},[74,788,789],{"class":76,"line":83},[74,790,791],{},"    H[\"🏠 Host（宿主应用）\u003Cbr\u002F>运行大模型的应用程序，如 AI 助手、IDE 插件\u003Cbr\u002F>内置 LLM 大语言模型\"]\n",[74,793,794],{"class":76,"line":89},[74,795,796],{},"    C[\"🔌 MCP Client（客户端）\u003Cbr\u002F>每个工具对应一个 Client，负责与 Server 一对一通信\u003Cbr\u002F>Client A \u002F Client B \u002F Client C\"]\n",[74,798,799],{"class":76,"line":95},[74,800,801],{},"    S[\"🧰 MCP Server（服务端）\u003Cbr\u002F>每个工具\u002F服务一个 Server，向 Client 暴露标准化的工具接口\u003Cbr\u002F>排队服务 \u002F 库存服务 \u002F 排班服务\"]\n",[74,803,804],{"class":76,"line":101},[74,805,806],{},"    T[\"🗄 外部工具与数据源\u003Cbr\u002F>MySQL 订单库 · 门店排队系统 · 库存中心接口 · RAG 知识库\"]\n",[74,808,809],{"class":76,"line":107},[74,810,141],{"emptyLinePlaceholder":140},[74,812,813],{"class":76,"line":113},[74,814,815],{},"    H --> C\n",[74,817,818],{"class":76,"line":119},[74,819,820],{},"    C --> S\n",[74,822,823],{"class":76,"line":125},[74,824,825],{},"    S --> T\n",[74,827,828],{"class":76,"line":131},[74,829,141],{"emptyLinePlaceholder":140},[74,831,832],{"class":76,"line":137},[74,833,834],{},"    style H fill:#F8FAFC,stroke:#64748B,stroke-width:2px\n",[74,836,837],{"class":76,"line":144},[74,838,839],{},"    style C fill:#EFF6FF,stroke:#2563EB,stroke-width:2px\n",[74,841,842],{"class":76,"line":150},[74,843,844],{},"    style S fill:#ECFDF5,stroke:#059669,stroke-width:2px\n",[74,846,847],{"class":76,"line":156},[74,848,849],{},"    style T fill:#FFF7ED,stroke:#EA580C,stroke-width:2px\n",[10,851,852],{},[13,853,854,856,857,860,861,864,865,868],{},[32,855,217],{}," 自上而下四层，职责逐层收敛——Host 是",[32,858,859],{},"跑着大模型的应用进程","（只有它知道用户意图）；MCP Client 是 Host 内部的对象，",[32,862,863],{},"一个 Server 配一个 Client","，负责把模型的意图翻译成协议请求；MCP Server 是",[32,866,867],{},"工具的封装层","，对外只暴露标准化接口，对内实现业务逻辑；最底层才是真正干活的数据库与第三方 API。分层的收益是：换数据源不用动模型，换模型也不用动数据源。",[13,870,871],{},"MCP 协议有两个核心角色：客户端与服务端。",[13,873,874],{},[32,875,876],{},"MCP 服务端（Tool Provider）：",[40,878,879,885,891],{},[43,880,881,884],{},[32,882,883],{},"角色","：工具的提供者。",[43,886,887,890],{},[32,888,889],{},"职责","：将一个或多个本地函数（例如 Python 函数）包装起来，通过一个标准的 MCP 接口暴露出去。它监听来自客户端的请求，执行对应的函数，并返回结果。",[43,892,893,896],{},[32,894,895],{},"例子","：一个门店排队查询服务、一个数学计算服务、一个数据库访问服务。",[13,898,899],{},[32,900,901],{},"MCP 客户端（Tool Consumer）：",[40,903,904,909,914],{},[43,905,906,908],{},[32,907,883],{},"：工具的调用者或消费者。",[43,910,911,913],{},[32,912,889],{},"：连接到 MCP 服务端，查询可用的工具列表（自发现），并根据需要调用这些工具。",[43,915,916,918],{},[32,917,895],{},"：大模型 Agent、自动化脚本、任何需要远程执行功能的应用程序。",[22,920,922],{"id":921},"_22-mcp-工具调用流程","2.2 MCP 工具调用流程",[65,924,926],{"className":67,"code":925,"language":69,"meta":70,"style":70},"sequenceDiagram\n    participant U as 用户\n    participant L as LLM\n    participant C as MCP Client\n    participant S as MCP Server\n\n    U->>L: ① 提问\n    L->>C: ② 工具调用指令\n    C->>S: ③ 发送请求\n    S->>S: ④ 执行工具\n    S-->>C: ⑤ 返回结果\n    C-->>L: ⑥ 回传结果\n    L-->>U: ⑦ 生成回答\n",[50,927,928,933,938,943,948,953,957,962,967,972,977,982,987],{"__ignoreMap":70},[74,929,930],{"class":76,"line":77},[74,931,932],{},"sequenceDiagram\n",[74,934,935],{"class":76,"line":83},[74,936,937],{},"    participant U as 用户\n",[74,939,940],{"class":76,"line":89},[74,941,942],{},"    participant L as LLM\n",[74,944,945],{"class":76,"line":95},[74,946,947],{},"    participant C as MCP Client\n",[74,949,950],{"class":76,"line":101},[74,951,952],{},"    participant S as MCP Server\n",[74,954,955],{"class":76,"line":107},[74,956,141],{"emptyLinePlaceholder":140},[74,958,959],{"class":76,"line":113},[74,960,961],{},"    U->>L: ① 提问\n",[74,963,964],{"class":76,"line":119},[74,965,966],{},"    L->>C: ② 工具调用指令\n",[74,968,969],{"class":76,"line":125},[74,970,971],{},"    C->>S: ③ 发送请求\n",[74,973,974],{"class":76,"line":131},[74,975,976],{},"    S->>S: ④ 执行工具\n",[74,978,979],{"class":76,"line":137},[74,980,981],{},"    S-->>C: ⑤ 返回结果\n",[74,983,984],{"class":76,"line":144},[74,985,986],{},"    C-->>L: ⑥ 回传结果\n",[74,988,989],{"class":76,"line":150},[74,990,991],{},"    L-->>U: ⑦ 生成回答\n",[10,993,994],{},[13,995,996,998,999,1002],{},[32,997,217],{}," 注意第 ④ 步是",[32,1000,1001],{},"自循环","——真正执行工具逻辑的动作发生在 MCP Server 内部，模型侧完全看不到实现细节。整条链路的分工是：LLM 只负责判断\"调哪个工具\"，MCP Client 负责通信与转发，MCP Server 负责执行。这也是 MCP 与 Function Call 的分界线所在。",[10,1004,1005,1008],{},[13,1006,1007],{},"MCP 主机（MCP Hosts）指的是发起请求的 LLM 应用程序。MCP 客户端（MCP Clients）指的是在主机程序内部的一个对象。",[13,1009,1010,1011,35],{},"核心要点：",[32,1012,1013],{},"MCP Client 负责与 Server 通信并调用工具；LLM 只负责判断\"该调哪个工具\"，并不直接执行工具",[13,1015,1016],{},"无论使用哪种传输方式（stdio \u002F SSE \u002F Streamable HTTP），Client 与 Server 的交互模式完全一致：",[65,1018,1020],{"className":67,"code":1019,"language":69,"meta":70,"style":70},"flowchart LR\n    S1[\"1 建立连接\u003Cbr\u002F>Client 连接 MCP Server\"]\n    S2[\"2 注册工具\u003Cbr\u002F>Server 返回可用工具列表\"]\n    S3[\"3 LLM 判断\u003Cbr\u002F>模型决定是否调工具\"]\n    S4[\"4 执行工具\u003Cbr\u002F>Client 转发，Server 执行\"]\n    S5[\"5 返回结果\u003Cbr\u002F>LLM 整合，生成回答\"]\n\n    S1 --> S2 --> S3 --> S4 --> S5\n\n    style S1 fill:#EFF6FF,stroke:#2563EB,stroke-width:2px\n    style S2 fill:#ECFDF5,stroke:#059669,stroke-width:2px\n    style S3 fill:#F5F3FF,stroke:#7C3AED,stroke-width:2px\n    style S4 fill:#FFF7ED,stroke:#EA580C,stroke-width:2px\n    style S5 fill:#ECFDF5,stroke:#059669,stroke-width:2px\n",[50,1021,1022,1026,1031,1036,1041,1046,1051,1055,1060,1064,1069,1074,1078,1082],{"__ignoreMap":70},[74,1023,1024],{"class":76,"line":77},[74,1025,80],{},[74,1027,1028],{"class":76,"line":83},[74,1029,1030],{},"    S1[\"1 建立连接\u003Cbr\u002F>Client 连接 MCP Server\"]\n",[74,1032,1033],{"class":76,"line":89},[74,1034,1035],{},"    S2[\"2 注册工具\u003Cbr\u002F>Server 返回可用工具列表\"]\n",[74,1037,1038],{"class":76,"line":95},[74,1039,1040],{},"    S3[\"3 LLM 判断\u003Cbr\u002F>模型决定是否调工具\"]\n",[74,1042,1043],{"class":76,"line":101},[74,1044,1045],{},"    S4[\"4 执行工具\u003Cbr\u002F>Client 转发，Server 执行\"]\n",[74,1047,1048],{"class":76,"line":107},[74,1049,1050],{},"    S5[\"5 返回结果\u003Cbr\u002F>LLM 整合，生成回答\"]\n",[74,1052,1053],{"class":76,"line":113},[74,1054,141],{"emptyLinePlaceholder":140},[74,1056,1057],{"class":76,"line":119},[74,1058,1059],{},"    S1 --> S2 --> S3 --> S4 --> S5\n",[74,1061,1062],{"class":76,"line":125},[74,1063,141],{"emptyLinePlaceholder":140},[74,1065,1066],{"class":76,"line":131},[74,1067,1068],{},"    style S1 fill:#EFF6FF,stroke:#2563EB,stroke-width:2px\n",[74,1070,1071],{"class":76,"line":137},[74,1072,1073],{},"    style S2 fill:#ECFDF5,stroke:#059669,stroke-width:2px\n",[74,1075,1076],{"class":76,"line":144},[74,1077,713],{},[74,1079,1080],{"class":76,"line":150},[74,1081,719],{},[74,1083,1084],{"class":76,"line":156},[74,1085,1086],{},"    style S5 fill:#ECFDF5,stroke:#059669,stroke-width:2px\n",[10,1088,1089],{},[13,1090,1091,1093,1094,1097],{},[32,1092,217],{}," 五个步骤里，第 1、2 步只在连接建立时发生一次（Host 为每个 MCP Server 创建一个对应的 Client，Server 回吐工具清单）；第 3、4、5 步则是每轮问答都会走一遍的循环。",[32,1095,1096],{},"关键：MCP Client 对 LLM 是透明的","——LLM 只输出\"调哪个工具 + 什么参数\"，通信、转发、执行全部由 Client 和 Server 自动完成，开发者不用手写对接代码。",[13,1099,1100],{},[32,1101,1102],{},"步骤 1：客户端注册并连接 MCP Server",[40,1104,1105,1108],{},[43,1106,1107],{},"MCP Client 启动后，根据配置文件或命令参数连接多个 MCP Server。",[43,1109,1110],{},"每个 Server 都会返回一份工具描述列表（Tool Manifest），包括：",[65,1112,1116],{"className":1113,"code":1114,"language":1115,"meta":70,"style":70},"language-json shiki shiki-themes github-light github-dark","[\n  {\n    \"name\": \"query_order_db\",\n    \"description\": \"执行订单库 SQL 查询\",\n    \"input_schema\": {},\n    \"output_schema\": {}\n  }\n]\n","json",[50,1117,1118,1124,1129,1145,1157,1165,1173,1178],{"__ignoreMap":70},[74,1119,1120],{"class":76,"line":77},[74,1121,1123],{"class":1122},"sVt8B","[\n",[74,1125,1126],{"class":76,"line":83},[74,1127,1128],{"class":1122},"  {\n",[74,1130,1131,1135,1138,1142],{"class":76,"line":89},[74,1132,1134],{"class":1133},"sj4cs","    \"name\"",[74,1136,1137],{"class":1122},": ",[74,1139,1141],{"class":1140},"sZZnC","\"query_order_db\"",[74,1143,1144],{"class":1122},",\n",[74,1146,1147,1150,1152,1155],{"class":76,"line":95},[74,1148,1149],{"class":1133},"    \"description\"",[74,1151,1137],{"class":1122},[74,1153,1154],{"class":1140},"\"执行订单库 SQL 查询\"",[74,1156,1144],{"class":1122},[74,1158,1159,1162],{"class":76,"line":101},[74,1160,1161],{"class":1133},"    \"input_schema\"",[74,1163,1164],{"class":1122},": {},\n",[74,1166,1167,1170],{"class":76,"line":107},[74,1168,1169],{"class":1133},"    \"output_schema\"",[74,1171,1172],{"class":1122},": {}\n",[74,1174,1175],{"class":76,"line":113},[74,1176,1177],{"class":1122},"  }\n",[74,1179,1180],{"class":76,"line":119},[74,1181,1182],{"class":1122},"]\n",[40,1184,1185],{},[43,1186,1187],{},"Client 将这些工具的元信息缓存并上报给 LLM，使大模型\"知道\"有哪些可用工具。",[13,1189,1190],{},[32,1191,1192],{},"步骤 2：LLM 接收用户输入并决定调用工具",[40,1194,1195,1198,1205],{},[43,1196,1197],{},"用户输入请求（如：\"帮我查一下 orders 表里昨天的订单量\"）。",[43,1199,1200,1201,1204],{},"LLM 分析语义后，判断需要使用 ",[50,1202,1203],{},"query_order_db"," 工具。",[43,1206,1207],{},"LLM 生成 function calling 格式的调用指令：",[65,1209,1211],{"className":1113,"code":1210,"language":1115,"meta":70,"style":70},"{\n  \"name\": \"query_order_db\",\n  \"arguments\": {\n    \"sql\": \"SELECT COUNT(*) FROM orders WHERE dt = '2026-09-14';\"\n  }\n}\n",[50,1212,1213,1218,1229,1237,1247,1251],{"__ignoreMap":70},[74,1214,1215],{"class":76,"line":77},[74,1216,1217],{"class":1122},"{\n",[74,1219,1220,1223,1225,1227],{"class":76,"line":83},[74,1221,1222],{"class":1133},"  \"name\"",[74,1224,1137],{"class":1122},[74,1226,1141],{"class":1140},[74,1228,1144],{"class":1122},[74,1230,1231,1234],{"class":76,"line":89},[74,1232,1233],{"class":1133},"  \"arguments\"",[74,1235,1236],{"class":1122},": {\n",[74,1238,1239,1242,1244],{"class":76,"line":95},[74,1240,1241],{"class":1133},"    \"sql\"",[74,1243,1137],{"class":1122},[74,1245,1246],{"class":1140},"\"SELECT COUNT(*) FROM orders WHERE dt = '2026-09-14';\"\n",[74,1248,1249],{"class":76,"line":101},[74,1250,1177],{"class":1122},[74,1252,1253],{"class":76,"line":107},[74,1254,1255],{"class":1122},"}\n",[13,1257,1258],{},[32,1259,1260],{},"步骤 3：MCP Client 执行工具调用",[40,1262,1263,1266],{},[43,1264,1265],{},"MCP Client 收到该调用后，匹配到对应的 Server。",[43,1267,1268],{},"按协议通过 stdio 或 WebSocket 将请求发送给 MCP Server，例如：",[65,1270,1272],{"className":1113,"code":1271,"language":1115,"meta":70,"style":70},"{\n  \"type\": \"tool_call\",\n  \"tool\": \"query_order_db\",\n  \"args\": {\"sql\": \"SELECT COUNT(*) FROM orders WHERE dt = '2026-09-14';\"}\n}\n",[50,1273,1274,1278,1290,1301,1319],{"__ignoreMap":70},[74,1275,1276],{"class":76,"line":77},[74,1277,1217],{"class":1122},[74,1279,1280,1283,1285,1288],{"class":76,"line":83},[74,1281,1282],{"class":1133},"  \"type\"",[74,1284,1137],{"class":1122},[74,1286,1287],{"class":1140},"\"tool_call\"",[74,1289,1144],{"class":1122},[74,1291,1292,1295,1297,1299],{"class":76,"line":89},[74,1293,1294],{"class":1133},"  \"tool\"",[74,1296,1137],{"class":1122},[74,1298,1141],{"class":1140},[74,1300,1144],{"class":1122},[74,1302,1303,1306,1309,1312,1314,1317],{"class":76,"line":95},[74,1304,1305],{"class":1133},"  \"args\"",[74,1307,1308],{"class":1122},": {",[74,1310,1311],{"class":1133},"\"sql\"",[74,1313,1137],{"class":1122},[74,1315,1316],{"class":1140},"\"SELECT COUNT(*) FROM orders WHERE dt = '2026-09-14';\"",[74,1318,1255],{"class":1122},[74,1320,1321],{"class":76,"line":101},[74,1322,1255],{"class":1122},[13,1324,1325],{},[32,1326,1327],{},"步骤 4：MCP Server 执行工具逻辑",[40,1329,1330,1333],{},[43,1331,1332],{},"MCP Server 内部执行工具逻辑（例如运行 SQL 查询）。",[43,1334,1335],{},"生成结果：",[65,1337,1339],{"className":1113,"code":1338,"language":1115,"meta":70,"style":70},"{\n  \"result\": [{\"count\": 1280}]\n}\n",[50,1340,1341,1345,1364],{"__ignoreMap":70},[74,1342,1343],{"class":76,"line":77},[74,1344,1217],{"class":1122},[74,1346,1347,1350,1353,1356,1358,1361],{"class":76,"line":83},[74,1348,1349],{"class":1133},"  \"result\"",[74,1351,1352],{"class":1122},": [{",[74,1354,1355],{"class":1133},"\"count\"",[74,1357,1137],{"class":1122},[74,1359,1360],{"class":1133},"1280",[74,1362,1363],{"class":1122},"}]\n",[74,1365,1366],{"class":76,"line":89},[74,1367,1255],{"class":1122},[40,1369,1370],{},[43,1371,1372],{},"将结果通过相同的通信通道返回给 MCP Client。",[13,1374,1375],{},[32,1376,1377],{},"步骤 5：结果回传给 LLM",[40,1379,1380,1383],{},[43,1381,1382],{},"MCP Client 接收结果，并包装为 ToolMessage 发送回 LLM。",[43,1384,1385],{},"LLM 读取结果上下文，再生成最终自然语言回答：\"9 月 14 日共产生 1280 笔订单。\"",[22,1387,1389],{"id":1388},"_23-mcp-的通信传输方式","2.3 MCP 的通信传输方式",[13,1391,1392],{},"MCP 传输方式与 MCP 协议本身无关，目前主要有三种通信传输方式：stdio、基于 HTTP 的 SSE 和 Streamable。",[13,1394,1395],{},[32,1396,1397],{},"（1）stdio（标准输入\u002F输出）",[40,1399,1400,1406,1416],{},[43,1401,1402,1405],{},[32,1403,1404],{},"类型","：一种非常经典和简单的进程间通信（IPC）方式。客户端启动服务端作为一个子进程。",[43,1407,1408,1411,1412,1415],{},[32,1409,1410],{},"工作原理","：客户端通过写入子进程的**标准输入（stdin）",[32,1413,1414],{},"来发送请求，并通过读取子进程的","标准输出（stdout）**来获取响应。这种方式简单高效，无需网络开销。",[43,1417,1418,1421,1422,1425],{},[32,1419,1420],{},"适用场景","：非常适合在",[32,1423,1424],{},"本地环境","中，将一个命令行工具或脚本快速封装成一个 MCP 服务。",[65,1427,1429],{"className":67,"code":1428,"language":69,"meta":70,"style":70},"flowchart LR\n    C[\"MCP Client\u003Cbr\u002F>主进程（父进程）\"]\n    S[\"MCP Server\u003Cbr\u002F>子进程（本地启动）\"]\n    C -->|stdin 写入请求| S\n    S -->|stdout 读取响应| C\n    style C fill:#EFF6FF,stroke:#2563EB,stroke-width:2px\n    style S fill:#ECFDF5,stroke:#059669,stroke-width:2px\n",[50,1430,1431,1435,1440,1445,1450,1455,1459],{"__ignoreMap":70},[74,1432,1433],{"class":76,"line":77},[74,1434,80],{},[74,1436,1437],{"class":76,"line":83},[74,1438,1439],{},"    C[\"MCP Client\u003Cbr\u002F>主进程（父进程）\"]\n",[74,1441,1442],{"class":76,"line":89},[74,1443,1444],{},"    S[\"MCP Server\u003Cbr\u002F>子进程（本地启动）\"]\n",[74,1446,1447],{"class":76,"line":95},[74,1448,1449],{},"    C -->|stdin 写入请求| S\n",[74,1451,1452],{"class":76,"line":101},[74,1453,1454],{},"    S -->|stdout 读取响应| C\n",[74,1456,1457],{"class":76,"line":107},[74,1458,839],{},[74,1460,1461],{"class":76,"line":113},[74,1462,844],{},[10,1464,1465,1474,1481],{},[13,1466,1467,1469,1470,1473],{},[32,1468,217],{}," stdio 不经过网络，父子进程之间用两根管道对话。",[32,1471,1472],{},"注意方向","：请求写进子进程的 stdin，响应从子进程的 stdout 读出来，所以这是一条双向但\"本地\"的通道。",[13,1475,1476,1477,1480],{},"类比：",[32,1478,1479],{},"从自己手边的书架上取书","。书架就摆在工位旁边（Server 作为本地子进程启动），你伸手把书抽出来（stdin 写入请求），书直接落到手里（stdout 读取响应）；不用出门、不用寄快递，所有动作都在本地完成，简单高效。适用场景是本地脚本封装、命令行工具、无需网络开销的快速集成。",[65,1482,1486],{"className":1483,"code":1484,"language":1485,"meta":70,"style":70},"language-python shiki shiki-themes github-light github-dark","server_params = StdioServerParameters(command=\"python\", args=[\"server.py\"])\nasync with stdio_client(server_params) as (read, write):  # 自动启动子进程\n","python",[50,1487,1488,1493],{"__ignoreMap":70},[74,1489,1490],{"class":76,"line":77},[74,1491,1492],{},"server_params = StdioServerParameters(command=\"python\", args=[\"server.py\"])\n",[74,1494,1495],{"class":76,"line":83},[74,1496,1497],{},"async with stdio_client(server_params) as (read, write):  # 自动启动子进程\n",[13,1499,1500],{},[32,1501,1502],{},"（2）SSE（Server-Sent Events）",[40,1504,1505,1514,1523],{},[43,1506,1507,1509,1510,1513],{},[32,1508,1404],{},"：SSE 是一种",[32,1511,1512],{},"基于 HTTP 的单向推送协议","，它允许服务器在保持连接开放的情况下，持续向客户端发送事件流。",[43,1515,1516,1518,1519,1522],{},[32,1517,1410],{},"：客户端发起一个 HTTP 请求，服务器接收请求并保持连接，然后以 ",[50,1520,1521],{},"text\u002Fevent-stream"," 格式将响应数据流式传输给客户端。这在 MCP 中被用来实现请求与响应的通信。",[43,1524,1525,1527,1528,1531],{},[32,1526,1420],{},"：适用于",[32,1529,1530],{},"分布式或网络环境","，当服务需要部署在远端，并通过网络供多个客户端访问时。",[65,1533,1535],{"className":67,"code":1534,"language":69,"meta":70,"style":70},"flowchart LR\n    C[\"MCP Client\u003Cbr\u002F>浏览器 \u002F 应用\"]\n    S[\"MCP Server\u003Cbr\u002F>远程服务器\"]\n    C -->|HTTP 请求（建立连接）| S\n    S -.->|text\u002Fevent-stream（单向推送）| C\n    style C fill:#EFF6FF,stroke:#2563EB,stroke-width:2px\n    style S fill:#FFFBEB,stroke:#D97706,stroke-width:2px\n",[50,1536,1537,1541,1546,1551,1556,1561,1565],{"__ignoreMap":70},[74,1538,1539],{"class":76,"line":77},[74,1540,80],{},[74,1542,1543],{"class":76,"line":83},[74,1544,1545],{},"    C[\"MCP Client\u003Cbr\u002F>浏览器 \u002F 应用\"]\n",[74,1547,1548],{"class":76,"line":89},[74,1549,1550],{},"    S[\"MCP Server\u003Cbr\u002F>远程服务器\"]\n",[74,1552,1553],{"class":76,"line":95},[74,1554,1555],{},"    C -->|HTTP 请求（建立连接）| S\n",[74,1557,1558],{"class":76,"line":101},[74,1559,1560],{},"    S -.->|text\u002Fevent-stream（单向推送）| C\n",[74,1562,1563],{"class":76,"line":107},[74,1564,839],{},[74,1566,1567],{"class":76,"line":113},[74,1568,1569],{},"    style S fill:#FFFBEB,stroke:#D97706,stroke-width:2px\n",[10,1571,1572,1581,1587],{},[13,1573,1574,1576,1577,1580],{},[32,1575,217],{}," 实线是客户端的 HTTP 请求（建立连接），虚线是服务端持续推送的事件流。",[32,1578,1579],{},"这里有个硬限制：SSE 只能服务端 → 客户端单向推送，客户端不能反向发消息","，所以早期的\"HTTP + SSE\"组合已经被规范标记为弃用。",[13,1582,1476,1583,1586],{},[32,1584,1585],{},"盯着银行大厅的叫号屏 \u002F 订阅微信公众号","。取号之后你能做的只有盯着屏幕（Server 单向推送）：\"请 A001 号到 3 号窗口\"\"请 A002 号到 5 号窗口\"……你只能看，没法跟屏幕对话；公众号也一样，它有新文章就推给你，你却不能顺着这条推送通道回话。适用场景是仅需接收服务器更新的场景，如行情推送、任务进度、日志流。",[65,1588,1590],{"className":1483,"code":1589,"language":1485,"meta":70,"style":70},"server_url = \"http:\u002F\u002Flocalhost:8001\u002Fsse\"\nasync with sse_client(url=server_url) as streams:  # 长连接，等待推送\n",[50,1591,1592,1597],{"__ignoreMap":70},[74,1593,1594],{"class":76,"line":77},[74,1595,1596],{},"server_url = \"http:\u002F\u002Flocalhost:8001\u002Fsse\"\n",[74,1598,1599],{"class":76,"line":83},[74,1600,1601],{},"async with sse_client(url=server_url) as streams:  # 长连接，等待推送\n",[13,1603,1604],{},[32,1605,1606],{},"（3）Streamable",[40,1608,1609,1614,1619],{},[43,1610,1611,1613],{},[32,1612,1404],{},"：Streamable-HTTP 是 MCP 提供的另一种基于 HTTP 的传输方式，它同样用于网络通信。",[43,1615,1616,1618],{},[32,1617,1410],{},"：客户端通过 HTTP 请求与服务器通信。与 SSE 的主要区别在于其传输格式和机制不同，比如 Streamable 的传输格式可以为任意格式，而 SSE 为特定格式；Streamable 的通信方向可以为双向，而 SSE 只能是单向。",[43,1620,1621,1623,1624,35],{},[32,1622,1420],{},"：与 SSE 类似，适用于需要",[32,1625,1626],{},"通过网络进行通信的分布式应用",[65,1628,1630],{"className":67,"code":1629,"language":69,"meta":70,"style":70},"flowchart LR\n    C[\"MCP Client\u003Cbr\u002F>浏览器 \u002F 应用\"]\n    S[\"MCP Server\u003Cbr\u002F>远程服务器\"]\n    C -->|HTTP 请求（发送指令）| S\n    S -->|HTTP 响应（返回结果）| C\n    style C fill:#EFF6FF,stroke:#2563EB,stroke-width:2px\n    style S fill:#ECFDF5,stroke:#059669,stroke-width:2px\n",[50,1631,1632,1636,1640,1644,1649,1654,1658],{"__ignoreMap":70},[74,1633,1634],{"class":76,"line":77},[74,1635,80],{},[74,1637,1638],{"class":76,"line":83},[74,1639,1545],{},[74,1641,1642],{"class":76,"line":89},[74,1643,1550],{},[74,1645,1646],{"class":76,"line":95},[74,1647,1648],{},"    C -->|HTTP 请求（发送指令）| S\n",[74,1650,1651],{"class":76,"line":101},[74,1652,1653],{},"    S -->|HTTP 响应（返回结果）| C\n",[74,1655,1656],{"class":76,"line":107},[74,1657,839],{},[74,1659,1660],{"class":76,"line":113},[74,1661,844],{},[10,1663,1664,1673,1679],{},[13,1665,1666,1668,1669,1672],{},[32,1667,217],{}," 与 SSE 相比，这里的返回通道不再是一条只读的事件流，而是",[32,1670,1671],{},"双向流","——客户端可以持续发指令，服务端可以持续回结果，并且支持会话 ID 在多次请求之间保持状态，避免重复初始化。",[13,1674,1476,1675,1678],{},[32,1676,1677],{},"微信聊天 \u002F 跟馆员一问一答","。你（Client）和馆员（Server）可以来回对话：\"帮我找本《三体》\"→\"在 3 楼 I 区，已经取来了\"→\"那顺便看看有没有《球状闪电》\"→\"有的，一并给您\"；就像微信聊天，双方随时都能发消息，不像公众号推送只能单向接收；与 SSE 的区别是：SSE 像叫号屏（只能看），Streamable 像聊天（可以来回说）。适用场景是需要实时双向交互的复杂任务，如多轮对话、大文件传输、流式处理。",[65,1680,1682],{"className":1483,"code":1681,"language":1485,"meta":70,"style":70},"server_url = \"http:\u002F\u002F127.0.0.1:8001\u002Fmcp\"\nasync with streamablehttp_client(server_url) as (read, write, _):  # 双向流\n",[50,1683,1684,1689],{"__ignoreMap":70},[74,1685,1686],{"class":76,"line":77},[74,1687,1688],{},"server_url = \"http:\u002F\u002F127.0.0.1:8001\u002Fmcp\"\n",[74,1690,1691],{"class":76,"line":83},[74,1692,1693],{},"async with streamablehttp_client(server_url) as (read, write, _):  # 双向流\n",[13,1695,1696],{},[32,1697,1698],{},"对比：",[65,1700,1702],{"className":67,"code":1701,"language":69,"meta":70,"style":70},"flowchart LR\n    subgraph T1[\"stdio（标准输入\u002F输出）\"]\n        T1A[\"MCP Client ⇄ MCP Server\u003Cbr\u002F>stdin \u002F stdout\"]\n        T1B[\"通信方式：本地进程间通信（IPC）\u003Cbr\u002F>Client 启动 Server 子进程\"]\n        T1C[\"优势：简单高效，无网络开销\u003Cbr\u002F>操作系统保证可靠性，安全性高\"]\n        T1D[\"适用场景：本地命令行工具封装、单机开发调试\"]\n        T1E[\"示例：server_stdio.py + client_raw.py\"]\n    end\n\n    subgraph T2[\"SSE（Server-Sent Events）\"]\n        T2A[\"MCP Client → POST → MCP Server\u003Cbr\u002F>MCP Server → SSE 流 → MCP Client\"]\n        T2B[\"通信方式：网络通信（HTTP 长连接）\u003Cbr\u002F>Server 持续推送事件流\"]\n        T2C[\"优势：浏览器兼容性好，适合单向数据推送\u003Cbr\u002F>TCP 保证可靠性\"]\n        T2D[\"❌ 已弃用（deprecated）\u003Cbr\u002F>2025-03-26 起推荐 Streamable\"]\n        T2E[\"示例：server_sse.py + client_raw.py\"]\n    end\n\n    subgraph T3[\"Streamable-HTTP（双向流式传输）\"]\n        T3A[\"MCP Client ⇄ 请求\u002F响应流 ⇄ MCP Server\"]\n        T3B[\"通信方式：网络通信（HTTP 双向流）\u003Cbr\u002F>支持实时双向通信\"]\n        T3C[\"优势：灵活性高，支持双向流\u003Cbr\u002F>提升大型任务响应效率，格式灵活\"]\n        T3D[\"适用场景：分布式远程服务、需实时双向交互的场景\"]\n        T3E[\"示例：server_streamable.py + client_raw.py\"]\n    end\n\n    style T1 fill:#EFF6FF,stroke:#2563EB,stroke-width:2px\n    style T2 fill:#FFFBEB,stroke:#D97706,stroke-width:2px\n    style T3 fill:#ECFDF5,stroke:#059669,stroke-width:2px\n",[50,1703,1704,1708,1713,1718,1723,1728,1733,1738,1742,1746,1751,1756,1761,1766,1771,1776,1780,1784,1789,1794,1799,1804,1809,1814,1818,1822,1827,1832],{"__ignoreMap":70},[74,1705,1706],{"class":76,"line":77},[74,1707,80],{},[74,1709,1710],{"class":76,"line":83},[74,1711,1712],{},"    subgraph T1[\"stdio（标准输入\u002F输出）\"]\n",[74,1714,1715],{"class":76,"line":89},[74,1716,1717],{},"        T1A[\"MCP Client ⇄ MCP Server\u003Cbr\u002F>stdin \u002F stdout\"]\n",[74,1719,1720],{"class":76,"line":95},[74,1721,1722],{},"        T1B[\"通信方式：本地进程间通信（IPC）\u003Cbr\u002F>Client 启动 Server 子进程\"]\n",[74,1724,1725],{"class":76,"line":101},[74,1726,1727],{},"        T1C[\"优势：简单高效，无网络开销\u003Cbr\u002F>操作系统保证可靠性，安全性高\"]\n",[74,1729,1730],{"class":76,"line":107},[74,1731,1732],{},"        T1D[\"适用场景：本地命令行工具封装、单机开发调试\"]\n",[74,1734,1735],{"class":76,"line":113},[74,1736,1737],{},"        T1E[\"示例：server_stdio.py + client_raw.py\"]\n",[74,1739,1740],{"class":76,"line":119},[74,1741,134],{},[74,1743,1744],{"class":76,"line":125},[74,1745,141],{"emptyLinePlaceholder":140},[74,1747,1748],{"class":76,"line":131},[74,1749,1750],{},"    subgraph T2[\"SSE（Server-Sent Events）\"]\n",[74,1752,1753],{"class":76,"line":137},[74,1754,1755],{},"        T2A[\"MCP Client → POST → MCP Server\u003Cbr\u002F>MCP Server → SSE 流 → MCP Client\"]\n",[74,1757,1758],{"class":76,"line":144},[74,1759,1760],{},"        T2B[\"通信方式：网络通信（HTTP 长连接）\u003Cbr\u002F>Server 持续推送事件流\"]\n",[74,1762,1763],{"class":76,"line":150},[74,1764,1765],{},"        T2C[\"优势：浏览器兼容性好，适合单向数据推送\u003Cbr\u002F>TCP 保证可靠性\"]\n",[74,1767,1768],{"class":76,"line":156},[74,1769,1770],{},"        T2D[\"❌ 已弃用（deprecated）\u003Cbr\u002F>2025-03-26 起推荐 Streamable\"]\n",[74,1772,1773],{"class":76,"line":162},[74,1774,1775],{},"        T2E[\"示例：server_sse.py + client_raw.py\"]\n",[74,1777,1778],{"class":76,"line":168},[74,1779,134],{},[74,1781,1782],{"class":76,"line":173},[74,1783,141],{"emptyLinePlaceholder":140},[74,1785,1786],{"class":76,"line":178},[74,1787,1788],{},"    subgraph T3[\"Streamable-HTTP（双向流式传输）\"]\n",[74,1790,1791],{"class":76,"line":184},[74,1792,1793],{},"        T3A[\"MCP Client ⇄ 请求\u002F响应流 ⇄ MCP Server\"]\n",[74,1795,1796],{"class":76,"line":189},[74,1797,1798],{},"        T3B[\"通信方式：网络通信（HTTP 双向流）\u003Cbr\u002F>支持实时双向通信\"]\n",[74,1800,1801],{"class":76,"line":195},[74,1802,1803],{},"        T3C[\"优势：灵活性高，支持双向流\u003Cbr\u002F>提升大型任务响应效率，格式灵活\"]\n",[74,1805,1806],{"class":76,"line":201},[74,1807,1808],{},"        T3D[\"适用场景：分布式远程服务、需实时双向交互的场景\"]\n",[74,1810,1811],{"class":76,"line":207},[74,1812,1813],{},"        T3E[\"示例：server_streamable.py + client_raw.py\"]\n",[74,1815,1816],{"class":76,"line":664},[74,1817,134],{},[74,1819,1820],{"class":76,"line":670},[74,1821,141],{"emptyLinePlaceholder":140},[74,1823,1824],{"class":76,"line":676},[74,1825,1826],{},"    style T1 fill:#EFF6FF,stroke:#2563EB,stroke-width:2px\n",[74,1828,1829],{"class":76,"line":682},[74,1830,1831],{},"    style T2 fill:#FFFBEB,stroke:#D97706,stroke-width:2px\n",[74,1833,1834],{"class":76,"line":688},[74,1835,1836],{},"    style T3 fill:#ECFDF5,stroke:#059669,stroke-width:2px\n",[10,1838,1839],{},[13,1840,1841,1843,1844,1847],{},[32,1842,217],{}," 三者的",[32,1845,1846],{},"工具定义代码完全相同","，差别只在连接层。选择策略很简单：本地开发用 stdio，远程部署用 Streamable-HTTP，而 SSE 因为只支持单向推送已经被规范弃用——新项目不建议再选。",[382,1849,1850,1866],{},[385,1851,1852],{},[388,1853,1854,1857,1860,1863],{},[391,1855,1856],{},"传输方式",[391,1858,1859],{},"stdio",[391,1861,1862],{},"SSE（Server-Sent Events）",[391,1864,1865],{},"Streamable-HTTP",[401,1867,1868,1882,1896,1910,1923],{},[388,1869,1870,1873,1876,1879],{},[406,1871,1872],{},"通信方向",[406,1874,1875],{},"双向（请求-响应）",[406,1877,1878],{},"单向（服务器推送到客户端）",[406,1880,1881],{},"双向（双向流）",[388,1883,1884,1887,1890,1893],{},[406,1885,1886],{},"通信模式",[406,1888,1889],{},"本地进程间通信（IPC）",[406,1891,1892],{},"网络通信（长连接流）",[406,1894,1895],{},"网络通信（双向流）",[388,1897,1898,1901,1904,1907],{},[406,1899,1900],{},"主要用途",[406,1902,1903],{},"封装本地命令行工具",[406,1905,1906],{},"仅需接收服务器更新的场景",[406,1908,1909],{},"复杂的、需要实时双向流的场景",[388,1911,1912,1915,1918,1921],{},[406,1913,1914],{},"是否容易丢失数据",[406,1916,1917],{},"由操作系统保证可靠性",[406,1919,1920],{},"由 TCP 协议保证可靠性",[406,1922,1920],{},[388,1924,1925,1928,1931,1934],{},[406,1926,1927],{},"关键优势",[406,1929,1930],{},"简单、高效、安全，无需网络开销",[406,1932,1933],{},"适用于简单、单向的数据推送，浏览器兼容性好",[406,1935,1936],{},"灵活性高，支持双向流式传输，提升大型任务的响应效率",[10,1938,1939],{},[13,1940,1941,1942,1945],{},"注意：此前在早期版本中，MCP 曾使用 \"HTTP + SSE\" 这种组合（客户端 POST、服务器 SSE 推送）作为远程通信方式。然而，该方式在规范中已被标注为",[32,1943,1944],{},"已弃用（deprecated）","，从 MCP 规范 2025-03-26 起推荐转向 Streamable HTTP。",[22,1947,1949],{"id":1948},"_24-mcp-与-function-call-的关系","2.4 MCP 与 Function Call 的关系",[13,1951,1952,1953,1956],{},"刚学过 Function Call，又学了 MCP，两者容易混淆。它们不是同一个层面的东西，而是",[32,1954,1955],{},"互补","关系：",[382,1958,1959,1971],{},[385,1960,1961],{},[388,1962,1963,1965,1968],{},[391,1964,393],{},[391,1966,1967],{},"Function Call",[391,1969,1970],{},"MCP（Model Context Protocol）",[401,1972,1973,1984,1995,2006,2021],{},[388,1974,1975,1978,1981],{},[406,1976,1977],{},"所属层面",[406,1979,1980],{},"大模型的能力（模型层）",[406,1982,1983],{},"工具暴露与调用的标准协议（工具层）",[388,1985,1986,1989,1992],{},[406,1987,1988],{},"核心作用",[406,1990,1991],{},"让模型判断\"该调哪个工具\"，并输出调用参数",[406,1993,1994],{},"让工具以统一标准被暴露、被发现、被调用",[388,1996,1997,2000,2003],{},[406,1998,1999],{},"谁在调用",[406,2001,2002],{},"LLM 直接生成函数调用指令",[406,2004,2005],{},"MCP Client 负责与 Server 通信、真正调用工具",[388,2007,2008,2011,2018],{},[406,2009,2010],{},"是否执行",[406,2012,2013,2014,2017],{},"模型",[32,2015,2016],{},"不执行","，只返回参数",[406,2019,2020],{},"Client \u002F Server 真正执行工具逻辑",[388,2022,2023,2026,2029],{},[406,2024,2025],{},"类比",[406,2027,2028],{},"模型的\"指令输出能力\"",[406,2030,2031],{},"工具的\"标准插座（Type-C）\"",[65,2033,2035],{"className":67,"code":2034,"language":69,"meta":70,"style":70},"flowchart TB\n    subgraph FC[\"Function Call 层（模型层）\"]\n        F1[\"LLM\u003Cbr\u002F>大语言模型\"]\n        F2[\"判断调哪个工具\u003Cbr\u002F>输出参数 JSON\"]\n        F3[\"整合结果，生成回答\u003Cbr\u002F>将工具返回数据组织为自然语言\"]\n        F1 --> F2 --> F3\n    end\n\n    subgraph MCPL[\"MCP 层（工具层）\"]\n        M1[\"MCP Client\u003Cbr\u002F>转发调用请求\"]\n        M2[\"MCP Server\u003Cbr\u002F>执行工具逻辑\"]\n        M3[\"数据源 \u002F API\u003Cbr\u002F>MySQL 订单库 \u002F 门店排队系统\"]\n        M1 --> M2 --> M3\n    end\n\n    F2 -.->|工具调用指令| M1\n    M3 -.->|执行结果| F3\n\n    style FC fill:#ECFDF5,stroke:#059669,stroke-width:2px\n    style MCPL fill:#EFF6FF,stroke:#2563EB,stroke-width:2px\n",[50,2036,2037,2041,2046,2051,2056,2061,2066,2070,2074,2079,2084,2089,2094,2099,2103,2107,2112,2117,2121,2126],{"__ignoreMap":70},[74,2038,2039],{"class":76,"line":77},[74,2040,557],{},[74,2042,2043],{"class":76,"line":83},[74,2044,2045],{},"    subgraph FC[\"Function Call 层（模型层）\"]\n",[74,2047,2048],{"class":76,"line":89},[74,2049,2050],{},"        F1[\"LLM\u003Cbr\u002F>大语言模型\"]\n",[74,2052,2053],{"class":76,"line":95},[74,2054,2055],{},"        F2[\"判断调哪个工具\u003Cbr\u002F>输出参数 JSON\"]\n",[74,2057,2058],{"class":76,"line":101},[74,2059,2060],{},"        F3[\"整合结果，生成回答\u003Cbr\u002F>将工具返回数据组织为自然语言\"]\n",[74,2062,2063],{"class":76,"line":107},[74,2064,2065],{},"        F1 --> F2 --> F3\n",[74,2067,2068],{"class":76,"line":113},[74,2069,134],{},[74,2071,2072],{"class":76,"line":119},[74,2073,141],{"emptyLinePlaceholder":140},[74,2075,2076],{"class":76,"line":125},[74,2077,2078],{},"    subgraph MCPL[\"MCP 层（工具层）\"]\n",[74,2080,2081],{"class":76,"line":131},[74,2082,2083],{},"        M1[\"MCP Client\u003Cbr\u002F>转发调用请求\"]\n",[74,2085,2086],{"class":76,"line":137},[74,2087,2088],{},"        M2[\"MCP Server\u003Cbr\u002F>执行工具逻辑\"]\n",[74,2090,2091],{"class":76,"line":144},[74,2092,2093],{},"        M3[\"数据源 \u002F API\u003Cbr\u002F>MySQL 订单库 \u002F 门店排队系统\"]\n",[74,2095,2096],{"class":76,"line":150},[74,2097,2098],{},"        M1 --> M2 --> M3\n",[74,2100,2101],{"class":76,"line":156},[74,2102,134],{},[74,2104,2105],{"class":76,"line":162},[74,2106,141],{"emptyLinePlaceholder":140},[74,2108,2109],{"class":76,"line":168},[74,2110,2111],{},"    F2 -.->|工具调用指令| M1\n",[74,2113,2114],{"class":76,"line":173},[74,2115,2116],{},"    M3 -.->|执行结果| F3\n",[74,2118,2119],{"class":76,"line":178},[74,2120,141],{"emptyLinePlaceholder":140},[74,2122,2123],{"class":76,"line":184},[74,2124,2125],{},"    style FC fill:#ECFDF5,stroke:#059669,stroke-width:2px\n",[74,2127,2128],{"class":76,"line":189},[74,2129,2130],{},"    style MCPL fill:#EFF6FF,stroke:#2563EB,stroke-width:2px\n",[10,2132,2133],{},[13,2134,2135,2137,2138,2141,2142,2145,2146,2149],{},[32,2136,217],{}," 上下两层各管一段：Function Call 层回答\"模型怎么表达要调用工具\"，产出的是",[32,2139,2140],{},"参数 JSON","；MCP 层回答\"工具怎么被统一暴露和执行\"，产出的是",[32,2143,2144],{},"真实数据","。虚线把两层缝在一起：模型的调用指令流向 MCP Client，工具的执行结果回到模型侧用于生成回答。",[32,2147,2148],{},"完整链路","：① LLM 通过 Function Call 输出指令 → ② MCP Client 接收 → ③ MCP Server 执行 → ④ 结果返回 LLM → ⑤ LLM 整合生成自然语言回答。",[13,2151,2152],{},[32,2153,2154],{},"简单理解：",[40,2156,2157,2160],{},[43,2158,2159],{},"Function Call 回答\"模型怎么表达要调用工具\"——它是大模型内建的能力，让模型输出结构化的工具调用指令。",[43,2161,2162],{},"MCP 回答\"工具怎么被统一暴露和调用\"——它是一套协议，把各类工具（数据库、API、本地函数）标准化成可插拔的 Server。",[13,2164,2165,2166,2169,2170,2172,2173,2176],{},"两者常",[32,2167,2168],{},"配合使用","：MCP Server 暴露的工具，最终会通过 ",[32,2171,1967],{}," 的方式被 LLM 识别和调用（LangChain 的 ",[50,2174,2175],{},"load_mcp_tools"," 就是把 MCP 工具转成可被模型调用的函数）。",[17,2178,2180],{"id":2179},"_3-mcp-包使用","3. mcp 包使用",[10,2182,2183,2190],{},[13,2184,2185,2186,2189],{},"注意：以下代码需要安装 ",[50,2187,2188],{},"langchain-mcp-adapters"," 包：",[65,2191,2195],{"className":2192,"code":2193,"language":2194,"meta":70,"style":70},"language-bash shiki shiki-themes github-light github-dark","pip install langchain-mcp-adapters --index-url https:\u002F\u002Fpypi.org\u002Fsimple\n","bash",[50,2196,2197],{"__ignoreMap":70},[74,2198,2199,2203,2206,2209,2212],{"class":76,"line":77},[74,2200,2202],{"class":2201},"sScJk","pip",[74,2204,2205],{"class":1140}," install",[74,2207,2208],{"class":1140}," langchain-mcp-adapters",[74,2210,2211],{"class":1133}," --index-url",[74,2213,2214],{"class":1140}," https:\u002F\u002Fpypi.org\u002Fsimple\n",[22,2216,2218],{"id":2217},"_31-stdio-传输方式","3.1 stdio 传输方式",[13,2220,2221,2222,2225],{},"stdio（Standard Input\u002FOutput，标准输入输出）是最简单的 MCP 通信方式。客户端和服务端运行在",[32,2223,2224],{},"同一台机器","上，客户端通过启动一个子进程来运行服务端脚本，两者通过进程的 stdin\u002Fstdout 管道交换 JSON-RPC 消息。",[40,2227,2228,2233],{},[43,2229,2230,2232],{},[32,2231,1420],{},"：本地开发调试、服务端不需要独立部署的场景。",[43,2234,2235,2238],{},[32,2236,2237],{},"核心特点","：客户端启动时自动拉起服务端进程，不需要手动先启动服务端。",[2240,2241,2243],"h4",{"id":2242},"_311-服务端","3.1.1 服务端",[13,2245,2246,2247,35],{},"服务端代码的任务很明确：",[32,2248,2249,2250,2253],{},"创建 FastMCP 实例 → 用 ",[50,2251,2252],{},"@mcp.tool"," 装饰器注册工具 → 启动服务",[10,2255,2256],{},[13,2257,2258,2259],{},"代码位置：",[50,2260,2261],{},"agent_learn\u002Fmcp_base\u002Fstdio\u002Fserver_stdio.py",[65,2263,2265],{"className":1483,"code":2264,"language":1485,"meta":70,"style":70},"\"\"\"\n需求：实现基于STDIO的MCP服务器，提供可调用的工具服务\n思路步骤：\n1. 创建FastMCP实例，配置服务器参数\n2. 定义可调用的工具函数（如门店排队查询、库存查询等）\n3. 启动STDIO传输协议的服务器\n4. 处理服务器异常和中断信号\n\"\"\"\n\nfrom fastmcp import FastMCP\n\n# 实例化mcp\nmcp = FastMCP(\"store-hub\")\n\n@mcp.tool(\n    name=\"get_queue_length\",\n    description=\"查询指定门店当前的排队人数与预计等待时长，返回一段文字说明。\",\n)\nasync def get_queue_length(store: str) -> str:\n    \"\"\"\n    门店排队查询\n    Args:\n        store: 门店名称，例如\"望京店\"\n    \"\"\"\n    try:\n        print(f\"调用查询排队的tool成功！！门店：{store}\")\n        return f\"{store}当前排队 6 人，预计等待 12 分钟\"\n    except Exception as e:\n        print(f\"Unexpected error in queue query: {str(e)}\")\n        raise\n\n@mcp.tool(\n    name=\"query_drink_stock\",\n    description=\"查询门店某种饮品或原料的剩余库存\"\n)\nasync def query_drink_stock(item: str) -> str:\n    \"\"\"\n    查询库存的tools\n    Args:\n        item: 饮品或原料名称，例如\"燕麦奶\"\n    \"\"\"\n    try:\n        print(f\"调用查询库存的tools：{item}\")\n        return f\"{item}剩余 18 盒\"\n    except Exception as e:\n        print(f\"Unexpected error in stock query: {str(e)}\")\n        raise\n\nif __name__ == \"__main__\":\n    mcp.run(transport=\"stdio\")\n",[50,2266,2267,2272,2277,2282,2287,2292,2297,2302,2306,2310,2315,2319,2324,2329,2333,2338,2343,2348,2353,2358,2363,2368,2373,2378,2382,2387,2392,2397,2402,2407,2412,2416,2420,2425,2431,2436,2442,2447,2453,2458,2464,2469,2474,2480,2486,2491,2497,2502,2507,2513],{"__ignoreMap":70},[74,2268,2269],{"class":76,"line":77},[74,2270,2271],{},"\"\"\"\n",[74,2273,2274],{"class":76,"line":83},[74,2275,2276],{},"需求：实现基于STDIO的MCP服务器，提供可调用的工具服务\n",[74,2278,2279],{"class":76,"line":89},[74,2280,2281],{},"思路步骤：\n",[74,2283,2284],{"class":76,"line":95},[74,2285,2286],{},"1. 创建FastMCP实例，配置服务器参数\n",[74,2288,2289],{"class":76,"line":101},[74,2290,2291],{},"2. 定义可调用的工具函数（如门店排队查询、库存查询等）\n",[74,2293,2294],{"class":76,"line":107},[74,2295,2296],{},"3. 启动STDIO传输协议的服务器\n",[74,2298,2299],{"class":76,"line":113},[74,2300,2301],{},"4. 处理服务器异常和中断信号\n",[74,2303,2304],{"class":76,"line":119},[74,2305,2271],{},[74,2307,2308],{"class":76,"line":125},[74,2309,141],{"emptyLinePlaceholder":140},[74,2311,2312],{"class":76,"line":131},[74,2313,2314],{},"from fastmcp import FastMCP\n",[74,2316,2317],{"class":76,"line":137},[74,2318,141],{"emptyLinePlaceholder":140},[74,2320,2321],{"class":76,"line":144},[74,2322,2323],{},"# 实例化mcp\n",[74,2325,2326],{"class":76,"line":150},[74,2327,2328],{},"mcp = FastMCP(\"store-hub\")\n",[74,2330,2331],{"class":76,"line":156},[74,2332,141],{"emptyLinePlaceholder":140},[74,2334,2335],{"class":76,"line":162},[74,2336,2337],{},"@mcp.tool(\n",[74,2339,2340],{"class":76,"line":168},[74,2341,2342],{},"    name=\"get_queue_length\",\n",[74,2344,2345],{"class":76,"line":173},[74,2346,2347],{},"    description=\"查询指定门店当前的排队人数与预计等待时长，返回一段文字说明。\",\n",[74,2349,2350],{"class":76,"line":178},[74,2351,2352],{},")\n",[74,2354,2355],{"class":76,"line":184},[74,2356,2357],{},"async def get_queue_length(store: str) -> str:\n",[74,2359,2360],{"class":76,"line":189},[74,2361,2362],{},"    \"\"\"\n",[74,2364,2365],{"class":76,"line":195},[74,2366,2367],{},"    门店排队查询\n",[74,2369,2370],{"class":76,"line":201},[74,2371,2372],{},"    Args:\n",[74,2374,2375],{"class":76,"line":207},[74,2376,2377],{},"        store: 门店名称，例如\"望京店\"\n",[74,2379,2380],{"class":76,"line":664},[74,2381,2362],{},[74,2383,2384],{"class":76,"line":670},[74,2385,2386],{},"    try:\n",[74,2388,2389],{"class":76,"line":676},[74,2390,2391],{},"        print(f\"调用查询排队的tool成功！！门店：{store}\")\n",[74,2393,2394],{"class":76,"line":682},[74,2395,2396],{},"        return f\"{store}当前排队 6 人，预计等待 12 分钟\"\n",[74,2398,2399],{"class":76,"line":688},[74,2400,2401],{},"    except Exception as e:\n",[74,2403,2404],{"class":76,"line":693},[74,2405,2406],{},"        print(f\"Unexpected error in queue query: {str(e)}\")\n",[74,2408,2409],{"class":76,"line":698},[74,2410,2411],{},"        raise\n",[74,2413,2414],{"class":76,"line":704},[74,2415,141],{"emptyLinePlaceholder":140},[74,2417,2418],{"class":76,"line":710},[74,2419,2337],{},[74,2421,2422],{"class":76,"line":716},[74,2423,2424],{},"    name=\"query_drink_stock\",\n",[74,2426,2428],{"class":76,"line":2427},34,[74,2429,2430],{},"    description=\"查询门店某种饮品或原料的剩余库存\"\n",[74,2432,2434],{"class":76,"line":2433},35,[74,2435,2352],{},[74,2437,2439],{"class":76,"line":2438},36,[74,2440,2441],{},"async def query_drink_stock(item: str) -> str:\n",[74,2443,2445],{"class":76,"line":2444},37,[74,2446,2362],{},[74,2448,2450],{"class":76,"line":2449},38,[74,2451,2452],{},"    查询库存的tools\n",[74,2454,2456],{"class":76,"line":2455},39,[74,2457,2372],{},[74,2459,2461],{"class":76,"line":2460},40,[74,2462,2463],{},"        item: 饮品或原料名称，例如\"燕麦奶\"\n",[74,2465,2467],{"class":76,"line":2466},41,[74,2468,2362],{},[74,2470,2472],{"class":76,"line":2471},42,[74,2473,2386],{},[74,2475,2477],{"class":76,"line":2476},43,[74,2478,2479],{},"        print(f\"调用查询库存的tools：{item}\")\n",[74,2481,2483],{"class":76,"line":2482},44,[74,2484,2485],{},"        return f\"{item}剩余 18 盒\"\n",[74,2487,2489],{"class":76,"line":2488},45,[74,2490,2401],{},[74,2492,2494],{"class":76,"line":2493},46,[74,2495,2496],{},"        print(f\"Unexpected error in stock query: {str(e)}\")\n",[74,2498,2500],{"class":76,"line":2499},47,[74,2501,2411],{},[74,2503,2505],{"class":76,"line":2504},48,[74,2506,141],{"emptyLinePlaceholder":140},[74,2508,2510],{"class":76,"line":2509},49,[74,2511,2512],{},"if __name__ == \"__main__\":\n",[74,2514,2516],{"class":76,"line":2515},50,[74,2517,2518],{},"    mcp.run(transport=\"stdio\")\n",[13,2520,2521,2524],{},[32,2522,2523],{},"代码解读","：",[40,2526,2527,2552,2566,2573],{},[43,2528,2529,2532,2533,2536,2537,2540,2541,2540,2544,2547,2548,2551],{},[50,2530,2531],{},"FastMCP(\"store-hub\")"," 创建 MCP 服务实例，",[50,2534,2535],{},"\"store-hub\""," 是服务名称。注意：fastmcp 3.4.7 不再在构造函数中接受 ",[50,2538,2539],{},"log_level","、",[50,2542,2543],{},"host",[50,2545,2546],{},"port"," 参数，这些需改为在 ",[50,2549,2550],{},"mcp.run()"," 中传入。",[43,2553,2554,2557,2558,2561,2562,2565],{},[50,2555,2556],{},"@mcp.tool(name=..., description=...)"," 装饰器将一个异步函数注册为 MCP 工具。",[50,2559,2560],{},"name"," 是工具的唯一标识（客户端调用时使用），",[50,2563,2564],{},"description"," 告诉大模型这个工具的用途，模型据此决定是否需要调用该工具。",[43,2567,2568,2569,2572],{},"第二个工具 ",[50,2570,2571],{},"query_drink_stock"," 同样用装饰器注册。两个工具都返回字符串，实际项目中可以返回 JSON 等结构化数据。",[43,2574,2575,2578,2579,2582,2583,2586,2587,2590],{},[50,2576,2577],{},"mcp.run(transport=\"stdio\")"," 以 stdio 模式启动服务。只需改 ",[50,2580,2581],{},"transport"," 参数为 ",[50,2584,2585],{},"\"sse\""," 或 ",[50,2588,2589],{},"\"streamable-http\""," 就能切换通信方式，其余代码完全不变。",[2240,2592,2594],{"id":2593},"_312-客户端直接调用","3.1.2 客户端（直接调用）",[13,2596,2597,2598,2601],{},"客户端（直接调用）是指",[32,2599,2600],{},"不经过大模型","，由代码直接指定调用哪个工具。这种方式适合测试服务端是否正常、或者明确知道要调用哪个工具的场景。",[65,2603,2605],{"className":67,"code":2604,"language":69,"meta":70,"style":70},"sequenceDiagram\n    participant C as client_raw.py\n    participant T as stdio_client\n    participant S as ClientSession\n    participant M as MCP Server\n\n    C->>C: ① 配置参数 StdioServerParameters\u003Cbr\u002F>command=python, args=[server_stdio.py]\n    C->>T: ② 启动 Server 子进程\n    T->>S: ③ 建立读写通道\u003Cbr\u002F>async with stdio_client → (read, write)\n    S->>M: ④ 初始化会话 session.initialize()\n    S->>S: ⑤ 加载工具列表\u003Cbr\u002F>load_mcp_tools(session) → [get_queue_length, …]\n    S->>M: ⑥ 调用工具 session.call_tool(\"get_queue_length\", {\"store\": \"望京店\"})\n",[50,2606,2607,2611,2616,2621,2626,2631,2635,2640,2645,2650,2655,2660],{"__ignoreMap":70},[74,2608,2609],{"class":76,"line":77},[74,2610,932],{},[74,2612,2613],{"class":76,"line":83},[74,2614,2615],{},"    participant C as client_raw.py\n",[74,2617,2618],{"class":76,"line":89},[74,2619,2620],{},"    participant T as stdio_client\n",[74,2622,2623],{"class":76,"line":95},[74,2624,2625],{},"    participant S as ClientSession\n",[74,2627,2628],{"class":76,"line":101},[74,2629,2630],{},"    participant M as MCP Server\n",[74,2632,2633],{"class":76,"line":107},[74,2634,141],{"emptyLinePlaceholder":140},[74,2636,2637],{"class":76,"line":113},[74,2638,2639],{},"    C->>C: ① 配置参数 StdioServerParameters\u003Cbr\u002F>command=python, args=[server_stdio.py]\n",[74,2641,2642],{"class":76,"line":119},[74,2643,2644],{},"    C->>T: ② 启动 Server 子进程\n",[74,2646,2647],{"class":76,"line":125},[74,2648,2649],{},"    T->>S: ③ 建立读写通道\u003Cbr\u002F>async with stdio_client → (read, write)\n",[74,2651,2652],{"class":76,"line":131},[74,2653,2654],{},"    S->>M: ④ 初始化会话 session.initialize()\n",[74,2656,2657],{"class":76,"line":137},[74,2658,2659],{},"    S->>S: ⑤ 加载工具列表\u003Cbr\u002F>load_mcp_tools(session) → [get_queue_length, …]\n",[74,2661,2662],{"class":76,"line":144},[74,2663,2664],{},"    S->>M: ⑥ 调用工具 session.call_tool(\"get_queue_length\", {\"store\": \"望京店\"})\n",[10,2666,2667],{},[13,2668,2669,2671,2672,2675,2676,2679,2680,2683,2684,2687,2688,2691,2692,2695],{},[32,2670,217],{}," 这张图展示的是",[32,2673,2674],{},"旧写法","的分层调用链——",[50,2677,2678],{},"client_raw.py"," 只负责配置参数，",[50,2681,2682],{},"stdio_client"," 负责拉起子进程并建立 read\u002Fwrite 通道，",[50,2685,2686],{},"ClientSession"," 负责初始化会话与加载工具，最后才落到 MCP Server 执行。当前 fastmcp 3.4.7 已把第 ②③④ 步全部收敛进 ",[50,2689,2690],{},"Client(transport)"," 的一行 ",[50,2693,2694],{},"async with"," 里，但理解这个分层有助于排查连接类问题。",[10,2697,2698,2701,2704,2707],{},[13,2699,2700],{},"注意：",[13,2702,2703],{},"（1）直接启动客户端即可，不需要启动服务端，因为客户端会自动启动服务端。",[13,2705,2706],{},"（2）如果直接运行报错，可能是编码集的问题，可以尝试使用命令行的方式运行：",[65,2708,2710],{"className":2192,"code":2709,"language":2194,"meta":70,"style":70},"set PYTHONIOENCODING=utf-8\npython client_raw.py\n",[50,2711,2712,2720],{"__ignoreMap":70},[74,2713,2714,2717],{"class":76,"line":77},[74,2715,2716],{"class":1133},"set",[74,2718,2719],{"class":1140}," PYTHONIOENCODING=utf-8\n",[74,2721,2722,2724],{"class":76,"line":83},[74,2723,1485],{"class":2201},[74,2725,2726],{"class":1140}," client_raw.py\n",[10,2728,2729],{},[13,2730,2258,2731],{},[50,2732,2733],{},"agent_learn\u002Fmcp_base\u002Fstdio\u002Fclient_raw.py",[65,2735,2737],{"className":1483,"code":2736,"language":1485,"meta":70,"style":70},"\"\"\"\n需求：实现基于STDIO的MCP原始客户端，连接服务器并调用远程工具\n思路步骤：\n1. 配置MCP服务器脚本路径\n2. 使用 fastmcp.Client + PythonStdioTransport 建立STDIO连接\n3. 列出服务器提供的工具列表\n4. 调用远程服务器的工具并处理响应\n5. 使用异步方式运行客户端程序\n\"\"\"\n\nimport asyncio\nfrom fastmcp import Client\nfrom fastmcp.client.transports import PythonStdioTransport\n\n# 配置mcp服务器脚本路径\nserver_script = r\"server_stdio.py\"\n\n# 主要的异步函数run\nasync def run():\n    # 使用 fastmcp.Client + PythonStdioTransport 建立STDIO连接\n    # Client 封装了会话创建和初始化，比 mcp 包原生 API 更简洁\n    transport = PythonStdioTransport(script_path=server_script)\n    async with Client(transport) as client:\n        # 列出服务器提供的工具列表\n        tools = await client.list_tools()\n        print(f\"tools-->{tools}\")\n\n        # 调用 MCP server 的 get_queue_length 工具\n        response = await client.call_tool(\"get_queue_length\", arguments={\"store\": \"望京店\"})\n        print(f\"response-->{response}\")\n\n# 启动运行\nif __name__ == \"__main__\":\n    asyncio.run(run())\n",[50,2738,2739,2743,2748,2752,2757,2762,2767,2772,2777,2781,2785,2790,2795,2800,2804,2809,2814,2818,2823,2828,2833,2838,2843,2848,2853,2858,2863,2867,2872,2877,2882,2886,2891,2895],{"__ignoreMap":70},[74,2740,2741],{"class":76,"line":77},[74,2742,2271],{},[74,2744,2745],{"class":76,"line":83},[74,2746,2747],{},"需求：实现基于STDIO的MCP原始客户端，连接服务器并调用远程工具\n",[74,2749,2750],{"class":76,"line":89},[74,2751,2281],{},[74,2753,2754],{"class":76,"line":95},[74,2755,2756],{},"1. 配置MCP服务器脚本路径\n",[74,2758,2759],{"class":76,"line":101},[74,2760,2761],{},"2. 使用 fastmcp.Client + PythonStdioTransport 建立STDIO连接\n",[74,2763,2764],{"class":76,"line":107},[74,2765,2766],{},"3. 列出服务器提供的工具列表\n",[74,2768,2769],{"class":76,"line":113},[74,2770,2771],{},"4. 调用远程服务器的工具并处理响应\n",[74,2773,2774],{"class":76,"line":119},[74,2775,2776],{},"5. 使用异步方式运行客户端程序\n",[74,2778,2779],{"class":76,"line":125},[74,2780,2271],{},[74,2782,2783],{"class":76,"line":131},[74,2784,141],{"emptyLinePlaceholder":140},[74,2786,2787],{"class":76,"line":137},[74,2788,2789],{},"import asyncio\n",[74,2791,2792],{"class":76,"line":144},[74,2793,2794],{},"from fastmcp import Client\n",[74,2796,2797],{"class":76,"line":150},[74,2798,2799],{},"from fastmcp.client.transports import PythonStdioTransport\n",[74,2801,2802],{"class":76,"line":156},[74,2803,141],{"emptyLinePlaceholder":140},[74,2805,2806],{"class":76,"line":162},[74,2807,2808],{},"# 配置mcp服务器脚本路径\n",[74,2810,2811],{"class":76,"line":168},[74,2812,2813],{},"server_script = r\"server_stdio.py\"\n",[74,2815,2816],{"class":76,"line":173},[74,2817,141],{"emptyLinePlaceholder":140},[74,2819,2820],{"class":76,"line":178},[74,2821,2822],{},"# 主要的异步函数run\n",[74,2824,2825],{"class":76,"line":184},[74,2826,2827],{},"async def run():\n",[74,2829,2830],{"class":76,"line":189},[74,2831,2832],{},"    # 使用 fastmcp.Client + PythonStdioTransport 建立STDIO连接\n",[74,2834,2835],{"class":76,"line":195},[74,2836,2837],{},"    # Client 封装了会话创建和初始化，比 mcp 包原生 API 更简洁\n",[74,2839,2840],{"class":76,"line":201},[74,2841,2842],{},"    transport = PythonStdioTransport(script_path=server_script)\n",[74,2844,2845],{"class":76,"line":207},[74,2846,2847],{},"    async with Client(transport) as client:\n",[74,2849,2850],{"class":76,"line":664},[74,2851,2852],{},"        # 列出服务器提供的工具列表\n",[74,2854,2855],{"class":76,"line":670},[74,2856,2857],{},"        tools = await client.list_tools()\n",[74,2859,2860],{"class":76,"line":676},[74,2861,2862],{},"        print(f\"tools-->{tools}\")\n",[74,2864,2865],{"class":76,"line":682},[74,2866,141],{"emptyLinePlaceholder":140},[74,2868,2869],{"class":76,"line":688},[74,2870,2871],{},"        # 调用 MCP server 的 get_queue_length 工具\n",[74,2873,2874],{"class":76,"line":693},[74,2875,2876],{},"        response = await client.call_tool(\"get_queue_length\", arguments={\"store\": \"望京店\"})\n",[74,2878,2879],{"class":76,"line":698},[74,2880,2881],{},"        print(f\"response-->{response}\")\n",[74,2883,2884],{"class":76,"line":704},[74,2885,141],{"emptyLinePlaceholder":140},[74,2887,2888],{"class":76,"line":710},[74,2889,2890],{},"# 启动运行\n",[74,2892,2893],{"class":76,"line":716},[74,2894,2512],{},[74,2896,2897],{"class":76,"line":2427},[74,2898,2899],{},"    asyncio.run(run())\n",[13,2901,2902,2524],{},[32,2903,2523],{},[40,2905,2906,2928,2937,2947,2957,2967],{},[43,2907,2908,2909,2912,2913,35,2916,2919,2920,2923,2924,2927],{},"导入 ",[50,2910,2911],{},"fastmcp.Client"," 和 ",[50,2914,2915],{},"PythonStdioTransport",[50,2917,2918],{},"Client"," 是 fastmcp 3.4.7 提供的高层客户端 API，自动处理连接建立、会话初始化和生命周期管理，比 ",[50,2921,2922],{},"mcp"," 包原生的 ",[50,2925,2926],{},"stdio_client + ClientSession"," 写法更简洁。",[43,2929,2930,2933,2934,2936],{},[50,2931,2932],{},"PythonStdioTransport(script_path=server_script)"," 配置 stdio 传输参数，指定服务端脚本路径。",[50,2935,2918],{}," 会自动启动服务端子进程并通过 stdin\u002Fstdout 通信。",[43,2938,2939,2942,2943,2946],{},[50,2940,2941],{},"async with Client(transport) as client:"," 一步完成子进程启动、连接建立、会话初始化——替代了旧写法中 ",[50,2944,2945],{},"stdio_client + ClientSession + session.initialize()"," 的三层嵌套。",[43,2948,2949,2952,2953,2956],{},[50,2950,2951],{},"client.list_tools()"," 列出服务端所有已注册工具，返回 ",[50,2954,2955],{},"mcp.types.Tool"," 对象列表。",[43,2958,2959,2962,2963,2966],{},[50,2960,2961],{},"client.call_tool(\"get_queue_length\", arguments={\"store\": \"望京店\"})"," 直接调用服务端注册的 ",[50,2964,2965],{},"get_queue_length"," 工具，并传入门店名。",[43,2968,2969,2972,2973,2976],{},[50,2970,2971],{},"asyncio.run(run())"," 在同步的 ",[50,2974,2975],{},"__main__"," 中启动异步方法。",[13,2978,2979],{},"运行结果：",[65,2981,2984],{"className":2982,"code":2983,"language":253,"meta":70},[251],"tools-->[StructuredTool(name='get_queue_length', description='查询指定门店当前的排队人数与预计等待时长，返回一段文字说明。', args_schema={'properties': {'store': {'title': 'Store', 'type': 'string'}}, 'required': ['store'], 'title': 'get_queue_lengthArguments', 'type': 'object'}, response_format='content_and_artifact', coroutine=\u003Cfunction convert_mcp_tool_to_langchain_tool.\u003Clocals>.call_tool at 0x000001E176F59900>), StructuredTool(name='query_drink_stock', description='查询门店某种饮品或原料的剩余库存', args_schema={'properties': {'item': {'title': 'Item', 'type': 'string'}}, 'required': ['item'], 'title': 'query_drink_stockArguments', 'type': 'object'}, response_format='content_and_artifact', coroutine=\u003Cfunction convert_mcp_tool_to_langchain_tool.\u003Clocals>.call_tool at 0x000001E176F59A20>)]\nresponse-->meta=None content=[TextContent(type='text', text='望京店当前排队 6 人，预计等待 12 分钟', annotations=None, meta=None)] structuredContent={'result': '望京店当前排队 6 人，预计等待 12 分钟'} isError=False\n",[50,2985,2983],{"__ignoreMap":70},[2240,2987,2989],{"id":2988},"_313-客户端agent-调用","3.1.3 客户端（agent 调用）",[10,2991,2992,2994,2996,2998],{},[13,2993,2700],{},[13,2995,2703],{},[13,2997,2706],{},[65,2999,3001],{"className":2192,"code":3000,"language":2194,"meta":70,"style":70},"set PYTHONIOENCODING=utf-8\npython client_agent.py\n",[50,3002,3003,3009],{"__ignoreMap":70},[74,3004,3005,3007],{"class":76,"line":77},[74,3006,2716],{"class":1133},[74,3008,2719],{"class":1140},[74,3010,3011,3013],{"class":76,"line":83},[74,3012,1485],{"class":2201},[74,3014,3015],{"class":1140}," client_agent.py\n",[10,3017,3018],{},[13,3019,2258,3020],{},[50,3021,3022],{},"agent_learn\u002Fmcp_base\u002Fstdio\u002Fclient_agent.py",[65,3024,3026],{"className":1483,"code":3025,"language":1485,"meta":70,"style":70},"\"\"\"\n需求：实现基于STDIO的MCP智能代理客户端，集成大语言模型和远程工具\n思路步骤：\n1. 创建大语言模型实例，配置API参数\n2. 配置MCP服务器脚本路径，构建 StdioConnection\n3. 使用 langchain-mcp-adapters 的 connection 模式加载工具\n4. 构建工具调用代理和执行器\n5. 实现交互式聊天循环，处理用户查询\n6. 使用异步方式运行客户端程序\n\"\"\"\n\nimport os\nimport sys\nsys.path.append(os.path.join(os.path.dirname(__file__), \"..\u002F..\u002F..\"))\nimport asyncio\nfrom langchain_mcp_adapters.tools import load_mcp_tools\nfrom langchain_mcp_adapters.sessions import StdioConnection\nfrom langchain_openai import ChatOpenAI\nfrom langchain.agents import create_agent\nfrom agent_learn.config import Config\n\nconf = Config()\n\n# 创建模型\nllm = ChatOpenAI(base_url=conf.base_url,\n                 api_key=conf.api_key,\n                 model=conf.model_name,\n                 temperature=0.1)\n\n# 配置mcp服务器脚本路径\nserver_script = r\"server_stdio.py\"\n\n# 构建 StdioConnection 连接配置\n# langchain-mcp-adapters 0.3.2 新增的 connection 模式：\n# 无需手动管理 stdio_client \u002F ClientSession，load_mcp_tools 内部自动处理连接生命周期\nstdio_connection = StdioConnection(\n    transport=\"stdio\",\n    command=\"python\",\n    args=[server_script],\n)\n\nasync def run_agent():\n    # 使用 connection 模式加载工具\n    tools = await load_mcp_tools(session=None, connection=stdio_connection)\n    print(f\"服务端支持的工具:{tools}\")\n\n    # 使用 create_agent 创建 Agent（langchain 1.3.x 新 API）\n    agent = create_agent(\n        model=llm,\n        tools=tools,\n        system_prompt=\"你是一个乐于助人的助手，能够调用工具回答用户问题。\",\n    )\n\n    # 代理调用\n    print(\"MCP客户端启动，输入'quit'退出\")\n    while True:\n        # 接收用户查询\n        query = input(\"\\nQuery: \").strip()\n        if query.lower() == \"quit\":\n            break\n        # 发送用户查询给代理，并打印\n        try:\n            result = await agent.ainvoke({\"messages\": [{\"role\": \"user\", \"content\": query}]})\n            print(f\"response-->{result['messages'][-1].content}\")\n        except Exception:\n            print(\"解析有问题\")\n\nif __name__ == \"__main__\":\n    asyncio.run(run_agent())\n",[50,3027,3028,3032,3037,3041,3046,3051,3056,3061,3066,3071,3075,3079,3084,3089,3094,3098,3103,3108,3113,3118,3123,3127,3132,3136,3141,3146,3151,3156,3161,3165,3169,3173,3177,3182,3187,3192,3197,3202,3207,3212,3216,3220,3225,3230,3235,3240,3244,3249,3254,3259,3264,3270,3276,3281,3287,3293,3299,3305,3311,3317,3323,3329,3335,3341,3347,3353,3359,3364,3369],{"__ignoreMap":70},[74,3029,3030],{"class":76,"line":77},[74,3031,2271],{},[74,3033,3034],{"class":76,"line":83},[74,3035,3036],{},"需求：实现基于STDIO的MCP智能代理客户端，集成大语言模型和远程工具\n",[74,3038,3039],{"class":76,"line":89},[74,3040,2281],{},[74,3042,3043],{"class":76,"line":95},[74,3044,3045],{},"1. 创建大语言模型实例，配置API参数\n",[74,3047,3048],{"class":76,"line":101},[74,3049,3050],{},"2. 配置MCP服务器脚本路径，构建 StdioConnection\n",[74,3052,3053],{"class":76,"line":107},[74,3054,3055],{},"3. 使用 langchain-mcp-adapters 的 connection 模式加载工具\n",[74,3057,3058],{"class":76,"line":113},[74,3059,3060],{},"4. 构建工具调用代理和执行器\n",[74,3062,3063],{"class":76,"line":119},[74,3064,3065],{},"5. 实现交互式聊天循环，处理用户查询\n",[74,3067,3068],{"class":76,"line":125},[74,3069,3070],{},"6. 使用异步方式运行客户端程序\n",[74,3072,3073],{"class":76,"line":131},[74,3074,2271],{},[74,3076,3077],{"class":76,"line":137},[74,3078,141],{"emptyLinePlaceholder":140},[74,3080,3081],{"class":76,"line":144},[74,3082,3083],{},"import os\n",[74,3085,3086],{"class":76,"line":150},[74,3087,3088],{},"import sys\n",[74,3090,3091],{"class":76,"line":156},[74,3092,3093],{},"sys.path.append(os.path.join(os.path.dirname(__file__), \"..\u002F..\u002F..\"))\n",[74,3095,3096],{"class":76,"line":162},[74,3097,2789],{},[74,3099,3100],{"class":76,"line":168},[74,3101,3102],{},"from langchain_mcp_adapters.tools import load_mcp_tools\n",[74,3104,3105],{"class":76,"line":173},[74,3106,3107],{},"from langchain_mcp_adapters.sessions import StdioConnection\n",[74,3109,3110],{"class":76,"line":178},[74,3111,3112],{},"from langchain_openai import ChatOpenAI\n",[74,3114,3115],{"class":76,"line":184},[74,3116,3117],{},"from langchain.agents import create_agent\n",[74,3119,3120],{"class":76,"line":189},[74,3121,3122],{},"from agent_learn.config import Config\n",[74,3124,3125],{"class":76,"line":195},[74,3126,141],{"emptyLinePlaceholder":140},[74,3128,3129],{"class":76,"line":201},[74,3130,3131],{},"conf = Config()\n",[74,3133,3134],{"class":76,"line":207},[74,3135,141],{"emptyLinePlaceholder":140},[74,3137,3138],{"class":76,"line":664},[74,3139,3140],{},"# 创建模型\n",[74,3142,3143],{"class":76,"line":670},[74,3144,3145],{},"llm = ChatOpenAI(base_url=conf.base_url,\n",[74,3147,3148],{"class":76,"line":676},[74,3149,3150],{},"                 api_key=conf.api_key,\n",[74,3152,3153],{"class":76,"line":682},[74,3154,3155],{},"                 model=conf.model_name,\n",[74,3157,3158],{"class":76,"line":688},[74,3159,3160],{},"                 temperature=0.1)\n",[74,3162,3163],{"class":76,"line":693},[74,3164,141],{"emptyLinePlaceholder":140},[74,3166,3167],{"class":76,"line":698},[74,3168,2808],{},[74,3170,3171],{"class":76,"line":704},[74,3172,2813],{},[74,3174,3175],{"class":76,"line":710},[74,3176,141],{"emptyLinePlaceholder":140},[74,3178,3179],{"class":76,"line":716},[74,3180,3181],{},"# 构建 StdioConnection 连接配置\n",[74,3183,3184],{"class":76,"line":2427},[74,3185,3186],{},"# langchain-mcp-adapters 0.3.2 新增的 connection 模式：\n",[74,3188,3189],{"class":76,"line":2433},[74,3190,3191],{},"# 无需手动管理 stdio_client \u002F ClientSession，load_mcp_tools 内部自动处理连接生命周期\n",[74,3193,3194],{"class":76,"line":2438},[74,3195,3196],{},"stdio_connection = StdioConnection(\n",[74,3198,3199],{"class":76,"line":2444},[74,3200,3201],{},"    transport=\"stdio\",\n",[74,3203,3204],{"class":76,"line":2449},[74,3205,3206],{},"    command=\"python\",\n",[74,3208,3209],{"class":76,"line":2455},[74,3210,3211],{},"    args=[server_script],\n",[74,3213,3214],{"class":76,"line":2460},[74,3215,2352],{},[74,3217,3218],{"class":76,"line":2466},[74,3219,141],{"emptyLinePlaceholder":140},[74,3221,3222],{"class":76,"line":2471},[74,3223,3224],{},"async def run_agent():\n",[74,3226,3227],{"class":76,"line":2476},[74,3228,3229],{},"    # 使用 connection 模式加载工具\n",[74,3231,3232],{"class":76,"line":2482},[74,3233,3234],{},"    tools = await load_mcp_tools(session=None, connection=stdio_connection)\n",[74,3236,3237],{"class":76,"line":2488},[74,3238,3239],{},"    print(f\"服务端支持的工具:{tools}\")\n",[74,3241,3242],{"class":76,"line":2493},[74,3243,141],{"emptyLinePlaceholder":140},[74,3245,3246],{"class":76,"line":2499},[74,3247,3248],{},"    # 使用 create_agent 创建 Agent（langchain 1.3.x 新 API）\n",[74,3250,3251],{"class":76,"line":2504},[74,3252,3253],{},"    agent = create_agent(\n",[74,3255,3256],{"class":76,"line":2509},[74,3257,3258],{},"        model=llm,\n",[74,3260,3261],{"class":76,"line":2515},[74,3262,3263],{},"        tools=tools,\n",[74,3265,3267],{"class":76,"line":3266},51,[74,3268,3269],{},"        system_prompt=\"你是一个乐于助人的助手，能够调用工具回答用户问题。\",\n",[74,3271,3273],{"class":76,"line":3272},52,[74,3274,3275],{},"    )\n",[74,3277,3279],{"class":76,"line":3278},53,[74,3280,141],{"emptyLinePlaceholder":140},[74,3282,3284],{"class":76,"line":3283},54,[74,3285,3286],{},"    # 代理调用\n",[74,3288,3290],{"class":76,"line":3289},55,[74,3291,3292],{},"    print(\"MCP客户端启动，输入'quit'退出\")\n",[74,3294,3296],{"class":76,"line":3295},56,[74,3297,3298],{},"    while True:\n",[74,3300,3302],{"class":76,"line":3301},57,[74,3303,3304],{},"        # 接收用户查询\n",[74,3306,3308],{"class":76,"line":3307},58,[74,3309,3310],{},"        query = input(\"\\nQuery: \").strip()\n",[74,3312,3314],{"class":76,"line":3313},59,[74,3315,3316],{},"        if query.lower() == \"quit\":\n",[74,3318,3320],{"class":76,"line":3319},60,[74,3321,3322],{},"            break\n",[74,3324,3326],{"class":76,"line":3325},61,[74,3327,3328],{},"        # 发送用户查询给代理，并打印\n",[74,3330,3332],{"class":76,"line":3331},62,[74,3333,3334],{},"        try:\n",[74,3336,3338],{"class":76,"line":3337},63,[74,3339,3340],{},"            result = await agent.ainvoke({\"messages\": [{\"role\": \"user\", \"content\": query}]})\n",[74,3342,3344],{"class":76,"line":3343},64,[74,3345,3346],{},"            print(f\"response-->{result['messages'][-1].content}\")\n",[74,3348,3350],{"class":76,"line":3349},65,[74,3351,3352],{},"        except Exception:\n",[74,3354,3356],{"class":76,"line":3355},66,[74,3357,3358],{},"            print(\"解析有问题\")\n",[74,3360,3362],{"class":76,"line":3361},67,[74,3363,141],{"emptyLinePlaceholder":140},[74,3365,3367],{"class":76,"line":3366},68,[74,3368,2512],{},[74,3370,3372],{"class":76,"line":3371},69,[74,3373,3374],{},"    asyncio.run(run_agent())\n",[13,3376,3377,2524],{},[32,3378,2523],{},[40,3380,3381,3394,3400,3413,3429,3443],{},[43,3382,2908,3383,2912,3385,35,3388,3390,3391,3393],{},[50,3384,2175],{},[50,3386,3387],{},"StdioConnection",[50,3389,3387],{}," 是 langchain-mcp-adapters 0.3.2 新增的连接配置类，用于描述 stdio 传输参数，替代了旧版手动管理 ",[50,3392,2926],{}," 的写法。",[43,3395,3396,3399],{},[50,3397,3398],{},"server_script = r\"server_stdio.py\""," 指定服务端脚本路径。",[43,3401,3402,3405,3406,2912,3409,3412],{},[50,3403,3404],{},"StdioConnection(transport=\"stdio\", command=\"python\", args=[server_script])"," 构建 stdio 连接配置。",[50,3407,3408],{},"command",[50,3410,3411],{},"args"," 定义了如何启动服务端子进程。",[43,3414,3415,3418,3419,2912,3422,3425,3426,3428],{},[50,3416,3417],{},"load_mcp_tools(session=None, connection=stdio_connection)"," 是新版核心变化——传入 ",[50,3420,3421],{},"session=None",[50,3423,3424],{},"connection"," 对象，",[50,3427,2175],{}," 内部自动创建子进程、建立会话、加载工具，无需手动编写三层嵌套。",[43,3430,3431,3434,3435,3438,3439,3442],{},[50,3432,3433],{},"create_agent"," 是 langchain 1.3.x 的新 API，替代了旧版的 ",[50,3436,3437],{},"create_tool_calling_agent + AgentExecutor"," 组合。它接收模型、工具列表和系统提示，返回一个 ",[50,3440,3441],{},"CompiledStateGraph","（LangGraph 编译后的状态图），内部自动处理\"调用 LLM → 检查工具调用 → 执行工具 → 循环\"的完整流程。",[43,3444,3445,3446,3448,3449,3452,3453,3456,3457,3460],{},"交互式聊天循环：",[50,3447,3433],{}," 使用 ",[50,3450,3451],{},"messages"," 列表作为输入，返回结果中 ",[50,3454,3455],{},"result['messages'][-1].content"," 即为 LLM 的最终回复。用户输入 query → agent 判断是否需要调用工具 → 如需调用则自动调用 MCP 工具 → 将结果返回给用户。输入 ",[50,3458,3459],{},"quit"," 退出。",[13,3462,2979],{},[65,3464,3467],{"className":3465,"code":3466,"language":253,"meta":70},[251],"MCP客户端启动，输入'quit'退出\n\nQuery: 望京店现在排队多久\n\n> Entering new AgentExecutor chain...\n\nInvoking: `get_queue_length` with `{'store': '望京店'}`\n\n望京店当前排队 6 人，预计等待 12 分钟望京店现在排队 6 人，预计等待 12 分钟左右。如果赶时间，建议先在小程序上点单，到店直接取。\n\n> Finished chain.\nresponse-->{'input': '望京店现在排队多久', 'output': '望京店现在排队 6 人，预计等待 12 分钟左右。如果赶时间，建议先在小程序上点单，到店直接取。'}\n",[50,3468,3466],{"__ignoreMap":70},[22,3470,3472],{"id":3471},"_32-sse-传输方式","3.2 SSE 传输方式",[13,3474,3475,3476,3479],{},"SSE（Server-Sent Events，服务器发送事件）是一种",[32,3477,3478],{},"基于 HTTP 的单向推送","通信方式。与 stdio 不同，SSE 的服务端是一个独立的 HTTP 服务进程，客户端通过 HTTP 请求连接到服务端，服务端通过 SSE 通道将数据推送给客户端。",[40,3481,3482,3487],{},[43,3483,3484,3486],{},[32,3485,1420],{},"：服务端需要独立部署、客户端和服务端可能在不同机器上的场景。",[43,3488,3489,3491,3492,3494,3495,3498],{},[32,3490,2237],{},"：需要先手动启动服务端（监听 HTTP 端口），客户端再通过 URL 连接。如需局域网内其他机器访问，可将 ",[50,3493,2543],{}," 改为具体 IP（如 ",[50,3496,3497],{},"192.168.1.100","）。",[2240,3500,3502],{"id":3501},"_321-服务端","3.2.1 服务端",[13,3504,3505,3506,3509,3510,2912,3512,3514,3515,3517,3518,2524],{},"SSE 服务端的代码结构与 stdio ",[32,3507,3508],{},"几乎完全相同","，唯一的区别在于 ",[50,3511,2543],{},[50,3513,2546],{}," 在 ",[50,3516,2550],{}," 中指定，以及启动方式改为 ",[50,3519,3520],{},"transport=\"sse\"",[10,3522,3523],{},[13,3524,2258,3525],{},[50,3526,3527],{},"agent_learn\u002Fmcp_base\u002Fsse\u002Fserver_sse.py",[65,3529,3531],{"className":1483,"code":3530,"language":1485,"meta":70,"style":70},"from fastmcp import FastMCP\n\n# 在 mcp.run() 中指定 host 和 port（fastmcp 3.4.7 不再在构造函数中接受）\nmcp = FastMCP(\"store-hub\")\n\n# …… 工具定义与 stdio 版本完全一致（略）……\n\ndef main():\n    print(\"正在启动MCP SSE服务器...\")\n    print(\"SSE端点: http:\u002F\u002Flocalhost:8001\u002Fsse\")\n    print(\"按 Ctrl+C 停止服务器\")\n\n    try:\n        # 运行SSE服务器（fastmcp 3.4.7: host\u002Fport 通过 run() 传入）\n        mcp.run(transport=\"sse\", host=\"127.0.0.1\", port=8001)\n    except KeyboardInterrupt:\n        print(\"\\n服务器已停止\")\n    except Exception as e:\n        print(f\"服务器启动失败: {e}\")\n\nif __name__ == \"__main__\":\n    main()\n",[50,3532,3533,3537,3541,3546,3550,3554,3559,3563,3568,3573,3578,3583,3587,3591,3596,3601,3606,3611,3615,3620,3624,3628],{"__ignoreMap":70},[74,3534,3535],{"class":76,"line":77},[74,3536,2314],{},[74,3538,3539],{"class":76,"line":83},[74,3540,141],{"emptyLinePlaceholder":140},[74,3542,3543],{"class":76,"line":89},[74,3544,3545],{},"# 在 mcp.run() 中指定 host 和 port（fastmcp 3.4.7 不再在构造函数中接受）\n",[74,3547,3548],{"class":76,"line":95},[74,3549,2328],{},[74,3551,3552],{"class":76,"line":101},[74,3553,141],{"emptyLinePlaceholder":140},[74,3555,3556],{"class":76,"line":107},[74,3557,3558],{},"# …… 工具定义与 stdio 版本完全一致（略）……\n",[74,3560,3561],{"class":76,"line":113},[74,3562,141],{"emptyLinePlaceholder":140},[74,3564,3565],{"class":76,"line":119},[74,3566,3567],{},"def main():\n",[74,3569,3570],{"class":76,"line":125},[74,3571,3572],{},"    print(\"正在启动MCP SSE服务器...\")\n",[74,3574,3575],{"class":76,"line":131},[74,3576,3577],{},"    print(\"SSE端点: http:\u002F\u002Flocalhost:8001\u002Fsse\")\n",[74,3579,3580],{"class":76,"line":137},[74,3581,3582],{},"    print(\"按 Ctrl+C 停止服务器\")\n",[74,3584,3585],{"class":76,"line":144},[74,3586,141],{"emptyLinePlaceholder":140},[74,3588,3589],{"class":76,"line":150},[74,3590,2386],{},[74,3592,3593],{"class":76,"line":156},[74,3594,3595],{},"        # 运行SSE服务器（fastmcp 3.4.7: host\u002Fport 通过 run() 传入）\n",[74,3597,3598],{"class":76,"line":162},[74,3599,3600],{},"        mcp.run(transport=\"sse\", host=\"127.0.0.1\", port=8001)\n",[74,3602,3603],{"class":76,"line":168},[74,3604,3605],{},"    except KeyboardInterrupt:\n",[74,3607,3608],{"class":76,"line":173},[74,3609,3610],{},"        print(\"\\n服务器已停止\")\n",[74,3612,3613],{"class":76,"line":178},[74,3614,2401],{},[74,3616,3617],{"class":76,"line":184},[74,3618,3619],{},"        print(f\"服务器启动失败: {e}\")\n",[74,3621,3622],{"class":76,"line":189},[74,3623,141],{"emptyLinePlaceholder":140},[74,3625,3626],{"class":76,"line":195},[74,3627,2512],{},[74,3629,3630],{"class":76,"line":201},[74,3631,3632],{},"    main()\n",[2240,3634,3636],{"id":3635},"_322-客户端直接调用","3.2.2 客户端（直接调用）",[13,3638,3639],{},"SSE 客户端的连接方式与 stdio 不同：不再启动子进程，而是通过 HTTP URL 连接到已经运行的服务端。",[10,3641,3642],{},[13,3643,2258,3644],{},[50,3645,3646],{},"agent_learn\u002Fmcp_base\u002Fsse\u002Fclient_raw.py",[65,3648,3650],{"className":1483,"code":3649,"language":1485,"meta":70,"style":70},"import asyncio\nfrom fastmcp import Client\n\n# MCP server URL for SSE connection\nserver_url = \"http:\u002F\u002Flocalhost:8001\u002Fsse\"\n\nasync def run():\n    # 使用 fastmcp.Client 建立SSE连接\n    # Client 会自动识别 http:\u002F\u002F 开头的 URL 并选择对应的传输协议（SSE）\n    async with Client(server_url) as client:\n        # 列出服务器提供的工具列表\n        tools = await client.list_tools()\n        print(f\"tools-->{tools}\")\n\n        # 调用 MCP server 的 get_queue_length 工具\n        response = await client.call_tool(\"get_queue_length\", arguments={\"store\": \"望京店\"})\n        print(f\"response-->{response}\")\n\n# 启动运行\nif __name__ == \"__main__\":\n    asyncio.run(run())\n",[50,3651,3652,3656,3660,3664,3669,3673,3677,3681,3686,3691,3696,3700,3704,3708,3712,3716,3720,3724,3728,3732,3736],{"__ignoreMap":70},[74,3653,3654],{"class":76,"line":77},[74,3655,2789],{},[74,3657,3658],{"class":76,"line":83},[74,3659,2794],{},[74,3661,3662],{"class":76,"line":89},[74,3663,141],{"emptyLinePlaceholder":140},[74,3665,3666],{"class":76,"line":95},[74,3667,3668],{},"# MCP server URL for SSE connection\n",[74,3670,3671],{"class":76,"line":101},[74,3672,1596],{},[74,3674,3675],{"class":76,"line":107},[74,3676,141],{"emptyLinePlaceholder":140},[74,3678,3679],{"class":76,"line":113},[74,3680,2827],{},[74,3682,3683],{"class":76,"line":119},[74,3684,3685],{},"    # 使用 fastmcp.Client 建立SSE连接\n",[74,3687,3688],{"class":76,"line":125},[74,3689,3690],{},"    # Client 会自动识别 http:\u002F\u002F 开头的 URL 并选择对应的传输协议（SSE）\n",[74,3692,3693],{"class":76,"line":131},[74,3694,3695],{},"    async with Client(server_url) as client:\n",[74,3697,3698],{"class":76,"line":137},[74,3699,2852],{},[74,3701,3702],{"class":76,"line":144},[74,3703,2857],{},[74,3705,3706],{"class":76,"line":150},[74,3707,2862],{},[74,3709,3710],{"class":76,"line":156},[74,3711,141],{"emptyLinePlaceholder":140},[74,3713,3714],{"class":76,"line":162},[74,3715,2871],{},[74,3717,3718],{"class":76,"line":168},[74,3719,2876],{},[74,3721,3722],{"class":76,"line":173},[74,3723,2881],{},[74,3725,3726],{"class":76,"line":178},[74,3727,141],{"emptyLinePlaceholder":140},[74,3729,3730],{"class":76,"line":184},[74,3731,2890],{},[74,3733,3734],{"class":76,"line":189},[74,3735,2512],{},[74,3737,3738],{"class":76,"line":195},[74,3739,2899],{},[13,3741,3742,2524],{},[32,3743,2523],{},[40,3745,3746,3756],{},[43,3747,3748,3751,3752,3755],{},[50,3749,3750],{},"server_url = \"http:\u002F\u002F127.0.0.1:8001\u002Fsse\""," 是 SSE 端点地址，",[50,3753,3754],{},"\u002Fsse"," 是 FastMCP 默认的 SSE 路径。",[43,3757,3758,3761,3762,2946,3765,3767],{},[50,3759,3760],{},"async with Client(server_url) as client:"," 一步完成 SSE 连接建立、会话创建和初始化——替代了旧写法中 ",[50,3763,3764],{},"sse_client + ClientSession + session.initialize()",[50,3766,2918],{}," 会根据 URL 自动识别传输协议。",[13,3769,3770,2524],{},[32,3771,3772],{},"与 stdio 客户端的核心区别",[382,3774,3775,3786],{},[385,3776,3777],{},[388,3778,3779,3781,3783],{},[391,3780],{},[391,3782,1859],{},[391,3784,3785],{},"SSE",[401,3787,3788,3799,3810],{},[388,3789,3790,3793,3796],{},[406,3791,3792],{},"连接方式",[406,3794,3795],{},"子进程 stdin\u002Fstdout",[406,3797,3798],{},"HTTP URL",[388,3800,3801,3804,3807],{},[406,3802,3803],{},"服务端启动",[406,3805,3806],{},"客户端自动拉起",[406,3808,3809],{},"需手动先启动",[388,3811,3812,3815,3818],{},[406,3813,3814],{},"跨机器",[406,3816,3817],{},"不支持",[406,3819,3820],{},"支持",[2240,3822,3824],{"id":3823},"_323-客户端agent-调用","3.2.3 客户端（agent 调用）",[13,3826,3827,3828,3830,3831,2524],{},"SSE 的 agent 调用客户端与 stdio 版本结构相同，只是连接方式从 ",[50,3829,3387],{}," 改为 ",[50,3832,3833],{},"SSEConnection",[65,3835,3837],{"className":1483,"code":3836,"language":1485,"meta":70,"style":70},"from langchain_mcp_adapters.sessions import SSEConnection\n\n# MCP server URL for SSE connection\nserver_url = \"http:\u002F\u002F127.0.0.1:8001\u002Fsse\"\n\n# 构建 SSEConnection 连接配置\nsse_connection = SSEConnection(\n    transport=\"sse\",\n    url=server_url,\n)\n\nasync def run_agent():\n    # 使用 connection 模式加载工具\n    tools = await load_mcp_tools(session=None, connection=sse_connection)\n\n    # 使用 create_agent 创建 Agent（langchain 1.3.x 新 API）\n    agent = create_agent(\n        model=llm,\n        tools=tools,\n        system_prompt=\"你是一个乐于助人的助手，能够调用工具回答用户问题。\",\n    )\n\n    # 代理调用\n    print(\"MCP客户端启动，输入'quit'退出\")\n    while True:\n        # 接收用户查询\n        query = input(\"\\nQuery: \").strip()\n        if query.lower() == \"quit\":\n            break\n        # 发送用户查询给代理，并打印\n        try:\n            result = await agent.ainvoke({\"messages\": [{\"role\": \"user\", \"content\": query}]})\n            print(f\"response-->{result['messages'][-1].content}\")\n        except Exception:\n            print(\"解析有问题\")\n",[50,3838,3839,3844,3848,3852,3857,3861,3866,3871,3876,3881,3885,3889,3893,3897,3902,3906,3910,3914,3918,3922,3926,3930,3934,3938,3942,3946,3950,3954,3958,3962,3966,3970,3974,3978,3982],{"__ignoreMap":70},[74,3840,3841],{"class":76,"line":77},[74,3842,3843],{},"from langchain_mcp_adapters.sessions import SSEConnection\n",[74,3845,3846],{"class":76,"line":83},[74,3847,141],{"emptyLinePlaceholder":140},[74,3849,3850],{"class":76,"line":89},[74,3851,3668],{},[74,3853,3854],{"class":76,"line":95},[74,3855,3856],{},"server_url = \"http:\u002F\u002F127.0.0.1:8001\u002Fsse\"\n",[74,3858,3859],{"class":76,"line":101},[74,3860,141],{"emptyLinePlaceholder":140},[74,3862,3863],{"class":76,"line":107},[74,3864,3865],{},"# 构建 SSEConnection 连接配置\n",[74,3867,3868],{"class":76,"line":113},[74,3869,3870],{},"sse_connection = SSEConnection(\n",[74,3872,3873],{"class":76,"line":119},[74,3874,3875],{},"    transport=\"sse\",\n",[74,3877,3878],{"class":76,"line":125},[74,3879,3880],{},"    url=server_url,\n",[74,3882,3883],{"class":76,"line":131},[74,3884,2352],{},[74,3886,3887],{"class":76,"line":137},[74,3888,141],{"emptyLinePlaceholder":140},[74,3890,3891],{"class":76,"line":144},[74,3892,3224],{},[74,3894,3895],{"class":76,"line":150},[74,3896,3229],{},[74,3898,3899],{"class":76,"line":156},[74,3900,3901],{},"    tools = await load_mcp_tools(session=None, connection=sse_connection)\n",[74,3903,3904],{"class":76,"line":162},[74,3905,141],{"emptyLinePlaceholder":140},[74,3907,3908],{"class":76,"line":168},[74,3909,3248],{},[74,3911,3912],{"class":76,"line":173},[74,3913,3253],{},[74,3915,3916],{"class":76,"line":178},[74,3917,3258],{},[74,3919,3920],{"class":76,"line":184},[74,3921,3263],{},[74,3923,3924],{"class":76,"line":189},[74,3925,3269],{},[74,3927,3928],{"class":76,"line":195},[74,3929,3275],{},[74,3931,3932],{"class":76,"line":201},[74,3933,141],{"emptyLinePlaceholder":140},[74,3935,3936],{"class":76,"line":207},[74,3937,3286],{},[74,3939,3940],{"class":76,"line":664},[74,3941,3292],{},[74,3943,3944],{"class":76,"line":670},[74,3945,3298],{},[74,3947,3948],{"class":76,"line":676},[74,3949,3304],{},[74,3951,3952],{"class":76,"line":682},[74,3953,3310],{},[74,3955,3956],{"class":76,"line":688},[74,3957,3316],{},[74,3959,3960],{"class":76,"line":693},[74,3961,3322],{},[74,3963,3964],{"class":76,"line":698},[74,3965,3328],{},[74,3967,3968],{"class":76,"line":704},[74,3969,3334],{},[74,3971,3972],{"class":76,"line":710},[74,3973,3340],{},[74,3975,3976],{"class":76,"line":716},[74,3977,3346],{},[74,3979,3980],{"class":76,"line":2427},[74,3981,3352],{},[74,3983,3984],{"class":76,"line":2433},[74,3985,3358],{},[10,3987,3988],{},[13,3989,3990,3991,35,3993,3996,3997,3999,4000,4002],{},"注意路径是 ",[50,3992,3754],{},[50,3994,3995],{},"load_mcp_tools(session=None, connection=sse_connection)"," 与 stdio 版本用法完全一致——",[50,3998,3421],{}," 让 ",[50,4001,2175],{}," 根据 connection 自动管理连接生命周期。",[22,4004,4006],{"id":4005},"_33-streamable-方式","3.3 Streamable 方式",[13,4008,4009,4010,4013],{},"Streamable HTTP 是 MCP 协议",[32,4011,4012],{},"最新推荐的传输方式","（取代了早期的 SSE）。它在 SSE 的基础上做了两项改进：",[4015,4016,4017,4023],"ol",{},[43,4018,4019,4022],{},[32,4020,4021],{},"双向通信","：SSE 是服务端单向推送，Streamable HTTP 支持客户端和服务端双向收发，更高效。",[43,4024,4025,4028],{},[32,4026,4027],{},"会话管理","：支持会话 ID（session ID），允许客户端在多次请求间保持状态，避免重复初始化。",[40,4030,4031,4036],{},[43,4032,4033,4035],{},[32,4034,1420],{},"：生产环境推荐使用 Streamable HTTP，它是 MCP 规范的标准传输方式。",[43,4037,4038,4040,4041,4044,4045,4047,4048,4050,4051,4053],{},[32,4039,2237],{},"：服务端地址路径是 ",[50,4042,4043],{},"\u002Fmcp","（而非 SSE 的 ",[50,4046,3754],{},"），客户端使用 ",[50,4049,2911],{}," 传入 ",[50,4052,4043],{}," 结尾的 URL 即可自动连接。",[2240,4055,4057],{"id":4056},"_331-服务端","3.3.1 服务端",[13,4059,4060],{},"Streamable HTTP 服务端的代码结构与前两种方式一致，区别仅在于 transport 参数：",[10,4062,4063],{},[13,4064,2258,4065],{},[50,4066,4067],{},"agent_learn\u002Fmcp_base\u002Fstreamable\u002Fserver_streamable.py",[65,4069,4071],{"className":1483,"code":4070,"language":1485,"meta":70,"style":70},"from fastmcp import FastMCP\n\n# 创建 MCP 实例（fastmcp 3.4.7: host\u002Fport 在 mcp.run() 中指定）\nmcp = FastMCP(\"store-hub\")\n\n# …… 工具定义与 stdio 版本完全一致（略）……\n\ndef main():\n    print(\"正在启动MCP Streamable HTTP服务器...\")\n    print(\"Streamable HTTP端点: http:\u002F\u002F127.0.0.1:8001\u002Fmcp\")\n\n    try:\n        mcp.run(transport=\"streamable-http\", host=\"127.0.0.1\", port=8001)\n    except KeyboardInterrupt:\n        print(\"\\n服务器已停止\")\n    except Exception as e:\n        print(f\"服务器启动失败: {e}\")\n\nif __name__ == \"__main__\":\n    main()\n",[50,4072,4073,4077,4081,4086,4090,4094,4098,4102,4106,4111,4116,4120,4124,4129,4133,4137,4141,4145,4149,4153],{"__ignoreMap":70},[74,4074,4075],{"class":76,"line":77},[74,4076,2314],{},[74,4078,4079],{"class":76,"line":83},[74,4080,141],{"emptyLinePlaceholder":140},[74,4082,4083],{"class":76,"line":89},[74,4084,4085],{},"# 创建 MCP 实例（fastmcp 3.4.7: host\u002Fport 在 mcp.run() 中指定）\n",[74,4087,4088],{"class":76,"line":95},[74,4089,2328],{},[74,4091,4092],{"class":76,"line":101},[74,4093,141],{"emptyLinePlaceholder":140},[74,4095,4096],{"class":76,"line":107},[74,4097,3558],{},[74,4099,4100],{"class":76,"line":113},[74,4101,141],{"emptyLinePlaceholder":140},[74,4103,4104],{"class":76,"line":119},[74,4105,3567],{},[74,4107,4108],{"class":76,"line":125},[74,4109,4110],{},"    print(\"正在启动MCP Streamable HTTP服务器...\")\n",[74,4112,4113],{"class":76,"line":131},[74,4114,4115],{},"    print(\"Streamable HTTP端点: http:\u002F\u002F127.0.0.1:8001\u002Fmcp\")\n",[74,4117,4118],{"class":76,"line":137},[74,4119,141],{"emptyLinePlaceholder":140},[74,4121,4122],{"class":76,"line":144},[74,4123,2386],{},[74,4125,4126],{"class":76,"line":150},[74,4127,4128],{},"        mcp.run(transport=\"streamable-http\", host=\"127.0.0.1\", port=8001)\n",[74,4130,4131],{"class":76,"line":156},[74,4132,3605],{},[74,4134,4135],{"class":76,"line":162},[74,4136,3610],{},[74,4138,4139],{"class":76,"line":168},[74,4140,2401],{},[74,4142,4143],{"class":76,"line":173},[74,4144,3619],{},[74,4146,4147],{"class":76,"line":178},[74,4148,141],{"emptyLinePlaceholder":140},[74,4150,4151],{"class":76,"line":184},[74,4152,2512],{},[74,4154,4155],{"class":76,"line":189},[74,4156,3632],{},[2240,4158,4160],{"id":4159},"_332-客户端直接调用","3.3.2 客户端（直接调用）",[10,4162,4163],{},[13,4164,2258,4165],{},[50,4166,4167],{},"agent_learn\u002Fmcp_base\u002Fstreamable\u002Fclient_raw.py",[65,4169,4171],{"className":1483,"code":4170,"language":1485,"meta":70,"style":70},"import asyncio\nfrom fastmcp import Client\n\n# 定义服务器地址（Streamable HTTP 端点）\nserver_url = \"http:\u002F\u002F127.0.0.1:8001\u002Fmcp\"\n\nasync def main():\n    # 使用 fastmcp.Client 建立Streamable HTTP连接\n    # Client 会自动识别以 \u002Fmcp 结尾的 URL 并选择 Streamable HTTP 传输协议\n    async with Client(server_url) as client:\n        # 列出服务器提供的工具列表\n        tools = await client.list_tools()\n        print(f\"tools-->{tools}\")\n\n        # 调用 MCP server 的 get_queue_length 工具\n        response = await client.call_tool(\"get_queue_length\", arguments={\"store\": \"望京店\"})\n        print(f\"response-->{response}\")\n\nif __name__ == \"__main__\":\n    asyncio.run(main())\n",[50,4172,4173,4177,4181,4185,4190,4194,4198,4203,4208,4213,4217,4221,4225,4229,4233,4237,4241,4245,4249,4253],{"__ignoreMap":70},[74,4174,4175],{"class":76,"line":77},[74,4176,2789],{},[74,4178,4179],{"class":76,"line":83},[74,4180,2794],{},[74,4182,4183],{"class":76,"line":89},[74,4184,141],{"emptyLinePlaceholder":140},[74,4186,4187],{"class":76,"line":95},[74,4188,4189],{},"# 定义服务器地址（Streamable HTTP 端点）\n",[74,4191,4192],{"class":76,"line":101},[74,4193,1688],{},[74,4195,4196],{"class":76,"line":107},[74,4197,141],{"emptyLinePlaceholder":140},[74,4199,4200],{"class":76,"line":113},[74,4201,4202],{},"async def main():\n",[74,4204,4205],{"class":76,"line":119},[74,4206,4207],{},"    # 使用 fastmcp.Client 建立Streamable HTTP连接\n",[74,4209,4210],{"class":76,"line":125},[74,4211,4212],{},"    # Client 会自动识别以 \u002Fmcp 结尾的 URL 并选择 Streamable HTTP 传输协议\n",[74,4214,4215],{"class":76,"line":131},[74,4216,3695],{},[74,4218,4219],{"class":76,"line":137},[74,4220,2852],{},[74,4222,4223],{"class":76,"line":144},[74,4224,2857],{},[74,4226,4227],{"class":76,"line":150},[74,4228,2862],{},[74,4230,4231],{"class":76,"line":156},[74,4232,141],{"emptyLinePlaceholder":140},[74,4234,4235],{"class":76,"line":162},[74,4236,2871],{},[74,4238,4239],{"class":76,"line":168},[74,4240,2876],{},[74,4242,4243],{"class":76,"line":173},[74,4244,2881],{},[74,4246,4247],{"class":76,"line":178},[74,4248,141],{"emptyLinePlaceholder":140},[74,4250,4251],{"class":76,"line":184},[74,4252,2512],{},[74,4254,4255],{"class":76,"line":189},[74,4256,4257],{},"    asyncio.run(main())\n",[2240,4259,4261],{"id":4260},"_333-客户端agent-调用","3.3.3 客户端（agent 调用）",[65,4263,4265],{"className":1483,"code":4264,"language":1485,"meta":70,"style":70},"from langchain_mcp_adapters.sessions import StreamableHttpConnection\n\n# MCP 服务器的 Streamable-HTTP 连接地址\nserver_url = \"http:\u002F\u002F127.0.0.1:8001\u002Fmcp\"\n\n# 构建 StreamableHttpConnection 连接配置\nstreamable_connection = StreamableHttpConnection(\n    transport=\"streamable_http\",\n    url=server_url,\n)\n\nasync def run_agent():\n    # 使用 connection 模式加载工具\n    tools = await load_mcp_tools(session=None, connection=streamable_connection)\n    print(f\"服务端支持的工具:{tools}\")\n\n    # 使用 create_agent 创建 Agent（langchain 1.3.x 新 API）\n    agent = create_agent(\n        model=llm,\n        tools=tools,\n        system_prompt=\"你是一个乐于助人的助手，能够调用工具回答用户问题。\",\n    )\n",[50,4266,4267,4272,4276,4281,4285,4289,4294,4299,4304,4308,4312,4316,4320,4324,4329,4333,4337,4341,4345,4349,4353,4357],{"__ignoreMap":70},[74,4268,4269],{"class":76,"line":77},[74,4270,4271],{},"from langchain_mcp_adapters.sessions import StreamableHttpConnection\n",[74,4273,4274],{"class":76,"line":83},[74,4275,141],{"emptyLinePlaceholder":140},[74,4277,4278],{"class":76,"line":89},[74,4279,4280],{},"# MCP 服务器的 Streamable-HTTP 连接地址\n",[74,4282,4283],{"class":76,"line":95},[74,4284,1688],{},[74,4286,4287],{"class":76,"line":101},[74,4288,141],{"emptyLinePlaceholder":140},[74,4290,4291],{"class":76,"line":107},[74,4292,4293],{},"# 构建 StreamableHttpConnection 连接配置\n",[74,4295,4296],{"class":76,"line":113},[74,4297,4298],{},"streamable_connection = StreamableHttpConnection(\n",[74,4300,4301],{"class":76,"line":119},[74,4302,4303],{},"    transport=\"streamable_http\",\n",[74,4305,4306],{"class":76,"line":125},[74,4307,3880],{},[74,4309,4310],{"class":76,"line":131},[74,4311,2352],{},[74,4313,4314],{"class":76,"line":137},[74,4315,141],{"emptyLinePlaceholder":140},[74,4317,4318],{"class":76,"line":144},[74,4319,3224],{},[74,4321,4322],{"class":76,"line":150},[74,4323,3229],{},[74,4325,4326],{"class":76,"line":156},[74,4327,4328],{},"    tools = await load_mcp_tools(session=None, connection=streamable_connection)\n",[74,4330,4331],{"class":76,"line":162},[74,4332,3239],{},[74,4334,4335],{"class":76,"line":168},[74,4336,141],{"emptyLinePlaceholder":140},[74,4338,4339],{"class":76,"line":173},[74,4340,3248],{},[74,4342,4343],{"class":76,"line":178},[74,4344,3253],{},[74,4346,4347],{"class":76,"line":184},[74,4348,3258],{},[74,4350,4351],{"class":76,"line":189},[74,4352,3263],{},[74,4354,4355],{"class":76,"line":195},[74,4356,3269],{},[74,4358,4359],{"class":76,"line":201},[74,4360,3275],{},[13,4362,4363,2524],{},[32,4364,2523],{},[40,4366,4367,4375,4394],{},[43,4368,4369,4372,4373,35],{},[50,4370,4371],{},"server_url = \"http:\u002F\u002F127.0.0.1:8001\u002Fmcp\""," 地址路径为 ",[50,4374,4043],{},[43,4376,4377,4380,4381,4383,4384,4387,4388,4390,4391,4393],{},[50,4378,4379],{},"StreamableHttpConnection(transport=\"streamable_http\", url=server_url)"," 构建 Streamable HTTP 连接配置。注意 ",[50,4382,2581],{}," 参数值为 ",[50,4385,4386],{},"\"streamable_http\"","（下划线），而非 ",[50,4389,2550],{}," 中的 ",[50,4392,2589],{},"（连字符）。",[43,4395,4396,4399],{},[50,4397,4398],{},"load_mcp_tools(session=None, connection=streamable_connection)"," 与 SSE \u002F stdio 版本用法完全一致。",[13,4401,4402,2524],{},[32,4403,4404],{},"三种传输方式总结",[382,4406,4407,4420],{},[385,4408,4409],{},[388,4410,4411,4413,4415,4417],{},[391,4412,393],{},[391,4414,1859],{},[391,4416,3785],{},[391,4418,4419],{},"Streamable HTTP",[401,4421,4422,4435,4448,4459,4477,4490],{},[388,4423,4424,4427,4429,4432],{},[406,4425,4426],{},"通信机制",[406,4428,3795],{},[406,4430,4431],{},"HTTP 单向推送",[406,4433,4434],{},"HTTP 双向通信",[388,4436,4437,4440,4443,4446],{},[406,4438,4439],{},"服务端部署",[406,4441,4442],{},"无需独立部署",[406,4444,4445],{},"需独立 HTTP 服务",[406,4447,4445],{},[388,4449,4450,4453,4455,4457],{},[406,4451,4452],{},"跨机器通信",[406,4454,3817],{},[406,4456,3820],{},[406,4458,3820],{},[388,4460,4461,4464,4467,4472],{},[406,4462,4463],{},"客户端地址",[406,4465,4466],{},"脚本路径",[406,4468,4469],{},[50,4470,4471],{},"http:\u002F\u002Fip:port\u002Fsse",[406,4473,4474],{},[50,4475,4476],{},"http:\u002F\u002Fip:port\u002Fmcp",[388,4478,4479,4481,4484,4487],{},[406,4480,1420],{},[406,4482,4483],{},"本地开发调试",[406,4485,4486],{},"需要远程访问",[406,4488,4489],{},"生产环境（推荐）",[388,4491,4492,4495,4498,4500],{},[406,4493,4494],{},"工具定义代码",[406,4496,4497],{},"完全相同",[406,4499,4497],{},[406,4501,4497],{},[10,4503,4504],{},[13,4505,4506,4507,4510,4511,4513],{},"核心结论：",[32,4508,4509],{},"三种传输方式只在连接层不同，工具的定义和注册代码完全一致","。切换传输方式只需修改 ",[50,4512,2581],{}," 参数和客户端的连接函数\u002F地址。",[17,4515,4517],{"id":4516},"_4-本节小结","4. 本节小结",[40,4519,4520,4527,4534,4540,4547],{},[43,4521,4522,4523,4526],{},"MCP 解决的是",[32,4524,4525],{},"接口标准的缺失","：让工具由最了解它的人自描述，从而\"一次编写，到处调用\"",[43,4528,4529,4530,4533],{},"架构上分四层：",[32,4531,4532],{},"Host → MCP Client → MCP Server → 外部工具与数据源","，Client 与 Server 一对一通信",[43,4535,4536,4537],{},"调用流程中 LLM 只负责\"调哪个工具\"，",[32,4538,4539],{},"MCP Client 负责通信、MCP Server 负责执行",[43,4541,4542,4543,4546],{},"三种传输方式只在连接层不同：",[32,4544,4545],{},"stdio 本地调试、SSE 已弃用、Streamable-HTTP 生产推荐","，工具定义代码完全一致",[43,4548,4549,4550,4553],{},"MCP 与 Function Call 是",[32,4551,4552],{},"模型层与工具层","的互补关系，实际项目中常配合使用",[4555,4556,4557],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}",{"title":70,"searchDepth":83,"depth":83,"links":4559},[4560,4565,4571,4576],{"id":19,"depth":83,"text":20,"children":4561},[4562,4563,4564],{"id":24,"depth":89,"text":25},{"id":234,"depth":89,"text":235},{"id":477,"depth":89,"text":478},{"id":732,"depth":83,"text":733,"children":4566},[4567,4568,4569,4570],{"id":776,"depth":89,"text":777},{"id":921,"depth":89,"text":922},{"id":1388,"depth":89,"text":1389},{"id":1948,"depth":89,"text":1949},{"id":2179,"depth":83,"text":2180,"children":4572},[4573,4574,4575],{"id":2217,"depth":89,"text":2218},{"id":3471,"depth":89,"text":3472},{"id":4005,"depth":89,"text":4006},{"id":4516,"depth":83,"text":4517},"2026-06-16","从“每接一个接口都要手写一份描述”的接口混乱讲起，理清 MCP 的 Host \u002F Client \u002F Server 三层架构与调用流程，并对比 stdio、SSE、Streamable HTTP 三种传输方式。",false,"md","article",{"migration":4583},{"generator":4584,"sourceSha256":4585},"nuxt-site\u002Fscripts\u002Fmigrate-content.mjs","6dc03ecbc903ec9f8b17e31cf4a7bad6e890a22a59813caa47a378ca8cb3303a","\u002Fagent\u002F02-mcp协议",null,"agent",{"title":5,"description":4578},"content\u002Fagent\u002F02-MCP协议.md","agent\u002F02-MCP协议",[4593,4594,4595],"Agent","MCP","协议","Cj8ZC173xI_T41KfSWjIw48Tc46xFIv325JMTq_9UoU",1791279145023]