From 9ddd10b84cf2d2d6ea899daeced4984851a56da0 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Wed, 29 Apr 2026 08:15:42 +0100 Subject: [PATCH] test: tighten MCP channel smoke route contract --- scripts/e2e/mcp-channels-docker-client.ts | 66 ++++++++++++++++++++++- scripts/e2e/mcp-channels-seed.ts | 10 ++-- src/mcp/channel-server.test.ts | 12 ++--- 3 files changed, 76 insertions(+), 12 deletions(-) diff --git a/scripts/e2e/mcp-channels-docker-client.ts b/scripts/e2e/mcp-channels-docker-client.ts index a0a300b26d6..158f8e50160 100644 --- a/scripts/e2e/mcp-channels-docker-client.ts +++ b/scripts/e2e/mcp-channels-docker-client.ts @@ -7,10 +7,52 @@ import { connectMcpClient, extractTextFromGatewayPayload, type ClaudeChannelNotification, + type GatewayRpcClient, maybeApprovePendingBridgePairing, waitFor, } from "./mcp-channels-harness.ts"; +function summarizeSessionRows(rows: Array> | undefined) { + return (rows ?? []).map((entry) => ({ + key: entry.key, + channel: entry.channel, + deliveryContext: entry.deliveryContext, + lastChannel: entry.lastChannel, + lastTo: entry.lastTo, + lastAccountId: entry.lastAccountId, + lastThreadId: entry.lastThreadId, + })); +} + +async function waitForGatewaySeededConversation(gateway: GatewayRpcClient) { + let lastList: { sessions?: Array> } | undefined; + try { + return await waitFor( + "seeded conversation in gateway sessions.list", + async () => { + lastList = await gateway.request<{ sessions?: Array> }>( + "sessions.list", + { limit: 50, includeDerivedTitles: true, includeLastMessage: true }, + ); + return lastList.sessions?.find((entry) => entry.key === "agent:main:main"); + }, + 60_000, + ); + } catch (error) { + throw new Error( + `gateway sessions.list did not include seeded conversation: ${JSON.stringify( + { + count: lastList?.sessions?.length ?? 0, + sessions: summarizeSessionRows(lastList?.sessions), + }, + null, + 2, + )}`, + { cause: error }, + ); + } +} + async function main() { const gatewayUrl = process.env.GW_URL?.trim(); const gatewayToken = process.env.GW_TOKEN?.trim(); @@ -36,6 +78,18 @@ async function main() { const callTool = (params: Parameters[0]) => mcp.callTool(params, undefined, { timeout: 240_000 }) as Promise; + const gatewayConversation = await waitForGatewaySeededConversation(gateway); + assert( + (gatewayConversation.deliveryContext as { channel?: unknown } | undefined)?.channel === + "imessage", + "expected seeded gateway deliveryContext channel", + ); + assert( + (gatewayConversation.deliveryContext as { to?: unknown } | undefined)?.to === "+15551234567", + "expected seeded gateway deliveryContext target", + ); + + let lastMcpConversationList: unknown; const conversation = await waitFor( "seeded conversation in conversations_list", async () => { @@ -45,12 +99,22 @@ async function main() { name: "conversations_list", arguments: {}, }); + lastMcpConversationList = listed; return listed.structuredContent?.conversations?.find( (entry) => entry.sessionKey === "agent:main:main", ); }, 240_000, - ); + ).catch((error) => { + throw new Error( + `timeout waiting for seeded MCP conversation: ${JSON.stringify( + lastMcpConversationList, + null, + 2, + )}`, + { cause: error }, + ); + }); assert(conversation.channel === "imessage", "expected seeded channel"); assert(conversation.to === "+15551234567", "expected seeded target"); diff --git a/scripts/e2e/mcp-channels-seed.ts b/scripts/e2e/mcp-channels-seed.ts index d8244cd3708..03cdf0e9dff 100644 --- a/scripts/e2e/mcp-channels-seed.ts +++ b/scripts/e2e/mcp-channels-seed.ts @@ -47,10 +47,12 @@ async function main() { sessionId: "sess-main", sessionFile, updatedAt: now, - lastChannel: "imessage", - lastTo: "+15551234567", - lastAccountId: "imessage-default", - lastThreadId: "thread-42", + deliveryContext: { + channel: "imessage", + to: "+15551234567", + accountId: "imessage-default", + threadId: "thread-42", + }, displayName: "Docker MCP Channel Smoke", derivedTitle: "Docker MCP Channel Smoke", lastMessagePreview: "seeded transcript", diff --git a/src/mcp/channel-server.test.ts b/src/mcp/channel-server.test.ts index 427db49a7df..dfa34800d2b 100644 --- a/src/mcp/channel-server.test.ts +++ b/src/mcp/channel-server.test.ts @@ -323,7 +323,7 @@ describe("openclaw channel mcp server", () => { ); }); - test("lists routed sessions that only expose modern channel fields", async () => { + test("lists routed sessions from deliveryContext without mirrored route fields", async () => { const bridge = new OpenClawChannelBridge({} as never, { claudeChannelMode: "off", verbose: false, @@ -332,21 +332,19 @@ describe("openclaw channel mcp server", () => { sessions: [ { key: "agent:main:channel-field", - channel: "telegram", deliveryContext: { + channel: "telegram", to: "-100111", }, }, { key: "agent:main:origin-field", - origin: { - provider: "imessage", + deliveryContext: { + channel: "imessage", + to: "+15551230000", accountId: "imessage-default", threadId: "thread-7", }, - deliveryContext: { - to: "+15551230000", - }, }, ], });