Skip to content

routes.mcp 是 REST /discovery 发出、objectui 真实消费、但 ApiRoutesSchema 从未声明的键(#4828 同族,低一层) #5679

Description

@os-zhuang

发现于 #4828 的实施(界外发现,查重无命中故新开;未认领)。

现象

#4828 收拾的是 discovery 顶层的未声明键(scoping / features / endpoints)。同一个病在低一层还有一例,而且这一例是有真实消费者的:

  • 生产者:packages/rest/src/rest-server.ts
    (discovery.routes as any).mcp = `${unscopedBase}/mcp`;
    ...
    delete (discovery.routes as any).mcp;
    那个 as any 就是证据本身 —— 不强转的话 TypeScript 会当场拒绝,因为
  • 声明:ApiRoutesSchema(packages/spec/src/api/discovery.zod.ts)声明了 data/metadata/discovery/ui/auth/automation/storage/analytics/packages/approvals/realtime/notifications/ai/i18n,没有 mcp
  • 消费者(与 endpoints 那种零消费者的情况完全相反):
    • objectui packages/app-shell/src/console/connect/ConnectAgentWidget.tsx:119 —— setMcpUrl(typeof routes.mcp === 'string' ? absoluteUrl(routes.mcp) : null)
    • objectui apps/console/src/pages/developer/AgentConnectSection.tsx:89 —— json?.data?.routes?.mcp ?? json?.routes?.mcp

为什么这是缺陷而不只是洁癖

ApiRoutesSchema 是普通 z.object(默认 strip)。所以任何按 spec 严格解析 discovery 的消费者,都会把 routes.mcp 悄悄丢掉 —— Integrations 页面的 MCP 连接卡就此空掉,而没有任何报错。今天没炸,只是因为 objectui 那两处读的是原始 JSON,没走 schema。

rest-server.ts 里那段注释本身还写着「both must advertise mcp on the same terms」,可见 mcp 被当成一等的核心能力在对待 —— 一等能力却没有进契约。

(注:dispatcher 侧的 getDiscoveryInfo() 不发 routes.mcp,只有 REST 这条路径发。这本身也是两个生产者的一处分歧,和 #4828 收敛掉的那几处同源。)

为什么 #4828 没有一起修

#4828 的裁定覆盖的是顶层四个子决策,它的闸门也刻意钉在顶层键集上。把闸门递归收严会立刻红在 routes.mcp 上,而修它需要一个新的契约决策 —— mcp 声明进 ApiRoutesSchema(看起来是对的:它有生产者、有消费者、有 ADR-0036 背书),这不属于该单已裁的四条,所以按 Prime Directive #10 记在这里。

建议

  1. ApiRoutesSchema 声明 mcp: z.string().optional()(与其它可选路由同形),并去掉 rest-server.ts 里的两处 as any;
  2. 顺带评估把 discovery 的一致性闸门从「顶层键集」下沉到 routes 一层(两个 discovery 生产者都在线上返回 schema 未声明的顶层字段(scoping / features / endpoints),且 REST 形状永远无法通过 DiscoverySchema #4828 已经建立了这套闸门,扩一层是小活)。

参考:#4828#3877(响应体从不与声明它的 schema 对账 —— 本例正是该单 Stage A 的延伸)、ADR-0036。

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions