三条通道
让 Agent 调用 Mini App:托管 MCP
每个 MCP 服务器只能选一种生命周期:- 普通插件 MCP:独立运行(比如 stdio),不依赖 Mini App 的 Node 服务。不要把它写进
mcpEndpoints。 - Mini App 托管 MCP:由 Mini App 的 Node 服务实现,只在服务运行时可用。适合和页面共享同一份业务状态。
*.mcp.json 里声明一个 Streamable HTTP 服务器,url 用这个固定的占位地址,发布后由宿主改写:servers.mcp.json
miniapp.json 里把它挂到 Node 服务的路径上,并在 plugin.json 的 mcpServers 里引用 servers.mcp.json:miniapp/miniapp.json
- Node 入口要在
start返回之前,在context.listen的这个路径上实现 Streamable HTTP MCP。宿主只改写这个服务器的地址,工具发现、排序、调用和错误仍由插件 MCP 运行时负责。 - 用户发送一条引用了该 Mini App 的消息时,宿主会在请求模型之前启动服务、连好 MCP、确认工具可用。必需的托管 MCP 不可用时,这次请求直接失败,不会让模型缺着工具继续。
tools/list要轻:只返回工具定义,不在这里导入数据、扫描文档或调用远程服务。业务初始化放到真正需要它的工具调用里。- MCP 处理器坏了不会影响页面,但在修好并重新发布之前,Agent 用不了这些工具。
交给输入框
适合”整理好上下文,由用户决定要不要发”的场景,用法见 message.append。如果要让 Agent 修改表格、卡片等业务对象,给它提供 MCP 工具,并在请求和工具里用稳定的业务 ID。输入框里的文字用户可以改、可以删,不能当作请求和回合之间的关联 ID。Agent API
Mini App 可以从页面(window.mcode.miniapp.agent)或 Node(context.agent)直接发起 Agent 回合。Agent 拥有完整能力:文件、Shell、Skill 和 MCP,包括这个 Mini App 自己的 MCP。开启
miniapp/miniapp.json
- 不写
agentAccess就是禁止。唯一合法值是"session.run",其他取值发布时以MINIAPP_AGENT_ACCESS_INVALID拒绝。 agentConcurrency可选,取 1 到 32,默认 4:这个 Mini App 同时运行的回合数。超出的调用按顺序排队,队列最多是并发数的 4 倍。每个会话同一时间只有一个回合。- 授权跟着进程生效:改了
agentAccess并重新发布,服务会重启。
会话属于谁
这些会话不出现在用户的会话列表里。每个 Mini App 只能续用自己创建的会话,续用时 agent 和目录不变;
run 和 answer 可以传 model 切换模型,必须是用户在 models() 里能看到的模型。这些会话和聊天之间的完整关系见 Mini App 与会话。方法
审批和问卷
宿主先确认有人能回答,再让审批等待;没人能回答就直接拒绝。
permission.requested→reply:工具调用等待批准。只有”允许一次”和”拒绝”,没有”始终允许”,Mini App 不会写入用户的全局权限规则。question.requested→answer:回合停在问卷上(ask_user、功能开启或 Plan 审阅)。等暂停的run返回之后再调用answer。- 审批只在有人能回答时等待:发起调用时传了
onEvent,或者页面用open把会话显示在侧栏里。否则直接拒绝,并告诉模型没人能批准、不用这个工具继续。 - 没有超时。等待中的调用靠取消、进程退出或重新发布释放。
- Agent 委派给子会话时,子会话的审批也会通过
onEvent到达,带着子会话自己的sessionId。不要按根回合过滤事件,否则调用会一直等下去。
页面示例
Node 示例
context.agent,不要在 start 里调用。服务重启会取消进行中的回合。事件
不认识的事件类型直接忽略,以后可能还会增加。
设计建议
- 把任务、数据范围、需要的交互、成功标准和停止条件都写进
text。页面上的标签、表单状态和宿主聊天的上下文不会自动带进去。 deny只拒绝这一次工具请求,不代表这个文件以后都不能访问。需要跨调用生效的边界,用宿主权限或 Hook 规则来守。- 根回合
finished不代表后台子任务都完成了。需要子任务结果时,在业务请求里使用前台委派。 AGENT_OUTCOME_UNKNOWN表示回合可能已经跑过。先核对会话状态,不要自动重试。