mcp-guide.md 27 KB

MCP 接入指南

写给:要把自己系统的能力做成 MCP 服务、接入 AgentServer 的开发者。 依据:MCP 规范 2025-11-25;平台的实现见 design/16-mcp-support.md。 示例代码:examples/mcp-reference-server/server.mjs(虚构的订单系统,覆盖本指南的全部写法)。 最后更新:2026-10-29

本指南不另立标准,只回答两个问题:MCP 规范里的可选项,在 AgentServer 上哪些有效、怎么用;工具怎么设计,模型才好用。


1. 先读这一页

五条原则

  1. 工具是写给模型用的。 名称、说明、参数、错误信息的读者都是模型,要让它不看文档也知道什么时候用、怎么填、出错了下一步做什么。
  2. 一个工具做一件事。 宁可多几个小工具,也不要一个工具带十几个可选参数和模式开关。
  3. 长时间的事交给平台等。 超过 3 分钟的操作用长任务(§5),不要让模型轮询。
  4. 如实声明工具提示。 只读、破坏性、幂等这几个提示决定平台是否审批、能否自动重试(§3.3)。
  5. 返回少而准的结果。 大结果分页、给摘要,文件以资源形式返回,不要把几万字塞进模型的上下文(§3.5、§4.3)。

平台支持情况速查

MCP 能力 平台的处理 章节
工具(tools) ✅ 转接给 Claude 与 Codex,工具名为 服务名__工具名 §3
工具提示(annotations) ✅ 决定默认的审批策略和自动重试,管理员可以覆盖 §3.3
结构化输出(outputSchema / structuredContent) ✅ 按 schema 校验;结构说明附在工具说明后告诉模型 §4.2
进度通知(progress) ✅ 收到进度时延长等待时间 §5.1
长任务(Tasks,实验性) ✅ 平台按任务 id 查询,完成后唤醒会话;服务重启后继续 §5
询问用户(Elicitation,表单 / 网址) ✅ 变成会话里的卡片 §6
工具列表变化(listChanged) ✅ 自动刷新 §7
资源(Resources)、资源模板 ✅ 模型按需读取;用户可以附加到消息 §8.1
提示模板(Prompts) ✅ 用户在输入框"快捷指令"中使用 §8.3
认证:请求头令牌、OAuth 2.1 ✅ 令牌由服务端保存;OAuth 按服务共享一个账号 §9
Sampling(服务借用平台的模型) ❌ 不支持 §10
资源订阅、Roots、补全(completion)、日志(logging) ❌ 暂不支持,声明了也不会使用 §10

2. 接入方式

2.1 传输

方式 适合 说明
Streamable HTTP(推荐) 独立部署的服务 平台按"服务 × 会话"建立连接;旧版 SSE 服务自动兼容
本地进程(stdio) 命令行工具、只在本机使用 在沙箱中运行:系统目录只读、独立的 home、默认不能联网、只能访问管理员开放的路径;密钥只通过环境变量传入。所有会话共用一个进程

需要询问用户(§6)的服务请用 HTTP:本地进程被多个会话同时使用时,平台无法确定询问属于哪个会话,会拒绝询问。

2.2 登记

管理员在后台"MCP 服务"页面添加服务、测试连接,再到 Profile 中勾选;勾选了这个服务的 Profile,对话中才会出现它的工具。

  • 服务名(工具名前缀):小写字母、数字、_、-,最多 32 位。模型看到的工具名是 服务名__工具名,整体最多 64 个字符,超出部分被截掉。所以工具名要短:get_order 好于 get_order_detail_by_order_number。
  • 服务的 instructions(初始化时返回的服务说明)目前不会转给模型,要让模型知道的内容写在各个工具的说明里。

2.3 SDK

推荐用官方 SDK:TypeScript @modelcontextprotocol/sdk(1.32 及以上,参考服务使用 1.32.1)、Python mcp。长任务和询问用户需要支持 2025-11-25 规范的版本。


3. 工具设计

3.1 粒度与命名

  • 按用户要完成的事划分工具,而不是照搬后端接口:cancel_order 好于 update_order(status='cancelled')。
  • 动词开头、snake_case:get_、list_、search_、create_、update_、delete_、export_。
  • 读和写分成不同的工具。只读工具可以免审批、在只读模式下使用;混在一起,整个工具都要按写操作对待。
  • 一个服务的工具控制在 20 个以内。工具越多,模型选错的概率越高,每一轮也要多花 token 列出它们。
  • 设置 title(显示名),后台和审批卡片会显示它。

3.2 说明与参数

工具说明(description)回答三件事:做什么、什么时候用、有什么限制。

按订单号查询订单的客户、金额、状态和商品。订单号形如 A1001。
不知道订单号时,先用 list_orders 按状态查找。
  • 前 2000 字以内说清楚(平台截断到 2000 字)。
  • 不要写"你必须……"、"忽略其他工具"之类的指令。这是工具投毒的常见手法,平台审计时会被当作风险。
  • 参数用 JSON Schema 写全:每个参数都有 description;能枚举的用 enum;格式用 pattern / format;给出 default。
  • 必填参数尽量少,3 到 5 个为宜。可选参数太多时拆成两个工具。
  • 不要让模型传大段内容。要处理文件时,参数里放文件地址或 id。

3.3 工具提示(annotations)

提示 含义 平台的用法 不写时
readOnlyHint: true 不修改任何东西 默认直接调用;只读模式下只提供这类工具 按非只读处理
destructiveHint: true 删除、覆盖、不可恢复 默认总是审批:自动模式下也要用户确认,而且每次都问 平台不据此强制审批(规范的默认值是 true,平台只认明确写出的 true)
idempotentHint: true 同样的参数重复调用,结果相同 遇到网络错误时自动重新连接并重试一次 不重试,避免重复执行
openWorldHint: false 只操作本系统,不与外部交互 后台和审计中不标"外部交互" 视为与外部交互
  • 提示必须准确。写错的后果:只读工具写成非只读,用户被多问;破坏性工具漏写,自动模式下不经确认就执行;非幂等工具写成幂等,网络抖动时可能重复下单。
  • 管理员可以在后台逐个工具覆盖这三个提示,但不要依赖管理员替你纠正。

3.4 错误

  • 业务错误用工具结果返回:isError: true,加一段写给模型的说明,讲清原因和下一步怎么做。

    { "isError": true, "content": [{ "type": "text", "text": "订单 A9999 不存在。可以先用 list_orders 查看现有订单号。" }] }
    
  • 协议错误(参数不符合 schema、工具不存在)用 JSON-RPC 错误返回,SDK 会处理。

  • 不要把堆栈、SQL、内部地址放进错误信息:模型会原样转述给用户。

  • 权限不足、令牌失效时说明清楚("令牌没有导出权限"),平台和用户才知道该找谁。

3.5 分页与结果大小

  • 列表类工具要分页:接收 cursor,返回 nextCursor,每页 20 到 50 条。
  • 默认只返回关键字段,详情另用一个工具查。
  • 平台的处理:文本超过 10 万字时只给模型前一部分,完整内容存成工作区文件;图片、音频超过 5 MB 时存成文件。但长结果本身就会消耗模型的上下文,最好在服务端控制在几千字以内。
  • 需要大量数据时,生成文件并以资源返回(§4.3),让模型去读文件、做检索。

3.6 幂等与重复提交

  • 会产生副作用的操作,尽量支持调用方传入去重键(例如 requestId),或者在服务端按业务键去重。
  • 提交类操作(创建作业、下单)做成幂等的:同样的任务已经在执行时,返回已有的结果或作业 id,不要再执行一次。这样就不需要模型先查一次状态再决定要不要提交。

4. 返回结果

4.1 文本

给模型读的结论放在最前面,例如"共 3 条,其中 1 条已逾期"。表格用 Markdown 或 CSV,不要用 HTML。

4.2 结构化输出

需要模型(或平台)准确使用字段时,声明 outputSchema 并返回 structuredContent,同时把同样的 JSON 序列化成一段文本放进 content(兼容只读文本的客户端):

server.registerTool('get_order', {
  description: '按订单号查询订单……',
  inputSchema: { orderId: z.string() },
  outputSchema: { id: z.string(), customer: z.string(), amount: z.number(), status: z.enum(['paid', 'shipped', 'cancelled']) },
  annotations: { readOnlyHint: true },
}, async ({ orderId }) => {
  const o = await db.getOrder(orderId)
  return { content: [{ type: 'text', text: JSON.stringify(o) }], structuredContent: o }
})

平台的处理:

  • 文本里已经有同样的 JSON 时不重复;没有时把 JSON 附在文本后面交给模型。
  • 按 outputSchema 校验 structuredContent。不符合时结果照常交给模型,审计中记录校验错误,管理员能看到。
  • 在工具说明后附上返回结构的简述(最多 1500 字),模型调用前就知道会得到什么。所以 schema 要精简,字段加 description。

4.3 文件

报表、导出、图片等文件,以嵌入资源返回:

return { content: [
  { type: 'text', text: '10 月销售报表已生成:共 1024 行' },
  { type: 'resource', resource: { uri: 'ref://reports/sales-2026-10.csv', mimeType: 'text/csv', text: csv } }, // 二进制用 blob(base64)
] }
  • 平台把嵌入资源一律保存到会话工作区的 .agent/mcp/。文件名取 URI 的最后一段,所以 URI 要以有意义的文件名结尾。
  • 模型只看到文件路径、大小和类型,看不到内容。需要时它会自己去读或分析这个文件,用户也可以下载。
  • 同时给一句文字摘要(行数、时间范围),模型不用读文件就能回答简单的问题。

5. 长任务

5.1 什么时候用

执行时间 做法
几秒到 3 分钟 普通工具。超过 30 秒的,建议发进度通知(notifications/progress),平台会延长等待时间
3 分钟以上,或者不确定 长任务(Tasks)

不支持 Tasks 的工具运行超过 3 分钟时,平台也会转到后台,保持连接等待(最长 24 小时)。但服务重启、网络断开都会让这次调用失败,所以超过几分钟的操作请用 Tasks。

不要再做"提交 + 查询"两个工具让模型轮询。 模型没有时钟,只能连续查询(浪费 token),或者这一轮结束后就没人再查了。查询进度的工具可以保留,供用户问"进度怎么样"时使用。

5.2 实现

const server = new McpServer({ name: 'orders', version: '1.0.0' }, {
  capabilities: { tasks: { requests: { tools: { call: {} } }, cancel: {} } },
  taskStore,                                   // 见 §5.3
  taskMessageQueue: new InMemoryTaskMessageQueue(),
})

server.experimental.tasks.registerToolTask('export_report', {
  description: '导出指定月份的销售报表。很慢,以长任务方式执行,完成后平台会把结果发给你。',
  inputSchema: { month: z.string().regex(/^\d{4}-\d{2}$/) },
  execution: { taskSupport: 'optional' },      // required:只能以任务方式调用
  annotations: { readOnlyHint: true },
}, {
  async createTask({ month }, { taskStore, taskRequestedTtl }) {
    const task = await taskStore.createTask({ ttl: taskRequestedTtl, pollInterval: 30_000 })
    startExport(month, {                        // 在后台执行,不要等它完成
      progress: pct => taskStore.updateTaskStatus(task.taskId, 'working', `已完成 ${pct}%`),
      done: result => taskStore.storeTaskResult(task.taskId, 'completed', result),
      fail: err => taskStore.storeTaskResult(task.taskId, 'failed', { isError: true, content: [{ type: 'text', text: err.message }] }),
    })
    return { task, _meta: { 'io.modelcontextprotocol/model-immediate-response': `${month} 报表已开始导出,预计 20 分钟` } }
  },
  getTask: async (_args, { taskId, taskStore }) => taskStore.getTask(taskId),
  getTaskResult: async (_args, { taskId, taskStore }) => taskStore.getTaskResult(taskId),
})

平台的处理:

  1. 以任务方式调用(任务保留时间 ttl 为 24 小时),先在前台查询最多 3 分钟。期间完成的,结果直接交给模型,和普通工具一样。
  2. 超过时间后转为后台:模型收到"已转为后台执行"和 model-immediate-response 中的说明,结束这一轮,告诉用户已提交。
  3. 平台按 pollInterval 查询状态(最短 5 秒,最长 5 分钟,不提供时为 30 秒),statusMessage 显示在后台调用栏和后台页面。
  4. 到达终态后取回结果,作为一条新消息发到会话(或工作组中发起调用的机器人),唤醒模型继续处理。结果的处理与普通工具相同(§4)。
  5. 用户或管理员取消时,平台调用 tasks/cancel。请实现取消,停止后台的执行。

createTask 要立即返回(几秒以内),实际工作在后台进行。

5.3 任务归属与保留

  • 按认证身份(令牌或 OAuth 账号)归属任务,不要绑定在 MCP 会话上。 平台重连或重启后,用新的 MCP 会话查询原来的任务;绑定在会话上的任务会查不到,平台只能按失败通知用户。SDK 自带的 InMemoryTaskStore 默认按会话绑定,参考服务给出了改为共享的写法(SharedTaskStore)。
  • 任务状态要持久化(数据库或 Redis),否则服务重启后任务就丢了。内存存储只适合示例。
  • 至少保留到 ttl 到期,不要早于平台的最长等待时间(24 小时)。
  • 任务 id 要随机、不可猜测;按身份隔离,A 的令牌查不到 B 的任务。

5.4 任务失败

  • 业务失败:storeTaskResult(taskId, 'failed', { isError: true, content: [...] }),说明写给模型看。
  • 平台查询连续失败超过 30 分钟,或者服务返回任务不存在时,按失败处理。

6. 询问用户(Elicitation)

6.1 什么时候用

工具执行到一半,缺少信息或需要确认时,可以向用户提问,不必直接报错再让模型来回追问:

  • 有歧义:"有两个叫张三的客户,选哪一个?"
  • 需要补充:"请填写收件地址"
  • 需要授权、付款等在别的页面完成的事:网址模式

不要把每个写操作都做成询问确认:审批由平台负责(§3.3 的工具提示)。

6.2 两种模式

表单模式:

const r = await server.server.elicitInput({
  mode: 'form',
  message: '请填写订单 A1001 的收件信息',
  requestedSchema: {
    type: 'object',
    properties: {
      name: { type: 'string', title: '收件人', minLength: 1 },
      speed: { type: 'string', title: '配送方式', oneOf: [{ const: 'standard', title: '普通' }, { const: 'express', title: '加急' }], default: 'standard' },
      insured: { type: 'boolean', title: '保价', default: false },
    },
    required: ['name'],
  },
})
if (r.action === 'accept') { /* r.content.name … */ }
else if (r.action === 'decline') { /* 用户拒绝 */ }
else { /* cancel:用户暂不处理或超时 */ }

平台支持的字段(规范限定为一层对象):

类型 写法 卡片
文本 type: 'string',可加 minLength、maxLength、format(email / uri / date / date-time) 输入框
数字 type: 'number' 或 'integer',可加 minimum、maximum 数字输入框
是否 type: 'boolean' 勾选框
单选 type: 'string' + enum(可加 enumNames)或 oneOf: [{ const, title }] 下拉框
多选 type: 'array' + items.enum 或 items.anyOf: [{ const, title }],可加 minItems、maxItems 多选按钮

每个字段都写 title,可以加 description 和 default。不支持嵌套对象。平台在用户提交时按这些约束校验一次,服务端仍要自己校验。

网址模式:

const r = await server.server.elicitInput({ mode: 'url', message: '请登录 CRM 并授权', url: 'https://crm.example.com/oauth/authorize?…', elicitationId: crypto.randomUUID() })

平台显示完整网址和域名,用户自己点开,完成后点"我已完成"(accept)。平台不会自动打开网址。

6.3 注意

  • 不要用表单索要密码、密钥、验证码(规范禁止)。需要授权的,用网址模式让用户在你的页面完成。
  • 三种结果都要处理。用户 10 分钟(后台可调)没有处理时,结果为 cancel。
  • 定时任务等无人值守的场景,询问会等到超时。需要无人值守执行的工具,要提供不询问的默认行为(例如参数中提供足够的信息时就不询问)。
  • 长任务中询问:先把任务状态设为 input_required,再发出询问,并带上 relatedTask(参考服务的 purge_cancelled)。平台会显示卡片,用户回答后任务继续。

7. 工具列表变化

工具会随配置或权限变化时,声明 capabilities.tools.listChanged: true(官方 SDK 在注册工具时自动声明并发送通知)。工具增减后发送 notifications/tools/list_changed,平台会重新获取工具列表:

  • Claude 在下一轮看到新的工具列表;Codex 的会话在下一轮切换到新的工具列表。
  • 正在进行的这一轮看不到新增的工具。工具删除后再被调用,会返回"工具不存在"。

工具列表最好保持稳定。频繁变化会让模型的行为不稳定,Codex 的会话也会频繁切换。


8. 资源与提示模板

8.1 资源(Resources)

适合做成资源的:参考资料,例如产品手册、接口说明、数据字典、表结构、配置、运行状态。它们由模型按需读取,或者由用户附加到对话,而不是"去做一件事"。

server.registerResource('order-api', 'ref://docs/order-api.md',
  { title: '订单系统接口说明', description: '订单状态的含义、退款规则', mimeType: 'text/markdown' },
  async uri => ({ contents: [{ uri: uri.href, mimeType: 'text/markdown', text: markdown }] }))

// 资源模板:按参数读取
server.registerResource('order', new ResourceTemplate('ref://orders/{orderId}', { list: listOrders }),
  { title: '订单详情', mimeType: 'application/json' },
  async (uri, { orderId }) => ({ contents: [{ uri: uri.href, mimeType: 'application/json', text: JSON.stringify(await getOrder(orderId)) }] }))

平台怎么用:

方式 说明 token 消耗
模型按需读取 网关提供 mcp_resources(列出目录)和 mcp_resource_read(读取)两个只读工具 列目录时只有标题和说明;只有读取时才消耗内容的篇幅
用户附加 输入框的"资料"按钮:选中的资源保存为会话文件,作为附件发出 这一轮附件的篇幅

写法建议:

  • title、description 写清楚内容和用途:模型和用户都是只看目录来挑选的。
  • 提供 mimeType 和 size。文本超过 2 万字时,平台只给模型开头,完整内容存成文件。所以大文档按章节拆成多个资源。
  • URI 用稳定的、可读的路径,以有意义的文件名结尾(用户附加时会保存成这个文件名)。
  • 规范中没有搜索资源的方法。 资料多(几十篇以上)的服务,另外提供一个 search_docs 工具,返回匹配的资源 URI 和片段。
  • 资源模板的参数尽量是简单值(id、日期),并在 description 中说明取值。

8.2 资源与工具怎么选

内容 做成
不需要参数、偶尔变化的参考资料 资源
按 id 读取一条记录 资源模板,或只读工具(两者都可以;需要筛选、分页时用工具)
查询、搜索、统计 只读工具
有副作用的操作 工具

8.3 提示模板(Prompts)

适合固定的工作流程,例如"订单复盘"、"生成周报"。用户在输入框的"快捷指令"中选择、填写参数后,展开的内容放进输入框,用户可以修改后发送。

server.registerPrompt('order_review', {
  title: '订单复盘', description: '针对一个订单写复盘:时间线、问题、改进建议',
  argsSchema: { orderId: z.string().describe('订单号'), focus: z.string().optional().describe('关注点') },
}, async ({ orderId, focus }) => ({
  messages: [
    { role: 'user', content: { type: 'text', text: `请对订单 ${orderId} 做一次复盘……` } },
    { role: 'user', content: { type: 'resource', resource: { uri: `ref://orders/${orderId}`, mimeType: 'application/json', text: json } } },
  ],
}))
  • 参数都写 description,它会显示为输入框的提示。参数值都是字符串。
  • 文本部分合并后放进输入框;嵌入的资源、图片保存为附件,一起发送。
  • 不需要附带资料时,只返回文本消息即可。

9. 认证与安全

9.1 请求头令牌

最简单的方式:管理员在后台为服务填写请求头(如 Authorization: Bearer …)。令牌只保存在服务端,后台和接口不会回显。

9.2 OAuth 2.1

需要登录授权的服务,按 MCP 的授权规范实现,平台作为 OAuth 客户端:

  1. MCP 端点在未授权时返回 401,带 WWW-Authenticate: Bearer resource_metadata="…/.well-known/oauth-protected-resource…"。
  2. 提供受保护资源元数据(/.well-known/oauth-protected-resource),其中的 authorization_servers 指向授权服务器。
  3. 授权服务器提供元数据(/.well-known/oauth-authorization-server),必须支持 PKCE(S256),并在 code_challenge_methods_supported 中声明。
  4. 客户端注册,两种方式任选:
    • 支持动态注册(registration_endpoint),平台会自动注册;
    • 或者预先为平台登记一个客户端,回调地址为 https://<平台地址>/admin/v1/mcp/oauth/callback,把 Client ID / Secret 交给管理员填写。
  5. 签发刷新令牌:平台在访问令牌过期后自动续期。没有刷新令牌时,令牌一过期,管理员就要重新授权。
  6. 支持 resource 参数(RFC 8707),令牌只对这个 MCP 服务有效。

平台的授权按服务共享:管理员授权一次,所有使用这个服务的会话都用这个账号。所以请为平台单独建一个权限合适的账号(最小权限),不要用个人管理员账号授权。

9.3 安全要求

  • 每个请求都校验令牌,包括 tasks/get、tasks/result、资源读取。
  • 只信任令牌,不信任参数里的身份字段。
  • 参数一律在服务端校验,不要依赖模型"会填对"。
  • 工具说明、资源内容、返回结果都会进入模型的上下文:不要在其中放入指令性的文字,也不要回显用户可控的内容而不加标注(提示词注入)。
  • 本地进程服务在沙箱中运行,默认不能联网、只能写自己的 home 目录。需要联网或访问额外目录时,在登记时说明,由管理员开放。

10. 不支持或不建议

能力 原因
Sampling(服务请平台调用模型) 花平台的 token,外部服务可以借此驱动模型。需要模型能力的服务,请自己接入模型
资源订阅(resources/subscribe) 暂不支持。资源变化后,下次读取时就是新的内容
Roots 平台不向服务暴露本地文件系统,文件通过资源或参数传递
补全(completion/complete) 暂不支持。参数的取值写在说明或 enum 中
服务端日志(notifications/message) 不会显示给用户。排查问题请看服务自己的日志
服务的 instructions 不转给模型,内容写进工具说明

11. 上线前自查

工具

  • 工具名短(服务名__工具名 不超过 64 个字符),动词开头,一个工具一件事
  • 说明写清做什么、什么时候用、限制;没有指令性文字
  • 参数都有说明;能枚举的用 enum;必填参数少
  • 只读 / 破坏性 / 幂等提示准确
  • 错误用 isError 返回,说明原因和下一步
  • 列表分页,结果控制在几千字以内

结果

  • 需要准确字段的工具有 outputSchema 和 structuredContent,并同时返回 JSON 文本
  • 文件以嵌入资源返回,URI 以文件名结尾,并附一句摘要

长任务与询问

  • 超过 3 分钟的操作用 Tasks;createTask 立即返回;提供 pollInterval 和进度说明;实现了取消
  • 任务按认证身份归属、持久化保存、至少保留 24 小时
  • 询问处理了 accept / decline / cancel 三种结果;不索要密码和密钥
  • 无人值守时工具有不询问的执行方式

资源、提示模板与安全

  • 资源有清楚的标题、说明、mimeType;大文档已拆分;资料多时提供搜索工具
  • 提示模板的参数都有说明
  • 每个请求都校验令牌;OAuth 支持 PKCE(S256)和刷新令牌;平台使用最小权限的账号

12. 参考服务与验证

参考服务 examples/mcp-reference-server 用一个虚构的订单系统演示了本指南的写法:

工具 / 资源 演示内容
get_order、list_orders 只读、结构化输出、分页、写给模型的错误信息
add_note、cancel_order 不幂等的写操作;破坏性 + 幂等(自动模式下也要确认)
ship_order、connect_crm 表单询问;网址询问
export_report 长任务:进度、即时说明、结果中返回 CSV 文件
purge_cancelled 长任务中询问用户确认
enable_beta 工具列表变化
ref://docs/order-api.md、ref://orders/{orderId} 资源、资源模板
order_review 提示模板(附带订单资源)
cd examples/mcp-reference-server
pnpm install            # 或 npm install
PORT=8790 REF_TOKEN=换成随机字符串 node server.mjs

在后台"MCP 服务"中添加:远程 HTTP,地址 http://<主机>:8790/mcp,请求头 Authorization: Bearer <REF_TOKEN>。点"刷新工具"后,工具列表中应当显示只读、破坏性、幂等、结构化输出、长任务等标记,服务旁显示"资源"、"提示模板"。在 Profile 中勾选这个服务,到 Playground 中试一试:

  • "查一下订单 A1001":直接返回,不审批
  • "取消订单 A1002":弹出审批,且没有"本会话不再询问"的选项
  • "给 A1001 安排发货":弹出收件信息表单
  • "导出 2026-10 的销售报表,执行 300 秒":转为后台,5 分钟后结果作为新消息出现,附带 CSV 文件
  • 输入框的"资料"中附加"订单系统接口说明","快捷指令"中使用"订单复盘"

自己的服务可以按同样的步骤验证。平台的自动化测试 apps/server/test/mcp-reference.test.ts 会启动参考服务并逐项检查,保证本指南、示例与平台的实际行为一致。