mcpField
M
mcp-ptitchef

mcp-ptitchef

本地服务
github.com游戏娱乐0今天更新

关于 mcp-ptitchef

mcp-ptitchef 将法国烹饪网站 Ptitchef 接入聊天客户端,适合搜索食谱、查看做法并按人数调整用量。它还支持按现有食材查找菜谱、浏览分类与榜单,以及查询食谱的其他语言版本,无需 API 密钥或账户。

主要功能

  1. 01按菜名或食材搜索食谱
  2. 02按现有食材寻找可做菜式
  3. 03浏览分类和常见榜单
  4. 04读取食谱并调整份量
  5. 05查询食谱的其他语言版本
  6. 06缩放任意食材清单

适用场景

  1. 01用冰箱现有食材寻找菜式
  2. 02按人数调整食谱用量
  3. 03查找高评分或最新食谱
  4. 04确认食谱是否有其他语言版本

MCP 相关

作为 MCP 服务,它向客户端提供食谱搜索与读取、分类和榜单浏览、食材匹配、用量缩放及译本查询工具。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

暂未收录安装方式

我们还没有获取到这个服务的安装包或远程地址,请按项目 README 中的说明安装。

代码仓库
安装包
npmmcp-ptitchef1.1.0
mcpbmcp-ptitchef-1.1.0.mcpb1.1.0

工具

7

收录的工具列表 · 更新于 今天

参数类型必填说明
limitinteger否要显示的条目数,默认 20,最多 200。若某个层级的条目数超过此值,会明确说明;“categories_published”始终表示页面列出的数量。
familystring否要打开的系列 slug,取自先前的调用。省略时读取系列本身,即分类树的起点。

详细介绍

README 配图

mcp-ptitchef

npm CI license MCP Registry Glama M8ven LobeHub 在 Cursor 中安装 在 VS Code 中安装

Ptitchef 是一个法国烹饪网站,家庭厨师会在上面 发布自己的食谱。每份食谱都列出食材、步骤(通常每一步都配有照片)、准备和烹饪时间、成本、 营养数据,以及读者留下的评分。网站按照食材类别树为食谱分类,并以多种语言 发布其中许多食谱。

此服务可将聊天客户端连接到该网站。你可以浏览类别树,按菜品或食材搜索食谱,浏览某个类别或网站的 常设清单,询问冰箱里的食材能做什么,查看一份食谱并按餐桌人数调整食材用量,以及查找食谱发布时使用的其他语言。无需 API 密钥或账号。

法语版


安装

一键安装

在 Cursor 中安装 在 VS Code 中安装

Claude Code

claude mcp add ptitchef -- npx -y mcp-ptitchef

Claude Desktop、Cursor 以及任何使用标准配置格式的客户端

{
  "mcpServers": {
    "ptitchef": {
      "command": "npx",
      "args": ["-y", "mcp-ptitchef"]
    }
  }
}

需要 Node 24 或更高版本,无需设置任何环境变量。

使用 Docker
{
  "mcpServers": {
    "ptitchef": {
      "command": "docker",
      "args": ["run", "-i", "--rm", "ghcr.io/smeet666/mcp-ptitchef:1.0.1"]
    }
  }
}

-i 会保持 stdin 处于打开状态,协议通过它传输;不使用 -t,因为 TTY 会改写数据流。容器需要能够通过 HTTPS 访问 www.ptitchef.com,除此之外不需要任何东西:无需卷、端口或凭据。

使用 Bundle,无需 npm

从 最新版本 下载 mcp-ptitchef-1.0.1.mcpb 并打开。支持 MCP Bundle 的客户端会自行安装,无需 npm,也无需编辑配置文件。Bundle 包含其依赖项,因此 安装时不会下载任何内容。

可以询问的内容

  • « Ptitchef 有哪些羽衣甘蓝食谱? »
  • "我可以用西葫芦、羊乳酪和薄荷做什么?"
  • "把那道适合八个人吃的焗烤菜谱读给我听。"
  • "显示网站上评分最高的食谱。"
  • "这道食谱也有西班牙语版本吗?"

Ptitchef 是一个法国网站,因此它的食谱都是法语。通常的流程是从列表找到食谱:列表中的一行带有 id,而 get_recipe 接收该 id。

工具

工具功能
list_categories浏览网站归类的食材类别树。
search_recipes按菜肴或食材查找食谱。
browse_recipes逐页浏览分类页面或固定列表。
search_by_ingredients根据烹饪者已有的食材查找可制作的菜肴。
get_recipe读取一道食谱,并按需调整为指定份数。
scale_ingredients调整任意食材清单的份量,无需向网站请求。
get_recipe_translations列出该食谱发布时使用的其他语言。

从 list_categories 开始。 网站会提供正确的地址,这样就不必手动构建:按这种方式构建的地址会指向网站首页。

list_categories

读取网站用于归类食谱的树状结构。不带参数调用时会返回类别系列;传入某个系列的 slug 作为 family,即可读取该系列下的内容。

参数类型必填功能
family字符串,1 到 80 个字符否某个系列的 slug,用于读取其下的分类。
limit整数,1 到 200,默认值为 20否返回的行数。

返回内容: 各行包含 slug,它会作为 family 或 category 返回;title 使用网站自己的措辞;url;description,若页面没有描述则为 null;以及 sample_children,即下一级分类。

search_recipes

按菜肴或食材搜索食谱。

参数类型必填功能
query字符串,1 到 120 个字符是法语的菜肴或食材。
limit整数,1 到 100,默认值为 20否返回的行数。

返回内容: results,其中各行包含 id、title、url、image_url、rating、rating_count 和 review_count;如果页面没有打印评论数,则该值为 null。返回封套会说明网站如何作答:如果答案来自网站自己的分类页面,kind 为 category,其 total_available 统计整个分类的数量;如果网站在单个页面上按自己的方式作答,kind 为 free_text,此时总数统计返回的行数。这两种总数统计的内容不同。对于网站手动撰写的主题,kind 也会是 guide;这类行包含名称和地址,并且没有总数。此外还会返回 result_count、rows_seen、page、single_page 和 url。如果标记为 single_page 的列表总数大于 rows_seen,则表示还有剩余内容,网站会统计但不会提供。

browse_recipes

逐页读取一个类别,或读取网站的一个固定列表。

参数类型必填说明
categorystring,1 到 120 个字符否类别 slug,由 list_categories 发布。
listinglatest、top_rated 或 most_viewed否固定列表,读取该列表而不是类别。
pageinteger,1 到 1000否要读取的类别页面。固定列表只有一页。
limitinteger,1 到 100,默认值为 20否返回的行数。

返回内容:search_recipes 返回的信封,其中 kind 的值为 category、standing 或 topic。page 是网站实际提供的页面;如果请求的页面 超过最后一页,则会回到第一页。

search_by_ingredients

根据烹饪者手头已有的食材,回答可以制作哪些菜肴。

参数类型必填说明
ingredients由 1 到 5 个字符串组成的数组,每个字符串为 1 到 60 个字符是手头已有的食材,使用法语。
limitinteger,1 到 100,默认值为 20否返回的行数。

**返回内容:**其他列表返回的信封,其中 kind 的值为 fridge。网站使用自身的词汇进行匹配,因此,如果某种食材的写法与网站不同,匹配范围会缩小,而不会扩大。

get_recipe

完整读取一道菜谱;如果提供了份数,则会按份数缩放食材用量。

参数类型必填说明
idstring,1 到 300 个字符是搜索或列表结果中某一行的 id。
servingsinteger,1 到 500否将食材用量缩放至指定份数。

返回内容:title、url、description、image_url、category、cuisine、 difficulty(采用网站自身的表述)、author、published、modified、 rating、rating_count、review_count、prep_minutes、cook_minutes、 total_minutes、nutrition(按其标明的份数发布)、estimated_cost、keywords、 faq 和 translations;如果页面未说明某项,则该项为 null。steps 按每步一行列出做法,illustrated_steps 则为相同步骤,并附上网站为每一步拍摄的照片。 yield 说明菜谱原本适用的份数,以及缩放后的份数。每种食材都带有 scaling 字段,其值为 scaled、rounded 或 unscaled:引用用量前请先查看该字段,因为 rounded 表示为了方便在厨房使用而调整过的用量。

scale_ingredients

对任意法语食材行列表应用相同的算术运算,不会向网站发送请求。

参数类型必填作用
ingredients1 到 100 个字符串组成的数组,每个最多 300 个字符是要重新换算的行,使用法语。
factor大于 0 且不超过 100 的数字二选一要应用的乘数。
from_servings大于 0 且不超过 500 的数字二选一列表对应的份数。
to_servings大于 0 且不超过 500 的数字二选一需要的份数。

传入 factor,或同时传入 from_servings 和 to_servings。

**返回内容:**所用的 factor、按 get_recipe 返回格式重新换算的 ingredients,以及 scaled_count、rounded_count 和 unscaled_count。

get_recipe_translations

根据网站自行发布的对应关系,列出某个食谱发布过的其他语言版本。

参数类型必填作用
id1 到 300 个字符的字符串是搜索结果或列表中某一行的 id。

返回内容:translations,其中每项包含网站发布的 language 标签和该版本的 url;还包含 translation_count,以及读取这些信息时所依据的法语页面的 url。

重新换算数量

数量会采用合适的单位,因此某一行返回的单位可能与食谱原本使用的单位不同:200 g 乘以二十后会变成 4 kg。

食材能被分割得多细,取决于食材本身。法棍可以切成两份、三份或四份;鸡蛋则不能分割。若换算后的数量介于这些数值之间,就会进行四舍五入,重新换算后的食谱也会与原有比例略有出入。该行会带有 rounded,并在其 note 中说明处理方式。

这些数字是本服务端计算得出的,因此展示时请说明它们是重新计算过的。如果食谱页面没有标明份数,就无法换算为指定人数的用量;返回结果会对此作出说明。

配置

所有变量均为可选项。请在客户端配置的 env 块中设置。

变量默认值作用
PTC_USER_AGENT项目标识向网站标识你的应用,并提供可联系到负责人的地址。
PTC_MIN_INTERVAL_MS1500两次请求之间的间隔,范围为 1000 至 60000。
PTC_TIMEOUT_MS20000单次请求的截止时间,范围为 1000 至 120000。
PTC_MAX_RETRIES3发生暂时性故障后的重试次数,范围为 0 至 8。
PTC_CACHE_TTL_MS900000页面在内存中的保留时间,范围为 0 至 86400000。
PTC_CACHE_MAX_ENTRIES200同时保存在内存中的页面数量,范围为 1 至 5000。
PTC_MAX_BODY_BYTES8000000完整读取的最大响应大小,范围为 100000 至 64000000。
PTC_BUDGET_MS60000单次读取必须在此时间内返回结果,包括重试和等待,范围为 5000 至 600000。
PTC_LOG_LEVELerrorsilent、error、info 或 debug,写入 stderr。

超出范围的值会回退为默认值,原因会写入 stderr。

错误

每次失败都会包含六种代码之一、一条消息,以及在有帮助时指出下一步操作的提示。

代码发生了什么应采取的操作
not_found网站已响应,但没有该食谱或页面。使用 list_categories 检查 slug,或通过搜索检查 id。
invalid_input请求发出前,参数已被拒绝。阅读消息,其中会指出对应的参数。
rate_limited网站要求此客户端降低请求频率。等待提示中指出的秒数,然后使用相同参数再次调用。该食谱仍然存在。
parse_failure页面已加载,但缺少预期内容。在问题跟踪页报告此问题。
network_error请求未能完成。稍后重试。
timeout请求超过了截止时间或时间预算。调高 PTC_TIMEOUT_MS 或 PTC_BUDGET_MS,或减少请求的行数。

作为库使用

读取网站的这一层单独发布,包含自己的请求间隔控制、缓存和错误处理,且不绑定任何协议。

import { PtitchefClient } from "mcp-ptitchef/client";

const client = new PtitchefClient();
const { data, cached } = await client.listCategories();
console.log(data.results.length, cached);

listCategories、searchRecipes、browseRecipes、searchByIngredients 和 getRecipe 均返回 { data, cached },并会抛出携带六种代码之一的错误。这里同样会限制两次请求之间的最短间隔。

请求频率与来源标注

请求逐个发送,间隔至少 1.5 秒,无论服务如何配置,间隔都不会低于 1 秒。User-Agent 始终以项目标识和可联系到真人的地址结尾。

每条结果都附有读取内容的页面地址,source 标明网站。食谱、标题和分类归 Ptitchef 及其撰写者所有。

此 MCP 服务是一个非官方项目,与 Ptitchef 无关。

隐私

此服务不会收集任何关于你的信息,也不会向作者发送任何信息。它在你的机器上运行,只联系 www.ptitchef.com,不联系其他任何地址;运行期间会将回答保存在内存中,不会写入磁盘。 PRIVACY.md 说明了请求会携带哪些信息,以及哪些设置会影响这些信息。

开发

npm install
npm run build:fixtures
npm test
npm run check

测试使用生成的模拟数据运行,不会发起网络请求。实时测试套件 npm run test:live 会针对每个路由发起一次请求,并每晚在网站本身上运行。

贡献

Bug、问题和想法请提交到 问题跟踪器。欢迎提交拉取请求;先提出问题有助于商定 修改方案。请参阅 CONTRIBUTING.md。

许可证

MIT,详见 LICENSE。食谱归 Ptitchef 及其作者所有。


mcp-ptitchef(法语)

英文版

Ptitchef 是一个法国美食网站,厨师们会在上面发布食谱。每道食谱都列出食材、步骤(通常会配有逐步拍摄的照片)、准备和烹饪时间、费用、营养价值,以及读者留下的评分。网站按食材类别树对食谱进行分类,并以多种语言发布了许多食谱。

此服务将对话客户端连接到该网站。你可以浏览分类树,按菜品或食材搜索食谱,查看某个分类或网站上的常设列表,询问能用冰箱里的食材做些什么,查看按用餐人数调整过食材用量的食谱,还可以查找某道食谱发布过的其他语言版本。无需 API 密钥,也无需账号。

安装

一键安装

在 Cursor 中安装 在 VS Code 中安装

Claude Code

claude mcp add ptitchef -- npx -y mcp-ptitchef

Claude Desktop、Cursor,以及所有采用标准配置格式的客户端

{
  "mcpServers": {
    "ptitchef": {
      "command": "npx",
      "args": ["-y", "mcp-ptitchef"]
    }
  }
}

需要 Node 24 或更高版本,无需设置任何环境变量。

使用 Docker
{
  "mcpServers": {
    "ptitchef": {
      "command": "docker",
      "args": ["run", "-i", "--rm", "ghcr.io/smeet666/mcp-ptitchef:1.0.1"]
    }
  }
}

-i 会保持标准输入开启,它是协议的通信通道;省略 -t 是因为 TTY 会重写数据流。容器需要能够通过 HTTPS 访问 www.ptitchef.com,除此之外无需访问其他任何内容:不需要卷、端口或凭据。

Bundle,无需 npm

从最新发布版本 下载 mcp-ptitchef-1.0.1.mcpb 并打开。支持 MCP bundle 的客户端会自动安装,无需 npm, 也无需修改配置文件。bundle 包含其依赖项,因此安装时不会下载任何内容。

可以询问什么

  • “Ptitchef 上有哪些羽衣甘蓝食谱?”
  • “我可以用西葫芦、羊乳酪和薄荷做什么?”
  • “请为我朗读这份适合 8 人食用的焗烤菜谱。”
  • “给我看看网站上评分最高的食谱。”
  • “这份食谱也有西班牙语版本吗?”

Ptitchef 是一个法国网站,因此食谱都是法语的。通常的操作流程是先浏览列表,再查看食谱:列表中的一行带有一个 id,get_recipe 会使用这个标识符。

工具

工具功能
list_categories浏览网站的食材类别树。
search_recipes按菜肴或食材查找食谱。
browse_recipes分页读取某个类别,或读取固定列表。
search_by_ingredients根据厨师已有的食材,回答可以做些什么。
get_recipe读取食谱,并可按需调整份数。
scale_ingredients调整任意食材列表,无需查询网站。
get_recipe_translations列出食谱发布过的其他语言版本。

请从 list_categories 开始。 网站会提供正确的网址,避免你手动构造网址:这样构造的网址会跳转到网站首页。

list_categories

读取网站用于分类食谱的类别树。不带参数调用时会返回类别系列;将某个系列的 slug 作为 family 传入,即可读取其下的内容。

参数类型必填功能
family字符串,1 到 80 个字符否某个系列的 slug,用于读取其下的类别。
limit整数,1 到 200,默认值为 20否返回的行数。

**返回内容:**各行包含 slug,可将其作为 family 或 category 传入;title 使用网站上的术语;url;description,如果页面没有描述则为 null;以及用于列出下一级类别的 sample_children。

search_recipes

按菜肴或食材搜索食谱。

参数类型必填功能
query字符串,1 到 120 个字符是法语菜肴名称或食材名称。
limit整数,1 到 100,默认值为 20否返回的行数。

返回内容:results 包含多行,每行带有 id、title、url、image_url、rating、rating_count 和 review_count;如果页面没有显示某个计数器,其值为 null。外层结构会说明网站如何响应:当结果来自类别页面时,kind 为 category,其中 total_available 统计整个类别;当网站在单个页面上以自己的方式返回结果时,kind 为 free_text,其中的总数统计返回的行数。这两种总数的统计对象不同。对于网站手动编写的专题文章,kind 也可能为 guide,其中的行包含名称和网址,但没有总数。此外还会返回 result_count、rows_seen、page、single_page 和 url。如果标记为 single_page 的列表中,总数大于 rows_seen,就表示还有剩余内容;网站会统计这些内容,但不会返回。

browse_recipes

逐页读取一个分类,或读取网站的一个固定列表。

参数类型必填作用
category字符串,1 至 120 个字符否由 list_categories 发布的分类 slug。
listinglatest、top_rated 或 most_viewed否要读取的固定列表,读取时会替代分类。
page整数,1 至 1000否要读取的分类页。固定列表只有一页。
limit整数,1 至 100,默认值为 20否要返回的行数。

**返回:**与 search_recipes 返回的封装相同,其中 kind 的值为 category、standing 或 topic。page 是网站实际提供的页面;如果请求的 页码超过最后一页,就会重新返回第一页。

search_by_ingredients

根据厨师手头已有的食材,返回可以制作的菜品。

参数类型必填作用
ingredients由 1 至 5 个字符串组成的数组,每个字符串 1 至 60 个字符是手头已有的食材,以法语填写。
limit整数,1 至 100,默认值为 20否要返回的行数。

**返回:**与其他列表相同的封装,其中 kind 的值为 fridge。网站会匹配自身使用的词汇,因此,如果它对某种食材使用了不同的写法,结果范围会缩小,而不是扩大。

get_recipe

读取完整食谱;如果提供份数,则会按份数调整食材用量。

参数类型必填作用
id字符串,1 至 300 个字符是搜索或列表行中的 id。
servings整数,1 至 500否按指定份数调整食材用量。

返回:title、url、description、image_url、category、 cuisine、网站使用的难度术语 difficulty、author、published、 modified、rating、rating_count、review_count、prep_minutes、 cook_minutes、total_minutes、按其标注的份量发布的 nutrition、 estimated_cost、keywords、faq 和 translations;如果页面未提供某项, 该项的值为 null。steps 按步骤逐行列出做法;illustrated_steps 则列出相同的 步骤,并附上网站为每一步拍摄的照片。yield 说明食谱原本适用的份数,以及调整后的份数。每种食材都包含 scaling,其值为 scaled、rounded 或 unscaled:引用用量前请先查看该字段;rounded 表示用量经过调整,以便在烹饪时使用。

scale_ingredients

无需查询网站,即可对任意法语食材列表应用相同的算术规则。

参数类型必填作用
ingredients1 到 100 个字符串组成的数组,每个字符串最多 300 个字符是要调整的法语行。
factor大于 0 且不超过 100 的数字二选一要应用的乘数。
from_servings大于 0 且不超过 500 的数字二选一原列表的份数。
to_servings大于 0 且不超过 500 的数字二选一目标份数。

传入 factor,或同时传入 from_servings 和 to_servings。

**返回内容:**使用的 factor、按 get_recipe 返回的格式调整后的 ingredients,以及 scaled_count、rounded_count 和 unscaled_count。

get_recipe_translations

根据网站自行发布的匹配信息,列出某道食谱发布过的其他语言版本。

参数类型必填作用
id1 到 300 个字符的字符串是搜索结果或列表行的 id。

返回内容:translations,其中每项包含网站发布的 language 标签和该版本的 url,以及 translation_count 和读取这些信息的法语页面的 url。

数量调整

数量以合适的单位表示。因此,调整后的一行可能会使用不同于食谱原文的单位:200 g 乘以 20 得到 4 kg。

食材可切分的精细程度取决于食材本身。法棍可以切成两份、三份或四份;鸡蛋则不能切分。因此,无法精确切分的数量会被四舍五入,调整后的食谱与原始比例会略有偏差。该行会标记为 rounded,其 note 会说明处理方式。

这些数字是此服务计算得出的,因此展示时请说明它们已重新计算。页面未注明份数的食谱无法换算为指定人数,响应中会对此作出说明。

配置

每个变量都是可选的。请将它们放在客户端配置的 env 块中。

变量默认值作用
PTC_USER_AGENT项目标识向网站标识您的应用,并提供联系相关人员的地址。
PTC_MIN_INTERVAL_MS1500两次请求之间的间隔,范围为 1000 到 60000。
PTC_TIMEOUT_MS20000单次请求的超时时间,范围为 1000 到 120000。
PTC_MAX_RETRIES3临时失败后的重试次数,范围为 0 到 8。
PTC_CACHE_TTL_MS900000页面在内存中的保留时间,范围为 0 到 86400000。
PTC_CACHE_MAX_ENTRIES200同时保存在内存中的页面数,范围为 1 到 5000。
PTC_MAX_BODY_BYTES8000000完整读取的最大响应大小,范围为 100000 到 64000000。
PTC_BUDGET_MS60000读取必须返回响应的时间限制,包括重试和等待,范围为 5000 到 600000。
PTC_LOG_LEVELerrorsilent、error、info 或 debug,日志写入错误输出。

超出范围的值会恢复为默认值,原因会写入错误输出。

错误

每个失败都带有六种代码之一和一条消息;如果有帮助,还会提示下一步该怎么做。

代码发生了什么如何处理
not_found网站已响应,但没有此食谱或页面。使用 list_categories 检查 slug,或通过搜索检查标识符。
invalid_input请求尚未发出,参数就已被拒绝。阅读消息,其中会指出相关参数。
rate_limited网站要求此客户端放慢请求速度。等待指定的秒数,然后使用相同参数重试。食谱仍然存在。
parse_failure页面已加载,但缺少预期内容。在问题跟踪页面报告此问题。
network_error请求未能完成。稍后重试。
timeout请求超时或超出预算。增大 PTC_TIMEOUT_MS 或 PTC_BUDGET_MS,或者减少请求的行数。

作为库使用

读取网站的层单独发布,包含自身的请求频率控制、缓存和错误处理,不绑定任何协议。

import { PtitchefClient } from "mcp-ptitchef/client";

const client = new PtitchefClient();
const { data, cached } = await client.listCategories();
console.log(data.results.length, cached);

listCategories、searchRecipes、browseRecipes、searchByIngredients 和 getRecipe 均会返回 { data, cached },并抛出带有六种代码之一的错误。这里同样会控制两次请求之间的最短间隔。

频率与归属

请求会逐一发送,间隔至少为 1.5 秒;无论如何配置,间隔下限都是 1 秒。User-Agent 始终以项目身份和联系人员的地址结尾。

每条结果都附有读取它的页面地址,source 则标明网站。食谱、标题和分类归 Ptitchef 及其作者所有。

此 MCP 项目为非官方项目,与 Ptitchef 无关联。

隐私

此服务不会收集您的任何信息,也不会向其作者发送任何信息。它在您的机器上运行,只会连接 www.ptitchef.com,运行期间会将响应保存在内存中,不会向磁盘写入任何内容。PRIVACY.md 说明了请求会携带哪些信息,以及哪些设置会改变这一点。

开发

npm install
npm run build:fixtures
npm test
npm run check

测试使用生成的 fixtures 运行,不会发送任何请求。实时测试套件 npm run test:live 会为每条路由发送一个请求,并每晚针对网站本身运行。

贡献

错误报告、问题和想法都欢迎提交到问题跟踪区。欢迎提交修改建议;先创建工单有助于就修改方案达成一致。请参阅 CONTRIBUTING.md。

许可证

MIT,详见 LICENSE。食谱归 Ptitchef 及其作者所有。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。