Skip to content

Commit 635792f

Browse files
committed
feat(copilot): support call MCP server on chat
1 parent 682a7d3 commit 635792f

14 files changed

+629
-209
lines changed

src/background.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { dialog } from 'electron'
2020
import ORMConfig from './database/database.config'
2121
import version from '@/version'
2222
import { initialize } from '@electron/remote/main'
23-
import { initMCPHandlers, cleanupMCPConnections } from './main/ai/mpc/MPCManager'
23+
import { initMCPHandlers, cleanupMCPConnections } from './main/ai/mcp/MCPManager'
2424

2525
declare const __static: string
2626

src/components/ai/Copilot.vue

+97-4
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import ConnectionsIndex from '@/views/connections/index.vue'
3838
import { CopilotMessage, CopilotRole, CopilotPresetPrompt, StreamError } from '@/types/copilot'
3939
import { needsUserInput } from '@/utils/ai/preset'
4040
import { SessionManager } from '@/utils/ai/SessionManager'
41+
import { callMCPTool, MCP_CALL_REGEX, processMCPCalls } from '@/utils/ai/mcp'
4142
4243
@Component({
4344
components: {
@@ -72,6 +73,10 @@ export default class Copilot extends Vue {
7273
content: '',
7374
}
7475
76+
get shouldProcessMCP() {
77+
return localStorage.getItem('mcpEnabled') === 'true' && this.sessionManager.getState().mcpData?.hasMCP === true
78+
}
79+
7580
/**
7681
* Finds the current connection record from ConnectionsDetail component
7782
* Returns undefined if no record is found
@@ -155,8 +160,8 @@ export default class Copilot extends Vue {
155160
this.currentPublishMsg = ''
156161
}
157162
158-
private buildMessageHistory(): Array<{ role: CopilotRole; content: string }> {
159-
const systemPrompt = this.sessionManager.getSystemPrompt(this.currentLang)
163+
private async buildMessageHistory(): Promise<Array<{ role: CopilotRole; content: string }>> {
164+
const systemPrompt = await this.sessionManager.getSystemPrompt(this.currentLang)
160165
161166
return [
162167
{
@@ -207,7 +212,7 @@ export default class Copilot extends Vue {
207212
apiKey,
208213
}),
209214
temperature: 0.8,
210-
messages: this.buildMessageHistory(),
215+
messages: await this.buildMessageHistory(),
211216
abortSignal: this.abortController.signal,
212217
onError: this.handleStreamError,
213218
})
@@ -218,7 +223,15 @@ export default class Copilot extends Vue {
218223
this.$nextTick(throttledScroll)
219224
}
220225
221-
responseMessage.content = this.responseStreamText
226+
if (this.shouldProcessMCP) {
227+
const processedContent = await processMCPCalls(this.responseStreamText)
228+
responseMessage.content = processedContent
229+
// AI TOOL CALL RESULT
230+
console.log(processedContent)
231+
} else {
232+
responseMessage.content = this.responseStreamText
233+
}
234+
222235
await this.saveAndDisplayResponse(responseMessage)
223236
}
224237
@@ -331,6 +344,17 @@ export default class Copilot extends Vue {
331344
}
332345
}
333346
347+
/**
348+
* Lifecycle hook when component is mounted
349+
*/
350+
private async mounted() {
351+
// Reload MCP data when component is mounted
352+
await this.sessionManager.reloadMCPData(this.currentLang)
353+
}
354+
355+
/**
356+
* Lifecycle hook when component is created
357+
*/
334358
private created() {
335359
this.loadMessages({ reset: true })
336360
}
@@ -377,4 +401,73 @@ export default class Copilot extends Vue {
377401
}
378402
}
379403
}
404+
405+
/* MCP Tool Call result styles */
406+
mcp-result {
407+
display: block;
408+
margin: 8px 0;
409+
padding: 12px;
410+
border-radius: 6px;
411+
font-family: monospace;
412+
white-space: pre-wrap;
413+
}
414+
415+
mcp-result[success='true'] {
416+
background-color: rgba(19, 206, 102, 0.1);
417+
border: 1px solid rgba(19, 206, 102, 0.3);
418+
}
419+
420+
mcp-result[success='false'] {
421+
background-color: rgba(245, 108, 108, 0.1);
422+
border: 1px solid rgba(245, 108, 108, 0.3);
423+
}
424+
425+
mcp-result server,
426+
mcp-result tool,
427+
mcp-result args {
428+
display: block;
429+
margin-bottom: 4px;
430+
font-weight: bold;
431+
}
432+
433+
mcp-result server::before {
434+
content: 'Server: ';
435+
color: var(--color-text-light);
436+
}
437+
438+
mcp-result tool::before {
439+
content: 'Tool: ';
440+
color: var(--color-text-light);
441+
}
442+
443+
mcp-result args::before {
444+
content: 'Arguments: ';
445+
color: var(--color-text-light);
446+
}
447+
448+
mcp-result result,
449+
mcp-result error {
450+
display: block;
451+
margin-top: 8px;
452+
padding: 8px;
453+
background-color: var(--color-bg-lighter);
454+
border-radius: 4px;
455+
overflow-x: auto;
456+
}
457+
458+
mcp-result result::before {
459+
content: 'Result:';
460+
display: block;
461+
margin-bottom: 4px;
462+
font-weight: bold;
463+
color: var(--color-text-light);
464+
}
465+
466+
mcp-result error::before {
467+
content: 'Error:';
468+
display: block;
469+
margin-bottom: 4px;
470+
font-weight: bold;
471+
color: var(--color-text-light);
472+
}
380473
</style>

src/components/ai/MCPSettings.vue

+1-8
Original file line numberDiff line numberDiff line change
@@ -117,8 +117,8 @@
117117
:loading="testingServer === name"
118118
icon="el-icon-connection"
119119
@click="testServerConnection(name, server)"
120-
>Test Connection</el-button
121120
>
121+
</el-button>
122122
<el-button size="mini" type="danger" icon="el-icon-delete" @click="removeMCPServer(name)"></el-button>
123123
</div>
124124
</div>
@@ -386,13 +386,6 @@ export default class MCPSettings extends Vue {
386386
message: `Successfully connected to server ${serverName}`,
387387
type: 'success',
388388
})
389-
390-
// Disconnect after testing
391-
try {
392-
await ipcRenderer.invoke('mcp:disconnect', serverName)
393-
} catch (disconnectError) {
394-
this.$log.error(`[MCP] Failed to disconnect: ${disconnectError}`)
395-
}
396389
} else {
397390
// If test fails, disable the server
398391
this.$set(this.serverEnabledStatus, serverName, false)

0 commit comments

Comments
 (0)