Skip to content

Commit ad75b69

Browse files
authored
Merge pull request #30 from trypear/mcp-config
MCP config from server
2 parents 8aa0256 + 63295d4 commit ad75b69

4 files changed

Lines changed: 122 additions & 5 deletions

File tree

src/extension.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,14 @@ export function activate(context: vscode.ExtensionContext) {
6767
console.dir(data)
6868
context.secrets.store("pearai-token", data.accessToken)
6969
context.secrets.store("pearai-refresh", data.refreshToken)
70+
// Update MCP server with new token
71+
const provider = await ClineProvider.getInstance()
72+
if (provider) {
73+
const mcpHub = provider.getMcpHub()
74+
if (mcpHub) {
75+
await mcpHub.updatePearAiApiKey(data.accessToken)
76+
}
77+
}
7078
vscode.commands.executeCommand("roo-cline.plusButtonClicked")
7179
}),
7280
)
@@ -76,6 +84,14 @@ export function activate(context: vscode.ExtensionContext) {
7684
console.dir("Logged out of PearAI:")
7785
context.secrets.delete("pearai-token")
7886
context.secrets.delete("pearai-refresh")
87+
// Clear MCP server token
88+
const provider = await ClineProvider.getInstance()
89+
if (provider) {
90+
const mcpHub = provider.getMcpHub()
91+
if (mcpHub) {
92+
await mcpHub.clearPearAiApiKey()
93+
}
94+
}
7995
}),
8096
)
8197

src/services/mcp/McpHub.ts

Lines changed: 104 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Client } from "@modelcontextprotocol/sdk/client/index.js"
2+
import { PEARAI_URL } from "../../shared/api"
23
import { StdioClientTransport, StdioServerParameters } from "@modelcontextprotocol/sdk/client/stdio.js"
34
import {
45
CallToolResultSchema,
@@ -55,11 +56,13 @@ export class McpHub {
5556
private disposables: vscode.Disposable[] = []
5657
private settingsWatcher?: vscode.FileSystemWatcher
5758
private fileWatchers: Map<string, FSWatcher> = new Map()
59+
private context: vscode.ExtensionContext
5860
connections: McpConnection[] = []
5961
isConnecting: boolean = false
6062

61-
constructor(provider: ClineProvider) {
63+
constructor(provider: ClineProvider, context: vscode.ExtensionContext) {
6264
this.providerRef = new WeakRef(provider)
65+
this.context = context
6366
this.watchMcpSettingsFile()
6467
this.initializeMcpServers()
6568
}
@@ -98,7 +101,7 @@ export class McpHub {
98101
mcpSettingsFilePath,
99102
`{
100103
"mcpServers": {
101-
104+
102105
}
103106
}`,
104107
)
@@ -136,12 +139,64 @@ export class McpHub {
136139
)
137140
}
138141

142+
private async fetchDefaultSettings(): Promise<Record<string, any>> {
143+
try {
144+
const response = await fetch(`${PEARAI_URL}/getDefaultAgentMCPSettings`)
145+
if (!response.ok) {
146+
throw new Error(`HTTP error! status: ${response.status}`)
147+
}
148+
const data = await response.json()
149+
if (data && data.mcpServers) {
150+
return data.mcpServers
151+
}
152+
return {}
153+
} catch (error) {
154+
console.error("Failed to fetch default MCP settings:", error)
155+
return {}
156+
}
157+
}
158+
159+
private async getPearAiApiKey(): Promise<string | null> {
160+
try {
161+
const token = await this.context.secrets.get("pearai-token")
162+
return token || null
163+
} catch (error) {
164+
console.error("Failed to get PearAI token from secrets:", error)
165+
return null
166+
}
167+
}
168+
139169
private async initializeMcpServers(): Promise<void> {
140170
try {
141171
const settingsPath = await this.getMcpSettingsFilePath()
142172
const content = await fs.readFile(settingsPath, "utf-8")
143173
const config = JSON.parse(content)
144-
await this.updateServerConnections(config.mcpServers || {})
174+
175+
// Fetch default settings
176+
const defaultSettings = await this.fetchDefaultSettings()
177+
// Only add new servers from default settings that don't exist in current settings
178+
const mergedServers = { ...(config.mcpServers || {}) }
179+
for (const [serverName, serverConfig] of Object.entries(defaultSettings)) {
180+
if (!mergedServers[serverName]) {
181+
mergedServers[serverName] = serverConfig
182+
}
183+
184+
// If this is the pearai server, check login status and update API key
185+
if (serverName === "pearai") {
186+
const apiKey = await this.getPearAiApiKey()
187+
if (apiKey) {
188+
mergedServers[serverName] = {
189+
...serverConfig,
190+
args: ["pearai-mcp", apiKey],
191+
}
192+
}
193+
}
194+
}
195+
196+
// Update the settings file with merged settings
197+
await fs.writeFile(settingsPath, JSON.stringify({ mcpServers: mergedServers }, null, 2))
198+
199+
await this.updateServerConnections(mergedServers)
145200
} catch (error) {
146201
console.error("Failed to initialize MCP servers:", error)
147202
}
@@ -450,6 +505,52 @@ export class McpHub {
450505
})
451506
}
452507

508+
public async clearPearAiApiKey(): Promise<void> {
509+
try {
510+
const settingsPath = await this.getMcpSettingsFilePath()
511+
const content = await fs.readFile(settingsPath, "utf-8")
512+
const config = JSON.parse(content)
513+
514+
if (config.mcpServers?.pearai) {
515+
config.mcpServers.pearai = {
516+
...config.mcpServers.pearai,
517+
args: ["pearai-mcp", "<PEARAI_API_KEY>"],
518+
}
519+
520+
await fs.writeFile(settingsPath, JSON.stringify(config, null, 2))
521+
await this.updateServerConnections(config.mcpServers)
522+
vscode.window.showInformationMessage("PearAI API key cleared successfully")
523+
}
524+
} catch (error) {
525+
console.error("Failed to clear PearAI API key:", error)
526+
vscode.window.showErrorMessage("Failed to clear PearAI API key")
527+
throw error
528+
}
529+
}
530+
531+
public async updatePearAiApiKey(apiKey: string): Promise<void> {
532+
try {
533+
const settingsPath = await this.getMcpSettingsFilePath()
534+
const content = await fs.readFile(settingsPath, "utf-8")
535+
const config = JSON.parse(content)
536+
537+
if (config.mcpServers?.pearai) {
538+
config.mcpServers.pearai = {
539+
...config.mcpServers.pearai,
540+
args: ["pearai-mcp", apiKey],
541+
}
542+
543+
await fs.writeFile(settingsPath, JSON.stringify(config, null, 2))
544+
await this.updateServerConnections(config.mcpServers)
545+
vscode.window.showInformationMessage("PearAI API key updated successfully")
546+
}
547+
} catch (error) {
548+
console.error("Failed to update PearAI API key:", error)
549+
vscode.window.showErrorMessage("Failed to update PearAI API key")
550+
throw error
551+
}
552+
}
553+
453554
public async toggleServerDisabled(serverName: string, disabled: boolean): Promise<void> {
454555
let settingsPath: string
455556
try {

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
}

src/shared/globalFileNames.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ export const GlobalFileNames = {
44
glamaModels: "glama_models.json",
55
openRouterModels: "openrouter_models.json",
66
requestyModels: "requesty_models.json",
7-
mcpSettings: "cline_mcp_settings.json",
7+
mcpSettings: "pearai_agent_mcp_settings.json",
88
unboundModels: "unbound_models.json",
99
}

0 commit comments

Comments
 (0)