@@ -31,6 +31,7 @@ import {
3131import { fileExistsAtPath } from "../../utils/fs"
3232import { arePathsEqual } from "../../utils/path"
3333import { injectEnv } from "../../utils/config"
34+ import { PEARAI_URL } from "../../shared/pearaiApi"
3435
3536export type McpConnection = {
3637 server : McpServer
@@ -111,14 +112,16 @@ export class McpHub {
111112 connections : McpConnection [ ] = [ ]
112113 isConnecting : boolean = false
113114 private refCount : number = 0 // Reference counter for active clients
115+ private context : vscode . ExtensionContext
114116
115- constructor ( provider : ClineProvider ) {
117+ constructor ( provider : ClineProvider , context : vscode . ExtensionContext ) {
116118 this . providerRef = new WeakRef ( provider )
117119 this . watchMcpSettingsFile ( )
118120 this . watchProjectMcpFile ( )
119121 this . setupWorkspaceFoldersWatcher ( )
120122 this . initializeGlobalMcpServers ( )
121123 this . initializeProjectMcpServers ( )
124+ this . context = context
122125 }
123126 /**
124127 * Registers a client (e.g., ClineProvider) using this hub.
@@ -357,6 +360,89 @@ export class McpHub {
357360 )
358361 }
359362
363+ private async fetchDefaultSettings ( ) : Promise < Record < string , any > > {
364+ try {
365+ const response = await fetch ( `${ PEARAI_URL } /getDefaultAgentMCPSettings` )
366+ if ( ! response . ok ) {
367+ throw new Error ( `HTTP error! status: ${ response . status } ` )
368+ }
369+ const data = await response . json ( )
370+ if ( data && data . mcpServers ) {
371+ return data . mcpServers
372+ }
373+ return { }
374+ } catch ( error ) {
375+ console . error ( "Failed to fetch default MCP settings:" , error )
376+ return { }
377+ }
378+ }
379+
380+ private async fetchServersToRemove ( ) : Promise < string [ ] > {
381+ try {
382+ const response = await fetch ( `${ PEARAI_URL } /getAgentMCPSettingsRemove` )
383+ if ( ! response . ok ) {
384+ throw new Error ( `HTTP error! status: ${ response . status } ` )
385+ }
386+ const data = await response . json ( )
387+ return data . serversToRemove || [ ]
388+ } catch ( error ) {
389+ console . error ( "Failed to fetch servers to remove:" , error )
390+ return [ ]
391+ }
392+ }
393+
394+ private async getPearAIApiKey ( ) : Promise < string | null > {
395+ try {
396+ const token = await this . context . secrets . get ( "pearaiApiKey" )
397+ return token || null
398+ } catch ( error ) {
399+ console . error ( "Failed to get PearAI token from secrets:" , error )
400+ return null
401+ }
402+ }
403+
404+ private async addPearAIMCP ( config : any , configPath : string ) : Promise < void > {
405+ // Fetch servers to remove and default settings
406+ const [ serversToRemove , defaultSettings ] = await Promise . all ( [
407+ this . fetchServersToRemove ( ) ,
408+ this . fetchDefaultSettings ( ) ,
409+ ] )
410+
411+ // Remove servers that should be removed from original config
412+ for ( const serverName of serversToRemove ) {
413+ if ( config . mcpServers ?. [ serverName ] ) {
414+ delete config . mcpServers [ serverName ]
415+ }
416+ }
417+
418+ // Create merged servers from cleaned config
419+ const mergedServers = { ...( config . mcpServers || { } ) }
420+
421+ // Add new servers from default settings that don't exist in current settings
422+ for ( const [ serverName , serverConfig ] of Object . entries ( defaultSettings ) ) {
423+ if ( ! mergedServers [ serverName ] ) {
424+ mergedServers [ serverName ] = serverConfig
425+ }
426+
427+ // If this is the pearai server, check login status and update API key
428+ if ( serverName === "pearai" ) {
429+ const apiKey = await this . getPearAIApiKey ( )
430+ if ( apiKey ) {
431+ mergedServers [ serverName ] = {
432+ ...serverConfig ,
433+ args : [ "pearai-mcp" , apiKey ] ,
434+ }
435+ }
436+ }
437+ }
438+
439+ // Update mcpServers while preserving config structure
440+ config . mcpServers = mergedServers
441+
442+ // Write updated config back to file
443+ await fs . writeFile ( configPath , JSON . stringify ( config , null , 2 ) )
444+ }
445+
360446 private async initializeMcpServers ( source : "global" | "project" ) : Promise < void > {
361447 try {
362448 const configPath =
@@ -368,6 +454,12 @@ export class McpHub {
368454
369455 const content = await fs . readFile ( configPath , "utf-8" )
370456 const config = JSON . parse ( content )
457+
458+ if ( source === "global" ) {
459+ // Add PearAI MCP configuration
460+ await this . addPearAIMCP ( config , configPath )
461+ }
462+
371463 const result = McpSettingsSchema . safeParse ( config )
372464
373465 if ( result . success ) {
@@ -1291,4 +1383,49 @@ export class McpHub {
12911383 }
12921384 this . disposables . forEach ( ( d ) => d . dispose ( ) )
12931385 }
1386+ public async clearPearAIApiKey ( ) : Promise < void > {
1387+ try {
1388+ const settingsPath = await this . getMcpSettingsFilePath ( )
1389+ const content = await fs . readFile ( settingsPath , "utf-8" )
1390+ const config = JSON . parse ( content )
1391+
1392+ if ( config . mcpServers ?. pearai ) {
1393+ config . mcpServers . pearai = {
1394+ ...config . mcpServers . pearai ,
1395+ args : [ "pearai-mcp" , "<PEARAI_API_KEY>" ] ,
1396+ }
1397+
1398+ await fs . writeFile ( settingsPath , JSON . stringify ( config , null , 2 ) )
1399+ await this . updateServerConnections ( config . mcpServers )
1400+ vscode . window . showInformationMessage ( "PearAI API key cleared successfully" )
1401+ }
1402+ } catch ( error ) {
1403+ console . error ( "Failed to clear PearAI API key:" , error )
1404+ vscode . window . showErrorMessage ( "Failed to clear PearAI API key" )
1405+ throw error
1406+ }
1407+ }
1408+
1409+ public async updatePearAIApiKey ( apiKey : string ) : Promise < void > {
1410+ try {
1411+ const settingsPath = await this . getMcpSettingsFilePath ( )
1412+ const content = await fs . readFile ( settingsPath , "utf-8" )
1413+ const config = JSON . parse ( content )
1414+
1415+ if ( config . mcpServers ?. pearai ) {
1416+ config . mcpServers . pearai = {
1417+ ...config . mcpServers . pearai ,
1418+ args : [ "pearai-mcp" , apiKey ] ,
1419+ }
1420+
1421+ await fs . writeFile ( settingsPath , JSON . stringify ( config , null , 2 ) )
1422+ await this . updateServerConnections ( config . mcpServers )
1423+ // vscode.window.showInformationMessage("PearAI API key updated successfully")
1424+ }
1425+ } catch ( error ) {
1426+ console . error ( "Failed to update PearAI API key:" , error )
1427+ vscode . window . showErrorMessage ( "Failed to update PearAI API key" )
1428+ throw error
1429+ }
1430+ }
12941431}
0 commit comments