Skip to content

Conversation

@autumnjava
Copy link

@autumnjava autumnjava commented Jan 4, 2026

Summary

Add MCP Progress Tracking Support

This PR implements real-time progress tracking for MCP (Model Context Protocol) tool calls, following the https://modelcontextprotocol.info/specification/draft/basic/utilities/progress/.

Changes

Files Modified

  1. api/server/services/MCP.js
    • Added comprehensive MCP (Model Coordination Protocol) progress tracking functionality
    • Implemented real-time progress updates for MCP operations
    • Added structured logging for MCP workflow steps
    • Integrated progress state management with existing API services
  2. client/src/components/Chat/Messages/Content/MCPProgress.tsx
    • Created new React component for displaying MCP progress indicators
    • Implemented visual progress bars and status tracking UI
    • Added real-time updates for MCP workflow steps
    • Integrated with Redux store for progress state management
  3. client/src/components/Chat/Messages/Content/Part.tsx
    • Modified message part rendering to support MCP progress components
    • Added conditional rendering logic for different content types
    • Enhanced type handling for MCP-related message parts
  4. client/src/components/Chat/Messages/Content/ToolCall.tsx
    • Enhanced tool call component to display MCP progress information
    • Added integration points for MCP workflow visualization
    • Updated styling to accommodate progress indicators
  5. client/src/hooks/SSE/useStepHandler.ts
    • Extended step handling hook to process MCP-specific events
    • Added logic for managing MCP progress updates through Server-Sent Events
  6. client/src/store/mcp.ts
    • Created new Redux store module for MCP state management
    • Implemented actions and reducers for tracking MCP progress and status
  7. packages/api/src/mcp/MCPManager.ts
    • Created new MCPManager class for handling Model Coordination Protocol operations
    • Implemented core MCP workflow orchestration logic
    • Added connection management and protocol handling
    • Integrated with existing API service architecture
  8. packages/api/src/mcp/connection.ts
    • Enhanced MCP connection utilities
    • Improved connection establishment and management for Model Context Protocol
  9. packages/api/src/mcp/parsers.ts
    • Updated MCP message parsers
    • Added parsing logic for new MCP message types and progress indicators
  10. packages/api/src/mcp/types/index.ts
    • Extended MCP type definitions
    • Added new interfaces and types for MCP progress tracking
  11. packages/data-provider/src/types/agents.ts
    • Added MCP-related properties to agent type definitions
    • Extended agent configuration to support Model Context Protocol features
  12. packages/data-provider/src/types/assistants.ts
    • Extended assistant types with MCP capability flags
    • Added support for MCP-enabled assistants in type definitions

Change Type

Please delete any irrelevant options.

  • New feature (non-breaking change which adds functionality)

Testing

  1. Connect to a MCP server that send progress tracking events
  2. Select this MCP and start chatting with it
  3. Verify that the progress tracking is visible during operations
  4. Confirm progress indicators show appropriate status messages
  5. Verify progress completes and disappears when operations finish

Screenshots

  1. Receiving progress tracking events
Screenshot from 2026-01-04 14-23-12
  1. Progress tracking is not visible when the response is complete
Screenshot from 2026-01-04 14-38-14

Checklist

Please delete any irrelevant options.

  • My code adheres to this project's style guidelines
  • I have performed a self-review of my own code
  • I have commented in any complex areas of my code
  • My changes do not introduce new warnings
  • Local unit tests pass with my changes
  • Any changes dependent on mine have been merged and published in downstream modules.

I would like to thank @existme who did the initial version

autumnjava and others added 7 commits December 31, 2025 17:35
…arding

  - Subscribe to MCP protocol progress notifications in MCPConnection
  - Implement direct SSE emission of progress events from MCP service
  - Handle progress delta events in client-side useStepHandler
  - Pass progressToken in MCP tool call requests for event correlation
  - Clean up progress tracking on tool completion and errors
@danny-avila
Copy link
Owner

Thanks for the PR! While I haven't looked deeply at the changes, I think the UI needs more polish, we will likely use this PR for reference only @dustinhealy @berry-13

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements real-time progress tracking for MCP (Model Context Protocol) tool calls following the MCP specification. It adds comprehensive progress monitoring infrastructure that spans from backend event handling through SSE communication to frontend UI display.

Key changes include:

  • Added progress notification subscriptions in MCP connections with event forwarding through MCPManager
  • Implemented client-side progress state management using Jotai atoms and SSE event handlers
  • Created a new MCPProgress React component to display real-time progress bars with percentage and status messages

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
packages/api/src/mcp/connection.ts Added subscription to MCP progress notifications and event emission
packages/api/src/mcp/MCPManager.ts Added EventEmitter delegation, progress token management, and progress event forwarding
packages/api/src/mcp/parsers.ts Extended return type to include isError flag in formatted content results
packages/api/src/mcp/types/index.ts Updated FormattedContentResult type to include optional isError boolean
api/server/services/MCP.js Added progress listener setup, SSE event emission, and error status handling with ToolMessage
packages/data-provider/src/types/agents.ts Added progress-related fields (progressToken, serverName, toolName, progress, total, message) and isError flag
packages/data-provider/src/types/assistants.ts Added isError field to FunctionToolCall type
client/src/store/mcp.ts Created progress and active state atoms with atomFamily selectors for per-conversation tracking
client/src/hooks/SSE/useStepHandler.ts Added handling for progress delta events and MCP active state management
client/src/components/Chat/Messages/Content/MCPProgress.tsx New component displaying progress bars with percentage, server/tool names, and status messages
client/src/components/Chat/Messages/Content/ToolCall.tsx Integrated MCPProgress component display during active tool calls
client/src/components/Chat/Messages/Content/Part.tsx Added conversationId and isError props propagation to ToolCall components

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +326 to +327
if (connection && progressListener) {
connection.off('progress', progressListener);
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The progress listener cleanup happens before the progressTokens map is cleared, but the cleanup only checks if connection exists, not if connection is still valid. If the connection fails or throws in the try block before being assigned, the cleanup will be skipped but the progressTokens entry will still be deleted. Consider checking progressListener existence alone or restructuring to ensure cleanup always happens.

Suggested change
if (connection && progressListener) {
connection.off('progress', progressListener);
if (progressListener) {
connection?.off('progress', progressListener);

Copilot uses AI. Check for mistakes.
Comment on lines +615 to +620
this.emit('progress', {
serverName: this.serverName,
progressToken: notification.params?.progressToken,
progress: notification.params?.progress,
total: notification.params?.total,
message: notification.params?.message,
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The progress notification handler doesn't validate that the parameters exist before emitting them. If a progress notification arrives with missing or undefined values for progressToken, progress, total, or message, they will be emitted as undefined. Consider adding validation or default values to ensure consistent event payloads.

Suggested change
this.emit('progress', {
serverName: this.serverName,
progressToken: notification.params?.progressToken,
progress: notification.params?.progress,
total: notification.params?.total,
message: notification.params?.message,
const params = notification.params;
if (!params) {
logger.warn(`${this.getLogPrefix()} Received progress notification without params`);
return;
}
const safeProgressToken = params.progressToken ?? null;
const safeProgress =
typeof params.progress === 'number' ? params.progress : 0;
const safeTotal =
typeof params.total === 'number' ? params.total : 0;
const safeMessage =
typeof params.message === 'string' ? params.message : '';
this.emit('progress', {
serverName: this.serverName,
progressToken: safeProgressToken,
progress: safeProgress,
total: safeTotal,
message: safeMessage,

Copilot uses AI. Check for mistakes.
}

const { progress, total, message } = latestProgress;
const percentage = total ? Math.round((progress / total) * 100) : Math.round(progress * 100);
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The percentage calculation could produce values greater than 100% if progress exceeds total, or if progress is a value greater than 1.0 when total is undefined. Consider clamping the percentage between 0 and 100 to ensure valid display values.

Suggested change
const percentage = total ? Math.round((progress / total) * 100) : Math.round(progress * 100);
const rawPercentage = total ? Math.round((progress / total) * 100) : Math.round(progress * 100);
const percentage = Math.max(0, Math.min(100, rawPercentage));

Copilot uses AI. Check for mistakes.
}

// Set up progress event listener
progressListener = (progressData: any) => {
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using any type reduces type safety. Consider defining a proper type for progressData that matches the event payload structure, such as creating an interface with fields like progressToken, serverName, toolName, userId, progress, total, and message.

Copilot uses AI. Check for mistakes.
*/
export const mcpProgressAtom = atom<Record<string, MCPProgress[]>>({});

/**
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The MCP progress state stored in mcpProgressAtom is never cleaned up. Progress data accumulates in the atom for each conversation without any cleanup logic. Consider adding cleanup when conversations are deleted or when progress is completed, to prevent unbounded memory growth over time.

Suggested change
/**
/**
* Write-only helper atom to clear MCP progress for a single conversation.
* This should be used when a conversation is deleted or when its progress
* data is no longer needed, to avoid unbounded growth of mcpProgressAtom.
*/
export const clearMCPProgressForConversationAtom = atom(
null,
(get, set, conversationId: string) => {
const current = get(mcpProgressAtom);
if (!current[conversationId]) {
return;
}
const { [conversationId]: _removed, ...rest } = current;
set(mcpProgressAtom, rest);
},
);
/**
* Write-only helper atom to clear all MCP progress data.
* This can be used on global resets (e.g., logout) to free memory.
*/
export const clearAllMCPProgressAtom = atom(null, (_get, set) => {
set(mcpProgressAtom, {});
});
/**

Copilot uses AI. Check for mistakes.
Comment on lines +620 to +628
// Clear active state for this conversation when tool completes
const conversationId =
submission?.initialResponse?.conversationId || userMessage.conversationId;
if (conversationId) {
setMcpActive((current) => ({
...current,
[conversationId]: false,
}));
}
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mcpActiveAtom is set to false on tool completion, but the accumulated progress data in mcpProgressAtom for that conversation is not cleared. This means old progress entries remain in memory. Consider clearing the progress data for this conversation when setting active to false.

Copilot uses AI. Check for mistakes.
Comment on lines 97 to 98
if (!RECOGNIZED_PROVIDERS.has(provider)) {
return [parseAsString(result), undefined];
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When returning early for unrecognized providers, the isError flag is not propagated to the result tuple. The function should return the 3-element tuple consistently, including the isError flag extracted on line 96.

Copilot uses AI. Check for mistakes.
attachments,
auth,
conversationId,
isError: toolIsError,
Copy link

Copilot AI Jan 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The isError parameter (destructured as toolIsError) is received but never used in the component. If this flag is meant to indicate an error state, it should be incorporated into the error handling logic or UI display. Consider using it to determine the cancelled state or to display error-specific styling.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants