Skip to content

Commit 392f35b

Browse files
committed
Added MCP Working
1 parent 2846692 commit 392f35b

3 files changed

Lines changed: 151 additions & 16 deletions

File tree

src/extension.ts

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -111,12 +111,10 @@ export async function activate(context: vscode.ExtensionContext) {
111111
})
112112
await provider.postStateToWebview()
113113
// Update MCP server with new token
114-
// TODO: REDO THIS I GUESS?!
115-
116-
// const mcpHub = provider.getMcpHub()
117-
// if (mcpHub) {
118-
// await mcpHub.updatePearAIApiKey(data.accessToken)
119-
// }
114+
const mcpHub = provider.getMcpHub()
115+
if (mcpHub) {
116+
await mcpHub.updatePearAIApiKey(data.accessToken)
117+
}
120118
}
121119
vscode.commands.executeCommand("roo-cline.plusButtonClicked")
122120
}),
@@ -136,10 +134,10 @@ export async function activate(context: vscode.ExtensionContext) {
136134
})
137135
await provider.postStateToWebview()
138136
// Update MCP server with new token
139-
// const mcpHub = provider.getMcpHub()
140-
// if (mcpHub) {
141-
// await mcpHub.updatePearAIApiKey(data.accessToken)
142-
// }
137+
const mcpHub = provider.getMcpHub()
138+
if (mcpHub) {
139+
await mcpHub.updatePearAIApiKey(data.accessToken)
140+
}
143141
}
144142
}),
145143
)
@@ -159,10 +157,10 @@ export async function activate(context: vscode.ExtensionContext) {
159157
})
160158
await provider.postStateToWebview()
161159
// Clear MCP server token
162-
// const mcpHub = provider.getMcpHub()
163-
// if (mcpHub) {
164-
// await mcpHub.clearPearAIApiKey()
165-
// }
160+
const mcpHub = provider.getMcpHub()
161+
if (mcpHub) {
162+
await mcpHub.clearPearAIApiKey()
163+
}
166164
}
167165
}),
168166
)

src/services/mcp/McpHub.ts

Lines changed: 138 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import {
3131
import { fileExistsAtPath } from "../../utils/fs"
3232
import { arePathsEqual } from "../../utils/path"
3333
import { injectEnv } from "../../utils/config"
34+
import { PEARAI_URL } from "../../shared/pearaiApi"
3435

3536
export 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
}

src/services/mcp/McpServerManager.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export class McpServerManager {
3636
try {
3737
// Double-check instance in case it was created while we were waiting
3838
if (!this.instance) {
39-
this.instance = new McpHub(provider)
39+
this.instance = new McpHub(provider, context)
4040
// Store a unique identifier in global state to track the primary instance
4141
await context.globalState.update(this.GLOBAL_STATE_KEY, Date.now().toString())
4242
}

0 commit comments

Comments
 (0)