@opensumi/ide-ai-native 3.8.3-next-1745568063.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 (102) 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/ChatToolRender.d.ts.map +1 -1
  10. package/lib/browser/components/ChatToolRender.js +2 -1
  11. package/lib/browser/components/ChatToolRender.js.map +1 -1
  12. package/lib/browser/components/ChatToolResult.d.ts +8 -0
  13. package/lib/browser/components/ChatToolResult.d.ts.map +1 -0
  14. package/lib/browser/components/ChatToolResult.js +38 -0
  15. package/lib/browser/components/ChatToolResult.js.map +1 -0
  16. package/lib/browser/components/ChatToolResult.module.less +24 -0
  17. package/lib/browser/components/mention-input/mention-input.d.ts.map +1 -1
  18. package/lib/browser/components/mention-input/mention-input.js +9 -7
  19. package/lib/browser/components/mention-input/mention-input.js.map +1 -1
  20. package/lib/browser/index.d.ts.map +1 -1
  21. package/lib/browser/index.js +15 -0
  22. package/lib/browser/index.js.map +1 -1
  23. package/lib/browser/mcp/config/components/mcp-config.module.less +4 -1
  24. package/lib/browser/mcp/config/components/mcp-config.view.d.ts.map +1 -1
  25. package/lib/browser/mcp/config/components/mcp-config.view.js +27 -119
  26. package/lib/browser/mcp/config/components/mcp-config.view.js.map +1 -1
  27. package/lib/browser/mcp/config/components/mcp-server-form.d.ts +1 -1
  28. package/lib/browser/mcp/config/components/mcp-server-form.d.ts.map +1 -1
  29. package/lib/browser/mcp/config/components/mcp-server-form.js +8 -8
  30. package/lib/browser/mcp/config/components/mcp-server-form.js.map +1 -1
  31. package/lib/browser/mcp/config/mcp-config.commands.d.ts +11 -4
  32. package/lib/browser/mcp/config/mcp-config.commands.d.ts.map +1 -1
  33. package/lib/browser/mcp/config/mcp-config.commands.js +23 -6
  34. package/lib/browser/mcp/config/mcp-config.commands.js.map +1 -1
  35. package/lib/browser/mcp/config/mcp-config.contribution.d.ts +4 -1
  36. package/lib/browser/mcp/config/mcp-config.contribution.d.ts.map +1 -1
  37. package/lib/browser/mcp/config/mcp-config.contribution.js +20 -1
  38. package/lib/browser/mcp/config/mcp-config.contribution.js.map +1 -1
  39. package/lib/browser/mcp/config/mcp-config.service.d.ts +30 -0
  40. package/lib/browser/mcp/config/mcp-config.service.d.ts.map +1 -0
  41. package/lib/browser/mcp/config/mcp-config.service.js +236 -0
  42. package/lib/browser/mcp/config/mcp-config.service.js.map +1 -0
  43. package/lib/browser/mcp/mcp-folder-preference-provider.d.ts +6 -0
  44. package/lib/browser/mcp/mcp-folder-preference-provider.d.ts.map +1 -0
  45. package/lib/browser/mcp/mcp-folder-preference-provider.js +29 -0
  46. package/lib/browser/mcp/mcp-folder-preference-provider.js.map +1 -0
  47. package/lib/browser/mcp/mcp-preferences-contribution.d.ts +15 -0
  48. package/lib/browser/mcp/mcp-preferences-contribution.d.ts.map +1 -0
  49. package/lib/browser/mcp/mcp-preferences-contribution.js +49 -0
  50. package/lib/browser/mcp/mcp-preferences-contribution.js.map +1 -0
  51. package/lib/browser/mcp/mcp-preferences.d.ts +6 -0
  52. package/lib/browser/mcp/mcp-preferences.d.ts.map +1 -0
  53. package/lib/browser/mcp/mcp-preferences.js +47 -0
  54. package/lib/browser/mcp/mcp-preferences.js.map +1 -0
  55. package/lib/browser/preferences/schema.d.ts.map +1 -1
  56. package/lib/browser/preferences/schema.js +3 -0
  57. package/lib/browser/preferences/schema.js.map +1 -1
  58. package/lib/common/mcp-server-manager.d.ts +2 -1
  59. package/lib/common/mcp-server-manager.d.ts.map +1 -1
  60. package/lib/common/mcp-server-manager.js +2 -1
  61. package/lib/common/mcp-server-manager.js.map +1 -1
  62. package/lib/common/types.d.ts +1 -1
  63. package/lib/common/types.d.ts.map +1 -1
  64. package/lib/node/mcp/sumi-mcp-server.d.ts +3 -3
  65. package/lib/node/mcp/sumi-mcp-server.js +1 -1
  66. package/lib/node/mcp/sumi-mcp-server.js.map +1 -1
  67. package/lib/node/mcp-server-manager-impl.d.ts.map +1 -1
  68. package/lib/node/mcp-server-manager-impl.js +9 -4
  69. package/lib/node/mcp-server-manager-impl.js.map +1 -1
  70. package/lib/node/mcp-server.sse.d.ts +10 -37
  71. package/lib/node/mcp-server.sse.d.ts.map +1 -1
  72. package/lib/node/mcp-server.sse.js +43 -15
  73. package/lib/node/mcp-server.sse.js.map +1 -1
  74. package/lib/node/mcp-server.stdio.d.ts +7 -34
  75. package/lib/node/mcp-server.stdio.d.ts.map +1 -1
  76. package/lib/node/mcp-server.stdio.js +27 -2
  77. package/lib/node/mcp-server.stdio.js.map +1 -1
  78. package/package.json +24 -24
  79. package/src/browser/ai-core.contribution.ts +71 -16
  80. package/src/browser/components/ChatInput.tsx +2 -2
  81. package/src/browser/components/ChatMentionInput.tsx +2 -2
  82. package/src/browser/components/ChatToolRender.tsx +3 -1
  83. package/src/browser/components/ChatToolResult.module.less +24 -0
  84. package/src/browser/components/ChatToolResult.tsx +64 -0
  85. package/src/browser/components/mention-input/mention-input.tsx +27 -23
  86. package/src/browser/index.ts +16 -0
  87. package/src/browser/mcp/config/components/mcp-config.module.less +4 -1
  88. package/src/browser/mcp/config/components/mcp-config.view.tsx +37 -125
  89. package/src/browser/mcp/config/components/mcp-server-form.tsx +10 -10
  90. package/src/browser/mcp/config/mcp-config.commands.ts +22 -6
  91. package/src/browser/mcp/config/mcp-config.contribution.ts +24 -2
  92. package/src/browser/mcp/config/mcp-config.service.ts +285 -0
  93. package/src/browser/mcp/mcp-folder-preference-provider.ts +23 -0
  94. package/src/browser/mcp/mcp-preferences-contribution.ts +62 -0
  95. package/src/browser/mcp/mcp-preferences.ts +48 -0
  96. package/src/browser/preferences/schema.ts +3 -0
  97. package/src/common/mcp-server-manager.ts +3 -1
  98. package/src/common/types.ts +1 -1
  99. package/src/node/mcp/sumi-mcp-server.ts +1 -1
  100. package/src/node/mcp-server-manager-impl.ts +8 -4
  101. package/src/node/mcp-server.sse.ts +41 -14
  102. package/src/node/mcp-server.stdio.ts +26 -2
@@ -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
 
@@ -11,19 +11,20 @@ import { SSEClientTransportOptions } from '../common/types';
11
11
  global.EventSource = EventSource as any;
12
12
  export class SSEMCPServer implements IMCPServer {
13
13
  private name: string;
14
- public serverHost: string;
14
+ public url: string;
15
15
  private transportOptions?: SSEClientTransportOptions;
16
16
  private client: Client;
17
17
  private started: boolean = false;
18
+ private toolNameMap: Map<string, string> = new Map(); // Map sanitized tool names to original names
18
19
 
19
20
  constructor(
20
21
  name: string,
21
- serverHost: string,
22
+ url: string,
22
23
  private readonly logger?: ILogger,
23
24
  private readonly options?: SSEClientTransportOptions,
24
25
  ) {
25
26
  this.name = name;
26
- this.serverHost = serverHost;
27
+ this.url = url;
27
28
  this.transportOptions = options;
28
29
  }
29
30
 
@@ -43,11 +44,11 @@ export class SSEMCPServer implements IMCPServer {
43
44
  if (this.started) {
44
45
  return;
45
46
  }
46
- this.logger?.log(`Starting server "${this.name}" with serverHost: ${this.serverHost}`);
47
+ this.logger?.log(`Starting server "${this.name}" with url: ${this.url}`);
47
48
 
48
49
  const SSEClientTransport = (await import('@modelcontextprotocol/sdk/client/sse.js')).SSEClientTransport;
49
50
 
50
- const transport = new SSEClientTransport(new URL(this.serverHost), this.transportOptions);
51
+ const transport = new SSEClientTransport(new URL(this.url), this.transportOptions);
51
52
 
52
53
  transport.onerror = (error) => {
53
54
  this.logger?.error('Transport Error:', error);
@@ -66,8 +67,13 @@ export class SSEMCPServer implements IMCPServer {
66
67
  this.logger?.error('Error in MCP client:', error);
67
68
  };
68
69
 
69
- await this.client.connect(transport);
70
- this.started = true;
70
+ try {
71
+ await this.client.connect(transport);
72
+ this.started = true;
73
+ } catch (error) {
74
+ this.logger?.error(`Error in startServer for ${this.name}:`, error);
75
+ throw error;
76
+ }
71
77
  }
72
78
 
73
79
  async callTool(toolName: string, toolCallId: string, arg_string: string) {
@@ -76,13 +82,15 @@ export class SSEMCPServer implements IMCPServer {
76
82
  args = JSON.parse(arg_string);
77
83
  } catch (error) {
78
84
  this.logger?.error(
79
- `Failed to parse arguments for calling tool "${toolName}" in MCP server "${this.name}" with serverHost "${this.serverHost}".
85
+ `Failed to parse arguments for calling tool "${toolName}" in MCP server "${this.name}" with url "${this.url}".
80
86
  Invalid JSON: ${arg_string}`,
81
87
  error,
82
88
  );
83
89
  }
90
+ // Convert sanitized tool name back to original name if it exists in the map
91
+ const originalToolName = this.toolNameMap.get(toolName) || toolName;
84
92
  const params = {
85
- name: toolName,
93
+ name: originalToolName,
86
94
  arguments: args,
87
95
  toolCallId,
88
96
  };
@@ -90,13 +98,32 @@ export class SSEMCPServer implements IMCPServer {
90
98
  }
91
99
 
92
100
  async getTools() {
93
- const tools = await this.client.listTools();
94
- this.logger?.log(`Got tools from MCP server "${this.name}" with serverHost "${this.serverHost}":`, tools);
95
- return tools;
101
+ const originalTools = await this.client.listTools();
102
+ this.toolNameMap.clear();
103
+ const toolsArray = originalTools.tools || [];
104
+ const sanitizedToolsArray = toolsArray.map((tool) => {
105
+ const originalName = tool.name;
106
+ // Remove Chinese characters from the tool name
107
+ // Claude 3.5+ Sonnet 不支持中文 Tool Name
108
+ const sanitizedName = originalName.replace(/[\u4e00-\u9fa5]/g, '');
109
+ // If the name changed, store the mapping
110
+ if (sanitizedName !== originalName) {
111
+ this.toolNameMap.set(sanitizedName, originalName);
112
+ return { ...tool, name: sanitizedName };
113
+ }
114
+ return tool;
115
+ });
116
+ const sanitizedTools = {
117
+ ...originalTools,
118
+ tools: sanitizedToolsArray,
119
+ };
120
+ this.logger?.log(`Got tools from MCP server "${this.name}" with url "${this.url}":`, sanitizedTools);
121
+ this.logger?.log('Tool name mapping: ', Object.fromEntries(this.toolNameMap));
122
+ return sanitizedTools;
96
123
  }
97
124
 
98
- update(serverHost: string): void {
99
- this.serverHost = serverHost;
125
+ update(url: string): void {
126
+ this.url = url;
100
127
  }
101
128
 
102
129
  async stop(): Promise<void> {
@@ -14,6 +14,7 @@ export class StdioMCPServer implements IMCPServer {
14
14
  private client: Client;
15
15
  private env?: { [key: string]: string };
16
16
  private started: boolean = false;
17
+ private toolNameMap: Map<string, string> = new Map(); // Map sanitized tool names to original names
17
18
 
18
19
  constructor(
19
20
  name: string,
@@ -95,8 +96,10 @@ export class StdioMCPServer implements IMCPServer {
95
96
  error,
96
97
  );
97
98
  }
99
+ // Convert sanitized tool name back to original name if it exists in the map
100
+ const originalToolName = this.toolNameMap.get(toolName) || toolName;
98
101
  const params = {
99
- name: toolName,
102
+ name: originalToolName,
100
103
  arguments: args,
101
104
  toolCallId,
102
105
  };
@@ -104,7 +107,28 @@ export class StdioMCPServer implements IMCPServer {
104
107
  }
105
108
 
106
109
  async getTools() {
107
- return await this.client.listTools();
110
+ const originalTools = await this.client.listTools();
111
+ this.toolNameMap.clear();
112
+ // Process tool names to remove Chinese characters and create mapping
113
+ const toolsArray = originalTools.tools || [];
114
+ const sanitizedToolsArray = toolsArray.map((tool) => {
115
+ const originalName = tool.name;
116
+ // Remove Chinese characters from the tool name
117
+ // Claude 3.5+ Sonnet 不支持中文 Tool Name
118
+ const sanitizedName = originalName.replace(/[\u4e00-\u9fa5]/g, '');
119
+ if (sanitizedName !== originalName) {
120
+ this.toolNameMap.set(sanitizedName, originalName);
121
+ return { ...tool, name: sanitizedName };
122
+ }
123
+ return tool;
124
+ });
125
+ const sanitizedTools = {
126
+ ...originalTools,
127
+ tools: sanitizedToolsArray,
128
+ };
129
+ this.logger?.log(`Got tools from MCP server "${this.name}":`, sanitizedTools);
130
+ this.logger?.log('Tool name mapping: ', Object.fromEntries(this.toolNameMap));
131
+ return sanitizedTools;
108
132
  }
109
133
 
110
134
  update(command: string, args?: string[], env?: { [key: string]: string }): void {