From 622d0f9d88f201ef24bb1c78daef1adbd1a339c3 Mon Sep 17 00:00:00 2001 From: Ishaan Jaffer Date: Tue, 10 Mar 2026 17:47:56 -0700 Subject: [PATCH] fix(chat-ui): move MCPEvent to shared mcp_tools/types, skip partial events on abort MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Move MCPEvent interface to mcp_tools/types.tsx (shared with MCPServer/MCPTool), eliminating the playground→chat cross-module dependency. chat/types.ts and both playground components now import from mcp_tools/types. - Only persist accumulated MCP events when the stream completes cleanly; aborted or errored turns drop partial events to avoid showing incomplete tool calls. --- .../src/components/chat/ChatPage.tsx | 5 ++-- .../src/components/chat/types.ts | 27 +------------------ .../src/components/mcp_tools/types.tsx | 27 +++++++++++++++++++ .../playground/chat_ui/MCPEventsDisplay.tsx | 2 +- .../playground/llm_calls/responses_api.tsx | 2 +- 5 files changed, 33 insertions(+), 30 deletions(-) diff --git a/ui/litellm-dashboard/src/components/chat/ChatPage.tsx b/ui/litellm-dashboard/src/components/chat/ChatPage.tsx index d60cb2e1e64..46c8ce4267a 100644 --- a/ui/litellm-dashboard/src/components/chat/ChatPage.tsx +++ b/ui/litellm-dashboard/src/components/chat/ChatPage.tsx @@ -320,8 +320,9 @@ const ChatPage: React.FC = ({ accessToken, userRole, userId, user }); } } finally { - // Persist MCP events once after the turn ends (single localStorage write). - if (accumulatedMCPEvents.length > 0) { + // Persist MCP events only when the stream completed cleanly — partial + // events from an aborted/errored turn would show incomplete tool calls. + if (accumulatedMCPEvents.length > 0 && !abortControllerRef.current?.signal.aborted) { updateLastAssistantMessage(convId!, { mcpEvents: accumulatedMCPEvents }); } setIsStreaming(false); diff --git a/ui/litellm-dashboard/src/components/chat/types.ts b/ui/litellm-dashboard/src/components/chat/types.ts index 5a05d1221dd..4c0da7a095e 100644 --- a/ui/litellm-dashboard/src/components/chat/types.ts +++ b/ui/litellm-dashboard/src/components/chat/types.ts @@ -1,29 +1,4 @@ -/** Represents a single MCP tool event emitted during an assistant turn. */ -export interface MCPEvent { - type: string; - sequence_number?: number; - output_index?: number; - item_id?: string; - item?: { - id?: string; - type?: string; - server_label?: string; - tools?: Array<{ - name: string; - description: string; - annotations?: { - read_only?: boolean; - }; - input_schema?: unknown; - }>; - name?: string; - arguments?: string; - output?: string; - }; - delta?: string; - arguments?: string; - timestamp?: number; -} +export type { MCPEvent } from "../mcp_tools/types"; export interface ChatMessage { id: string; diff --git a/ui/litellm-dashboard/src/components/mcp_tools/types.tsx b/ui/litellm-dashboard/src/components/mcp_tools/types.tsx index 3f8bc41e206..38868b50a5e 100644 --- a/ui/litellm-dashboard/src/components/mcp_tools/types.tsx +++ b/ui/litellm-dashboard/src/components/mcp_tools/types.tsx @@ -1,3 +1,30 @@ +/** A single MCP tool event emitted by the LiteLLM proxy during a Responses API turn. */ +export interface MCPEvent { + type: string; + sequence_number?: number; + output_index?: number; + item_id?: string; + item?: { + id?: string; + type?: string; + server_label?: string; + tools?: Array<{ + name: string; + description: string; + annotations?: { + read_only?: boolean; + }; + input_schema?: unknown; + }>; + name?: string; + arguments?: string; + output?: string; + }; + delta?: string; + arguments?: string; + timestamp?: number; +} + export interface Team { team_id: string; team_alias?: string; diff --git a/ui/litellm-dashboard/src/components/playground/chat_ui/MCPEventsDisplay.tsx b/ui/litellm-dashboard/src/components/playground/chat_ui/MCPEventsDisplay.tsx index 6bf6ed38d2d..cd7ecbf266f 100644 --- a/ui/litellm-dashboard/src/components/playground/chat_ui/MCPEventsDisplay.tsx +++ b/ui/litellm-dashboard/src/components/playground/chat_ui/MCPEventsDisplay.tsx @@ -1,6 +1,6 @@ import React from "react"; import { Typography, Collapse } from "antd"; -import type { MCPEvent } from "../../chat/types"; +import type { MCPEvent } from "../../mcp_tools/types"; const { Text } = Typography; const { Panel } = Collapse; diff --git a/ui/litellm-dashboard/src/components/playground/llm_calls/responses_api.tsx b/ui/litellm-dashboard/src/components/playground/llm_calls/responses_api.tsx index da7325642c2..923c613d77b 100644 --- a/ui/litellm-dashboard/src/components/playground/llm_calls/responses_api.tsx +++ b/ui/litellm-dashboard/src/components/playground/llm_calls/responses_api.tsx @@ -3,7 +3,7 @@ import { MessageType } from "../chat_ui/types"; import { TokenUsage } from "../chat_ui/ResponseMetrics"; import { getProxyBaseUrl } from "@/components/networking"; import NotificationManager from "@/components/molecules/notifications_manager"; -import type { MCPEvent } from "../../chat/types"; +import type { MCPEvent } from "../../mcp_tools/types"; import { MCPServer } from "../../mcp_tools/types"; import { CodeInterpreterResult,