@opensumi/ide-ai-native 3.8.3-next-1745805174.0 → 3.8.3-next-1745835516.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.
Files changed (93) hide show
  1. package/lib/browser/ai-core.contribution.d.ts +2 -0
  2. package/lib/browser/ai-core.contribution.d.ts.map +1 -1
  3. package/lib/browser/ai-core.contribution.js +58 -12
  4. package/lib/browser/ai-core.contribution.js.map +1 -1
  5. package/lib/browser/components/ChatInput.js +1 -1
  6. package/lib/browser/components/ChatInput.js.map +1 -1
  7. package/lib/browser/components/ChatMentionInput.js +1 -1
  8. package/lib/browser/components/ChatMentionInput.js.map +1 -1
  9. package/lib/browser/components/ChatToolResult.module.less +0 -2
  10. package/lib/browser/components/mention-input/mention-input.d.ts.map +1 -1
  11. package/lib/browser/components/mention-input/mention-input.js +9 -7
  12. package/lib/browser/components/mention-input/mention-input.js.map +1 -1
  13. package/lib/browser/index.d.ts.map +1 -1
  14. package/lib/browser/index.js +15 -0
  15. package/lib/browser/index.js.map +1 -1
  16. package/lib/browser/mcp/config/components/mcp-config.module.less +4 -1
  17. package/lib/browser/mcp/config/components/mcp-config.view.d.ts.map +1 -1
  18. package/lib/browser/mcp/config/components/mcp-config.view.js +27 -119
  19. package/lib/browser/mcp/config/components/mcp-config.view.js.map +1 -1
  20. package/lib/browser/mcp/config/components/mcp-server-form.d.ts +1 -1
  21. package/lib/browser/mcp/config/components/mcp-server-form.d.ts.map +1 -1
  22. package/lib/browser/mcp/config/components/mcp-server-form.js +8 -8
  23. package/lib/browser/mcp/config/components/mcp-server-form.js.map +1 -1
  24. package/lib/browser/mcp/config/mcp-config.commands.d.ts +11 -4
  25. package/lib/browser/mcp/config/mcp-config.commands.d.ts.map +1 -1
  26. package/lib/browser/mcp/config/mcp-config.commands.js +23 -6
  27. package/lib/browser/mcp/config/mcp-config.commands.js.map +1 -1
  28. package/lib/browser/mcp/config/mcp-config.contribution.d.ts +4 -1
  29. package/lib/browser/mcp/config/mcp-config.contribution.d.ts.map +1 -1
  30. package/lib/browser/mcp/config/mcp-config.contribution.js +20 -1
  31. package/lib/browser/mcp/config/mcp-config.contribution.js.map +1 -1
  32. package/lib/browser/mcp/config/mcp-config.service.d.ts +30 -0
  33. package/lib/browser/mcp/config/mcp-config.service.d.ts.map +1 -0
  34. package/lib/browser/mcp/config/mcp-config.service.js +236 -0
  35. package/lib/browser/mcp/config/mcp-config.service.js.map +1 -0
  36. package/lib/browser/mcp/mcp-folder-preference-provider.d.ts +6 -0
  37. package/lib/browser/mcp/mcp-folder-preference-provider.d.ts.map +1 -0
  38. package/lib/browser/mcp/mcp-folder-preference-provider.js +29 -0
  39. package/lib/browser/mcp/mcp-folder-preference-provider.js.map +1 -0
  40. package/lib/browser/mcp/mcp-preferences-contribution.d.ts +15 -0
  41. package/lib/browser/mcp/mcp-preferences-contribution.d.ts.map +1 -0
  42. package/lib/browser/mcp/mcp-preferences-contribution.js +49 -0
  43. package/lib/browser/mcp/mcp-preferences-contribution.js.map +1 -0
  44. package/lib/browser/mcp/mcp-preferences.d.ts +6 -0
  45. package/lib/browser/mcp/mcp-preferences.d.ts.map +1 -0
  46. package/lib/browser/mcp/mcp-preferences.js +47 -0
  47. package/lib/browser/mcp/mcp-preferences.js.map +1 -0
  48. package/lib/browser/preferences/schema.d.ts.map +1 -1
  49. package/lib/browser/preferences/schema.js +3 -0
  50. package/lib/browser/preferences/schema.js.map +1 -1
  51. package/lib/common/mcp-server-manager.d.ts +2 -1
  52. package/lib/common/mcp-server-manager.d.ts.map +1 -1
  53. package/lib/common/mcp-server-manager.js +2 -1
  54. package/lib/common/mcp-server-manager.js.map +1 -1
  55. package/lib/common/types.d.ts +1 -1
  56. package/lib/common/types.d.ts.map +1 -1
  57. package/lib/node/mcp/sumi-mcp-server.d.ts +3 -3
  58. package/lib/node/mcp/sumi-mcp-server.js +1 -1
  59. package/lib/node/mcp/sumi-mcp-server.js.map +1 -1
  60. package/lib/node/mcp-server-manager-impl.d.ts.map +1 -1
  61. package/lib/node/mcp-server-manager-impl.js +9 -4
  62. package/lib/node/mcp-server-manager-impl.js.map +1 -1
  63. package/lib/node/mcp-server.sse.d.ts +10 -37
  64. package/lib/node/mcp-server.sse.d.ts.map +1 -1
  65. package/lib/node/mcp-server.sse.js +43 -15
  66. package/lib/node/mcp-server.sse.js.map +1 -1
  67. package/lib/node/mcp-server.stdio.d.ts +7 -34
  68. package/lib/node/mcp-server.stdio.d.ts.map +1 -1
  69. package/lib/node/mcp-server.stdio.js +27 -2
  70. package/lib/node/mcp-server.stdio.js.map +1 -1
  71. package/package.json +24 -24
  72. package/src/browser/ai-core.contribution.ts +71 -16
  73. package/src/browser/components/ChatInput.tsx +2 -2
  74. package/src/browser/components/ChatMentionInput.tsx +2 -2
  75. package/src/browser/components/ChatToolResult.module.less +0 -2
  76. package/src/browser/components/mention-input/mention-input.tsx +27 -23
  77. package/src/browser/index.ts +16 -0
  78. package/src/browser/mcp/config/components/mcp-config.module.less +4 -1
  79. package/src/browser/mcp/config/components/mcp-config.view.tsx +37 -125
  80. package/src/browser/mcp/config/components/mcp-server-form.tsx +10 -10
  81. package/src/browser/mcp/config/mcp-config.commands.ts +22 -6
  82. package/src/browser/mcp/config/mcp-config.contribution.ts +24 -2
  83. package/src/browser/mcp/config/mcp-config.service.ts +285 -0
  84. package/src/browser/mcp/mcp-folder-preference-provider.ts +23 -0
  85. package/src/browser/mcp/mcp-preferences-contribution.ts +62 -0
  86. package/src/browser/mcp/mcp-preferences.ts +48 -0
  87. package/src/browser/preferences/schema.ts +3 -0
  88. package/src/common/mcp-server-manager.ts +3 -1
  89. package/src/common/types.ts +1 -1
  90. package/src/node/mcp/sumi-mcp-server.ts +1 -1
  91. package/src/node/mcp-server-manager-impl.ts +8 -4
  92. package/src/node/mcp-server.sse.ts +41 -14
  93. package/src/node/mcp-server.stdio.ts +26 -2
@@ -1,22 +1,32 @@
1
1
  import { Autowired } from '@opensumi/di';
2
2
  import { CommandContribution, CommandRegistry, URI } from '@opensumi/ide-core-browser';
3
- import { Domain } from '@opensumi/ide-core-common';
3
+ import { Domain, MCPConfigServiceToken } from '@opensumi/ide-core-common';
4
4
  import { WorkbenchEditorService } from '@opensumi/ide-editor';
5
5
 
6
6
  import { MCP_CONFIG_COMPONENTS_SCHEME_ID } from './mcp-config.contribution';
7
+ import { MCPConfigService } from './mcp-config.service';
7
8
 
8
- export const OPEN_MCP_CONFIG_COMMAND = {
9
- id: 'opensumi-mcp.openConfig',
10
- label: 'Open MCP Configuration',
11
- };
9
+ export namespace MCPConfigCommands {
10
+ export const OPEN_MCP_CONFIG = {
11
+ id: 'mcp.openConfig',
12
+ label: 'Open MCP Configuration',
13
+ };
12
14
 
15
+ export const OPEN_MCP_CONFIG_FILE = {
16
+ id: 'mcp.openConfigFile',
17
+ label: 'Open MCP Configuration (JSON)',
18
+ };
19
+ }
13
20
  @Domain(CommandContribution)
14
21
  export class MCPConfigCommandContribution implements CommandContribution {
15
22
  @Autowired(WorkbenchEditorService)
16
23
  private readonly editorService: WorkbenchEditorService;
17
24
 
25
+ @Autowired(MCPConfigServiceToken)
26
+ private readonly mcpConfigService: MCPConfigService;
27
+
18
28
  registerCommands(registry: CommandRegistry) {
19
- registry.registerCommand(OPEN_MCP_CONFIG_COMMAND, {
29
+ registry.registerCommand(MCPConfigCommands.OPEN_MCP_CONFIG, {
20
30
  execute: () => {
21
31
  const uri = new URI().withScheme(MCP_CONFIG_COMPONENTS_SCHEME_ID);
22
32
  this.editorService.open(uri, {
@@ -25,5 +35,11 @@ export class MCPConfigCommandContribution implements CommandContribution {
25
35
  });
26
36
  },
27
37
  });
38
+
39
+ registry.registerCommand(MCPConfigCommands.OPEN_MCP_CONFIG_FILE, {
40
+ execute: () => {
41
+ this.mcpConfigService.openConfigFile();
42
+ },
43
+ });
28
44
  }
29
45
  }
@@ -1,5 +1,8 @@
1
1
  import { Autowired } from '@opensumi/di';
2
2
  import { getIcon } from '@opensumi/ide-components';
3
+ import { MenuContribution } from '@opensumi/ide-core-browser/lib/menu/next';
4
+ import { IMenuRegistry } from '@opensumi/ide-core-browser/lib/menu/next/base';
5
+ import { MenuId } from '@opensumi/ide-core-browser/lib/menu/next/menu-id';
3
6
  import { LabelService } from '@opensumi/ide-core-browser/lib/services';
4
7
  import { Domain, URI, localize } from '@opensumi/ide-core-common';
5
8
  import {
@@ -13,14 +16,15 @@ import { IconService } from '@opensumi/ide-theme/lib/browser';
13
16
  import { IWorkspaceService } from '@opensumi/ide-workspace/lib/common';
14
17
 
15
18
  import { MCPConfigView } from './components/mcp-config.view';
19
+ import { MCPConfigCommands } from './mcp-config.commands';
16
20
 
17
21
  const COMPONENTS_ID = 'opensumi-mcp-config-viewer';
18
22
  export const MCP_CONFIG_COMPONENTS_SCHEME_ID = 'mcp-config';
19
23
 
20
24
  export type IMCPConfigResource = IResource<{ configType: string }>;
21
25
 
22
- @Domain(BrowserEditorContribution)
23
- export class MCPConfigContribution implements BrowserEditorContribution {
26
+ @Domain(BrowserEditorContribution, MenuContribution)
27
+ export class MCPConfigContribution implements BrowserEditorContribution, MenuContribution {
24
28
  @Autowired(IWorkspaceService)
25
29
  protected readonly workspaceService: IWorkspaceService;
26
30
 
@@ -63,4 +67,22 @@ export class MCPConfigContribution implements BrowserEditorContribution {
63
67
  },
64
68
  });
65
69
  }
70
+
71
+ registerMenus(menus: IMenuRegistry) {
72
+ menus.registerMenuItem(MenuId.EditorTitle, {
73
+ command: MCPConfigCommands.OPEN_MCP_CONFIG_FILE.id,
74
+ iconClass: getIcon('open'),
75
+ group: 'navigation',
76
+ order: 4,
77
+ when: `resourceScheme == ${MCP_CONFIG_COMPONENTS_SCHEME_ID}`,
78
+ });
79
+
80
+ menus.registerMenuItem(MenuId.EditorTitle, {
81
+ command: MCPConfigCommands.OPEN_MCP_CONFIG.id,
82
+ iconClass: getIcon('open'),
83
+ group: 'navigation',
84
+ order: 4,
85
+ when: 'resourceFilename =~ /mcp.json/',
86
+ });
87
+ }
66
88
  }
@@ -0,0 +1,285 @@
1
+ import { Autowired, Injectable } from '@opensumi/di';
2
+ import { ILogger } from '@opensumi/ide-core-browser';
3
+ import { PreferenceService } from '@opensumi/ide-core-browser/lib/preferences';
4
+ import {
5
+ Deferred,
6
+ Disposable,
7
+ Emitter,
8
+ IStorage,
9
+ PreferenceScope,
10
+ STORAGE_NAMESPACE,
11
+ StorageProvider,
12
+ localize,
13
+ } from '@opensumi/ide-core-common';
14
+ import { WorkbenchEditorService } from '@opensumi/ide-editor';
15
+ import { IMessageService } from '@opensumi/ide-overlay';
16
+
17
+ import { BUILTIN_MCP_SERVER_NAME, ISumiMCPServerBackend, SumiMCPServerProxyServicePath } from '../../../common';
18
+ import {
19
+ MCPServerDescription,
20
+ MCPServersEnabledKey,
21
+ SSEMCPServerDescription,
22
+ StdioMCPServerDescription,
23
+ } from '../../../common/mcp-server-manager';
24
+ import { MCPServer, MCP_SERVER_TYPE } from '../../../common/types';
25
+ import { MCPServerProxyService } from '../mcp-server-proxy.service';
26
+
27
+ import { MCPServerFormData } from './components/mcp-server-form';
28
+
29
+ @Injectable()
30
+ export class MCPConfigService extends Disposable {
31
+ @Autowired(SumiMCPServerProxyServicePath)
32
+ private readonly sumiMCPServerBackendProxy: ISumiMCPServerBackend;
33
+
34
+ @Autowired(MCPServerProxyService)
35
+ private readonly mcpServerProxyService: MCPServerProxyService;
36
+
37
+ @Autowired(PreferenceService)
38
+ private readonly preferenceService: PreferenceService;
39
+
40
+ @Autowired(IMessageService)
41
+ private readonly messageService: IMessageService;
42
+
43
+ @Autowired(StorageProvider)
44
+ private readonly storageProvider: StorageProvider;
45
+
46
+ @Autowired(WorkbenchEditorService)
47
+ private readonly workbenchEditorService: WorkbenchEditorService;
48
+
49
+ @Autowired(ILogger)
50
+ private readonly logger: ILogger;
51
+
52
+ private chatStorage: IStorage;
53
+ private whenReadyDeferred = new Deferred<void>();
54
+
55
+ private readonly mcpServersChangeEventEmitter = new Emitter<boolean>();
56
+
57
+ constructor() {
58
+ super();
59
+
60
+ this.init();
61
+ this.disposables.push(
62
+ this.mcpServerProxyService.onChangeMCPServers(() => {
63
+ this.fireMCPServersChange();
64
+ }),
65
+ );
66
+ this.disposables.push(
67
+ this.preferenceService.onSpecificPreferenceChange('mcp', () => {
68
+ this.fireMCPServersChange();
69
+ }),
70
+ );
71
+ }
72
+
73
+ private async init() {
74
+ this.chatStorage = await this.storageProvider(STORAGE_NAMESPACE.CHAT);
75
+ this.whenReadyDeferred.resolve();
76
+ }
77
+
78
+ get whenReady() {
79
+ return this.whenReadyDeferred.promise;
80
+ }
81
+
82
+ get onMCPServersChange() {
83
+ return this.mcpServersChangeEventEmitter.event;
84
+ }
85
+
86
+ fireMCPServersChange(isInit: boolean = false) {
87
+ this.mcpServersChangeEventEmitter.fire(isInit);
88
+ }
89
+
90
+ async getServers(): Promise<MCPServer[]> {
91
+ // Get workspace MCP server configurations
92
+ const { value: mcpConfig } = this.preferenceService.resolve<{ mcpServers: Record<string, any> }>(
93
+ 'mcp',
94
+ { mcpServers: {} },
95
+ undefined,
96
+ );
97
+
98
+ if (!mcpConfig?.mcpServers || Object.keys(mcpConfig.mcpServers).length === 0) {
99
+ const runningServers = await this.mcpServerProxyService.$getServers();
100
+ const builtinServer = runningServers.find((server) => server.name === BUILTIN_MCP_SERVER_NAME);
101
+ return builtinServer ? [builtinServer] : [];
102
+ }
103
+
104
+ const userServers = mcpConfig.mcpServers.map((server) => {
105
+ const name = Object.keys(server)[0];
106
+ const serverConfig = server[name];
107
+ if (serverConfig.url) {
108
+ return {
109
+ name,
110
+ type: MCP_SERVER_TYPE.SSE,
111
+ url: serverConfig.url,
112
+ };
113
+ }
114
+ return {
115
+ name,
116
+ type: MCP_SERVER_TYPE.STDIO,
117
+ command: serverConfig.command,
118
+ args: serverConfig.args,
119
+ env: serverConfig.env,
120
+ };
121
+ });
122
+
123
+ const runningServers = await this.mcpServerProxyService.$getServers();
124
+ const builtinServer = runningServers.find((server) => server.name === BUILTIN_MCP_SERVER_NAME);
125
+
126
+ // Merge server configs with running status
127
+ const allServers = userServers.map((server) => {
128
+ const runningServer = runningServers.find((s) => s.name === server.name);
129
+ return {
130
+ ...server,
131
+ isStarted: runningServer?.isStarted || false,
132
+ tools: runningServer?.tools || [],
133
+ };
134
+ }) as MCPServer[];
135
+
136
+ // Add built-in server at the beginning if it exists
137
+ if (builtinServer) {
138
+ allServers.unshift(builtinServer);
139
+ }
140
+
141
+ return allServers;
142
+ }
143
+
144
+ async controlServer(serverName: string, start: boolean): Promise<void> {
145
+ try {
146
+ if (start) {
147
+ await this.mcpServerProxyService.$startServer(serverName);
148
+ } else {
149
+ await this.mcpServerProxyService.$stopServer(serverName);
150
+ }
151
+
152
+ const enabledMCPServers = this.chatStorage.get<string[]>(MCPServersEnabledKey, [BUILTIN_MCP_SERVER_NAME]);
153
+ const enabledMCPServersSet = new Set(enabledMCPServers);
154
+
155
+ if (start) {
156
+ enabledMCPServersSet.add(serverName);
157
+ } else {
158
+ enabledMCPServersSet.delete(serverName);
159
+ }
160
+ this.chatStorage.set(MCPServersEnabledKey, Array.from(enabledMCPServersSet));
161
+ } catch (error) {
162
+ const msg = error.message || error;
163
+ this.logger.error(`Failed to ${start ? 'start' : 'stop'} server ${serverName}:`, msg);
164
+ this.messageService.error(msg);
165
+ throw error;
166
+ }
167
+ }
168
+
169
+ async saveServer(data: MCPServerFormData): Promise<void> {
170
+ await this.whenReady;
171
+ const { value: mcpConfig } = this.preferenceService.resolve<{ mcpServers: Record<string, any>[] }>(
172
+ 'mcp',
173
+ { mcpServers: [] },
174
+ undefined,
175
+ );
176
+ const servers = mcpConfig!.mcpServers;
177
+ const existingIndex = servers?.findIndex((s) => s.name === data.name);
178
+
179
+ let serverConfig;
180
+ if (data.type === MCP_SERVER_TYPE.SSE) {
181
+ serverConfig = { [data.name]: { url: (data as SSEMCPServerDescription).url } };
182
+ } else {
183
+ serverConfig = {
184
+ [data.name]: {
185
+ command: (data as StdioMCPServerDescription).command,
186
+ args: (data as StdioMCPServerDescription).args,
187
+ env: (data as StdioMCPServerDescription).env,
188
+ },
189
+ };
190
+ }
191
+ if (existingIndex !== undefined && existingIndex >= 0) {
192
+ servers[existingIndex] = serverConfig;
193
+ } else {
194
+ servers.push(serverConfig);
195
+ }
196
+ await this.sumiMCPServerBackendProxy.$addOrUpdateServer(data as MCPServerDescription);
197
+ await this.preferenceService.set('mcp', { mcpServers: servers });
198
+ }
199
+
200
+ async deleteServer(serverName: string): Promise<void> {
201
+ const { value: mcpConfig } = this.preferenceService.resolve<{ mcpServers: Record<string, any>[] }>(
202
+ 'mcp',
203
+ { mcpServers: [] },
204
+ undefined,
205
+ );
206
+ const servers = mcpConfig?.mcpServers;
207
+ const serverIndex = servers?.findIndex((s) => Object.keys(s)[0] === serverName);
208
+ if (serverIndex !== undefined && serverIndex >= 0) {
209
+ servers?.splice(serverIndex, 1);
210
+ }
211
+ await this.sumiMCPServerBackendProxy.$removeServer(serverName);
212
+ await this.preferenceService.set('mcp', { mcpServers: servers });
213
+ }
214
+
215
+ async syncServer(serverName: string): Promise<void> {
216
+ await this.sumiMCPServerBackendProxy.$syncServer(serverName);
217
+ }
218
+
219
+ async getServerConfigByName(serverName: string): Promise<MCPServerDescription | undefined> {
220
+ const { value: mcpConfig } = this.preferenceService.resolve<{ mcpServers: Record<string, any>[] }>(
221
+ 'mcp',
222
+ { mcpServers: [] },
223
+ undefined,
224
+ );
225
+ await this.whenReady;
226
+ const enabledMCPServers = this.chatStorage.get<string[]>(MCPServersEnabledKey, [BUILTIN_MCP_SERVER_NAME]);
227
+ const servers = mcpConfig?.mcpServers;
228
+ const server = servers?.find((s) => Object.keys(s)[0] === serverName);
229
+ if (server) {
230
+ if (server[serverName].url) {
231
+ return {
232
+ name: serverName,
233
+ type: MCP_SERVER_TYPE.SSE,
234
+ url: server[serverName].url,
235
+ enabled: enabledMCPServers.includes(serverName),
236
+ };
237
+ } else {
238
+ return {
239
+ name: serverName,
240
+ type: MCP_SERVER_TYPE.STDIO,
241
+ command: server[serverName].command,
242
+ args: server[serverName].args,
243
+ env: server[serverName].env,
244
+ enabled: enabledMCPServers.includes(serverName),
245
+ };
246
+ }
247
+ }
248
+ return undefined;
249
+ }
250
+
251
+ getReadableServerType(type: string): string {
252
+ switch (type) {
253
+ case MCP_SERVER_TYPE.STDIO:
254
+ return localize('ai.native.mcp.type.stdio');
255
+ case MCP_SERVER_TYPE.SSE:
256
+ return localize('ai.native.mcp.type.sse');
257
+ case MCP_SERVER_TYPE.BUILTIN:
258
+ return localize('ai.native.mcp.type.builtin');
259
+ default:
260
+ return type;
261
+ }
262
+ }
263
+
264
+ async openConfigFile(): Promise<void> {
265
+ let config = this.preferenceService.resolve<{ mcpServers: Record<string, any>[] }>(
266
+ 'mcp',
267
+ { mcpServers: [] },
268
+ undefined,
269
+ );
270
+ if (config.scope === PreferenceScope.Default) {
271
+ await this.preferenceService.set('mcp', { mcpServers: [] }, PreferenceScope.Workspace);
272
+ config = this.preferenceService.resolve<{ mcpServers: Record<string, any>[] }>(
273
+ 'mcp',
274
+ { mcpServers: [] },
275
+ undefined,
276
+ );
277
+ }
278
+ const uri = config.configUri;
279
+ if (uri) {
280
+ this.workbenchEditorService.open(uri, {
281
+ preview: false,
282
+ });
283
+ }
284
+ }
285
+ }
@@ -0,0 +1,23 @@
1
+ import { Injectable } from '@opensumi/di';
2
+ import { FolderFilePreferenceProvider } from '@opensumi/ide-preferences/lib/browser/folder-file-preference-provider';
3
+
4
+ @Injectable()
5
+ export class MCPFolderPreferenceProvider extends FolderFilePreferenceProvider {
6
+ protected parse(content: string): any {
7
+ const mcp = super.parse(content);
8
+ if (mcp === undefined) {
9
+ return undefined;
10
+ }
11
+ return { mcp: { ...mcp } };
12
+ }
13
+
14
+ protected getPath(preferenceName: string): string[] | undefined {
15
+ if (preferenceName === 'mcp') {
16
+ return [];
17
+ }
18
+ if (preferenceName.startsWith('mcp.')) {
19
+ return [preferenceName.substr('mcp.'.length)];
20
+ }
21
+ return undefined;
22
+ }
23
+ }
@@ -0,0 +1,62 @@
1
+ import { Autowired, Injectable } from '@opensumi/di';
2
+ import {
3
+ CodeSchemaId,
4
+ Domain,
5
+ IJSONSchema,
6
+ IJSONSchemaRegistry,
7
+ JsonSchemaContribution,
8
+ MaybePromise,
9
+ PreferenceConfiguration,
10
+ PreferenceContribution,
11
+ PreferenceSchema,
12
+ URI,
13
+ getIcon,
14
+ localize,
15
+ } from '@opensumi/ide-core-browser';
16
+ import {
17
+ BrowserEditorContribution,
18
+ IResource,
19
+ IResourceProvider,
20
+ ResourceService,
21
+ } from '@opensumi/ide-editor/lib/browser';
22
+
23
+ import { MCPPreferencesSchema, MCPSchema, MCPSchemaUri } from './mcp-preferences';
24
+
25
+ @Injectable()
26
+ export class MCPResourceProvider implements IResourceProvider {
27
+ provideResource(uri: URI): MaybePromise<IResource<any>> {
28
+ return {
29
+ supportsRevive: true,
30
+ name: localize('menu-bar.title.debug'),
31
+ icon: getIcon('debug'),
32
+ uri,
33
+ };
34
+ }
35
+
36
+ provideResourceSubname(): string | null {
37
+ return null;
38
+ }
39
+
40
+ async shouldCloseResource(): Promise<boolean> {
41
+ return true;
42
+ }
43
+ }
44
+
45
+ @Domain(PreferenceContribution, PreferenceConfiguration, BrowserEditorContribution, JsonSchemaContribution)
46
+ export class MCPPreferencesContribution
47
+ implements PreferenceContribution, PreferenceConfiguration, BrowserEditorContribution, JsonSchemaContribution
48
+ {
49
+ @Autowired(MCPResourceProvider)
50
+ private readonly prefResourceProvider: MCPResourceProvider;
51
+
52
+ schema: PreferenceSchema = MCPPreferencesSchema;
53
+ name = 'mcp';
54
+
55
+ registerResource(resourceService: ResourceService): void {
56
+ resourceService.registerResourceProvider(this.prefResourceProvider);
57
+ }
58
+
59
+ registerSchema(registry: IJSONSchemaRegistry) {
60
+ registry.registerSchema(MCPSchemaUri, MCPSchema, ['mcp.json']);
61
+ }
62
+ }
@@ -0,0 +1,48 @@
1
+ import { PreferenceSchema } from '@opensumi/ide-core-browser';
2
+ import { CodeSchemaId, IJSONSchema } from '@opensumi/ide-core-common';
3
+
4
+ export const MCPSchemaUri = `${CodeSchemaId.mcp}/user`;
5
+
6
+ export const MCPPreferencesSchema: PreferenceSchema = {
7
+ type: 'object',
8
+ scope: 'resource',
9
+ properties: {
10
+ mcp: {
11
+ $ref: MCPSchemaUri,
12
+ description: 'MCP configuration for Workspace.',
13
+ defaultValue: { mcpServers: [] },
14
+ },
15
+ },
16
+ };
17
+
18
+ export const MCPSchema: IJSONSchema = {
19
+ $id: MCPSchemaUri,
20
+ type: 'object',
21
+ title: 'MCP',
22
+ required: [],
23
+ default: { mcpServers: [] },
24
+ properties: {
25
+ mcpServers: {
26
+ type: 'object',
27
+ description: 'List of MCP Servers. Add new servers or edit existing ones by using IntelliSense.',
28
+ properties: {
29
+ command: {
30
+ type: 'string',
31
+ description: 'The command to start the MCP server.',
32
+ },
33
+ args: {
34
+ type: 'array',
35
+ description: 'The arguments for the command to start the MCP server.',
36
+ },
37
+ env: {
38
+ type: 'object',
39
+ description: 'The environment variables for the command to start the MCP server.',
40
+ },
41
+ url: {
42
+ type: 'string',
43
+ description: 'The SSE URL for the MCP server.',
44
+ },
45
+ },
46
+ },
47
+ },
48
+ };
@@ -105,6 +105,9 @@ export const aiNativePreferenceSchema: PreferenceSchema = {
105
105
  type: 'number',
106
106
  description: localize('preference.ai.native.maxTokens.description'),
107
107
  },
108
+ /**
109
+ * @deprecated This configuration will be removed in the future. Please use `mcp.json` instead.
110
+ */
108
111
  [AINativeSettingSectionsId.MCPServers]: {
109
112
  type: 'array',
110
113
  default: [],
@@ -77,7 +77,7 @@ export interface SSEMCPServerDescription extends BaseMCPServerDescription {
77
77
  /**
78
78
  * The host of the MCP server.
79
79
  */
80
- serverHost: string;
80
+ url: string;
81
81
  transportOptions?: SSEClientTransportOptions;
82
82
  }
83
83
 
@@ -99,3 +99,5 @@ export type MCPServerDescription =
99
99
 
100
100
  export const MCPServerManager = Symbol('MCPServerManager');
101
101
  export const MCPServerManagerPath = 'ServicesMCPServerManager';
102
+
103
+ export const MCPServersEnabledKey = 'mcp_servers_enabled';
@@ -49,7 +49,7 @@ export interface MCPServer {
49
49
  tools?: MCPTool[];
50
50
  command?: string;
51
51
  type?: string;
52
- serverHost?: string;
52
+ url?: string;
53
53
  }
54
54
 
55
55
  export interface MCPTool {
@@ -176,7 +176,7 @@ export class SumiMCPServerBackend extends RPCService<IMCPServerProxyService> imp
176
176
  name: server.getServerName(),
177
177
  isStarted: server.isStarted(),
178
178
  type: MCP_SERVER_TYPE.SSE,
179
- serverHost: server.serverHost,
179
+ url: server.url,
180
180
  tools,
181
181
  };
182
182
  }
@@ -157,11 +157,11 @@ export class MCPServerManagerImpl implements MCPServerManager {
157
157
  this.servers.set(name, newServer);
158
158
  }
159
159
  } else if (description.type === MCP_SERVER_TYPE.SSE) {
160
- const { name, serverHost, transportOptions } = description;
160
+ const { name, url, transportOptions } = description;
161
161
  if (existingServer) {
162
- existingServer.update(serverHost);
162
+ existingServer.update(url);
163
163
  } else {
164
- const newServer = new SSEMCPServer(name, serverHost, this.logger, transportOptions);
164
+ const newServer = new SSEMCPServer(name, url, this.logger, transportOptions);
165
165
  this.servers.set(name, newServer);
166
166
  }
167
167
  }
@@ -188,7 +188,11 @@ export class MCPServerManagerImpl implements MCPServerManager {
188
188
  // 如果是 enabled 为 false 的 server,则不进行启动
189
189
  continue;
190
190
  }
191
- await this.startServer(server.name);
191
+ try {
192
+ await this.startServer(server.name);
193
+ } catch (error) {
194
+ this.logger.error(`Error in addExternalMCPServers for ${server.name}:`, error);
195
+ }
192
196
  }
193
197
  }
194
198