关于 mcp-server-trello
mcp-server-trello 是一个 MCP 服务,让 AI Agent 访问 Trello 看板中的卡片、列表、清单、附件、评论、自定义字段和工作区。它基于 Bun 运行,内置速率限制,并提供验收标准提取等工作流工具。
主要功能
- 01覆盖卡片、列表、清单、附件、评论等 Trello 数据
- 02提取卡片的验收标准清单并统计完成情况
- 03按名称或描述查询清单项
- 04内置速率限制,遵循 Trello API 限制
- 05运行时切换看板与工作区,无需重启
- 06支持列表创建、更新、重新排序与归档
适用场景
- 01让 Agent 读取卡片的验收标准并跟踪完成进度
- 02在 Trello 中批量管理列表与卡片
- 03通过 MCP 客户端为项目看板添加附件与评论
MCP 相关
该项目是一个 MCP 服务,向 MCP 客户端暴露 57 个 Trello 工具,可通过 npx 或 bunx 安装。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
57收录的工具列表 · 更新于 2 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| fields | string | 否 | 要返回的字段,以逗号分隔(例如:"name,idShort,labels,due,dueComplete")。省略则返回所有字段。 |
| listId | string | 是 | Trello 列表的 ID |
| boardId | string | 否 | Trello 看板的 ID(未提供时使用默认值) |
| nameFilter | string | 否 | 按名称筛选卡片时使用的可选子字符串(不区分大小写) |
| descMaxLength | integer | 否 | 每张卡片的描述预览最大长度。默认值为 200。增大此值可查看更多描述内容。 |
| omitDescThresholdBytes | integer | 否 | 省略描述前的近似响应大小阈值。默认值为 50000 字节。 |
详细介绍
MCP Server Trello
一个 Model Context Protocol(MCP)服务,可让 AI Agent 全面访问你的 Trello 看板,包括卡片、列表、清单、附件、评论、自定义字段和工作区。它内置限流和类型安全,并提供普通 API 封装中没有的工作流级工具,例如验收标准提取和清单依赖项查询。共 57 个工具,一条 npx 安装命令,由 Bun 驱动。
亮点
- 原生支持验收标准:
get_acceptance_criteria可将卡片的 AC 清单直接提取到 Agent 上下文中——其他同类工具都不支持。 - 关注任何内容:
watch_card和watch_list可将卡片和列表动态转入你的 Trello 通知。 - 全面的列表管理:创建、更新、重新排序(
update_list_position)并归档列表。 - 随时切换看板和工作区:无需重启或编辑配置。
- 自动处理限流:自动遵守 Trello API 限制(每个密钥每 10 秒 300 个请求,每个令牌每 10 秒 100 个请求)。
- 由 Bun 驱动:启动迅速,性能比旧版 Node 构建提升 2.8–4.4 倍。
npx和npm也能正常使用。
更新日志
如需查看详细更新记录,请参阅 CHANGELOG.md。
功能
- 全面集成 Trello 看板:与卡片、列表和看板活动交互
- 提取验收标准:将卡片的验收标准清单直接提取到 Agent 上下文中
- 清单智能查询:按名称或描述查询清单项目、跟踪完成情况并管理项目
- 提取完整卡片数据:获取所有卡片详细信息,包括清单、附件、标签、成员和评论
- 💬 评论管理:添加、更新、删除和检索卡片评论
- 活动订阅:关注卡片和列表,让它们的活动显示在 Trello 通知中
- 列表管理:创建、更新、重新排序和归档列表
- 文件附件:通过 URL 将任意类型的文件附加到卡片(PDF、文档、视频、图片等)
- 自定义字段:读取看板自定义字段定义并更新卡片值
- 内置限流:遵守 Trello API 限制(每个 API 密钥每 10 秒 300 个请求,每个令牌每 10 秒 100 个请求)
- 类型安全的实现:使用 TypeScript 编写,并提供全面的类型定义
- 输入验证:对所有 API 输入进行严格验证
- 错误处理:妥善处理错误并提供清晰的提示信息
- 动态选择看板:无需重启即可在看板和工作区之间切换
- Markdown 格式:以易读的 Markdown 格式导出卡片数据
安装
此服务已发布到 npm,名称为 @delorenj/mcp-server-trello。将其添加到你的 MCP 客户端即可——无需克隆或构建。
快速开始(Claude Desktop、Cursor 和其他 MCP 客户端)
将服务添加到客户端的 MCP 配置中:
{
"mcpServers": {
"trello": {
"command": "bunx",
"args": ["@delorenj/mcp-server-trello"],
"env": {
"TRELLO_API_KEY": "your-trello-api-key",
"TRELLO_TOKEN": "your-trello-token"
}
}
}
}
bunx 启动最快,但 npx 的效果相同。前往 trello.com/app-key 获取 API 密钥,并在同一页面生成令牌。
Claude Code
使用命令行注册此服务:
claude mcp add trello \
--env TRELLO_API_KEY=your-trello-api-key \
--env TRELLO_TOKEN=your-trello-token \
-- bunx @delorenj/mcp-server-trello
MCP Registry
此服务已列入官方 MCP Registry,名称为 io.github.delorenj/mcp-server-trello,因此支持 Registry 的客户端可以直接发现并安装它。
Agent 技能包(可选)
此仓库还附带一个与 BMAD 兼容的技能包,用于 Trello MCP 服务。通过 Agent 的技能管理工作流安装 skill/ 目录,或将其放入 Agent 的技能目录。
Agent 激活该技能后,会遵循 skill/SKILL.md。首次使用时,Agent 会运行捆绑的安装程序:
bash skill/scripts/install.sh
如果 Bun 可用,安装程序会从 skill/assets/source/ 构建 MCP 服务。如果 Bun 不可用,则会回退到已发布的 Smithery 安装路径 @delorenj/mcp-server-trello,并创建相同的本地 build/index.js 命令路径,供技能激活检查使用。
技能包结构
技能是此仓库面向 Agent 的入口。
skill/SKILL.md:激活、路由和 Agent 工作流规则。skill/scripts/install.sh:用于首次运行的捆绑服务安装程序。skill/references/trello-mcp/:关于设置、工具、工作流和注意事项的专题参考资料。skill/assets/source/:用于本地构建的捆绑 MCP 服务源代码。
对于 AI Agent,请从 skill/SKILL.md 开始,而不要从此 README 开始。README 是面向用户的概览;技能参考资料则是工具选择和 Trello 工作流规则的操作指南。
维护者可以在打包前刷新捆绑的源代码:
mise run package
配置
环境变量
可以使用环境变量配置服务。在根目录中创建 .env 文件,并设置以下变量:
# Required: Your Trello API credentials
TRELLO_API_KEY=your-api-key
TRELLO_TOKEN=your-token
# Optional (Deprecated): Default board ID (can be changed later using set_active_board)
TRELLO_BOARD_ID=your-board-id
# Optional: Initial workspace ID (can be changed later using set_active_workspace)
TRELLO_WORKSPACE_ID=your-workspace-id
# Optional: HTTPS proxy URL (for corporate proxies or restricted networks)
https_proxy=http://your-proxy:8080
# Optional: Restrict access to specific workspaces (comma-separated IDs)
# If set, only the listed workspaces will be accessible via MCP tools
TRELLO_ALLOWED_WORKSPACES=workspace-id-1,workspace-id-2
代理支持: 如果你位于企业代理之后,或所处环境会通过代理路由流量,请设置
https_proxy或HTTPS_PROXY环境变量。服务会自动通过指定的代理路由所有 Trello API 请求。
你可以通过以下方式获取这些值:
- API 密钥:https://trello.com/app-key
- Token:使用你的 API 密钥生成
- Board ID(可选,已弃用):可在看板 URL 中找到(例如,
https://trello.com/b/abc123/example-board) - Workspace ID:可在工作区设置中找到,或使用
list_workspaces工具获取
看板和工作区管理
从版本 0.3.0 开始,MCP 服务支持多种看板使用方式:
-
多看板支持:现在所有方法都接受可选的
boardId参数 - 省略TRELLO_BOARD_ID,并在每次 API 调用中提供boardId- 将TRELLO_BOARD_ID设为默认值,并可通过boardId参数进行覆盖 -
动态选择看板:使用工作区管理工具 -
.env文件中的TRELLO_BOARD_ID用作初始/默认看板 ID - 你可以随时使用set_active_board工具更改当前看板 - 所选看板会在服务重启后保留(存储在~/.trello-mcp/config.json中) - 同样,你也可以使用set_active_workspace设置并保留当前工作区
这样,你就可以在不重启服务的情况下使用多个看板和工作区。
工作区访问限制
你可以选择使用 TRELLO_ALLOWED_WORKSPACES 环境变量,将 MCP 访问限制为特定工作区。这适用于以下情况:
- 安全性:将 AI Agent 的访问权限限制为仅可访问已批准的工作区
- 多租户配置:确保 Agent 只能访问相关工作区
- 测试:将测试环境与生产数据隔离
设置 TRELLO_ALLOWED_WORKSPACES 后:
list_workspaces仅返回允许列表中的工作区list_boards仅返回允许工作区中的看板set_active_workspace会拒绝不在允许列表中的工作区list_boards_in_workspace会拒绝不允许的工作区 IDcreate_board会拒绝在不允许的工作区中创建看板
配置示例:
# Only allow access to two specific workspaces
TRELLO_ALLOWED_WORKSPACES=697c549ce04dc460af133a75,5f8a3b2c1d4e5f6a7b8c9d0e
如果未设置 TRELLO_ALLOWED_WORKSPACES 或其值为空,则 Token 可访问的所有工作区都可用(默认行为)。
示例工作流
- 首先列出可用看板:
{
name: 'list_boards',
arguments: {}
}
- 设置当前看板:
{
name: 'set_active_board',
arguments: {
boardId: "abc123" // ID from list_boards response
}
}
- 根据需要列出工作区:
{
name: 'list_workspaces',
arguments: {}
}
- 根据需要设置当前工作区:
{
name: 'set_active_workspace',
arguments: {
workspaceId: "xyz789" // ID from list_workspaces response
}
}
- 检查当前看板信息:
{
name: 'get_active_board_info',
arguments: {}
}
日期格式指南
使用 Trello MCP 服务处理日期时,请注意不同的格式要求:
- 截止日期(
dueDate):接受包含时间的完整 ISO 8601 格式(例如,2023-12-31T12:00:00Z) - 开始日期(
start):仅接受 YYYY-MM-DD 格式的日期(例如,2025-08-05)
这种区别遵循 Trello API 的约定:开始日期是按天标记的,而截止日期可以包含具体时间。
可用工具
清单管理工具 🆕
get_checklist_items
按名称获取清单中的所有项目。
{
name: 'get_checklist_items',
arguments: {
name: string, // Name of the checklist to retrieve items from
boardId?: string // Optional: ID of the board (uses default if not provided)
}
}
add_checklist_item
向现有清单添加新项目。
{
name: 'add_checklist_item',
arguments: {
text: string, // Text content of the checklist item
checkListName: string, // Name of the checklist to add the item to
boardId?: string // Optional: ID of the board (uses default if not provided)
}
}
find_checklist_items_by_description
搜索包含特定文本的清单项目。
{
name: 'find_checklist_items_by_description',
arguments: {
description: string, // Text to search for in checklist item descriptions
boardId?: string // Optional: ID of the board (uses default if not provided)
}
}
get_acceptance_criteria
获取卡片(或看板)的验收标准,并兼容团队实际使用的常见清单标题。清单名称与 Acceptance Criteria、AC、DoD 或 Definition of Done 相同(不区分大小写,并会去除首尾空格)时,即视为匹配。按上述顺序,使用第一个存在匹配项的别名。
{
name: 'get_acceptance_criteria',
arguments: {
cardId?: string, // Optional: ID of the card to scope the search to (recommended to avoid ambiguity)
boardId?: string // Optional: ID of the board (uses default if not provided)
}
}
匹配时,返回:
{
found: true,
items: CheckListItem[], // All items of the matching checklist(s), in Trello's order
unmet: CheckListItem[], // The incomplete subset of items
percentComplete: number, // Rounded percentage complete; 0 when there are no items
matchedChecklistName: string // The checklist name as written on the board, original casing
}
没有匹配项时,该工具会明确说明,而不是返回空列表——这样就不会把“此卡片没有验收标准”误认为“清单名称不同”:
{
found: false,
reason: string, // Human-readable explanation naming the aliases that were tried
availableChecklists: string[] // Names of the checklists that do exist in the searched scope
}
如果清单匹配但没有项目,则返回 found: true 和 items: [],这与上面的未找到响应不同。
get_checklist_by_name
按名称获取完整清单,包括所有项目和完成百分比。
{
name: 'get_checklist_by_name',
arguments: {
name: string, // Name of the checklist to retrieve
boardId?: string // Optional: ID of the board (uses default if not provided)
}
}
**返回:**包含以下内容的 CheckList 对象:
id:清单标识符name:清单名称items:CheckListItem对象数组percentComplete:完成百分比(0-100)
update_checklist_item
更新现有清单项目。
{
name: 'update_checklist_item',
arguments: {
cardId: string, // ID of the card containing the checklist item
checkItemId: string, // ID of the checklist item to update
name?: string, // Optional: new checklist item text
state?: 'complete' | 'incomplete', // Optional: new checklist item state
pos?: number | 'top' | 'bottom', // Optional: new checklist item position
due?: string | null, // Optional: ISO 8601 due date, or null to clear it
dueReminder?: number | null, // Optional: reminder offset in minutes, or null to clear it
idMember?: string | null // Optional: member ID to assign, or null to clear it
}
}
delete_checklist_item
删除现有清单项目。
{
name: 'delete_checklist_item',
arguments: {
cardId: string, // ID of the card containing the checklist item
checkItemId: string // ID of the checklist item to delete
}
}
get_card 🆕
获取特定 Trello 卡片的全面详情,达到与人工查看相同的完整程度。
{
name: 'get_card',
arguments: {
cardId: string, // ID of the Trello card (short ID like 'FdhbArbK' or full ID)
includeMarkdown?: boolean // Return formatted markdown instead of JSON (default: false)
}
}
**返回:**完整卡片数据,包括:
- ✅ 清单及其项目状态和分配情况
- 📎 附件及其预览和元数据
- 🏷️ 标签及其名称和颜色
- 👥 已分配的成员
- 💬 评论和活动
- 📊 统计信息(徽章)
- 🎨 封面图片
- 📍 看板和列表上下文
get_cards_by_list_id
获取指定列表中的所有卡片。
{
name: 'get_cards_by_list_id',
arguments: {
boardId?: string, // Optional: ID of the board (uses default if not provided)
listId: string // ID of the Trello list
}
}
get_lists
获取看板中的所有列表。
{
name: 'get_lists',
arguments: {
boardId?: string // Optional: ID of the board (uses default if not provided)
}
}
get_recent_activity
获取看板上的近期活动。
{
name: 'get_recent_activity',
arguments: {
boardId?: string, // Optional: ID of the board (uses default if not provided)
limit?: number // Optional: Number of activities to fetch (default: 10)
}
}
add_card_to_list
向指定列表添加新卡片。
{
name: 'add_card_to_list',
arguments: {
boardId?: string, // Optional: ID of the board (uses default if not provided)
listId: string, // ID of the list to add the card to
name: string, // Name of the card
description?: string, // Optional: Description of the card
mbs; dueDate?: string, // Optional: Due date (ISO 8601 format with time)
start?: string, // Optional: Start date (YYYY-MM-DD format, date only)
labels?: string[] // Optional: Array of label IDs
}
}
update_card_details
更新现有卡片的详情。
{
name: 'update_card_details',
arguments: {
boardId?: string, // Optional: ID of the board (uses default if not provided)
cardId: string, // ID of the card to update
name?: string, // Optional: New name for the card
description?: string, // Optional: New description
dueDate?: string, // Optional: New due date (ISO 8601 format with time)
start?: string, // Optional: New start date (YYYY-MM-DD format, date only)
dueComplete?: boolean,// Optional: Mark the due date as complete (true) or incomplete (false)
labels?: string[] // Optional: New array of label IDs
}
}
archive_card
将卡片移至归档。
{
name: 'archive_card',
arguments: {
boardId?: string, // Optional: ID of the board (uses default if not provided)
cardId: string // ID of the card to archive
}
}
add_list_to_board
向看板添加新列表。
{
name: 'add_list_to_board',
arguments: {
boardId?: string, // Optional: ID of the board (uses default if not provided)
name: string // Name of the new list
}
}
archive_list
将列表移至归档。
{
name: 'archive_list',
arguments: {
boardId?: string, // Optional: ID of the board (uses default if not provided)
listId: string // ID of the list to archive
}
}
update_list
更新列表名称、归档状态、订阅状态或所属看板。要调整看板内列表的顺序,请使用 update_list_position。
{
name: 'update_list',
arguments: {
listId: string, // ID of the list to update
name?: string, // Optional: New name for the list
closed?: boolean, // Optional: Whether to close (archive) the list
subscribed?: boolean, // Optional: Whether to subscribe to the list
idBoard?: string // Optional: ID of a board to move the list to
}
}
update_list_position
更新列表在看板上的位置。Trello 使用分数索引:每个列表都有一个浮点数位置;要将列表放在另外两个列表之间,请使用它们位置的平均值(例如,放在位置 1024 和 2048 之间时,使用 1536)。使用 "top"/"bottom" 快捷值可将列表移至边缘。
{
name: 'update_list_position',
arguments: {
listId: string, // ID of the list to reposition
position: string // "top", "bottom", or a positive numeric string (e.g. "1536")
}
}
get_my_cards
获取分配给当前用户的所有卡片。
{
name: 'get_my_cards',
arguments: {}
}
move_card
将卡片移至其他列表。
{
name: 'move_card',
arguments: {
boardId?: string, // Optional: ID of the target board (uses default if not provided)
s; cardId: string, // ID of the card to move
listId: string // ID of the target list
}
}
attach_image_to_card
直接通过 URL 将图片附加到卡片。
{
name: 'attach_image_to_card',
arguments: {
boardId?: string, // Optional: ID of the board (uses default if not provided)
cardId: string, // ID of the card to attach the image to
imageUrl: string, // URL of the image to attach
name?: string // Optional: Name for the attachment (defaults to "Image Attachment")
}
}
attach_file_to_card
通过 URL 或本地文件路径(例如,file:///path/to/your/file.pdf)将任意类型的文件附加到卡片。
{
name: 'attach_file_to_card',
arguments: {
boardId?: string, // Optional: ID of the board (uses default if not provided)
cardId: string,s; // ID of the card to attach the file to
fileUrl: string, // URL or local file path (using the file:// protocol) of the file to attach
name?: string, // Optional: Name for the attachment (defaults to the file name for local files)
mimeType?: string // Optional: MIME type (e.g., "application/pdf", "text/plain", "video/mp4")
}
}
download_attachment
按 ID 下载卡片上的附件。附件 ID 可在 get_card 返回的 attachments 数组中找到。
{
name: 'download_attachment',
arguments: {
cardId: string, // ID of the card containing the attachment
attachmentId: string // ID of the attachment to download
}
}
**返回:**对于图片附件(image/*),返回可内嵌查看的图片数据。对于所有其他文件类型,返回包含以下内容的 JSON 对象:
fileName:原始文件名mimeType:文件的 MIME 类型data:以 Base64 编码的文件内容
评论管理工具
add_comment
向 Trello 卡片添加评论。
{
name: 'add_comment',
arguments: {
cardId: string, // ID of the card to comment on
text: string // The text of the comment to add
}
}
update_comment
更新卡片上的现有评论。
{
name: 'update_comment',
arguments: {
commentId: string, // ID of the comment to change
text: string // The new text of the comment
}
}
delete_comment
删除卡片上的评论。
{
name: 'delete_comment',
arguments: {
commentId: string // ID of the comment to delete
}
}
get_card_comments
获取指定卡片的所有评论,无需获取卡片的全部数据。
{
name: 'get_card_comments',
arguments: {
cardId: string, // ID of the card to get comments from
limit?: number // Optional: Maximum number of comments to retrieve (default: 100)
}
}
list_boards
列出用户有权访问的所有看板。
{
name: 'list_boards',
arguments: {}
}
set_active_board
设置后续操作使用的活动看板。
{
name: 'set_active_board',
arguments: {
boardId: string // ID of the board to set as active
}
}
list_workspaces
列出用户有权访问的所有工作区。
{
s; name: 'list_workspaces',
arguments: {}
}
set_active_workspace
设置后续操作使用的活动工作区。
{
name: 'set_active_workspace',
arguments: {
workspaceId: string // ID of the workspace to set as active
}
}
list_boards_in_workspace
列出指定工作区中的所有看板。
{
name: 'list_boards_in_workspace',
arguments: {
workspaceId: string // ID of the workspace to list boards from
}
}
get_active_board_info
获取当前活动看板的信息。
{
s; name: 'get_active_board_info',
arguments: {}
}
自定义字段管理工具
**注意:**自定义字段需要 Trello Standard 套餐或更高版本。
get_board_custom_fields
获取看板上的所有自定义字段定义。对于下拉列表字段,还会返回可用选项及其 ID。
{
name: 'get_board_custom_fields',
arguments: {
boardId?: string // Optional: ID of the board (uses default if not provided)
}
}
**返回:**自定义字段定义数组,包括:
- 字段 ID、名称和类型(
text、number、checkbox、date、list) - 对于
list类型字段:可用选项及其 ID(设置值时请使用这些 ID)
update_card_custom_field
设置或清除卡片上的自定义字段值。
{
name: 'update_card_custom_field',
arguments: {
cardId: string, // ID of the card to update
customFieldId: string,// ID of the custom field definition
type: string, // Field type: 'text' | 'number' | 'checkbox' | 'date' | 'list' | 'clear'
value?: string // The value to set (not needed when type is 'clear')
}
}
各类型的值格式:
text:任意字符串number:数字字符串(例如,"42.5")checkbox:"true"或"false"date:ISO 8601 字符串(例如,"2025-12-31T00:00:00.000Z")list:来自get_board_custom_fields的选项 IDclear:省略值即可移除字段值
集成示例
🎨 与 Ideogram MCP 服务配合使用
Trello MCP 服务与 @flowluap/ideogram-mcp-server 配合得非常出色,可用于 AI 驱动的视觉内容创作。使用 Ideogram 生成图片,并将其直接附加到 Trello 卡片!
工作流示例
- 使用 Ideogram 生成图片:
// Using ideogram-mcp-server
{
name: 'generate_image',
arguments: {
prompt: "A futuristic dashboard design with neon accents",
aspect_ratio: "16:9"
}
}
// Returns: { image_url: "https://..." }
- 将生成的图片附加到 Trello 卡片:
// Using trello-mcp-server
{
name: 'attach_image_to_card',
arguments: {
cardId: "your-card-id",
imageUrl: "https://...", // URL from Ideogram
name: "Dashboard Mockup v1"
}
}
设置两个服务
将两个服务都添加到 Claude Desktop 配置中。使用 bunx 可实现最快启动。
{
"mcpServers": {
"trello": {
"command": "bunx",
"args": ["@delorenj/mcp-server-trello"],
"env": {
"TRELLO_API_KEY": "your-trello-api-key",
"TRELLO_TOKEN": "your-trello-token"
}
},
"ideogram": {
"command": "bunx",
"args": ["@flowluap/ideogram-mcp-server"],
"env": {
"IDEOGRAM_API_KEY": "your-ideogram-api-key"
}
}
}
}
现在,你可以在 Claude 中无缝创建视觉内容并在 Trello 中进行整理!
速率限制
该服务使用令牌桶算法实施速率限制,以符合 Trello API 的限制:
- 每个 API 密钥每 10 秒 300 个请求
- 每个令牌每 10 秒 100 个请求
速率限制会自动处理,达到限制时,请求将进入队列。
错误处理
该服务针对各种情况提供详细的错误消息:
- 输入参数无效
- 超出速率限制
- API 身份验证错误
- 网络问题
- 看板/列表/卡片 ID 无效
开发
前置条件
- Bun(v1.0.0 或更高版本)
设置
- 克隆仓库
git clone https://github.com/delorenj/mcp-server-trello
cd mcp-server-trello
- 安装依赖项
bun install
- 构建项目
bun run build
运行测试
运行以下命令即可运行测试:
bun test
运行评测
评测包会加载 MCP 客户端,然后运行 index.ts 文件,因此测试之间无需重新构建。可以在 bunx 命令前添加环境变量来加载它们。完整文档请参阅此处。
OPENAI_API_KEY=your-key bunx mcp-eval src/evals/evals.ts src/index.ts
贡献
欢迎贡献!
许可证
本项目采用 MIT 许可证,详情请参阅 LICENSE 文件。
致谢
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。