From 8a4fa427a0c253c8f04dc7ebb0e58a224a7add45 Mon Sep 17 00:00:00 2001 From: nang-dev Date: Tue, 18 Mar 2025 14:38:33 -0400 Subject: [PATCH 1/4] Working --- src/services/mcp/McpHub.ts | 39 +++++++++++++++++++++++++++++++++-- src/shared/globalFileNames.ts | 2 +- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/services/mcp/McpHub.ts b/src/services/mcp/McpHub.ts index 6c906c7cf89..1d3ffbb5677 100644 --- a/src/services/mcp/McpHub.ts +++ b/src/services/mcp/McpHub.ts @@ -1,4 +1,5 @@ import { Client } from "@modelcontextprotocol/sdk/client/index.js" +import { PEARAI_URL } from "../../shared/api" import { StdioClientTransport, StdioServerParameters } from "@modelcontextprotocol/sdk/client/stdio.js" import { CallToolResultSchema, @@ -98,7 +99,7 @@ export class McpHub { mcpSettingsFilePath, `{ "mcpServers": { - + } }`, ) @@ -136,12 +137,46 @@ export class McpHub { ) } + private async fetchDefaultSettings(): Promise> { + try { + const response = await fetch(`${PEARAI_URL}/getDefaultAgentMCPSettings`) + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`) + } + const data = await response.json() + if (data && data.mcpServers) { + return data.mcpServers + } + return {} + } catch (error) { + console.error("Failed to fetch default MCP settings:", error) + return {} + } + } + private async initializeMcpServers(): Promise { try { const settingsPath = await this.getMcpSettingsFilePath() const content = await fs.readFile(settingsPath, "utf-8") const config = JSON.parse(content) - await this.updateServerConnections(config.mcpServers || {}) + + // Fetch default settings + const defaultSettings = await this.fetchDefaultSettings() + + console.dir(defaultSettings) + + // Only add new servers from default settings that don't exist in current settings + const mergedServers = { ...(config.mcpServers || {}) } + for (const [serverName, serverConfig] of Object.entries(defaultSettings)) { + if (!mergedServers[serverName]) { + mergedServers[serverName] = serverConfig + } + } + + // Update the settings file with merged settings + await fs.writeFile(settingsPath, JSON.stringify({ mcpServers: mergedServers }, null, 2)) + + await this.updateServerConnections(mergedServers) } catch (error) { console.error("Failed to initialize MCP servers:", error) } diff --git a/src/shared/globalFileNames.ts b/src/shared/globalFileNames.ts index 6088e95d999..9eec311b909 100644 --- a/src/shared/globalFileNames.ts +++ b/src/shared/globalFileNames.ts @@ -4,6 +4,6 @@ export const GlobalFileNames = { glamaModels: "glama_models.json", openRouterModels: "openrouter_models.json", requestyModels: "requesty_models.json", - mcpSettings: "cline_mcp_settings.json", + mcpSettings: "pearai_agent_mcp_settings.json", unboundModels: "unbound_models.json", } From 40ade36652074b4d99182aecaabd6cb8f6115f84 Mon Sep 17 00:00:00 2001 From: nang-dev Date: Tue, 18 Mar 2025 14:39:38 -0400 Subject: [PATCH 2/4] Working --- src/services/mcp/McpHub.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/services/mcp/McpHub.ts b/src/services/mcp/McpHub.ts index 1d3ffbb5677..881f2b67763 100644 --- a/src/services/mcp/McpHub.ts +++ b/src/services/mcp/McpHub.ts @@ -162,9 +162,6 @@ export class McpHub { // Fetch default settings const defaultSettings = await this.fetchDefaultSettings() - - console.dir(defaultSettings) - // Only add new servers from default settings that don't exist in current settings const mergedServers = { ...(config.mcpServers || {}) } for (const [serverName, serverConfig] of Object.entries(defaultSettings)) { From 02795f6790557f9096f4a1c823a423ecc118fe7a Mon Sep 17 00:00:00 2001 From: nang-dev Date: Tue, 18 Mar 2025 16:22:23 -0400 Subject: [PATCH 3/4] Added login working --- src/extension.ts | 8 +++++ src/services/mcp/McpHub.ts | 48 +++++++++++++++++++++++++++- src/services/mcp/McpServerManager.ts | 2 +- 3 files changed, 56 insertions(+), 2 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index ef8895ee24b..452c106cd81 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -67,6 +67,14 @@ export function activate(context: vscode.ExtensionContext) { console.dir(data) context.secrets.store("pearai-token", data.accessToken) context.secrets.store("pearai-refresh", data.refreshToken) + // Update MCP server with new token + const provider = await ClineProvider.getInstance() + if (provider) { + const mcpHub = provider.getMcpHub() + if (mcpHub) { + await mcpHub.updatePearAiApiKey(data.accessToken) + } + } vscode.commands.executeCommand("roo-cline.plusButtonClicked") }), ) diff --git a/src/services/mcp/McpHub.ts b/src/services/mcp/McpHub.ts index 881f2b67763..50486234e21 100644 --- a/src/services/mcp/McpHub.ts +++ b/src/services/mcp/McpHub.ts @@ -56,11 +56,13 @@ export class McpHub { private disposables: vscode.Disposable[] = [] private settingsWatcher?: vscode.FileSystemWatcher private fileWatchers: Map = new Map() + private context: vscode.ExtensionContext connections: McpConnection[] = [] isConnecting: boolean = false - constructor(provider: ClineProvider) { + constructor(provider: ClineProvider, context: vscode.ExtensionContext) { this.providerRef = new WeakRef(provider) + this.context = context this.watchMcpSettingsFile() this.initializeMcpServers() } @@ -154,6 +156,16 @@ export class McpHub { } } + private async getPearAiApiKey(): Promise { + try { + const token = await this.context.secrets.get("pearai-token") + return token || null + } catch (error) { + console.error("Failed to get PearAI token from secrets:", error) + return null + } + } + private async initializeMcpServers(): Promise { try { const settingsPath = await this.getMcpSettingsFilePath() @@ -168,6 +180,17 @@ export class McpHub { if (!mergedServers[serverName]) { mergedServers[serverName] = serverConfig } + + // If this is the pearai server, check login status and update API key + if (serverName === "pearai") { + const apiKey = await this.getPearAiApiKey() + if (apiKey) { + mergedServers[serverName] = { + ...serverConfig, + args: ["pearai-mcp", apiKey], + } + } + } } // Update the settings file with merged settings @@ -482,6 +505,29 @@ export class McpHub { }) } + public async updatePearAiApiKey(apiKey: string): Promise { + try { + const settingsPath = await this.getMcpSettingsFilePath() + const content = await fs.readFile(settingsPath, "utf-8") + const config = JSON.parse(content) + + if (config.mcpServers?.pearai) { + config.mcpServers.pearai = { + ...config.mcpServers.pearai, + args: ["pearai-mcp", apiKey], + } + + await fs.writeFile(settingsPath, JSON.stringify(config, null, 2)) + await this.updateServerConnections(config.mcpServers) + vscode.window.showInformationMessage("PearAI API key updated successfully") + } + } catch (error) { + console.error("Failed to update PearAI API key:", error) + vscode.window.showErrorMessage("Failed to update PearAI API key") + throw error + } + } + public async toggleServerDisabled(serverName: string, disabled: boolean): Promise { let settingsPath: string try { diff --git a/src/services/mcp/McpServerManager.ts b/src/services/mcp/McpServerManager.ts index e15f9db0a7a..54e8c88aa57 100644 --- a/src/services/mcp/McpServerManager.ts +++ b/src/services/mcp/McpServerManager.ts @@ -36,7 +36,7 @@ export class McpServerManager { try { // Double-check instance in case it was created while we were waiting if (!this.instance) { - this.instance = new McpHub(provider) + this.instance = new McpHub(provider, context) // Store a unique identifier in global state to track the primary instance await context.globalState.update(this.GLOBAL_STATE_KEY, Date.now().toString()) } From 63295d40bdd2a577728fbbaada5c0a741f152ba9 Mon Sep 17 00:00:00 2001 From: nang-dev Date: Tue, 18 Mar 2025 16:25:17 -0400 Subject: [PATCH 4/4] Added logout working --- src/extension.ts | 8 ++++++++ src/services/mcp/McpHub.ts | 23 +++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/src/extension.ts b/src/extension.ts index 452c106cd81..5dcfd3169e5 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -84,6 +84,14 @@ export function activate(context: vscode.ExtensionContext) { console.dir("Logged out of PearAI:") context.secrets.delete("pearai-token") context.secrets.delete("pearai-refresh") + // Clear MCP server token + const provider = await ClineProvider.getInstance() + if (provider) { + const mcpHub = provider.getMcpHub() + if (mcpHub) { + await mcpHub.clearPearAiApiKey() + } + } }), ) diff --git a/src/services/mcp/McpHub.ts b/src/services/mcp/McpHub.ts index 50486234e21..050e7ae2ba9 100644 --- a/src/services/mcp/McpHub.ts +++ b/src/services/mcp/McpHub.ts @@ -505,6 +505,29 @@ export class McpHub { }) } + public async clearPearAiApiKey(): Promise { + try { + const settingsPath = await this.getMcpSettingsFilePath() + const content = await fs.readFile(settingsPath, "utf-8") + const config = JSON.parse(content) + + if (config.mcpServers?.pearai) { + config.mcpServers.pearai = { + ...config.mcpServers.pearai, + args: ["pearai-mcp", ""], + } + + await fs.writeFile(settingsPath, JSON.stringify(config, null, 2)) + await this.updateServerConnections(config.mcpServers) + vscode.window.showInformationMessage("PearAI API key cleared successfully") + } + } catch (error) { + console.error("Failed to clear PearAI API key:", error) + vscode.window.showErrorMessage("Failed to clear PearAI API key") + throw error + } + } + public async updatePearAiApiKey(apiKey: string): Promise { try { const settingsPath = await this.getMcpSettingsFilePath()