@opensumi/ide-ai-native 3.7.1-next-1737628160.0 → 3.7.1-next-1737703128.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 +31 -4
- 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 +21 -9
- package/lib/browser/chat/chat-model.js.map +1 -1
- package/lib/browser/chat/chat-proxy.service.d.ts +1 -0
- package/lib/browser/chat/chat-proxy.service.d.ts.map +1 -1
- package/lib/browser/chat/chat-proxy.service.js +11 -0
- package/lib/browser/chat/chat-proxy.service.js.map +1 -1
- package/lib/browser/components/ChatEditor.d.ts +8 -0
- package/lib/browser/components/ChatEditor.d.ts.map +1 -1
- package/lib/browser/components/ChatEditor.js +8 -7
- package/lib/browser/components/ChatEditor.js.map +1 -1
- package/lib/browser/components/ChatReply.d.ts.map +1 -1
- package/lib/browser/components/ChatReply.js +33 -4
- 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 +24 -0
- package/lib/browser/components/ChatToolRender.js.map +1 -0
- package/lib/browser/components/components.module.less +32 -31
- package/lib/browser/contrib/intelligent-completions/index.d.ts +1 -5
- package/lib/browser/contrib/intelligent-completions/index.d.ts.map +1 -1
- package/lib/browser/contrib/intelligent-completions/index.js.map +1 -1
- package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.d.ts.map +1 -1
- package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.js +1 -2
- package/lib/browser/contrib/intelligent-completions/intelligent-completions.controller.js.map +1 -1
- package/lib/browser/contrib/intelligent-completions/source/base.d.ts +2 -1
- package/lib/browser/contrib/intelligent-completions/source/base.d.ts.map +1 -1
- package/lib/browser/contrib/intelligent-completions/source/base.js.map +1 -1
- package/lib/browser/contrib/intelligent-completions/source/line-change.source.d.ts +3 -2
- package/lib/browser/contrib/intelligent-completions/source/line-change.source.d.ts.map +1 -1
- package/lib/browser/contrib/intelligent-completions/source/line-change.source.js +21 -51
- package/lib/browser/contrib/intelligent-completions/source/line-change.source.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 +39 -3
- package/lib/browser/index.js.map +1 -1
- package/lib/browser/mcp/mcp-server-proxy.service.d.ts +17 -0
- package/lib/browser/mcp/mcp-server-proxy.service.d.ts.map +1 -0
- package/lib/browser/mcp/mcp-server-proxy.service.js +36 -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 +45 -0
- package/lib/browser/mcp/mcp-server.feature.registry.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 +84 -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/preferences/schema.d.ts.map +1 -1
- package/lib/browser/preferences/schema.js +0 -4
- package/lib/browser/preferences/schema.js.map +1 -1
- package/lib/browser/types.d.ts +31 -0
- package/lib/browser/types.d.ts.map +1 -1
- package/lib/browser/types.js +4 -1
- package/lib/browser/types.js.map +1 -1
- package/lib/common/index.d.ts +5 -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/mcp-server-manager.d.ts +39 -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 +67 -0
- package/lib/common/tool-invocation-registry.d.ts.map +1 -0
- package/lib/common/tool-invocation-registry.js +68 -0
- package/lib/common/tool-invocation-registry.js.map +1 -0
- package/lib/common/types.d.ts +14 -0
- package/lib/common/types.d.ts.map +1 -1
- package/lib/node/anthropic/anthropic-language-model.d.ts +13 -0
- package/lib/node/anthropic/anthropic-language-model.d.ts.map +1 -0
- package/lib/node/anthropic/anthropic-language-model.js +79 -0
- package/lib/node/anthropic/anthropic-language-model.js.map +1 -0
- package/lib/node/index.d.ts.map +1 -1
- package/lib/node/index.js +21 -0
- package/lib/node/index.js.map +1 -1
- package/lib/node/mcp/sumi-mcp-server.d.ts +84 -0
- package/lib/node/mcp/sumi-mcp-server.d.ts.map +1 -0
- package/lib/node/mcp/sumi-mcp-server.js +134 -0
- package/lib/node/mcp/sumi-mcp-server.js.map +1 -0
- package/lib/node/mcp-server-manager-impl.d.ts +20 -0
- package/lib/node/mcp-server-manager-impl.d.ts.map +1 -0
- package/lib/node/mcp-server-manager-impl.js +123 -0
- package/lib/node/mcp-server-manager-impl.js.map +1 -0
- package/lib/node/mcp-server.d.ts +205 -0
- package/lib/node/mcp-server.d.ts.map +1 -0
- package/lib/node/mcp-server.js +86 -0
- package/lib/node/mcp-server.js.map +1 -0
- package/lib/node/openai/openai-language-model.d.ts +12 -0
- package/lib/node/openai/openai-language-model.d.ts.map +1 -0
- package/lib/node/openai/openai-language-model.js +136 -0
- package/lib/node/openai/openai-language-model.js.map +1 -0
- package/package.json +26 -21
- package/src/browser/ai-core.contribution.ts +47 -4
- package/src/browser/chat/chat-model.ts +21 -9
- package/src/browser/chat/chat-proxy.service.ts +12 -0
- package/src/browser/components/ChatEditor.tsx +6 -4
- package/src/browser/components/ChatReply.tsx +40 -4
- package/src/browser/components/ChatToolRender.tsx +27 -0
- package/src/browser/components/components.module.less +32 -31
- package/src/browser/contrib/intelligent-completions/index.ts +2 -3
- package/src/browser/contrib/intelligent-completions/intelligent-completions.controller.ts +1 -2
- package/src/browser/contrib/intelligent-completions/source/base.ts +2 -0
- package/src/browser/contrib/intelligent-completions/source/line-change.source.ts +24 -79
- package/src/browser/index.ts +50 -4
- package/src/browser/mcp/mcp-server-proxy.service.ts +32 -0
- package/src/browser/mcp/mcp-server.feature.registry.ts +47 -0
- package/src/browser/mcp/tools/createNewFileWithText.ts +85 -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/preferences/schema.ts +0 -4
- package/src/browser/types.ts +39 -0
- package/src/common/index.ts +9 -0
- package/src/common/mcp-server-manager.ts +45 -0
- package/src/common/tool-invocation-registry.ts +124 -0
- package/src/common/types.ts +18 -0
- package/src/node/anthropic/anthropic-language-model.ts +96 -0
- package/src/node/index.ts +24 -0
- package/src/node/mcp/sumi-mcp-server.ts +161 -0
- package/src/node/mcp-server-manager-impl.ts +130 -0
- package/src/node/mcp-server.ts +118 -0
- package/src/node/openai/openai-language-model.ts +152 -0
- package/lib/browser/contrib/intelligent-completions/source/typing.source.d.ts +0 -9
- package/lib/browser/contrib/intelligent-completions/source/typing.source.d.ts.map +0 -1
- package/lib/browser/contrib/intelligent-completions/source/typing.source.js +0 -38
- package/lib/browser/contrib/intelligent-completions/source/typing.source.js.map +0 -1
- package/src/browser/contrib/intelligent-completions/source/typing.source.ts +0 -36
package/src/browser/index.ts
CHANGED
|
@@ -19,8 +19,16 @@ import {
|
|
|
19
19
|
TerminalRegistryToken,
|
|
20
20
|
} from '@opensumi/ide-core-common';
|
|
21
21
|
|
|
22
|
-
import {
|
|
23
|
-
|
|
22
|
+
import {
|
|
23
|
+
ChatProxyServiceToken,
|
|
24
|
+
IAIInlineCompletionsProvider,
|
|
25
|
+
IChatAgentService,
|
|
26
|
+
IChatInternalService,
|
|
27
|
+
IChatManagerService,
|
|
28
|
+
SumiMCPServerProxyServicePath,
|
|
29
|
+
TokenMCPServerProxyService,
|
|
30
|
+
} from '../common';
|
|
31
|
+
import { MCPServerManager, MCPServerManagerPath } from '../common/mcp-server-manager';
|
|
24
32
|
|
|
25
33
|
import { AINativeBrowserContribution } from './ai-core.contribution';
|
|
26
34
|
import { ChatAgentService } from './chat/chat-agent.service';
|
|
@@ -43,8 +51,18 @@ import { RenameCandidatesProviderRegistry } from './contrib/rename/rename.featur
|
|
|
43
51
|
import { TerminalAIContribution } from './contrib/terminal/terminal-ai.contributon';
|
|
44
52
|
import { TerminalFeatureRegistry } from './contrib/terminal/terminal.feature.registry';
|
|
45
53
|
import { LanguageParserService } from './languages/service';
|
|
54
|
+
import { MCPServerProxyService } from './mcp/mcp-server-proxy.service';
|
|
55
|
+
import { MCPServerRegistry } from './mcp/mcp-server.feature.registry';
|
|
56
|
+
import { CreateNewFileWithTextTool } from './mcp/tools/createNewFileWithText';
|
|
57
|
+
import { FindFilesByNameSubstringTool } from './mcp/tools/findFilesByNameSubstring';
|
|
58
|
+
import { GetCurrentFilePathTool } from './mcp/tools/getCurrentFilePath';
|
|
59
|
+
import { GetDiagnosticsByPathTool } from './mcp/tools/getDiagnosticsByPath';
|
|
60
|
+
import { GetFileTextByPathTool } from './mcp/tools/getFileTextByPath';
|
|
61
|
+
import { GetOpenEditorFileDiagnosticsTool } from './mcp/tools/getOpenEditorFileDiagnostics';
|
|
62
|
+
import { GetOpenEditorFileTextTool } from './mcp/tools/getOpenEditorFileText';
|
|
63
|
+
import { GetSelectedTextTool } from './mcp/tools/getSelectedText';
|
|
46
64
|
import { AINativePreferencesContribution } from './preferences';
|
|
47
|
-
import { AINativeCoreContribution } from './types';
|
|
65
|
+
import { AINativeCoreContribution, MCPServerContribution, TokenMCPServerRegistry } from './types';
|
|
48
66
|
import { InlineChatFeatureRegistry } from './widget/inline-chat/inline-chat.feature.registry';
|
|
49
67
|
import { AIInlineChatService } from './widget/inline-chat/inline-chat.service';
|
|
50
68
|
import { InlineDiffService } from './widget/inline-diff';
|
|
@@ -59,7 +77,7 @@ export class AINativeModule extends BrowserModule {
|
|
|
59
77
|
this.aiNativeConfig.setAINativeModuleLoaded(true);
|
|
60
78
|
}
|
|
61
79
|
|
|
62
|
-
contributionProvider = AINativeCoreContribution;
|
|
80
|
+
contributionProvider = [AINativeCoreContribution, MCPServerContribution];
|
|
63
81
|
providers: Provider[] = [
|
|
64
82
|
AINativeBrowserContribution,
|
|
65
83
|
InterfaceNavigationContribution,
|
|
@@ -68,6 +86,26 @@ export class AINativeModule extends BrowserModule {
|
|
|
68
86
|
AICodeActionContribution,
|
|
69
87
|
AINativePreferencesContribution,
|
|
70
88
|
IntelligentCompletionsContribution,
|
|
89
|
+
|
|
90
|
+
// MCP Server Contributions START
|
|
91
|
+
CreateNewFileWithTextTool,
|
|
92
|
+
GetSelectedTextTool,
|
|
93
|
+
GetOpenEditorFileDiagnosticsTool,
|
|
94
|
+
GetOpenEditorFileTextTool,
|
|
95
|
+
GetFileTextByPathTool,
|
|
96
|
+
GetCurrentFilePathTool,
|
|
97
|
+
FindFilesByNameSubstringTool,
|
|
98
|
+
GetDiagnosticsByPathTool,
|
|
99
|
+
// MCP Server Contributions END
|
|
100
|
+
|
|
101
|
+
{
|
|
102
|
+
token: TokenMCPServerRegistry,
|
|
103
|
+
useClass: MCPServerRegistry,
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
token: TokenMCPServerProxyService,
|
|
107
|
+
useClass: MCPServerProxyService,
|
|
108
|
+
},
|
|
71
109
|
{
|
|
72
110
|
token: InlineChatFeatureRegistryToken,
|
|
73
111
|
useClass: InlineChatFeatureRegistry,
|
|
@@ -148,5 +186,13 @@ export class AINativeModule extends BrowserModule {
|
|
|
148
186
|
token: AIBackSerivceToken,
|
|
149
187
|
clientToken: ChatProxyServiceToken,
|
|
150
188
|
},
|
|
189
|
+
{
|
|
190
|
+
servicePath: MCPServerManagerPath,
|
|
191
|
+
token: MCPServerManager,
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
clientToken: TokenMCPServerProxyService,
|
|
195
|
+
servicePath: SumiMCPServerProxyServicePath,
|
|
196
|
+
},
|
|
151
197
|
];
|
|
152
198
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Autowired, Injectable } from '@opensumi/di';
|
|
2
|
+
import { ILogger } from '@opensumi/ide-core-browser';
|
|
3
|
+
|
|
4
|
+
import { IMCPServerRegistry, TokenMCPServerRegistry } from '../types';
|
|
5
|
+
|
|
6
|
+
@Injectable()
|
|
7
|
+
export class MCPServerProxyService {
|
|
8
|
+
@Autowired(TokenMCPServerRegistry)
|
|
9
|
+
private readonly mcpServerRegistry: IMCPServerRegistry;
|
|
10
|
+
|
|
11
|
+
@Autowired(ILogger)
|
|
12
|
+
private readonly logger: ILogger;
|
|
13
|
+
|
|
14
|
+
$callMCPTool(name: string, args: any) {
|
|
15
|
+
return this.mcpServerRegistry.callMCPTool(name, args);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async $getMCPTools() {
|
|
19
|
+
const tools = await this.mcpServerRegistry.getMCPTools().map((tool) =>
|
|
20
|
+
// 不要传递 handler
|
|
21
|
+
({
|
|
22
|
+
name: tool.name,
|
|
23
|
+
description: tool.description,
|
|
24
|
+
inputSchema: tool.inputSchema,
|
|
25
|
+
}),
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
this.logger.log('SUMI MCP tools', tools);
|
|
29
|
+
|
|
30
|
+
return tools;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// OpenSumi as MCP Server 前端的代理服务
|
|
2
|
+
import { Autowired, Injectable } from '@opensumi/di';
|
|
3
|
+
import { IAIBackService, ILogger } from '@opensumi/ide-core-common';
|
|
4
|
+
|
|
5
|
+
import { IMCPServerRegistry, MCPLogger, MCPToolDefinition } from '../types';
|
|
6
|
+
|
|
7
|
+
class LoggerAdapter implements MCPLogger {
|
|
8
|
+
constructor(private readonly logger: ILogger) {}
|
|
9
|
+
|
|
10
|
+
appendLine(message: string): void {
|
|
11
|
+
this.logger.log(message);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
@Injectable()
|
|
16
|
+
export class MCPServerRegistry implements IMCPServerRegistry {
|
|
17
|
+
private tools: MCPToolDefinition[] = [];
|
|
18
|
+
|
|
19
|
+
@Autowired(ILogger)
|
|
20
|
+
private readonly baseLogger: ILogger;
|
|
21
|
+
|
|
22
|
+
private get logger(): MCPLogger {
|
|
23
|
+
return new LoggerAdapter(this.baseLogger);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
registerMCPTool(tool: MCPToolDefinition): void {
|
|
27
|
+
this.tools.push(tool);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
getMCPTools(): MCPToolDefinition[] {
|
|
31
|
+
return this.tools;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
callMCPTool(
|
|
35
|
+
name: string,
|
|
36
|
+
args: any,
|
|
37
|
+
): Promise<{
|
|
38
|
+
content: { type: string; text: string }[];
|
|
39
|
+
isError?: boolean;
|
|
40
|
+
}> {
|
|
41
|
+
const tool = this.tools.find((tool) => tool.name === name);
|
|
42
|
+
if (!tool) {
|
|
43
|
+
throw new Error(`MCP tool ${name} not found`);
|
|
44
|
+
}
|
|
45
|
+
return tool.handler(args, this.logger);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import * as path from 'path';
|
|
2
|
+
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { zodToJsonSchema } from 'zod-to-json-schema';
|
|
5
|
+
|
|
6
|
+
import { Autowired, Injectable } from '@opensumi/di';
|
|
7
|
+
import { Domain, URI, path as UriPath } from '@opensumi/ide-core-common';
|
|
8
|
+
import { IFileServiceClient } from '@opensumi/ide-file-service';
|
|
9
|
+
import { IWorkspaceService } from '@opensumi/ide-workspace';
|
|
10
|
+
|
|
11
|
+
import { IMCPServerRegistry, MCPLogger, MCPServerContribution, MCPToolDefinition } from '../../types';
|
|
12
|
+
|
|
13
|
+
const inputSchema = z.object({
|
|
14
|
+
pathInProject: z.string().describe('The relative path where the file should be created'),
|
|
15
|
+
text: z.string().describe('The content to write into the new file'),
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
@Domain(MCPServerContribution)
|
|
19
|
+
export class CreateNewFileWithTextTool implements MCPServerContribution {
|
|
20
|
+
@Autowired(IWorkspaceService)
|
|
21
|
+
private readonly workspaceService: IWorkspaceService;
|
|
22
|
+
|
|
23
|
+
@Autowired(IFileServiceClient)
|
|
24
|
+
private readonly fileService: IFileServiceClient;
|
|
25
|
+
|
|
26
|
+
registerMCPServer(registry: IMCPServerRegistry): void {
|
|
27
|
+
registry.registerMCPTool(this.getToolDefinition());
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
getToolDefinition(): MCPToolDefinition {
|
|
31
|
+
return {
|
|
32
|
+
name: 'create_new_file_with_text',
|
|
33
|
+
description:
|
|
34
|
+
'Creates a new file at the specified path within the project directory and populates it with the provided text. ' +
|
|
35
|
+
'Use this tool to generate new files in your project structure. ' +
|
|
36
|
+
'Requires two parameters: ' +
|
|
37
|
+
'- pathInProject: The relative path where the file should be created ' +
|
|
38
|
+
'- text: The content to write into the new file ' +
|
|
39
|
+
'Returns one of two possible responses: ' +
|
|
40
|
+
'"ok" if the file was successfully created and populated, ' +
|
|
41
|
+
'"can\'t find project dir" if the project directory cannot be determined. ' +
|
|
42
|
+
'Note: Creates any necessary parent directories automatically.',
|
|
43
|
+
inputSchema: zodToJsonSchema(inputSchema),
|
|
44
|
+
handler: this.handler.bind(this),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
private async handler(args: z.infer<typeof inputSchema>, logger: MCPLogger) {
|
|
49
|
+
try {
|
|
50
|
+
// 获取工作区根目录
|
|
51
|
+
const workspaceRoots = this.workspaceService.tryGetRoots();
|
|
52
|
+
if (!workspaceRoots || workspaceRoots.length === 0) {
|
|
53
|
+
logger.appendLine('Error: Cannot determine project directory');
|
|
54
|
+
return {
|
|
55
|
+
content: [{ type: 'text', text: "can't find project dir" }],
|
|
56
|
+
isError: true,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// 构建完整的文件路径
|
|
61
|
+
const rootUri = URI.parse(workspaceRoots[0].uri);
|
|
62
|
+
const fullPath = UriPath.join(rootUri.codeUri.fsPath, args.pathInProject);
|
|
63
|
+
const fileUri = URI.file(fullPath);
|
|
64
|
+
|
|
65
|
+
// 创建父目录
|
|
66
|
+
const parentDir = path.dirname(fullPath);
|
|
67
|
+
const parentUri = URI.file(parentDir);
|
|
68
|
+
await this.fileService.createFolder(parentUri.toString());
|
|
69
|
+
|
|
70
|
+
// 写入文件内容
|
|
71
|
+
await this.fileService.createFile(fileUri.toString(), { content: args.text });
|
|
72
|
+
|
|
73
|
+
logger.appendLine(`Successfully created file at: ${args.pathInProject}`);
|
|
74
|
+
return {
|
|
75
|
+
content: [{ type: 'text', text: 'ok' }],
|
|
76
|
+
};
|
|
77
|
+
} catch (error) {
|
|
78
|
+
logger.appendLine(`Error during file creation: ${error}`);
|
|
79
|
+
return {
|
|
80
|
+
content: [{ type: 'text', text: 'unknown error' }],
|
|
81
|
+
isError: true,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import * as path from 'path';
|
|
2
|
+
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { zodToJsonSchema } from 'zod-to-json-schema';
|
|
5
|
+
|
|
6
|
+
import { Autowired, Injectable } from '@opensumi/di';
|
|
7
|
+
import { Domain, URI } from '@opensumi/ide-core-common';
|
|
8
|
+
import { IFileSearchService } from '@opensumi/ide-file-search/lib/common';
|
|
9
|
+
import { IWorkspaceService } from '@opensumi/ide-workspace';
|
|
10
|
+
|
|
11
|
+
import { IMCPServerRegistry, MCPLogger, MCPServerContribution, MCPToolDefinition } from '../../types';
|
|
12
|
+
|
|
13
|
+
const inputSchema = z.object({
|
|
14
|
+
nameSubstring: z.string().describe('The substring to search for in file names'),
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
@Domain(MCPServerContribution)
|
|
18
|
+
export class FindFilesByNameSubstringTool implements MCPServerContribution {
|
|
19
|
+
@Autowired(IWorkspaceService)
|
|
20
|
+
private readonly workspaceService: IWorkspaceService;
|
|
21
|
+
|
|
22
|
+
@Autowired(IFileSearchService)
|
|
23
|
+
private readonly fileSearchService: IFileSearchService;
|
|
24
|
+
|
|
25
|
+
registerMCPServer(registry: IMCPServerRegistry): void {
|
|
26
|
+
registry.registerMCPTool(this.getToolDefinition());
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
getToolDefinition(): MCPToolDefinition {
|
|
30
|
+
return {
|
|
31
|
+
name: 'find_files_by_name_substring',
|
|
32
|
+
description:
|
|
33
|
+
'Searches for all files in the project whose names contain the specified substring (case-insensitive). ' +
|
|
34
|
+
'Use this tool to locate files when you know part of the filename. ' +
|
|
35
|
+
'Requires a nameSubstring parameter for the search term. ' +
|
|
36
|
+
'Returns a JSON array of objects containing file information: ' +
|
|
37
|
+
'- path: Path relative to project root ' +
|
|
38
|
+
'- name: File name ' +
|
|
39
|
+
'Returns an empty array ([]) if no matching files are found. ' +
|
|
40
|
+
'Note: Only searches through files within the project directory, excluding libraries and external dependencies.',
|
|
41
|
+
inputSchema: zodToJsonSchema(inputSchema),
|
|
42
|
+
handler: this.handler.bind(this),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
private async handler(args: z.infer<typeof inputSchema>, logger: MCPLogger) {
|
|
47
|
+
try {
|
|
48
|
+
// 获取工作区根目录
|
|
49
|
+
const workspaceRoots = this.workspaceService.tryGetRoots();
|
|
50
|
+
if (!workspaceRoots || workspaceRoots.length === 0) {
|
|
51
|
+
logger.appendLine('Error: Cannot determine project directory');
|
|
52
|
+
return {
|
|
53
|
+
content: [{ type: 'text', text: '[]' }],
|
|
54
|
+
isError: true,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// 使用 OpenSumi 的文件搜索 API
|
|
59
|
+
const searchPattern = `**/*${args.nameSubstring}*`;
|
|
60
|
+
const searchResults = await this.fileSearchService.find(searchPattern, {
|
|
61
|
+
rootUris: [workspaceRoots[0].uri],
|
|
62
|
+
excludePatterns: ['**/node_modules/**'],
|
|
63
|
+
limit: 1000,
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// 转换结果为所需的格式
|
|
67
|
+
const results = searchResults.map((file) => {
|
|
68
|
+
const uri = URI.parse(file);
|
|
69
|
+
const rootUri = URI.parse(workspaceRoots[0].uri);
|
|
70
|
+
const relativePath = path.relative(rootUri.codeUri.fsPath, uri.codeUri.fsPath);
|
|
71
|
+
const fileName = path.basename(uri.codeUri.fsPath);
|
|
72
|
+
return {
|
|
73
|
+
path: relativePath,
|
|
74
|
+
name: fileName,
|
|
75
|
+
};
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// 将结果转换为 JSON 字符串
|
|
79
|
+
const resultJson = JSON.stringify(results, null, 2);
|
|
80
|
+
logger.appendLine(`Found ${results.length} files matching "${args.nameSubstring}"`);
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
content: [{ type: 'text', text: resultJson }],
|
|
84
|
+
};
|
|
85
|
+
} catch (error) {
|
|
86
|
+
logger.appendLine(`Error during file search: ${error}`);
|
|
87
|
+
return {
|
|
88
|
+
content: [{ type: 'text', text: '[]' }],
|
|
89
|
+
isError: true,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { zodToJsonSchema } from 'zod-to-json-schema';
|
|
3
|
+
|
|
4
|
+
import { Autowired, Injectable } from '@opensumi/di';
|
|
5
|
+
import { Domain } from '@opensumi/ide-core-common';
|
|
6
|
+
import { WorkbenchEditorService } from '@opensumi/ide-editor';
|
|
7
|
+
|
|
8
|
+
import { IMCPServerRegistry, MCPLogger, MCPServerContribution, MCPToolDefinition } from '../../types';
|
|
9
|
+
|
|
10
|
+
const inputSchema = z.object({});
|
|
11
|
+
|
|
12
|
+
@Domain(MCPServerContribution)
|
|
13
|
+
export class GetCurrentFilePathTool implements MCPServerContribution {
|
|
14
|
+
@Autowired(WorkbenchEditorService)
|
|
15
|
+
private readonly editorService: WorkbenchEditorService;
|
|
16
|
+
|
|
17
|
+
registerMCPServer(registry: IMCPServerRegistry): void {
|
|
18
|
+
registry.registerMCPTool(this.getToolDefinition());
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
getToolDefinition(): MCPToolDefinition {
|
|
22
|
+
return {
|
|
23
|
+
name: 'get_open_in_editor_file_path',
|
|
24
|
+
description:
|
|
25
|
+
'Retrieves the absolute path of the currently active file in the VS Code editor. ' +
|
|
26
|
+
'Use this tool to get the file location for tasks requiring file path information. ' +
|
|
27
|
+
'Returns an empty string if no file is currently open.',
|
|
28
|
+
inputSchema: zodToJsonSchema(inputSchema),
|
|
29
|
+
handler: this.handler.bind(this),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
private async handler(args: z.infer<typeof inputSchema>, logger: MCPLogger) {
|
|
34
|
+
const editor = this.editorService.currentEditor;
|
|
35
|
+
if (!editor || !editor.currentUri) {
|
|
36
|
+
logger.appendLine('Error: No active text editor found');
|
|
37
|
+
return {
|
|
38
|
+
content: [{ type: 'text', text: '' }],
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const path = editor.currentUri.toString();
|
|
43
|
+
logger.appendLine(`Current file path: ${path}`);
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
content: [{ type: 'text', text: path }],
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import * as path from 'path';
|
|
2
|
+
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { zodToJsonSchema } from 'zod-to-json-schema';
|
|
5
|
+
|
|
6
|
+
import { Autowired, Injectable } from '@opensumi/di';
|
|
7
|
+
import { Domain, URI } from '@opensumi/ide-core-common';
|
|
8
|
+
import { IWorkspaceService } from '@opensumi/ide-workspace';
|
|
9
|
+
import { URI as MonacoURI } from '@opensumi/monaco-editor-core/esm/vs/base/common/uri';
|
|
10
|
+
import { IMarkerService, MarkerSeverity } from '@opensumi/monaco-editor-core/esm/vs/platform/markers/common/markers';
|
|
11
|
+
|
|
12
|
+
import { IMCPServerRegistry, MCPLogger, MCPServerContribution, MCPToolDefinition } from '../../types';
|
|
13
|
+
|
|
14
|
+
const inputSchema = z.object({
|
|
15
|
+
filePathInProject: z.string().describe('The relative path to the file to get diagnostics for'),
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
@Domain(MCPServerContribution)
|
|
19
|
+
export class GetDiagnosticsByPathTool implements MCPServerContribution {
|
|
20
|
+
@Autowired(IWorkspaceService)
|
|
21
|
+
private readonly workspaceService: IWorkspaceService;
|
|
22
|
+
|
|
23
|
+
@Autowired(IMarkerService)
|
|
24
|
+
private readonly markerService: IMarkerService;
|
|
25
|
+
|
|
26
|
+
registerMCPServer(registry: IMCPServerRegistry): void {
|
|
27
|
+
registry.registerMCPTool(this.getToolDefinition());
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
getToolDefinition(): MCPToolDefinition {
|
|
31
|
+
return {
|
|
32
|
+
name: 'get_diagnostics_by_path',
|
|
33
|
+
description:
|
|
34
|
+
'Retrieves diagnostic information (errors, warnings, etc.) from a specific file in the project. ' +
|
|
35
|
+
'Use this tool to get information about problems in any project file. ' +
|
|
36
|
+
'IMPORTANT: This tool should be called after any code generation or modification operations to verify and fix potential issues. ' +
|
|
37
|
+
'Requires a filePathInProject parameter specifying the target file path relative to project root. ' +
|
|
38
|
+
'Returns a JSON-formatted list of diagnostics, where each entry contains: ' +
|
|
39
|
+
'- path: The file path where the diagnostic was found ' +
|
|
40
|
+
'- line: The line number (1-based) of the diagnostic ' +
|
|
41
|
+
'- severity: The severity level ("error", "warning", "information", or "hint") ' +
|
|
42
|
+
'- message: The diagnostic message ' +
|
|
43
|
+
"Returns an empty list ([]) if no diagnostics are found or the file doesn't exist. " +
|
|
44
|
+
'Best Practice: Always check diagnostics after code generation to ensure code quality and fix any issues immediately. ' +
|
|
45
|
+
'Use this tool in combination with get_open_in_editor_file_diagnostics to verify all affected files after code changes. ' +
|
|
46
|
+
'Diagnostic Severity Handling Guidelines: ' +
|
|
47
|
+
'- "error": Must be fixed immediately as they indicate critical issues that will prevent code from working correctly. ' +
|
|
48
|
+
'- "warning": For user code, preserve unless the warning indicates a clear improvement opportunity. For generated code, optimize to remove warnings. ' +
|
|
49
|
+
'- "information"/"hint": For user code, preserve as they might reflect intentional patterns. For generated code, optimize if it improves code quality without changing functionality.',
|
|
50
|
+
inputSchema: zodToJsonSchema(inputSchema),
|
|
51
|
+
handler: this.handler.bind(this),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
private async handler(args: z.infer<typeof inputSchema>, logger: MCPLogger) {
|
|
56
|
+
try {
|
|
57
|
+
// 获取工作区根目录
|
|
58
|
+
const workspaceRoots = this.workspaceService.tryGetRoots();
|
|
59
|
+
if (!workspaceRoots || workspaceRoots.length === 0) {
|
|
60
|
+
logger.appendLine('Error: Cannot determine project directory');
|
|
61
|
+
return {
|
|
62
|
+
content: [{ type: 'text', text: '[]' }],
|
|
63
|
+
isError: true,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// 构建完整的文件路径
|
|
68
|
+
const rootUri = URI.parse(workspaceRoots[0].uri);
|
|
69
|
+
const fullPath = path.join(rootUri.codeUri.fsPath, args.filePathInProject);
|
|
70
|
+
const uri = MonacoURI.file(fullPath);
|
|
71
|
+
|
|
72
|
+
// 检查文件是否在项目目录内
|
|
73
|
+
const relativePath = path.relative(rootUri.codeUri.fsPath, fullPath);
|
|
74
|
+
if (relativePath.startsWith('..') || path.isAbsolute(relativePath)) {
|
|
75
|
+
logger.appendLine('Error: File is outside of project scope');
|
|
76
|
+
return {
|
|
77
|
+
content: [{ type: 'text', text: '[]' }],
|
|
78
|
+
isError: true,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// 获取文件的诊断信息
|
|
83
|
+
const markers = this.markerService.read({ resource: uri });
|
|
84
|
+
|
|
85
|
+
// 转换诊断信息
|
|
86
|
+
const diagnosticInfos = markers.map((marker) => ({
|
|
87
|
+
path: args.filePathInProject,
|
|
88
|
+
line: marker.startLineNumber,
|
|
89
|
+
severity: this.getSeverityString(marker.severity),
|
|
90
|
+
message: marker.message,
|
|
91
|
+
}));
|
|
92
|
+
|
|
93
|
+
// 将结果转换为 JSON 字符串
|
|
94
|
+
const resultJson = JSON.stringify(diagnosticInfos, null, 2);
|
|
95
|
+
logger.appendLine(`Found ${diagnosticInfos.length} diagnostics in ${args.filePathInProject}`);
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
content: [{ type: 'text', text: resultJson }],
|
|
99
|
+
};
|
|
100
|
+
} catch (error) {
|
|
101
|
+
logger.appendLine(`Error getting diagnostics: ${error}`);
|
|
102
|
+
return {
|
|
103
|
+
content: [{ type: 'text', text: '[]' }],
|
|
104
|
+
isError: true,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
private getSeverityString(severity: MarkerSeverity): string {
|
|
110
|
+
switch (severity) {
|
|
111
|
+
case MarkerSeverity.Error:
|
|
112
|
+
return 'error';
|
|
113
|
+
case MarkerSeverity.Warning:
|
|
114
|
+
return 'warning';
|
|
115
|
+
case MarkerSeverity.Info:
|
|
116
|
+
return 'information';
|
|
117
|
+
case MarkerSeverity.Hint:
|
|
118
|
+
return 'hint';
|
|
119
|
+
default:
|
|
120
|
+
return 'unknown';
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import * as path from 'path';
|
|
2
|
+
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { zodToJsonSchema } from 'zod-to-json-schema';
|
|
5
|
+
|
|
6
|
+
import { Autowired, Injectable } from '@opensumi/di';
|
|
7
|
+
import { Domain, URI } from '@opensumi/ide-core-common';
|
|
8
|
+
import { IFileServiceClient } from '@opensumi/ide-file-service';
|
|
9
|
+
import { IWorkspaceService } from '@opensumi/ide-workspace';
|
|
10
|
+
|
|
11
|
+
import { IMCPServerRegistry, MCPLogger, MCPServerContribution, MCPToolDefinition } from '../../types';
|
|
12
|
+
|
|
13
|
+
const inputSchema = z.object({
|
|
14
|
+
pathInProject: z.string().describe('The file location relative to project root'),
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
@Domain(MCPServerContribution)
|
|
18
|
+
export class GetFileTextByPathTool implements MCPServerContribution {
|
|
19
|
+
@Autowired(IWorkspaceService)
|
|
20
|
+
private readonly workspaceService: IWorkspaceService;
|
|
21
|
+
|
|
22
|
+
@Autowired(IFileServiceClient)
|
|
23
|
+
private readonly fileService: IFileServiceClient;
|
|
24
|
+
|
|
25
|
+
registerMCPServer(registry: IMCPServerRegistry): void {
|
|
26
|
+
registry.registerMCPTool(this.getToolDefinition());
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
getToolDefinition(): MCPToolDefinition {
|
|
30
|
+
return {
|
|
31
|
+
name: 'get_file_text_by_path',
|
|
32
|
+
description:
|
|
33
|
+
'Retrieves the text content of a file using its path relative to project root. ' +
|
|
34
|
+
"Use this tool to read file contents when you have the file's project-relative path. " +
|
|
35
|
+
'Requires a pathInProject parameter specifying the file location from project root. ' +
|
|
36
|
+
'Returns one of these responses: ' +
|
|
37
|
+
"- The file's content if the file exists and belongs to the project " +
|
|
38
|
+
'- error "project dir not found" if project directory cannot be determined ' +
|
|
39
|
+
'- error "file not found" if the file doesn\'t exist or is outside project scope ' +
|
|
40
|
+
'Note: Automatically refreshes the file system before reading',
|
|
41
|
+
inputSchema: zodToJsonSchema(inputSchema),
|
|
42
|
+
handler: this.handler.bind(this),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
private async handler(args: z.infer<typeof inputSchema>, logger: MCPLogger) {
|
|
47
|
+
try {
|
|
48
|
+
// 获取工作区根目录
|
|
49
|
+
const workspaceRoots = this.workspaceService.tryGetRoots();
|
|
50
|
+
if (!workspaceRoots || workspaceRoots.length === 0) {
|
|
51
|
+
logger.appendLine('Error: Cannot determine project directory');
|
|
52
|
+
return {
|
|
53
|
+
content: [{ type: 'text', text: 'project dir not found' }],
|
|
54
|
+
isError: true,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// 构建完整的文件路径
|
|
59
|
+
const rootUri = URI.parse(workspaceRoots[0].uri);
|
|
60
|
+
const fullPath = path.join(rootUri.codeUri.fsPath, args.pathInProject);
|
|
61
|
+
const fileUri = URI.file(fullPath);
|
|
62
|
+
|
|
63
|
+
// 检查文件是否在项目目录内
|
|
64
|
+
const relativePath = path.relative(rootUri.codeUri.fsPath, fullPath);
|
|
65
|
+
if (relativePath.startsWith('..') || path.isAbsolute(relativePath)) {
|
|
66
|
+
logger.appendLine('Error: File is outside of project scope');
|
|
67
|
+
return {
|
|
68
|
+
content: [{ type: 'text', text: 'file not found' }],
|
|
69
|
+
isError: true,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// 检查文件是否存在并读取内容
|
|
74
|
+
try {
|
|
75
|
+
const result = await this.fileService.readFile(fileUri.toString());
|
|
76
|
+
const content = result.content.toString();
|
|
77
|
+
logger.appendLine(`Successfully read file: ${args.pathInProject}`);
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
content: [{ type: 'text', text: content }],
|
|
81
|
+
};
|
|
82
|
+
} catch (error) {
|
|
83
|
+
logger.appendLine('Error: File does not exist');
|
|
84
|
+
return {
|
|
85
|
+
content: [{ type: 'text', text: 'file not found' }],
|
|
86
|
+
isError: true,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
} catch (error) {
|
|
90
|
+
logger.appendLine(`Error reading file: ${error}`);
|
|
91
|
+
return {
|
|
92
|
+
content: [{ type: 'text', text: 'file not found' }],
|
|
93
|
+
isError: true,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|