@opensumi/ide-ai-native 3.7.2-next-1739859371.0 → 3.7.2-next-1740013940.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/browser/ai-core.contribution.d.ts +3 -0
- package/lib/browser/ai-core.contribution.d.ts.map +1 -1
- package/lib/browser/ai-core.contribution.js +68 -2
- package/lib/browser/ai-core.contribution.js.map +1 -1
- package/lib/browser/chat/chat-model.d.ts +2 -2
- package/lib/browser/chat/chat-model.d.ts.map +1 -1
- package/lib/browser/chat/chat-model.js +16 -5
- package/lib/browser/chat/chat-model.js.map +1 -1
- package/lib/browser/chat/chat-proxy.service.d.ts +4 -0
- package/lib/browser/chat/chat-proxy.service.d.ts.map +1 -1
- package/lib/browser/chat/chat-proxy.service.js +43 -0
- package/lib/browser/chat/chat-proxy.service.js.map +1 -1
- package/lib/browser/chat/chat.view.d.ts.map +1 -1
- package/lib/browser/chat/chat.view.js +29 -2
- package/lib/browser/chat/chat.view.js.map +1 -1
- package/lib/browser/components/ChatContext/ContextSelector.d.ts +12 -0
- package/lib/browser/components/ChatContext/ContextSelector.d.ts.map +1 -0
- package/lib/browser/components/ChatContext/ContextSelector.js +113 -0
- package/lib/browser/components/ChatContext/ContextSelector.js.map +1 -0
- package/lib/browser/components/ChatContext/index.d.ts +4 -0
- package/lib/browser/components/ChatContext/index.d.ts.map +1 -0
- package/lib/browser/components/ChatContext/index.js +84 -0
- package/lib/browser/components/ChatContext/index.js.map +1 -0
- package/lib/browser/components/ChatContext/style.module.less +189 -0
- package/lib/browser/components/ChatInput.d.ts.map +1 -1
- package/lib/browser/components/ChatInput.js.map +1 -1
- package/lib/browser/components/ChatReply.d.ts.map +1 -1
- package/lib/browser/components/ChatReply.js +25 -0
- package/lib/browser/components/ChatReply.js.map +1 -1
- package/lib/browser/components/ChatToolRender.d.ts +6 -0
- package/lib/browser/components/ChatToolRender.d.ts.map +1 -0
- package/lib/browser/components/ChatToolRender.js +53 -0
- package/lib/browser/components/ChatToolRender.js.map +1 -0
- package/lib/browser/components/ChatToolRender.module.less +86 -0
- package/lib/browser/components/components.module.less +32 -31
- package/lib/browser/components/utils.d.ts +2 -2
- package/lib/browser/context/llm-context.contribution.d.ts +7 -0
- package/lib/browser/context/llm-context.contribution.d.ts.map +1 -0
- package/lib/browser/context/llm-context.contribution.js +21 -0
- package/lib/browser/context/llm-context.contribution.js.map +1 -0
- package/lib/browser/context/llm-context.service.d.ts +24 -0
- package/lib/browser/context/llm-context.service.d.ts.map +1 -0
- package/lib/browser/context/llm-context.service.js +136 -0
- package/lib/browser/context/llm-context.service.js.map +1 -0
- package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.d.ts +2 -2
- package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.d.ts.map +1 -1
- package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.js.map +1 -1
- package/lib/browser/contrib/intelligent-completions/intelligent-completions.feature.registry.d.ts +4 -0
- package/lib/browser/contrib/intelligent-completions/intelligent-completions.feature.registry.d.ts.map +1 -1
- package/lib/browser/contrib/intelligent-completions/intelligent-completions.feature.registry.js +7 -0
- package/lib/browser/contrib/intelligent-completions/intelligent-completions.feature.registry.js.map +1 -1
- package/lib/browser/index.d.ts +11 -3
- package/lib/browser/index.d.ts.map +1 -1
- package/lib/browser/index.js +56 -3
- package/lib/browser/index.js.map +1 -1
- package/lib/browser/mcp/mcp-server-proxy.service.d.ts +25 -0
- package/lib/browser/mcp/mcp-server-proxy.service.d.ts.map +1 -0
- package/lib/browser/mcp/mcp-server-proxy.service.js +56 -0
- package/lib/browser/mcp/mcp-server-proxy.service.js.map +1 -0
- package/lib/browser/mcp/mcp-server.feature.registry.d.ts +16 -0
- package/lib/browser/mcp/mcp-server.feature.registry.d.ts.map +1 -0
- package/lib/browser/mcp/mcp-server.feature.registry.js +53 -0
- package/lib/browser/mcp/mcp-server.feature.registry.js.map +1 -0
- package/lib/browser/mcp/mcp-tools-dialog.module.less +44 -0
- package/lib/browser/mcp/mcp-tools-dialog.view.d.ts +8 -0
- package/lib/browser/mcp/mcp-tools-dialog.view.d.ts.map +1 -0
- package/lib/browser/mcp/mcp-tools-dialog.view.js +16 -0
- package/lib/browser/mcp/mcp-tools-dialog.view.js.map +1 -0
- package/lib/browser/mcp/tools/createNewFileWithText.d.ts +9 -0
- package/lib/browser/mcp/tools/createNewFileWithText.d.ts.map +1 -0
- package/lib/browser/mcp/tools/createNewFileWithText.js +83 -0
- package/lib/browser/mcp/tools/createNewFileWithText.js.map +1 -0
- package/lib/browser/mcp/tools/findFilesByNameSubstring.d.ts +9 -0
- package/lib/browser/mcp/tools/findFilesByNameSubstring.d.ts.map +1 -0
- package/lib/browser/mcp/tools/findFilesByNameSubstring.js +92 -0
- package/lib/browser/mcp/tools/findFilesByNameSubstring.js.map +1 -0
- package/lib/browser/mcp/tools/getCurrentFilePath.d.ts +8 -0
- package/lib/browser/mcp/tools/getCurrentFilePath.d.ts.map +1 -0
- package/lib/browser/mcp/tools/getCurrentFilePath.js +49 -0
- package/lib/browser/mcp/tools/getCurrentFilePath.js.map +1 -0
- package/lib/browser/mcp/tools/getDiagnosticsByPath.d.ts +10 -0
- package/lib/browser/mcp/tools/getDiagnosticsByPath.d.ts.map +1 -0
- package/lib/browser/mcp/tools/getDiagnosticsByPath.js +119 -0
- package/lib/browser/mcp/tools/getDiagnosticsByPath.js.map +1 -0
- package/lib/browser/mcp/tools/getFileTextByPath.d.ts +9 -0
- package/lib/browser/mcp/tools/getFileTextByPath.d.ts.map +1 -0
- package/lib/browser/mcp/tools/getFileTextByPath.js +97 -0
- package/lib/browser/mcp/tools/getFileTextByPath.js.map +1 -0
- package/lib/browser/mcp/tools/getOpenEditorFileDiagnostics.d.ts +11 -0
- package/lib/browser/mcp/tools/getOpenEditorFileDiagnostics.d.ts.map +1 -0
- package/lib/browser/mcp/tools/getOpenEditorFileDiagnostics.js +119 -0
- package/lib/browser/mcp/tools/getOpenEditorFileDiagnostics.js.map +1 -0
- package/lib/browser/mcp/tools/getOpenEditorFileText.d.ts +8 -0
- package/lib/browser/mcp/tools/getOpenEditorFileText.d.ts.map +1 -0
- package/lib/browser/mcp/tools/getOpenEditorFileText.js +50 -0
- package/lib/browser/mcp/tools/getOpenEditorFileText.js.map +1 -0
- package/lib/browser/mcp/tools/getSelectedText.d.ts +8 -0
- package/lib/browser/mcp/tools/getSelectedText.d.ts.map +1 -0
- package/lib/browser/mcp/tools/getSelectedText.js +57 -0
- package/lib/browser/mcp/tools/getSelectedText.js.map +1 -0
- package/lib/browser/mcp/tools/handlers/ListDir.d.ts +21 -0
- package/lib/browser/mcp/tools/handlers/ListDir.d.ts.map +1 -0
- package/lib/browser/mcp/tools/handlers/ListDir.js +112 -0
- package/lib/browser/mcp/tools/handlers/ListDir.js.map +1 -0
- package/lib/browser/mcp/tools/handlers/ReadFile.d.ts +47 -0
- package/lib/browser/mcp/tools/handlers/ReadFile.d.ts.map +1 -0
- package/lib/browser/mcp/tools/handlers/ReadFile.js +147 -0
- package/lib/browser/mcp/tools/handlers/ReadFile.js.map +1 -0
- package/lib/browser/mcp/tools/listDir.d.ts +8 -0
- package/lib/browser/mcp/tools/listDir.d.ts.map +1 -0
- package/lib/browser/mcp/tools/listDir.js +65 -0
- package/lib/browser/mcp/tools/listDir.js.map +1 -0
- package/lib/browser/mcp/tools/readFile.d.ts +8 -0
- package/lib/browser/mcp/tools/readFile.d.ts.map +1 -0
- package/lib/browser/mcp/tools/readFile.js +82 -0
- package/lib/browser/mcp/tools/readFile.js.map +1 -0
- package/lib/browser/mcp/tools/replaceOpenEditorFile.d.ts +8 -0
- package/lib/browser/mcp/tools/replaceOpenEditorFile.d.ts.map +1 -0
- package/lib/browser/mcp/tools/replaceOpenEditorFile.js +79 -0
- package/lib/browser/mcp/tools/replaceOpenEditorFile.js.map +1 -0
- package/lib/browser/mcp/tools/replaceOpenEditorFileByDiffPreviewer.d.ts +8 -0
- package/lib/browser/mcp/tools/replaceOpenEditorFileByDiffPreviewer.d.ts.map +1 -0
- package/lib/browser/mcp/tools/replaceOpenEditorFileByDiffPreviewer.js +84 -0
- package/lib/browser/mcp/tools/replaceOpenEditorFileByDiffPreviewer.js.map +1 -0
- package/lib/browser/mcp/tools/runTerminalCmd.d.ts +18 -0
- package/lib/browser/mcp/tools/runTerminalCmd.d.ts.map +1 -0
- package/lib/browser/mcp/tools/runTerminalCmd.js +96 -0
- package/lib/browser/mcp/tools/runTerminalCmd.js.map +1 -0
- package/lib/browser/preferences/schema.d.ts.map +1 -1
- package/lib/browser/preferences/schema.js +60 -0
- package/lib/browser/preferences/schema.js.map +1 -1
- package/lib/browser/types.d.ts +64 -3
- package/lib/browser/types.d.ts.map +1 -1
- package/lib/browser/types.js +5 -1
- package/lib/browser/types.js.map +1 -1
- package/lib/browser/widget/inline-chat/inline-chat-editor.controller.js +1 -1
- package/lib/browser/widget/inline-chat/inline-chat-editor.controller.js.map +1 -1
- package/lib/browser/widget/inline-diff/inline-diff.controller.d.ts.map +1 -1
- package/lib/browser/widget/inline-input/inline-input.controller.d.ts.map +1 -1
- package/lib/common/index.d.ts +9 -0
- package/lib/common/index.d.ts.map +1 -1
- package/lib/common/index.js +4 -1
- package/lib/common/index.js.map +1 -1
- package/lib/common/llm-context.d.ts +37 -0
- package/lib/common/llm-context.d.ts.map +1 -0
- package/lib/common/llm-context.js +5 -0
- package/lib/common/llm-context.js.map +1 -0
- package/lib/common/mcp-server-manager.d.ts +40 -0
- package/lib/common/mcp-server-manager.d.ts.map +1 -0
- package/lib/common/mcp-server-manager.js +6 -0
- package/lib/common/mcp-server-manager.js.map +1 -0
- package/lib/common/tool-invocation-registry.d.ts +91 -0
- package/lib/common/tool-invocation-registry.d.ts.map +1 -0
- package/lib/common/tool-invocation-registry.js +90 -0
- package/lib/common/tool-invocation-registry.js.map +1 -0
- package/lib/common/types.d.ts +17 -0
- package/lib/common/types.d.ts.map +1 -1
- package/lib/node/anthropic/anthropic-language-model.d.ts +9 -0
- package/lib/node/anthropic/anthropic-language-model.d.ts.map +1 -0
- package/lib/node/anthropic/anthropic-language-model.js +26 -0
- package/lib/node/anthropic/anthropic-language-model.js.map +1 -0
- package/lib/node/base-language-model.d.ts +14 -0
- package/lib/node/base-language-model.d.ts.map +1 -0
- package/lib/node/base-language-model.js +136 -0
- package/lib/node/base-language-model.js.map +1 -0
- package/lib/node/deepseek/deepseek-language-model.d.ts +9 -0
- package/lib/node/deepseek/deepseek-language-model.d.ts.map +1 -0
- package/lib/node/deepseek/deepseek-language-model.js +26 -0
- package/lib/node/deepseek/deepseek-language-model.js.map +1 -0
- package/lib/node/index.d.ts.map +1 -1
- package/lib/node/index.js +19 -0
- package/lib/node/index.js.map +1 -1
- package/lib/node/mcp/sumi-mcp-server.d.ts +91 -0
- package/lib/node/mcp/sumi-mcp-server.d.ts.map +1 -0
- package/lib/node/mcp/sumi-mcp-server.js +172 -0
- package/lib/node/mcp/sumi-mcp-server.js.map +1 -0
- package/lib/node/mcp-server-manager-impl.d.ts +27 -0
- package/lib/node/mcp-server-manager-impl.d.ts.map +1 -0
- package/lib/node/mcp-server-manager-impl.js +127 -0
- package/lib/node/mcp-server-manager-impl.js.map +1 -0
- package/lib/node/mcp-server.d.ts +207 -0
- package/lib/node/mcp-server.d.ts.map +1 -0
- package/lib/node/mcp-server.js +91 -0
- package/lib/node/mcp-server.js.map +1 -0
- package/lib/node/openai/openai-language-model.d.ts +9 -0
- package/lib/node/openai/openai-language-model.d.ts.map +1 -0
- package/lib/node/openai/openai-language-model.js +29 -0
- package/lib/node/openai/openai-language-model.js.map +1 -0
- package/package.json +34 -22
- package/src/browser/ai-core.contribution.ts +77 -1
- package/src/browser/chat/chat-model.ts +24 -6
- package/src/browser/chat/chat-proxy.service.ts +42 -0
- package/src/browser/chat/chat.view.tsx +59 -6
- package/src/browser/components/ChatContext/ContextSelector.tsx +177 -0
- package/src/browser/components/ChatContext/index.tsx +135 -0
- package/src/browser/components/ChatContext/style.module.less +189 -0
- package/src/browser/components/ChatInput.tsx +1 -0
- package/src/browser/components/ChatReply.tsx +32 -0
- package/src/browser/components/ChatToolRender.module.less +86 -0
- package/src/browser/components/ChatToolRender.tsx +77 -0
- package/src/browser/components/components.module.less +32 -31
- package/src/browser/context/llm-context.contribution.ts +14 -0
- package/src/browser/context/llm-context.service.ts +156 -0
- package/src/browser/contrib/intelligent-completions/intelligent-completions.controller.ts +2 -3
- package/src/browser/contrib/intelligent-completions/intelligent-completions.feature.registry.ts +11 -0
- package/src/browser/index.ts +68 -4
- package/src/browser/mcp/mcp-server-proxy.service.ts +53 -0
- package/src/browser/mcp/mcp-server.feature.registry.ts +54 -0
- package/src/browser/mcp/mcp-tools-dialog.module.less +44 -0
- package/src/browser/mcp/mcp-tools-dialog.view.tsx +24 -0
- package/src/browser/mcp/tools/createNewFileWithText.ts +83 -0
- package/src/browser/mcp/tools/findFilesByNameSubstring.ts +93 -0
- package/src/browser/mcp/tools/getCurrentFilePath.ts +49 -0
- package/src/browser/mcp/tools/getDiagnosticsByPath.ts +123 -0
- package/src/browser/mcp/tools/getFileTextByPath.ts +97 -0
- package/src/browser/mcp/tools/getOpenEditorFileDiagnostics.ts +121 -0
- package/src/browser/mcp/tools/getOpenEditorFileText.ts +50 -0
- package/src/browser/mcp/tools/getSelectedText.ts +57 -0
- package/src/browser/mcp/tools/handlers/ListDir.ts +117 -0
- package/src/browser/mcp/tools/handlers/ReadFile.ts +174 -0
- package/src/browser/mcp/tools/listDir.ts +66 -0
- package/src/browser/mcp/tools/readFile.ts +82 -0
- package/src/browser/mcp/tools/replaceOpenEditorFile.ts +80 -0
- package/src/browser/mcp/tools/replaceOpenEditorFileByDiffPreviewer.ts +91 -0
- package/src/browser/mcp/tools/runTerminalCmd.ts +107 -0
- package/src/browser/preferences/schema.ts +60 -0
- package/src/browser/types.ts +92 -3
- package/src/browser/widget/inline-chat/inline-chat-editor.controller.ts +1 -1
- package/src/browser/widget/inline-diff/inline-diff.controller.ts +1 -1
- package/src/browser/widget/inline-input/inline-input.controller.ts +1 -1
- package/src/common/index.ts +14 -0
- package/src/common/llm-context.ts +41 -0
- package/src/common/mcp-server-manager.ts +46 -0
- package/src/common/tool-invocation-registry.ts +170 -0
- package/src/common/types.ts +22 -0
- package/src/node/anthropic/anthropic-language-model.ts +25 -0
- package/src/node/base-language-model.ts +163 -0
- package/src/node/deepseek/deepseek-language-model.ts +25 -0
- package/src/node/index.ts +21 -0
- package/src/node/mcp/sumi-mcp-server.ts +197 -0
- package/src/node/mcp-server-manager-impl.ts +148 -0
- package/src/node/mcp-server.ts +126 -0
- package/src/node/openai/openai-language-model.ts +25 -0
package/src/node/index.ts
CHANGED
|
@@ -3,6 +3,11 @@ import { AIBackSerivcePath, AIBackSerivceToken } from '@opensumi/ide-core-common
|
|
|
3
3
|
import { NodeModule } from '@opensumi/ide-core-node';
|
|
4
4
|
import { BaseAIBackService } from '@opensumi/ide-core-node/lib/ai-native/base-back.service';
|
|
5
5
|
|
|
6
|
+
import { SumiMCPServerProxyServicePath, TokenMCPServerProxyService } from '../common';
|
|
7
|
+
import { ToolInvocationRegistryManager, ToolInvocationRegistryManagerImpl } from '../common/tool-invocation-registry';
|
|
8
|
+
|
|
9
|
+
import { SumiMCPServerBackend } from './mcp/sumi-mcp-server';
|
|
10
|
+
|
|
6
11
|
@Injectable()
|
|
7
12
|
export class AINativeModule extends NodeModule {
|
|
8
13
|
providers: Provider[] = [
|
|
@@ -10,6 +15,14 @@ export class AINativeModule extends NodeModule {
|
|
|
10
15
|
token: AIBackSerivceToken,
|
|
11
16
|
useClass: BaseAIBackService,
|
|
12
17
|
},
|
|
18
|
+
{
|
|
19
|
+
token: ToolInvocationRegistryManager,
|
|
20
|
+
useClass: ToolInvocationRegistryManagerImpl,
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
token: TokenMCPServerProxyService,
|
|
24
|
+
useClass: SumiMCPServerBackend,
|
|
25
|
+
},
|
|
13
26
|
];
|
|
14
27
|
|
|
15
28
|
backServices = [
|
|
@@ -17,5 +30,13 @@ export class AINativeModule extends NodeModule {
|
|
|
17
30
|
servicePath: AIBackSerivcePath,
|
|
18
31
|
token: AIBackSerivceToken,
|
|
19
32
|
},
|
|
33
|
+
// {
|
|
34
|
+
// servicePath: MCPServerManagerPath,
|
|
35
|
+
// token: MCPServerManager,
|
|
36
|
+
// },
|
|
37
|
+
{
|
|
38
|
+
servicePath: SumiMCPServerProxyServicePath,
|
|
39
|
+
token: TokenMCPServerProxyService,
|
|
40
|
+
},
|
|
20
41
|
];
|
|
21
42
|
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
// 想要通过 MCP 的方式暴露 Opensumi 的 IDE 能力,就需要 Node.js 层打通 MCP 的通信
|
|
2
|
+
// 因为大部分 MCP 功能的实现在前端,因此需要再这里做前后端通信
|
|
3
|
+
|
|
4
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
5
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
6
|
+
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
7
|
+
|
|
8
|
+
import { Autowired, Injectable } from '@opensumi/di';
|
|
9
|
+
import { RPCService } from '@opensumi/ide-connection';
|
|
10
|
+
import { ILogger } from '@opensumi/ide-core-common';
|
|
11
|
+
import { INodeLogger } from '@opensumi/ide-core-node';
|
|
12
|
+
|
|
13
|
+
import { ISumiMCPServerBackend } from '../../common';
|
|
14
|
+
import { MCPServerDescription, MCPServerManager } from '../../common/mcp-server-manager';
|
|
15
|
+
import { IToolInvocationRegistryManager, ToolInvocationRegistryManager } from '../../common/tool-invocation-registry';
|
|
16
|
+
import { IMCPServerProxyService, MCPTool } from '../../common/types';
|
|
17
|
+
import { IMCPServer } from '../mcp-server';
|
|
18
|
+
import { MCPServerManagerImpl } from '../mcp-server-manager-impl';
|
|
19
|
+
|
|
20
|
+
// 每个 BrowserTab 都对应了一个 SumiMCPServerBackend 实例
|
|
21
|
+
// SumiMCPServerBackend 需要做的事情:
|
|
22
|
+
// 维护 Browser 端工具的注册和调用
|
|
23
|
+
// 处理第三方 MCP Server 的注册和调用
|
|
24
|
+
|
|
25
|
+
@Injectable({ multiple: true })
|
|
26
|
+
export class SumiMCPServerBackend extends RPCService<IMCPServerProxyService> implements ISumiMCPServerBackend {
|
|
27
|
+
// 这里需要考虑不同的 BrowserTab 的区分问题,目前的 POC 所有的 Tab 都会注册到 tools 中
|
|
28
|
+
// 后续需要区分不同的 Tab 对应的实例
|
|
29
|
+
private readonly mcpServerManager: MCPServerManagerImpl;
|
|
30
|
+
|
|
31
|
+
@Autowired(ToolInvocationRegistryManager)
|
|
32
|
+
private readonly toolInvocationRegistryManager: IToolInvocationRegistryManager;
|
|
33
|
+
|
|
34
|
+
@Autowired(INodeLogger)
|
|
35
|
+
private readonly logger: ILogger;
|
|
36
|
+
|
|
37
|
+
private server: Server | undefined;
|
|
38
|
+
|
|
39
|
+
// 对应 BrowserTab 的 clientId
|
|
40
|
+
private clientId: string = '';
|
|
41
|
+
|
|
42
|
+
constructor() {
|
|
43
|
+
super();
|
|
44
|
+
this.mcpServerManager = new MCPServerManagerImpl(this.toolInvocationRegistryManager, this.logger);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
public setConnectionClientId(clientId: string) {
|
|
48
|
+
this.clientId = clientId;
|
|
49
|
+
this.mcpServerManager.setClientId(clientId);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async getMCPTools() {
|
|
53
|
+
if (!this.client) {
|
|
54
|
+
throw new Error('SUMI MCP RPC Client not initialized');
|
|
55
|
+
}
|
|
56
|
+
// 获取 MCP 工具
|
|
57
|
+
const tools = await this.client.$getMCPTools();
|
|
58
|
+
this.logger.log('[Node backend] SUMI MCP tools', tools);
|
|
59
|
+
return tools;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async callMCPTool(name: string, args: any) {
|
|
63
|
+
if (!this.client) {
|
|
64
|
+
throw new Error('SUMI MCP RPC Client not initialized');
|
|
65
|
+
}
|
|
66
|
+
return await this.client.$callMCPTool(name, args);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
getServer() {
|
|
70
|
+
return this.server;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// TODO 这里涉及到 Chat Stream Call 中带上 ClientID,具体方案需要进一步讨论
|
|
74
|
+
async getAllMCPTools(): Promise<MCPTool[]> {
|
|
75
|
+
const registry = this.toolInvocationRegistryManager.getRegistry(this.clientId);
|
|
76
|
+
return registry.getAllFunctions().map((tool) => ({
|
|
77
|
+
name: tool.name || 'no-name',
|
|
78
|
+
description: tool.description || 'no-description',
|
|
79
|
+
inputSchema: tool.parameters,
|
|
80
|
+
providerName: tool.providerName || 'no-provider-name',
|
|
81
|
+
}));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
public async initBuiltinMCPServer() {
|
|
85
|
+
const builtinMCPServer = new BuiltinMCPServer(this, this.logger);
|
|
86
|
+
this.mcpServerManager.setClientId(this.clientId);
|
|
87
|
+
await this.mcpServerManager.initBuiltinServer(builtinMCPServer);
|
|
88
|
+
this.client?.$updateMCPServers();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
public async initExternalMCPServers(servers: MCPServerDescription[]) {
|
|
92
|
+
this.mcpServerManager.setClientId(this.clientId);
|
|
93
|
+
await this.mcpServerManager.addExternalMCPServers(servers);
|
|
94
|
+
this.client?.$updateMCPServers();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async initExposedMCPServer() {
|
|
98
|
+
// 初始化 MCP Server
|
|
99
|
+
this.server = new Server(
|
|
100
|
+
{
|
|
101
|
+
name: 'sumi-ide-mcp-server',
|
|
102
|
+
version: '0.2.0',
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
capabilities: {
|
|
106
|
+
tools: {},
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
// 设置工具列表请求处理器
|
|
112
|
+
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
113
|
+
const tools = await this.getMCPTools();
|
|
114
|
+
return { tools };
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// 设置工具调用请求处理器
|
|
118
|
+
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
119
|
+
try {
|
|
120
|
+
const { name, arguments: args } = request.params;
|
|
121
|
+
return await this.callMCPTool(name, args);
|
|
122
|
+
} catch (error) {
|
|
123
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
124
|
+
return {
|
|
125
|
+
content: [{ type: 'text', text: `Error: ${errorMessage}` }],
|
|
126
|
+
isError: true,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
return this.server;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export const TokenBuiltinMCPServer = Symbol('TokenBuiltinMCPServer');
|
|
136
|
+
|
|
137
|
+
export class BuiltinMCPServer implements IMCPServer {
|
|
138
|
+
private started: boolean = true;
|
|
139
|
+
|
|
140
|
+
constructor(private readonly sumiMCPServer: SumiMCPServerBackend, private readonly logger: ILogger) {}
|
|
141
|
+
|
|
142
|
+
isStarted(): boolean {
|
|
143
|
+
return this.started;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
getServerName(): string {
|
|
147
|
+
return 'sumi-builtin';
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
async start(): Promise<void> {
|
|
151
|
+
if (this.started) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
// TODO 考虑 MCP Server 的对外暴露
|
|
155
|
+
// await this.sumiMCPServer.initMCPServer();
|
|
156
|
+
this.started = true;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
async callTool(toolName: string, arg_string: string): Promise<any> {
|
|
160
|
+
if (!this.started) {
|
|
161
|
+
throw new Error('MCP Server not started');
|
|
162
|
+
}
|
|
163
|
+
let args;
|
|
164
|
+
try {
|
|
165
|
+
args = JSON.parse(arg_string);
|
|
166
|
+
} catch (error) {
|
|
167
|
+
this.logger.error(
|
|
168
|
+
`Failed to parse arguments for calling tool "${toolName}" in Builtin MCP server.
|
|
169
|
+
Invalid JSON: ${arg_string}`,
|
|
170
|
+
error,
|
|
171
|
+
);
|
|
172
|
+
throw error;
|
|
173
|
+
}
|
|
174
|
+
return this.sumiMCPServer.callMCPTool(toolName, args);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
async getTools(): ReturnType<Client['listTools']> {
|
|
178
|
+
if (!this.started) {
|
|
179
|
+
throw new Error('MCP Server not started');
|
|
180
|
+
}
|
|
181
|
+
const tools = await this.sumiMCPServer.getMCPTools();
|
|
182
|
+
this.logger.debug('[BuiltinMCPServer] getTools', tools);
|
|
183
|
+
return { tools } as any;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
update(_command: string, _args?: string[], _env?: { [key: string]: string }): void {
|
|
187
|
+
// No-op for builtin server as it doesn't need command/args/env updates
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
stop(): void {
|
|
191
|
+
if (!this.started) {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
// No explicit cleanup needed for in-memory server
|
|
195
|
+
this.started = false;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { ILogger } from '@opensumi/ide-core-common';
|
|
2
|
+
|
|
3
|
+
import { MCPServerDescription, MCPServerManager, MCPTool } from '../common/mcp-server-manager';
|
|
4
|
+
import { IToolInvocationRegistryManager, ToolRequest } from '../common/tool-invocation-registry';
|
|
5
|
+
|
|
6
|
+
import { BuiltinMCPServer } from './mcp/sumi-mcp-server';
|
|
7
|
+
import { IMCPServer, MCPServerImpl } from './mcp-server';
|
|
8
|
+
|
|
9
|
+
// 这应该是 Browser Tab 维度的,每个 Tab 对应一个 MCPServerManagerImpl
|
|
10
|
+
export class MCPServerManagerImpl implements MCPServerManager {
|
|
11
|
+
protected servers: Map<string, IMCPServer> = new Map();
|
|
12
|
+
|
|
13
|
+
// 当前实例对应的 clientId
|
|
14
|
+
private clientId: string;
|
|
15
|
+
|
|
16
|
+
constructor(
|
|
17
|
+
private readonly toolInvocationRegistryManager: IToolInvocationRegistryManager,
|
|
18
|
+
private readonly logger: ILogger,
|
|
19
|
+
) {}
|
|
20
|
+
|
|
21
|
+
setClientId(clientId: string) {
|
|
22
|
+
this.clientId = clientId;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async stopServer(serverName: string): Promise<void> {
|
|
26
|
+
const server = this.servers.get(serverName);
|
|
27
|
+
if (!server) {
|
|
28
|
+
throw new Error(`MCP server "${serverName}" not found.`);
|
|
29
|
+
}
|
|
30
|
+
server.stop();
|
|
31
|
+
this.logger.log(`MCP server "${serverName}" stopped.`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async getStartedServers(): Promise<string[]> {
|
|
35
|
+
const startedServers: string[] = [];
|
|
36
|
+
for (const [name, server] of this.servers.entries()) {
|
|
37
|
+
if (server.isStarted()) {
|
|
38
|
+
startedServers.push(name);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return startedServers;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
callTool(serverName: string, toolName: string, arg_string: string): ReturnType<IMCPServer['callTool']> {
|
|
45
|
+
const server = this.servers.get(serverName);
|
|
46
|
+
if (!server) {
|
|
47
|
+
throw new Error(`MCP server "${toolName}" not found.`);
|
|
48
|
+
}
|
|
49
|
+
return server.callTool(toolName, arg_string);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async startServer(serverName: string): Promise<void> {
|
|
53
|
+
const server = this.servers.get(serverName);
|
|
54
|
+
if (!server) {
|
|
55
|
+
throw new Error(`MCP server "${serverName}" not found.`);
|
|
56
|
+
}
|
|
57
|
+
await server.start();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async getServerNames(): Promise<string[]> {
|
|
61
|
+
return Array.from(this.servers.keys());
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
private convertToToolRequest(tool: MCPTool, serverName: string): ToolRequest {
|
|
65
|
+
const id = `mcp_${serverName}_${tool.name}`;
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
id,
|
|
69
|
+
name: id,
|
|
70
|
+
providerName: serverName,
|
|
71
|
+
parameters: tool.inputSchema,
|
|
72
|
+
description: tool.description,
|
|
73
|
+
handler: async (arg_string: string) => {
|
|
74
|
+
try {
|
|
75
|
+
const res = await this.callTool(serverName, tool.name, arg_string);
|
|
76
|
+
this.logger.debug(`[MCP: ${serverName}] ${tool.name} called with ${arg_string}`);
|
|
77
|
+
this.logger.debug('Tool execution result:', res);
|
|
78
|
+
return JSON.stringify(res);
|
|
79
|
+
} catch (error) {
|
|
80
|
+
this.logger.error(`Error in tool handler for ${tool.name} on MCP server ${serverName}:`, error);
|
|
81
|
+
throw error;
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
public async registerTools(serverName: string): Promise<void> {
|
|
88
|
+
const server = this.servers.get(serverName);
|
|
89
|
+
if (!server) {
|
|
90
|
+
throw new Error(`MCP server "${serverName}" not found.`);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const { tools } = await server.getTools();
|
|
94
|
+
const toolRequests: ToolRequest[] = tools.map((tool) => this.convertToToolRequest(tool, serverName));
|
|
95
|
+
|
|
96
|
+
const registry = this.toolInvocationRegistryManager.getRegistry(this.clientId);
|
|
97
|
+
for (const toolRequest of toolRequests) {
|
|
98
|
+
registry.registerTool(toolRequest);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
public async getTools(serverName: string): ReturnType<IMCPServer['getTools']> {
|
|
103
|
+
const server = this.servers.get(serverName);
|
|
104
|
+
if (!server) {
|
|
105
|
+
throw new Error(`MCP server "${serverName}" not found.`);
|
|
106
|
+
}
|
|
107
|
+
return server.getTools();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
addOrUpdateServer(description: MCPServerDescription): void {
|
|
111
|
+
const { name, command, args, env } = description;
|
|
112
|
+
const existingServer = this.servers.get(name);
|
|
113
|
+
|
|
114
|
+
if (existingServer) {
|
|
115
|
+
existingServer.update(command, args, env);
|
|
116
|
+
} else {
|
|
117
|
+
const newServer = new MCPServerImpl(name, command, args, env, this.logger);
|
|
118
|
+
this.servers.set(name, newServer);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
addOrUpdateServerDirectly(server: IMCPServer): void {
|
|
123
|
+
this.servers.set(server.getServerName(), server);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
async initBuiltinServer(builtinMCPServer: BuiltinMCPServer): Promise<void> {
|
|
127
|
+
this.addOrUpdateServerDirectly(builtinMCPServer);
|
|
128
|
+
await this.registerTools(builtinMCPServer.getServerName());
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
async addExternalMCPServers(servers: MCPServerDescription[]): Promise<void> {
|
|
132
|
+
for (const server of servers) {
|
|
133
|
+
this.addOrUpdateServer(server);
|
|
134
|
+
await this.startServer(server.name);
|
|
135
|
+
await this.registerTools(server.name);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
removeServer(name: string): void {
|
|
140
|
+
const server = this.servers.get(name);
|
|
141
|
+
if (server) {
|
|
142
|
+
server.stop();
|
|
143
|
+
this.servers.delete(name);
|
|
144
|
+
} else {
|
|
145
|
+
this.logger.warn(`MCP server "${name}" not found.`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
// have to import with extension since the exports map is ./* -> ./dist/cjs/*
|
|
2
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
3
|
+
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
4
|
+
|
|
5
|
+
import { ILogger } from '@opensumi/ide-core-common';
|
|
6
|
+
|
|
7
|
+
export interface IMCPServer {
|
|
8
|
+
isStarted(): boolean;
|
|
9
|
+
start(): Promise<void>;
|
|
10
|
+
getServerName(): string;
|
|
11
|
+
callTool(toolName: string, arg_string: string): ReturnType<Client['callTool']>;
|
|
12
|
+
getTools(): ReturnType<Client['listTools']>;
|
|
13
|
+
update(command: string, args?: string[], env?: { [key: string]: string }): void;
|
|
14
|
+
stop(): void;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export class MCPServerImpl implements IMCPServer {
|
|
18
|
+
private name: string;
|
|
19
|
+
private command: string;
|
|
20
|
+
private args?: string[];
|
|
21
|
+
private client: Client;
|
|
22
|
+
private env?: { [key: string]: string };
|
|
23
|
+
private started: boolean = false;
|
|
24
|
+
|
|
25
|
+
constructor(
|
|
26
|
+
name: string,
|
|
27
|
+
command: string,
|
|
28
|
+
args?: string[],
|
|
29
|
+
env?: Record<string, string>,
|
|
30
|
+
private readonly logger?: ILogger,
|
|
31
|
+
) {
|
|
32
|
+
this.name = name;
|
|
33
|
+
this.command = command;
|
|
34
|
+
this.args = args;
|
|
35
|
+
this.env = env;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
isStarted(): boolean {
|
|
39
|
+
return this.started;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
getServerName(): string {
|
|
43
|
+
return this.name;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async start(): Promise<void> {
|
|
47
|
+
if (this.started) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
this.logger?.log(
|
|
51
|
+
`Starting server "${this.name}" with command: ${this.command} and args: ${this.args?.join(
|
|
52
|
+
' ',
|
|
53
|
+
)} and env: ${JSON.stringify(this.env)}`,
|
|
54
|
+
);
|
|
55
|
+
// Filter process.env to exclude undefined values
|
|
56
|
+
const sanitizedEnv: Record<string, string> = Object.fromEntries(
|
|
57
|
+
Object.entries(process.env).filter((entry): entry is [string, string] => entry[1] !== undefined),
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
const mergedEnv: Record<string, string> = {
|
|
61
|
+
...sanitizedEnv,
|
|
62
|
+
...(this.env || {}),
|
|
63
|
+
};
|
|
64
|
+
const transport = new StdioClientTransport({
|
|
65
|
+
command: this.command,
|
|
66
|
+
args: this.args,
|
|
67
|
+
env: mergedEnv,
|
|
68
|
+
});
|
|
69
|
+
transport.onerror = (error) => {
|
|
70
|
+
this.logger?.error('Transport Error:', error);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
this.client = new Client(
|
|
74
|
+
{
|
|
75
|
+
name: 'opensumi-mcp-client',
|
|
76
|
+
version: '1.0.0',
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
capabilities: {},
|
|
80
|
+
},
|
|
81
|
+
);
|
|
82
|
+
this.client.onerror = (error) => {
|
|
83
|
+
this.logger?.error('Error in MCP client:', error);
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
await this.client.connect(transport);
|
|
87
|
+
this.started = true;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async callTool(toolName: string, arg_string: string) {
|
|
91
|
+
let args;
|
|
92
|
+
try {
|
|
93
|
+
args = JSON.parse(arg_string);
|
|
94
|
+
} catch (error) {
|
|
95
|
+
this.logger?.error(
|
|
96
|
+
`Failed to parse arguments for calling tool "${toolName}" in MCP server "${this.name}" with command "${this.command}".
|
|
97
|
+
Invalid JSON: ${arg_string}`,
|
|
98
|
+
error,
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
const params = {
|
|
102
|
+
name: toolName,
|
|
103
|
+
arguments: args,
|
|
104
|
+
};
|
|
105
|
+
return this.client.callTool(params);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async getTools() {
|
|
109
|
+
return await this.client.listTools();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
update(command: string, args?: string[], env?: { [key: string]: string }): void {
|
|
113
|
+
this.command = command;
|
|
114
|
+
this.args = args;
|
|
115
|
+
this.env = env;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
stop(): void {
|
|
119
|
+
if (!this.started || !this.client) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
this.logger?.log(`Stopping MCP server "${this.name}"`);
|
|
123
|
+
this.client.close();
|
|
124
|
+
this.started = false;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { OpenAIProvider, createOpenAI } from '@ai-sdk/openai';
|
|
2
|
+
|
|
3
|
+
import { Injectable } from '@opensumi/di';
|
|
4
|
+
import { AINativeSettingSectionsId, IAIBackServiceOption } from '@opensumi/ide-core-common';
|
|
5
|
+
|
|
6
|
+
import { BaseLanguageModel } from '../base-language-model';
|
|
7
|
+
export const DeepSeekModelIdentifier = Symbol('DeepSeekModelIdentifier');
|
|
8
|
+
|
|
9
|
+
@Injectable()
|
|
10
|
+
export class OpenAIModel extends BaseLanguageModel {
|
|
11
|
+
protected initializeProvider(options: IAIBackServiceOption): OpenAIProvider {
|
|
12
|
+
const apiKey = options.apiKey;
|
|
13
|
+
if (!apiKey) {
|
|
14
|
+
throw new Error(`Please provide OpenAI API Key in preferences (${AINativeSettingSectionsId.OpenaiApiKey})`);
|
|
15
|
+
}
|
|
16
|
+
return createOpenAI({
|
|
17
|
+
apiKey,
|
|
18
|
+
baseURL: options.baseURL || 'https://dashscope.aliyuncs.com/compatible-mode/v1',
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
protected getModelIdentifier(provider: OpenAIProvider) {
|
|
23
|
+
return provider('qwen-max');
|
|
24
|
+
}
|
|
25
|
+
}
|