Skip to content

[Bug] MCP Marketplace causes infinite request loops and high CPU usageΒ #4930

@indiesewell

Description

@indiesewell

App Version

v3.20.1

API Provider

Anthropic

Model Used

Claude 4 Sonnet

πŸ” Steps to Reproduce

πŸ› Bug Report

Affected Version: v3.20.1 and later

1. Summary

Since the introduction of the MCP Marketplace, the extension can enter an infinite loop of API requests, causing high CPU usage and making the extension completely unresponsive. This is triggered by two main factors:

  1. Inefficient Data Fetching: The marketplace data is fetched on every single UI state update, regardless of whether the user is interacting with the marketplace.
  2. Network Request Failures: In certain network environments (especially behind a VPN or on slow connections), the API requests to fetch marketplace data fail or time out. This is likely due to a deeper issue with axios being blocked by Cloudflare's WAF (this will be detailed in a separate, related issue).

The combination of constant, unnecessary requests and frequent network failures creates a vicious cycle that paralyzes the extension.

2. Root Cause Analysis

A. Unconditional API Invocation

The primary performance issue lies in src/core/webview/ClineProvider.ts. The getStateToPostToWebview method unconditionally calls this.marketplaceManager.getCurrentItems(). Since this state-syncing method is called very frequently, it results in a flood of API requests, creating a huge performance bottleneck and exacerbating the network failure issue.

B. Network Request Instability

The requests made from src/services/marketplace/RemoteConfigLoader.ts are unreliable in some environments. While the root cause seems to be axios's incompatibility with Cloudflare, an immediate workaround is to switch to a more robust request mechanism like Node.js's native https module, which has proven to be more reliable in similar situations within this codebase.

3. Proposed Solution

This solution focuses on immediate mitigation of the performance and unresponsiveness bug.

  1. Implement On-Demand Data Loading in ClineProvider.ts:

    • Wrap the marketplace data fetching logic in a conditional check. The data should only be fetched if the MCP feature is actually enabled by the user.

    Example Implementation:

    // In src/core/webview/ClineProvider.ts, inside getStateToPostToWebview()
    
    let marketplaceItems: any[] = [];
    let marketplaceInstalledMetadata: any = { project: {}, global: {} };
    
    const { mcpEnabled } = await this.getState();
    if (mcpEnabled) {
        marketplaceItems = (await this.marketplaceManager.getCurrentItems()) || [];
        marketplaceInstalledMetadata = await this.marketplaceManager.getInstallationMetadata();
    }
  2. Stabilize Network Request in RemoteConfigLoader.ts:

    • As a quick and effective fix, replace the axios.get() call with a request using the native https module. This has been shown to bypass WAF issues.
    • Note: This is a tactical fix. A broader, strategic discussion about replacing axios throughout the application will be raised in a separate issue.

    Example Implementation:

    // In src/services/marketplace/RemoteConfigLoader.ts
    import * as https from 'https';
    
    private async fetchWithRetry<T>(url: string, maxRetries = 3): Promise<T> {
        // ... (retry logic)
        try {
            return new Promise<T>((resolve, reject) => {
                const options = {
                    // ... (hostname, path, etc. from URL)
                    method: "GET",
                    timeout: 60000,
                    headers: {
                        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36",
                    },
                };
                const req = https.request(options, (res) => {
                    let data = "";
                    res.on("data", (chunk) => (data += chunk));
                    res.on("end", () => {
                        if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
                            resolve(data as T); // Return raw string for YAML parsing
                        } else {
                            reject(new Error(`Request failed: ${res.statusCode}`));
                        }
                    });
                });
                req.on("error", (e) => reject(e));
                req.end();
            });
        } catch (error) {
            // ... (error handling)
        }
        // ...
    }

4. Impact

  • Severity: Critical. This bug makes the extension unusable for a growing number of users.
  • Urgency: High. Fixing this is essential to restore core functionality.

Implementing these two changes will immediately resolve the infinite loop and make the extension stable again for affected users.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Issue - Unassigned / ActionableClear and approved. Available for contributors to pick up.UI/UXUI/UX related or focusedbugSomething isn't working

    Type

    No type

    Projects

    Status

    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions