@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
@@ -1,190 +1,99 @@
1
1
  import cls from 'classnames';
2
2
  import React, { useCallback } from 'react';
3
3
 
4
- import { Badge, Button, Popover, PopoverTriggerType } from '@opensumi/ide-components';
5
- import { AINativeSettingSectionsId, ILogger, useInjectable } from '@opensumi/ide-core-browser';
6
- import { PreferenceService } from '@opensumi/ide-core-browser/lib/preferences';
7
- import { PreferenceScope, localize } from '@opensumi/ide-core-common';
8
- import { IMessageService } from '@opensumi/ide-overlay';
4
+ import { Badge, Button, Icon, Popover, PopoverTriggerType } from '@opensumi/ide-components';
5
+ import { useInjectable } from '@opensumi/ide-core-browser';
6
+ import { MCPConfigServiceToken, localize } from '@opensumi/ide-core-common';
9
7
 
10
- import { BUILTIN_MCP_SERVER_NAME, ISumiMCPServerBackend, SumiMCPServerProxyServicePath } from '../../../../common';
11
- import { MCPServerDescription } from '../../../../common/mcp-server-manager';
12
- import { MCPServer, MCP_SERVER_TYPE } from '../../../../common/types';
13
- import { MCPServerProxyService } from '../../mcp-server-proxy.service';
8
+ import { BUILTIN_MCP_SERVER_NAME } from '../../../../common';
9
+ import { MCPServer } from '../../../../common/types';
10
+ import { MCPConfigService } from '../mcp-config.service';
14
11
 
15
12
  import styles from './mcp-config.module.less';
16
13
  import { MCPServerForm, MCPServerFormData } from './mcp-server-form';
17
14
 
18
15
  export const MCPConfigView: React.FC = () => {
19
- const mcpServerProxyService = useInjectable<MCPServerProxyService>(MCPServerProxyService);
20
- const preferenceService = useInjectable<PreferenceService>(PreferenceService);
21
- const messageService = useInjectable<IMessageService>(IMessageService);
22
- const sumiMCPServerBackendProxy = useInjectable<ISumiMCPServerBackend>(SumiMCPServerProxyServicePath);
23
- const logger = useInjectable<ILogger>(ILogger);
16
+ const mcpConfigService = useInjectable<MCPConfigService>(MCPConfigServiceToken);
24
17
  const [servers, setServers] = React.useState<MCPServer[]>([]);
25
18
  const [formVisible, setFormVisible] = React.useState(false);
26
19
  const [editingServer, setEditingServer] = React.useState<MCPServerFormData | undefined>();
27
20
  const [loadingServer, setLoadingServer] = React.useState<string | undefined>();
21
+ const [isReady, setIsReady] = React.useState(false);
22
+
28
23
  const loadServers = useCallback(async () => {
29
- const userServers = preferenceService.get<MCPServerDescription[]>(AINativeSettingSectionsId.MCPServers, []);
30
- const runningServers = await mcpServerProxyService.$getServers();
31
- const builtinServer = runningServers.find((server) => server.name === BUILTIN_MCP_SERVER_NAME);
32
- const allServers = userServers
33
- .filter((server) => server.type === MCP_SERVER_TYPE.STDIO || server.type === MCP_SERVER_TYPE.SSE)
34
- .map((server) => {
35
- const runningServer = runningServers.find((s) => s.name === server.name);
36
- return {
37
- ...server,
38
- name: server.name,
39
- isStarted: runningServer?.isStarted,
40
- tools: runningServer?.tools,
41
- };
42
- }) as MCPServer[];
43
- if (builtinServer) {
44
- allServers.unshift(builtinServer);
45
- }
24
+ const allServers = await mcpConfigService.getServers();
46
25
  setServers(allServers);
47
- }, [mcpServerProxyService]);
26
+ }, [mcpConfigService]);
48
27
 
49
28
  React.useEffect(() => {
50
29
  loadServers();
51
- const disposer = mcpServerProxyService.onChangeMCPServers(() => {
30
+ const disposer = mcpConfigService.onMCPServersChange((isReady) => {
31
+ if (isReady) {
32
+ setIsReady(true);
33
+ }
52
34
  loadServers();
53
35
  });
54
36
 
55
37
  return () => {
56
38
  disposer.dispose();
57
39
  };
58
- }, []);
40
+ }, [loadServers]);
59
41
 
60
42
  const handleServerControl = useCallback(
61
43
  async (serverName: string, start: boolean) => {
62
44
  try {
63
45
  setLoadingServer(serverName);
64
- if (start) {
65
- await mcpServerProxyService.$startServer(serverName);
66
- } else {
67
- await mcpServerProxyService.$stopServer(serverName);
68
- }
69
-
70
- // Update enabled state in preferences
71
- const servers = preferenceService.get<MCPServerDescription[]>(AINativeSettingSectionsId.MCPServers, []);
72
- let updatedServers = servers;
73
- // 处理内置服务器的特殊情况
74
- if (serverName === BUILTIN_MCP_SERVER_NAME) {
75
- const builtinServerExists = servers.some((server) => server.name === BUILTIN_MCP_SERVER_NAME);
76
- if (!builtinServerExists && !start) {
77
- // 如果是停止内置服务器且之前没有配置,添加一个新的配置项
78
- // 内置服务器不需要 command,因为它是直接集成在 IDE 中的
79
- updatedServers = [
80
- ...servers,
81
- {
82
- name: BUILTIN_MCP_SERVER_NAME,
83
- enabled: false,
84
- type: MCP_SERVER_TYPE.BUILTIN,
85
- },
86
- ];
87
- } else {
88
- // 如果已经存在配置,更新 enabled 状态
89
- updatedServers = servers.map((server) => {
90
- if (server.name === BUILTIN_MCP_SERVER_NAME) {
91
- return { ...server, enabled: start };
92
- }
93
- return server;
94
- });
95
- }
96
- } else {
97
- // 处理其他外部服务器
98
- updatedServers = servers.map((server) => {
99
- if (server.name === serverName) {
100
- return { ...server, enabled: start };
101
- }
102
- return server;
103
- });
104
- }
105
-
106
- await preferenceService.set(AINativeSettingSectionsId.MCPServers, updatedServers, PreferenceScope.User);
46
+ await mcpConfigService.controlServer(serverName, start);
107
47
  await loadServers();
108
48
  setLoadingServer(undefined);
109
49
  } catch (error) {
110
- const msg = error.message || error;
111
- logger.error(`Failed to ${start ? 'start' : 'stop'} server ${serverName}:`, msg);
112
- messageService.error(msg);
113
50
  setLoadingServer(undefined);
114
51
  }
115
52
  },
116
- [mcpServerProxyService, preferenceService, sumiMCPServerBackendProxy, loadServers],
53
+ [mcpConfigService, loadServers],
117
54
  );
118
55
 
119
56
  const handleAddServer = useCallback(() => {
120
57
  setEditingServer(undefined);
121
58
  setFormVisible(true);
122
- }, [editingServer, formVisible]);
59
+ }, []);
123
60
 
124
61
  const handleEditServer = useCallback(
125
- (server: MCPServer) => {
126
- const servers = preferenceService.get<MCPServerFormData[]>(AINativeSettingSectionsId.MCPServers, []);
127
- const serverConfig = servers.find((s) => s.name === server.name);
128
-
62
+ async (server: MCPServer) => {
63
+ const serverConfig = await mcpConfigService.getServerConfigByName(server.name);
129
64
  if (serverConfig) {
130
65
  setEditingServer(serverConfig);
131
66
  setFormVisible(true);
132
67
  }
133
68
  },
134
- [editingServer, formVisible],
69
+ [mcpConfigService],
135
70
  );
136
71
 
137
72
  const handleDeleteServer = useCallback(
138
73
  async (serverName: string) => {
139
- const servers = preferenceService.get<MCPServerFormData[]>(AINativeSettingSectionsId.MCPServers, []);
140
- const updatedServers = servers.filter((s) => s.name !== serverName);
141
- sumiMCPServerBackendProxy.$removeServer(serverName);
142
- await preferenceService.set(AINativeSettingSectionsId.MCPServers, updatedServers, PreferenceScope.User);
74
+ await mcpConfigService.deleteServer(serverName);
143
75
  await loadServers();
144
76
  },
145
- [editingServer, formVisible],
77
+ [mcpConfigService, loadServers],
146
78
  );
147
79
 
148
80
  const handleSaveServer = useCallback(
149
81
  async (data: MCPServerFormData) => {
150
- const servers = preferenceService.get<MCPServerFormData[]>(AINativeSettingSectionsId.MCPServers, []);
151
- const existingIndex = servers.findIndex((s) => s.name === data.name);
152
-
153
- if (existingIndex >= 0) {
154
- servers[existingIndex] = data;
155
- } else {
156
- servers.push(data);
157
- }
158
- setServers(servers as MCPServer[]);
82
+ await mcpConfigService.saveServer(data);
159
83
  setFormVisible(false);
160
- await sumiMCPServerBackendProxy.$addOrUpdateServer(data as MCPServerDescription);
161
- await preferenceService.set(AINativeSettingSectionsId.MCPServers, servers, PreferenceScope.User);
162
84
  await loadServers();
163
85
  },
164
- [servers, formVisible, loadServers],
86
+ [mcpConfigService, loadServers],
165
87
  );
166
88
 
167
- const getReadableServerType = useCallback((type: string) => {
168
- switch (type) {
169
- case MCP_SERVER_TYPE.STDIO:
170
- return localize('ai.native.mcp.type.stdio');
171
- case MCP_SERVER_TYPE.SSE:
172
- return localize('ai.native.mcp.type.sse');
173
- case MCP_SERVER_TYPE.BUILTIN:
174
- return localize('ai.native.mcp.type.builtin');
175
- default:
176
- return type;
177
- }
178
- }, []);
179
-
180
89
  const handleSyncServer = useCallback(
181
90
  async (server: MCPServer) => {
182
91
  setLoadingServer(server.name);
183
- await sumiMCPServerBackendProxy.$syncServer(server.name);
92
+ await mcpConfigService.syncServer(server.name);
184
93
  await loadServers();
185
94
  setLoadingServer(undefined);
186
95
  },
187
- [loadServers, loadingServer],
96
+ [mcpConfigService, loadServers],
188
97
  );
189
98
 
190
99
  return (
@@ -194,8 +103,9 @@ export const MCPConfigView: React.FC = () => {
194
103
  <h2 className={styles.title}>MCP Servers</h2>
195
104
  <p className={styles.description}>{localize('ai.native.mcp.manage.connections')}</p>
196
105
  </div>
197
- <button className={styles.addButton} onClick={handleAddServer}>
198
- + {localize('ai.native.mcp.addMCPServer.title')}
106
+ <button className={styles.actionButton} onClick={handleAddServer}>
107
+ <Icon icon='plus' className={styles.actionButtonIcon} />
108
+ {localize('ai.native.mcp.addMCPServer.title')}
199
109
  </button>
200
110
  </div>
201
111
  <div className={styles.serversList}>
@@ -225,7 +135,7 @@ export const MCPConfigView: React.FC = () => {
225
135
  >
226
136
  <i
227
137
  className={`codicon ${
228
- loadingServer === server.name
138
+ loadingServer === server.name || (!isReady && server.name !== BUILTIN_MCP_SERVER_NAME)
229
139
  ? 'codicon-loading kt-icon-loading'
230
140
  : server.isStarted
231
141
  ? 'codicon-check'
@@ -268,7 +178,9 @@ export const MCPConfigView: React.FC = () => {
268
178
  {server.type && (
269
179
  <div className={styles.detailRow}>
270
180
  <span className={styles.detailLabel}>Type:</span>
271
- <Badge className={cls(styles.serverType, styles.typeTag)}>{getReadableServerType(server.type)}</Badge>
181
+ <Badge className={cls(styles.serverType, styles.typeTag)}>
182
+ {mcpConfigService.getReadableServerType(server.type)}
183
+ </Badge>
272
184
  </div>
273
185
  )}
274
186
  </div>
@@ -294,11 +206,11 @@ export const MCPConfigView: React.FC = () => {
294
206
  </div>
295
207
  </div>
296
208
  )}
297
- {server.serverHost && (
209
+ {server.url && (
298
210
  <div className={styles.serverDetail}>
299
211
  <div className={styles.detailRow}>
300
212
  <span className={styles.detailLabel}>Server Link:</span>
301
- <span className={cls(styles.detailContent, styles.link)}>{server.serverHost}</span>
213
+ <span className={cls(styles.detailContent, styles.link)}>{server.url}</span>
302
214
  </div>
303
215
  </div>
304
216
  )}
@@ -17,7 +17,7 @@ export interface MCPServerFormData {
17
17
  args?: string[];
18
18
  env?: Record<string, string>;
19
19
  type: MCP_SERVER_TYPE;
20
- serverHost?: string;
20
+ url?: string;
21
21
  }
22
22
 
23
23
  interface Props {
@@ -81,9 +81,9 @@ export const MCPServerForm: FC<Props> = ({ visible, initialData, onSave, onCance
81
81
  return false;
82
82
  }
83
83
  if (formData.type === MCP_SERVER_TYPE.SSE) {
84
- const isServerHostValid = formData.serverHost?.trim() !== '';
84
+ const isServerHostValid = formData.url?.trim() !== '';
85
85
  if (!isServerHostValid) {
86
- messageService.error(localize('ai.native.mcp.serverHost.isRequired'));
86
+ messageService.error(localize('ai.native.mcp.url.isRequired'));
87
87
  }
88
88
  return isServerHostValid;
89
89
  }
@@ -107,7 +107,7 @@ export const MCPServerForm: FC<Props> = ({ visible, initialData, onSave, onCance
107
107
  ...formData,
108
108
  };
109
109
  if (formData.type === MCP_SERVER_TYPE.SSE) {
110
- form.serverHost = form.serverHost?.trim();
110
+ form.url = form.url?.trim();
111
111
  } else {
112
112
  const args = argsText.split(' ').filter(Boolean);
113
113
  const env = envText
@@ -127,7 +127,7 @@ export const MCPServerForm: FC<Props> = ({ visible, initialData, onSave, onCance
127
127
  setFormData({
128
128
  ...formData,
129
129
  command: '',
130
- serverHost: '',
130
+ url: '',
131
131
  args: [],
132
132
  env: {},
133
133
  });
@@ -160,7 +160,7 @@ export const MCPServerForm: FC<Props> = ({ visible, initialData, onSave, onCance
160
160
 
161
161
  const handleServerHostChange = useCallback(
162
162
  (e: ChangeEvent<HTMLTextAreaElement>) => {
163
- setFormData({ ...formData, serverHost: e.target.value });
163
+ setFormData({ ...formData, url: e.target.value });
164
164
  },
165
165
  [formData],
166
166
  );
@@ -173,7 +173,7 @@ export const MCPServerForm: FC<Props> = ({ visible, initialData, onSave, onCance
173
173
  command: '',
174
174
  args: [],
175
175
  env: {},
176
- serverHost: '',
176
+ url: '',
177
177
  });
178
178
  },
179
179
  [formData],
@@ -217,11 +217,11 @@ export const MCPServerForm: FC<Props> = ({ visible, initialData, onSave, onCance
217
217
  return (
218
218
  <>
219
219
  <div className={styles.formItem}>
220
- <label>{localize('ai.native.mcp.serverHost')}</label>
220
+ <label>{localize('ai.native.mcp.url')}</label>
221
221
  <textarea
222
- value={formData.serverHost}
222
+ value={formData.url}
223
223
  onChange={handleServerHostChange}
224
- placeholder={localize('ai.native.mcp.serverHost.placeHolder')}
224
+ placeholder={localize('ai.native.mcp.url.placeHolder')}
225
225
  rows={3}
226
226
  />
227
227
  </div>
@@ -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
  }