@opensumi/ide-ai-native 3.8.1-next-1740452912.0 → 3.8.1-next-1740463566.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 (122) hide show
  1. package/lib/browser/ai-core.contribution.d.ts.map +1 -1
  2. package/lib/browser/ai-core.contribution.js +10 -3
  3. package/lib/browser/ai-core.contribution.js.map +1 -1
  4. package/lib/browser/chat/chat-manager.service.d.ts +5 -0
  5. package/lib/browser/chat/chat-manager.service.d.ts.map +1 -1
  6. package/lib/browser/chat/chat-manager.service.js +18 -1
  7. package/lib/browser/chat/chat-manager.service.js.map +1 -1
  8. package/lib/browser/chat/chat-model.d.ts +2 -0
  9. package/lib/browser/chat/chat-model.d.ts.map +1 -1
  10. package/lib/browser/chat/chat-model.js +8 -2
  11. package/lib/browser/chat/chat-model.js.map +1 -1
  12. package/lib/browser/chat/chat.view.d.ts.map +1 -1
  13. package/lib/browser/chat/chat.view.js +31 -8
  14. package/lib/browser/chat/chat.view.js.map +1 -1
  15. package/lib/browser/components/ChatContext/index.js +2 -2
  16. package/lib/browser/components/ChatContext/index.js.map +1 -1
  17. package/lib/browser/context/llm-context.service.d.ts +16 -5
  18. package/lib/browser/context/llm-context.service.d.ts.map +1 -1
  19. package/lib/browser/context/llm-context.service.js +78 -47
  20. package/lib/browser/context/llm-context.service.js.map +1 -1
  21. package/lib/browser/index.d.ts.map +1 -1
  22. package/lib/browser/index.js +4 -0
  23. package/lib/browser/index.js.map +1 -1
  24. package/lib/browser/mcp/config/components/mcp-config.module.less +178 -0
  25. package/lib/browser/mcp/config/components/mcp-config.view.d.ts +3 -0
  26. package/lib/browser/mcp/config/components/mcp-config.view.d.ts.map +1 -0
  27. package/lib/browser/mcp/config/components/mcp-config.view.js +150 -0
  28. package/lib/browser/mcp/config/components/mcp-config.view.js.map +1 -0
  29. package/lib/browser/mcp/config/components/mcp-server-form.d.ts +16 -0
  30. package/lib/browser/mcp/config/components/mcp-server-form.d.ts.map +1 -0
  31. package/lib/browser/mcp/config/components/mcp-server-form.js +84 -0
  32. package/lib/browser/mcp/config/components/mcp-server-form.js.map +1 -0
  33. package/lib/browser/mcp/config/components/mcp-server-form.module.less +78 -0
  34. package/lib/browser/mcp/config/mcp-config.commands.d.ts +10 -0
  35. package/lib/browser/mcp/config/mcp-config.commands.d.ts.map +1 -0
  36. package/lib/browser/mcp/config/mcp-config.commands.js +35 -0
  37. package/lib/browser/mcp/config/mcp-config.commands.js.map +1 -0
  38. package/lib/browser/mcp/config/mcp-config.contribution.d.ts +16 -0
  39. package/lib/browser/mcp/config/mcp-config.contribution.d.ts.map +1 -0
  40. package/lib/browser/mcp/config/mcp-config.contribution.js +62 -0
  41. package/lib/browser/mcp/config/mcp-config.contribution.js.map +1 -0
  42. package/lib/browser/mcp/mcp-server-proxy.service.d.ts +6 -0
  43. package/lib/browser/mcp/mcp-server-proxy.service.d.ts.map +1 -1
  44. package/lib/browser/mcp/mcp-server-proxy.service.js +10 -1
  45. package/lib/browser/mcp/mcp-server-proxy.service.js.map +1 -1
  46. package/lib/browser/mcp/mcp-server.feature.registry.d.ts.map +1 -1
  47. package/lib/browser/mcp/mcp-server.feature.registry.js +3 -2
  48. package/lib/browser/mcp/mcp-server.feature.registry.js.map +1 -1
  49. package/lib/browser/mcp/tools/handlers/RunCommand.d.ts.map +1 -1
  50. package/lib/browser/mcp/tools/handlers/RunCommand.js +2 -0
  51. package/lib/browser/mcp/tools/handlers/RunCommand.js.map +1 -1
  52. package/lib/browser/preferences/schema.d.ts.map +1 -1
  53. package/lib/browser/preferences/schema.js +16 -0
  54. package/lib/browser/preferences/schema.js.map +1 -1
  55. package/lib/common/index.d.ts +8 -1
  56. package/lib/common/index.d.ts.map +1 -1
  57. package/lib/common/index.js +3 -1
  58. package/lib/common/index.js.map +1 -1
  59. package/lib/common/llm-context.d.ts +12 -9
  60. package/lib/common/llm-context.d.ts.map +1 -1
  61. package/lib/common/llm-context.js.map +1 -1
  62. package/lib/common/mcp-server-manager.d.ts +17 -1
  63. package/lib/common/mcp-server-manager.d.ts.map +1 -1
  64. package/lib/common/mcp-server-manager.js.map +1 -1
  65. package/lib/common/prompts/context-prompt-provider.d.ts +2 -3
  66. package/lib/common/prompts/context-prompt-provider.d.ts.map +1 -1
  67. package/lib/common/prompts/context-prompt-provider.js +21 -22
  68. package/lib/common/prompts/context-prompt-provider.js.map +1 -1
  69. package/lib/common/tool-invocation-registry.d.ts +2 -2
  70. package/lib/common/tool-invocation-registry.d.ts.map +1 -1
  71. package/lib/common/tool-invocation-registry.js +1 -1
  72. package/lib/common/tool-invocation-registry.js.map +1 -1
  73. package/lib/common/types.d.ts +6 -0
  74. package/lib/common/types.d.ts.map +1 -1
  75. package/lib/common/utils.d.ts.map +1 -1
  76. package/lib/common/utils.js +2 -1
  77. package/lib/common/utils.js.map +1 -1
  78. package/lib/node/mcp/sumi-mcp-server.d.ts +17 -3
  79. package/lib/node/mcp/sumi-mcp-server.d.ts.map +1 -1
  80. package/lib/node/mcp/sumi-mcp-server.js +59 -6
  81. package/lib/node/mcp/sumi-mcp-server.js.map +1 -1
  82. package/lib/node/mcp-server-manager-impl.d.ts +4 -3
  83. package/lib/node/mcp-server-manager-impl.d.ts.map +1 -1
  84. package/lib/node/mcp-server-manager-impl.js +26 -6
  85. package/lib/node/mcp-server-manager-impl.js.map +1 -1
  86. package/lib/node/mcp-server.d.ts +5 -16
  87. package/lib/node/mcp-server.d.ts.map +1 -1
  88. package/lib/node/mcp-server.js +12 -6
  89. package/lib/node/mcp-server.js.map +1 -1
  90. package/lib/node/openai/openai-language-model.d.ts +4 -3
  91. package/lib/node/openai/openai-language-model.d.ts.map +1 -1
  92. package/lib/node/openai/openai-language-model.js +3 -2
  93. package/lib/node/openai/openai-language-model.js.map +1 -1
  94. package/package.json +27 -27
  95. package/src/browser/ai-core.contribution.ts +13 -4
  96. package/src/browser/chat/chat-manager.service.ts +17 -1
  97. package/src/browser/chat/chat-model.ts +18 -3
  98. package/src/browser/chat/chat.view.tsx +48 -8
  99. package/src/browser/components/ChatContext/index.tsx +2 -2
  100. package/src/browser/context/llm-context.service.ts +90 -54
  101. package/src/browser/index.ts +4 -0
  102. package/src/browser/mcp/config/components/mcp-config.module.less +178 -0
  103. package/src/browser/mcp/config/components/mcp-config.view.tsx +215 -0
  104. package/src/browser/mcp/config/components/mcp-server-form.module.less +78 -0
  105. package/src/browser/mcp/config/components/mcp-server-form.tsx +144 -0
  106. package/src/browser/mcp/config/mcp-config.commands.ts +29 -0
  107. package/src/browser/mcp/config/mcp-config.contribution.ts +65 -0
  108. package/src/browser/mcp/mcp-server-proxy.service.ts +14 -2
  109. package/src/browser/mcp/mcp-server.feature.registry.ts +3 -2
  110. package/src/browser/mcp/tools/handlers/RunCommand.ts +2 -0
  111. package/src/browser/preferences/schema.ts +16 -0
  112. package/src/common/index.ts +7 -1
  113. package/src/common/llm-context.ts +10 -4
  114. package/src/common/mcp-server-manager.ts +17 -1
  115. package/src/common/prompts/context-prompt-provider.ts +26 -28
  116. package/src/common/tool-invocation-registry.ts +2 -2
  117. package/src/common/types.ts +6 -0
  118. package/src/common/utils.ts +3 -1
  119. package/src/node/mcp/sumi-mcp-server.ts +67 -9
  120. package/src/node/mcp-server-manager-impl.ts +30 -9
  121. package/src/node/mcp-server.ts +11 -14
  122. package/src/node/openai/openai-language-model.ts +7 -4
@@ -0,0 +1,144 @@
1
+ import React from 'react';
2
+
3
+ import { Button } from '@opensumi/ide-components/lib/button';
4
+ import { Modal } from '@opensumi/ide-components/lib/modal';
5
+
6
+ import styles from './mcp-server-form.module.less';
7
+
8
+ export interface MCPServerFormData {
9
+ name: string;
10
+ command: string;
11
+ args: string[];
12
+ env?: Record<string, string>;
13
+ }
14
+
15
+ interface Props {
16
+ visible: boolean;
17
+ initialData?: MCPServerFormData;
18
+ onSave: (data: MCPServerFormData) => void;
19
+ onCancel: () => void;
20
+ }
21
+
22
+ export const MCPServerForm: React.FC<Props> = ({ visible, initialData, onSave, onCancel }) => {
23
+ const [formData, setFormData] = React.useState<MCPServerFormData>(() => ({
24
+ name: '',
25
+ command: '',
26
+ args: [],
27
+ env: {},
28
+ type: 'stdio', // TODO: 支持 SSE
29
+ ...initialData,
30
+ }));
31
+
32
+ const [argsText, setArgsText] = React.useState(() => initialData?.args?.join(' ') || '');
33
+ const [envText, setEnvText] = React.useState(() => {
34
+ if (!initialData?.env) {
35
+ return '';
36
+ }
37
+ return Object.entries(initialData.env)
38
+ .map(([key, value]) => `${key}=${value}`)
39
+ .join('\n');
40
+ });
41
+
42
+ // Update form data when initialData changes
43
+ React.useEffect(() => {
44
+ setFormData({
45
+ name: '',
46
+ command: '',
47
+ args: [],
48
+ env: {},
49
+ ...initialData,
50
+ });
51
+ setArgsText(initialData?.args?.join(' ') || '');
52
+ setEnvText(
53
+ initialData?.env
54
+ ? Object.entries(initialData.env)
55
+ .map(([key, value]) => `${key}=${value}`)
56
+ .join('\n')
57
+ : '',
58
+ );
59
+ }, [initialData]);
60
+
61
+ const handleSubmit = (e: React.FormEvent) => {
62
+ e.preventDefault();
63
+ const args = argsText.split(' ').filter(Boolean);
64
+ const env = envText
65
+ .split('\n')
66
+ .filter(Boolean)
67
+ .reduce((acc, line) => {
68
+ const [key, value] = line.split('=');
69
+ if (key && value) {
70
+ acc[key.trim()] = value.trim();
71
+ }
72
+ return acc;
73
+ }, {} as Record<string, string>);
74
+
75
+ onSave({
76
+ ...formData,
77
+ args,
78
+ env,
79
+ });
80
+ };
81
+
82
+ return (
83
+ <Modal
84
+ title={initialData ? 'Edit MCP Server' : 'Add New MCP Server'}
85
+ visible={visible}
86
+ onCancel={onCancel}
87
+ centered
88
+ width={600}
89
+ footer={null}
90
+ style={{
91
+ background: 'var(--editor-background)',
92
+ }}
93
+ >
94
+ <form className={styles.form} onSubmit={(e) => e.preventDefault()}>
95
+ <div className={styles.formItem}>
96
+ <label>Name:</label>
97
+ <input
98
+ type='text'
99
+ value={formData.name}
100
+ onChange={(e) => setFormData({ ...formData, name: e.target.value })}
101
+ placeholder='Enter server name'
102
+ required
103
+ />
104
+ </div>
105
+ <div className={styles.formItem}>
106
+ <label>Command:</label>
107
+ <input
108
+ type='text'
109
+ value={formData.command}
110
+ onChange={(e) => setFormData({ ...formData, command: e.target.value })}
111
+ placeholder='Enter command (e.g., npx)'
112
+ required
113
+ />
114
+ </div>
115
+ <div className={styles.formItem}>
116
+ <label>Arguments:</label>
117
+ <textarea
118
+ value={argsText}
119
+ onChange={(e) => setArgsText(e.target.value)}
120
+ placeholder='Enter arguments separated by space'
121
+ rows={3}
122
+ />
123
+ </div>
124
+ <div className={styles.formItem}>
125
+ <label>Environment Variables:</label>
126
+ <textarea
127
+ value={envText}
128
+ onChange={(e) => setEnvText(e.target.value)}
129
+ placeholder='KEY=value (one per line)'
130
+ rows={3}
131
+ />
132
+ </div>
133
+ <div className={styles.formActions}>
134
+ <Button onClick={onCancel} type='secondary'>
135
+ Cancel
136
+ </Button>
137
+ <Button onClick={handleSubmit} type='primary'>
138
+ Save
139
+ </Button>
140
+ </div>
141
+ </form>
142
+ </Modal>
143
+ );
144
+ };
@@ -0,0 +1,29 @@
1
+ import { Autowired } from '@opensumi/di';
2
+ import { CommandContribution, CommandRegistry, URI } from '@opensumi/ide-core-browser';
3
+ import { Domain } from '@opensumi/ide-core-common';
4
+ import { WorkbenchEditorService } from '@opensumi/ide-editor';
5
+
6
+ import { MCP_CONFIG_COMPONENTS_SCHEME_ID } from './mcp-config.contribution';
7
+
8
+ export const OPEN_MCP_CONFIG_COMMAND = {
9
+ id: 'opensumi-mcp.openConfig',
10
+ label: 'Open MCP Configuration',
11
+ };
12
+
13
+ @Domain(CommandContribution)
14
+ export class MCPConfigCommandContribution implements CommandContribution {
15
+ @Autowired(WorkbenchEditorService)
16
+ private readonly editorService: WorkbenchEditorService;
17
+
18
+ registerCommands(registry: CommandRegistry) {
19
+ registry.registerCommand(OPEN_MCP_CONFIG_COMMAND, {
20
+ execute: () => {
21
+ const uri = new URI().withScheme(MCP_CONFIG_COMPONENTS_SCHEME_ID);
22
+ this.editorService.open(uri, {
23
+ preview: false,
24
+ focus: true,
25
+ });
26
+ },
27
+ });
28
+ }
29
+ }
@@ -0,0 +1,65 @@
1
+ import { Autowired } from '@opensumi/di';
2
+ import { LabelService } from '@opensumi/ide-core-browser/lib/services';
3
+ import { Domain, Schemes, URI } from '@opensumi/ide-core-common';
4
+ import {
5
+ BrowserEditorContribution,
6
+ EditorComponentRegistry,
7
+ EditorComponentRenderMode,
8
+ IResource,
9
+ ResourceService,
10
+ } from '@opensumi/ide-editor/lib/browser/types';
11
+ import { IconService } from '@opensumi/ide-theme/lib/browser';
12
+ import { IWorkspaceService } from '@opensumi/ide-workspace/lib/common';
13
+
14
+ import { MCPConfigView } from './components/mcp-config.view';
15
+
16
+ const COMPONENTS_ID = 'opensumi-mcp-config-viewer';
17
+ export const MCP_CONFIG_COMPONENTS_SCHEME_ID = 'mcp-config';
18
+
19
+ export type IMCPConfigResource = IResource<{ configType: string }>;
20
+
21
+ @Domain(BrowserEditorContribution)
22
+ export class MCPConfigContribution implements BrowserEditorContribution {
23
+ @Autowired(IWorkspaceService)
24
+ protected readonly workspaceService: IWorkspaceService;
25
+
26
+ @Autowired(IconService)
27
+ protected readonly iconService: IconService;
28
+
29
+ @Autowired()
30
+ labelService: LabelService;
31
+
32
+ registerEditorComponent(registry: EditorComponentRegistry) {
33
+ registry.registerEditorComponent({
34
+ uid: COMPONENTS_ID,
35
+ scheme: MCP_CONFIG_COMPONENTS_SCHEME_ID,
36
+ component: MCPConfigView,
37
+ renderMode: EditorComponentRenderMode.ONE_PER_WORKBENCH,
38
+ });
39
+
40
+ registry.registerEditorComponentResolver(MCP_CONFIG_COMPONENTS_SCHEME_ID, (resource, results) => {
41
+ results.push({
42
+ type: 'component',
43
+ componentId: COMPONENTS_ID,
44
+ });
45
+ });
46
+ }
47
+
48
+ registerResource(service: ResourceService) {
49
+ service.registerResourceProvider({
50
+ scheme: MCP_CONFIG_COMPONENTS_SCHEME_ID,
51
+ provideResource: async (uri: URI): Promise<IMCPConfigResource> => {
52
+ const { configType } = uri.getParsedQuery();
53
+
54
+ return {
55
+ uri,
56
+ name: 'MCP Configuration',
57
+ icon: 'settings',
58
+ metadata: {
59
+ configType,
60
+ },
61
+ };
62
+ },
63
+ });
64
+ }
65
+ }
@@ -4,7 +4,7 @@ import { Autowired, Injectable } from '@opensumi/di';
4
4
  import { ILogger } from '@opensumi/ide-core-browser';
5
5
  import { Emitter, Event } from '@opensumi/ide-core-common';
6
6
 
7
- import { ISumiMCPServerBackend, SumiMCPServerProxyServicePath } from '../../common';
7
+ import { BUILTIN_MCP_SERVER_NAME, ISumiMCPServerBackend, SumiMCPServerProxyServicePath } from '../../common';
8
8
  import { IMCPServerProxyService } from '../../common/types';
9
9
  import { IMCPServerRegistry, TokenMCPServerRegistry } from '../types';
10
10
 
@@ -35,7 +35,7 @@ export class MCPServerProxyService implements IMCPServerProxyService {
35
35
  name: tool.name,
36
36
  description: tool.description,
37
37
  inputSchema: zodToJsonSchema(tool.inputSchema),
38
- providerName: 'sumi-builtin',
38
+ providerName: BUILTIN_MCP_SERVER_NAME,
39
39
  }),
40
40
  );
41
41
 
@@ -52,4 +52,16 @@ export class MCPServerProxyService implements IMCPServerProxyService {
52
52
  async getAllMCPTools() {
53
53
  return this.sumiMCPServerProxyService.getAllMCPTools();
54
54
  }
55
+
56
+ async $getServers() {
57
+ return this.sumiMCPServerProxyService.getServers();
58
+ }
59
+
60
+ async $startServer(serverName: string) {
61
+ await this.sumiMCPServerProxyService.startServer(serverName);
62
+ }
63
+
64
+ async $stopServer(serverName: string) {
65
+ await this.sumiMCPServerProxyService.stopServer(serverName);
66
+ }
55
67
  }
@@ -2,6 +2,7 @@
2
2
  import { Autowired, Injectable } from '@opensumi/di';
3
3
  import { ILogger } from '@opensumi/ide-core-common';
4
4
 
5
+ import { BUILTIN_MCP_SERVER_NAME } from '../../common';
5
6
  import { getToolName } from '../../common/utils';
6
7
  import { IMCPServerRegistry, IMCPServerToolComponentProps, MCPLogger, MCPToolDefinition } from '../types';
7
8
 
@@ -25,7 +26,7 @@ export class MCPServerRegistry implements IMCPServerRegistry {
25
26
  return new LoggerAdapter(this.baseLogger);
26
27
  }
27
28
 
28
- getMCPTool(name: string, serverName = 'sumi-builtin'): MCPToolDefinition | undefined {
29
+ getMCPTool(name: string, serverName = BUILTIN_MCP_SERVER_NAME): MCPToolDefinition | undefined {
29
30
  return this.tools.find((tool) => getToolName(tool.name, serverName) === name);
30
31
  }
31
32
 
@@ -36,7 +37,7 @@ export class MCPServerRegistry implements IMCPServerRegistry {
36
37
  registerToolComponent(
37
38
  name: string,
38
39
  component: React.FC<IMCPServerToolComponentProps>,
39
- serverName = 'sumi-builtin',
40
+ serverName = BUILTIN_MCP_SERVER_NAME,
40
41
  ): void {
41
42
  this.toolComponents[getToolName(name, serverName)] = component;
42
43
  }
@@ -49,6 +49,7 @@ export class RunCommandHandler {
49
49
  }
50
50
 
51
51
  async handler(args: z.infer<typeof inputSchema> & { toolCallId: string }, logger: MCPLogger) {
52
+ logger.appendLine(`Executing command: ${args.command}`);
52
53
  if (args.require_user_approval) {
53
54
  const def = new Deferred<boolean>();
54
55
  this.approvalDeferredMap.set(args.toolCallId, def);
@@ -89,6 +90,7 @@ export class RunCommandHandler {
89
90
  content: result,
90
91
  });
91
92
 
93
+ logger.appendLine(`Command ${args.command} finished with exit code: ${e.code}`);
92
94
  terminalClient.term.writeln(
93
95
  `\n${color.italic}> Command ${args.command} executed successfully. Terminal will close in ${
94
96
  3000 / 1000
@@ -108,11 +108,27 @@ export const aiNativePreferenceSchema: PreferenceSchema = {
108
108
  type: 'string',
109
109
  description: localize('preference.ai.native.mcp.servers.command.description'),
110
110
  },
111
+ type: {
112
+ type: 'string',
113
+ enum: ['stdio', 'sse'],
114
+ enumDescriptions: [
115
+ localize('preference.ai.native.mcp.servers.type.stdio'),
116
+ localize('preference.ai.native.mcp.servers.type.sse'),
117
+ ],
118
+ description: localize('preference.ai.native.mcp.servers.type.description'),
119
+ default: 'stdio',
120
+ },
121
+ enabled: {
122
+ type: 'boolean',
123
+ description: localize('preference.ai.native.mcp.servers.enabled.description'),
124
+ default: true,
125
+ },
111
126
  args: {
112
127
  type: 'array',
113
128
  items: {
114
129
  type: 'string',
115
130
  },
131
+ default: [],
116
132
  description: localize('preference.ai.native.mcp.servers.args.description'),
117
133
  },
118
134
  env: {
@@ -31,6 +31,9 @@ export const AI_CHAT_CONTAINER_ID = 'AI-Chat-Container';
31
31
  export const AI_CHAT_LOGO_AVATAR_ID = 'AI-Chat-Logo-Avatar';
32
32
  export const AI_MENU_BAR_DEBUG_TOOLBAR = 'AI_MENU_BAR_DEBUG_TOOLBAR';
33
33
 
34
+ // 内置 MCP 服务器名称
35
+ export const BUILTIN_MCP_SERVER_NAME = 'sumi-builtin';
36
+
34
37
  /**
35
38
  * @deprecated Use {@link DESIGN_MENUBAR_CONTAINER_VIEW_ID} instead
36
39
  */
@@ -123,9 +126,12 @@ export const ChatProxyServiceToken = Symbol('ChatProxyServiceToken');
123
126
  export const TokenMCPServerProxyService = Symbol('TokenMCPServerProxyService');
124
127
 
125
128
  export interface ISumiMCPServerBackend {
126
- initBuiltinMCPServer(): void;
129
+ initBuiltinMCPServer(enabled: boolean): void;
127
130
  initExternalMCPServers(servers: MCPServerDescription[]): void;
128
131
  getAllMCPTools(): Promise<MCPTool[]>;
132
+ getServers(): Promise<Array<{ name: string; isStarted: boolean }>>;
133
+ startServer(serverName: string): Promise<void>;
134
+ stopServer(serverName: string): Promise<void>;
129
135
  }
130
136
 
131
137
  export const SumiMCPServerProxyServicePath = 'SumiMCPServerProxyServicePath';
@@ -15,13 +15,13 @@ export interface LLMContextService {
15
15
  */
16
16
  cleanFileContext(): void;
17
17
 
18
- onDidContextFilesChangeEvent: Event<FileContext[]>;
18
+ onDidContextFilesChangeEvent: Event<{ viewed: FileContext[]; attached: FileContext[] }>;
19
19
 
20
20
  /**
21
21
  * 从 context 中移除文件
22
22
  * @param uri URI
23
23
  */
24
- removeFileFromContext(uri: URI): void;
24
+ removeFileFromContext(uri: URI, isManual?: boolean): void;
25
25
 
26
26
  /** 导出为可序列化格式 */
27
27
  serialize(): SerializedContext;
@@ -30,12 +30,18 @@ export interface LLMContextService {
30
30
  export interface FileContext {
31
31
  uri: URI;
32
32
  selection?: [number, number];
33
- isManual: boolean;
34
33
  }
35
34
 
36
35
  export const LLMContextServiceToken = Symbol('LLMContextService');
37
36
 
37
+ export interface AttachFileContext {
38
+ content: string;
39
+ lineErrors: string[];
40
+ path: string;
41
+ language: string;
42
+ }
43
+
38
44
  export interface SerializedContext {
39
45
  recentlyViewFiles: string[];
40
- attachedFiles: Array<{ content: string; lineErrors: string[]; path: string; language: string }>;
46
+ attachedFiles: Array<AttachFileContext>;
41
47
  }
@@ -1,5 +1,15 @@
1
1
  import { Client } from '@modelcontextprotocol/sdk/client/index.js';
2
2
 
3
+ export interface IMCPServer {
4
+ isStarted(): boolean;
5
+ start(): Promise<void>;
6
+ getServerName(): string;
7
+ callTool(toolName: string, toolCallId: string, arg_string: string): ReturnType<Client['callTool']>;
8
+ getTools(): ReturnType<Client['listTools']>;
9
+ update(command: string, args?: string[], env?: { [key: string]: string }): void;
10
+ stop(): void;
11
+ }
12
+
3
13
  export interface MCPServerManager {
4
14
  callTool(
5
15
  serverName: string,
@@ -11,7 +21,7 @@ export interface MCPServerManager {
11
21
  addOrUpdateServer(description: MCPServerDescription): void;
12
22
  // invoke in node.js only
13
23
  addOrUpdateServerDirectly(server: any): void;
14
- initBuiltinServer(builtinMCPServer: any): void;
24
+ initBuiltinServer(builtinMCPServer: any, enabled: boolean): void;
15
25
  getTools(serverName: string): ReturnType<Client['listTools']>;
16
26
  getServerNames(): Promise<string[]>;
17
27
  startServer(serverName: string): Promise<void>;
@@ -19,6 +29,7 @@ export interface MCPServerManager {
19
29
  getStartedServers(): Promise<string[]>;
20
30
  registerTools(serverName: string): Promise<void>;
21
31
  addExternalMCPServers(servers: MCPServerDescription[]): void;
32
+ getServers(): Map<string, IMCPServer>;
22
33
  }
23
34
 
24
35
  export type MCPTool = Awaited<ReturnType<MCPServerManager['getTools']>>['tools'][number];
@@ -45,6 +56,11 @@ export interface MCPServerDescription {
45
56
  * Optional environment variables to set when starting the server.
46
57
  */
47
58
  env?: { [key: string]: string };
59
+
60
+ /**
61
+ * Whether to enable the MCP server.
62
+ */
63
+ enabled?: boolean;
48
64
  }
49
65
 
50
66
  export const MCPServerManager = Symbol('MCPServerManager');
@@ -1,5 +1,4 @@
1
1
  import { Injectable } from '@opensumi/di';
2
- import { MaybePromise } from '@opensumi/ide-core-common/lib/utils';
3
2
 
4
3
  import { SerializedContext } from '../llm-context';
5
4
 
@@ -10,37 +9,36 @@ export interface ChatAgentPromptProvider {
10
9
  * 提供上下文提示
11
10
  * @param context 上下文
12
11
  */
13
- provideContextPrompt(context: SerializedContext, userMessage: string): MaybePromise<string>;
12
+ provideContextPrompt(context: SerializedContext, userMessage: string): string;
14
13
  }
15
14
 
16
15
  @Injectable()
17
16
  export class DefaultChatAgentPromptProvider implements ChatAgentPromptProvider {
18
- provideContextPrompt(context: SerializedContext, userMessage: string): MaybePromise<string> {
17
+ provideContextPrompt(context: SerializedContext, userMessage: string): string {
19
18
  return `
20
- <additional_data>
21
- Below are some potentially helpful/relevant pieces of information for figuring out to respond
22
- <recently_viewed_files>
23
- ${context.recentlyViewFiles.map((file, idx) => `${idx + 1} : ${file}`)}
24
- </recently_viewed_files>
25
- <attached_files>
26
- ${context.attachedFiles.map(
27
- (file) =>
28
- `
29
- <file_contents>
30
- \`\`\`${file.language} ${file.path}
31
- ${file.content}
32
- \`\`\`
33
- </file_contents>
34
- <linter_errors>
35
- ${file.lineErrors.join('\n')}
36
- </linter_errors>
37
- `,
38
- )}
39
-
40
- </attached_files>
41
- </additional_data>
42
- <user_query>
43
- ${userMessage}
44
- </user_query>`;
19
+ <additional_data>
20
+ Below are some potentially helpful/relevant pieces of information for figuring out to respond
21
+ <recently_viewed_files>
22
+ ${context.recentlyViewFiles.map((file, idx) => ` ${idx + 1}: ${file}`).join('\n')}
23
+ </recently_viewed_files>
24
+ <attached_files>
25
+ ${context.attachedFiles.map(
26
+ (file) =>
27
+ `
28
+ <file_contents>
29
+ \`\`\`${file.language} ${file.path}
30
+ ${file.content}
31
+ \`\`\`
32
+ </file_contents>
33
+ <linter_errors>
34
+ ${file.lineErrors.join('\n')}
35
+ </linter_errors>
36
+ `,
37
+ )}
38
+ </attached_files>
39
+ </additional_data>
40
+ <user_query>
41
+ ${userMessage}
42
+ </user_query>`;
45
43
  }
46
44
  }
@@ -72,7 +72,7 @@ export interface ToolInvocationRegistry {
72
72
  *
73
73
  * @param providerName - 要移除其工具的工具提供者名称(在 `ToolRequest` 中指定)
74
74
  */
75
- unregisterAllTools(providerName: string): void;
75
+ unregisterProviderTools(providerName: string): void;
76
76
  }
77
77
 
78
78
  export const ToolProvider = Symbol('ToolProvider');
@@ -83,7 +83,7 @@ export interface ToolProvider {
83
83
  export class ToolInvocationRegistryImpl implements ToolInvocationRegistry {
84
84
  private tools: Map<string, ToolRequest> = new Map<string, ToolRequest>();
85
85
 
86
- unregisterAllTools(providerName: string): void {
86
+ unregisterProviderTools(providerName: string): void {
87
87
  const toolsToRemove: string[] = [];
88
88
  for (const [id, tool] of this.tools.entries()) {
89
89
  if (tool.providerName === providerName) {
@@ -32,6 +32,12 @@ export interface IMCPServerProxyService {
32
32
  $getMCPTools(): Promise<MCPTool[]>;
33
33
  // 通知前端 MCP 服务注册表发生了变化
34
34
  $updateMCPServers(): Promise<void>;
35
+ // 获取所有 MCP 服务器列表
36
+ $getServers(): Promise<Array<{ name: string; isStarted: boolean }>>;
37
+ // 启动指定的 MCP 服务器
38
+ $startServer(serverName: string): Promise<void>;
39
+ // 停止指定的 MCP 服务器
40
+ $stopServer(serverName: string): Promise<void>;
35
41
  }
36
42
 
37
43
  export interface MCPTool {
@@ -1,5 +1,7 @@
1
1
  import { IEditorDocumentModel } from '@opensumi/ide-editor';
2
2
 
3
+ import { BUILTIN_MCP_SERVER_NAME } from './index';
4
+
3
5
  const BACK_QUOTE_3_SYMBOL = '```';
4
6
  const MIN_PROMPT_CHARS = 10;
5
7
 
@@ -49,4 +51,4 @@ export const extractCodeBlocks = (content: string): string => {
49
51
  return newContents.join('\n');
50
52
  };
51
53
 
52
- export const getToolName = (toolName: string, serverName = 'sumi-builtin') => `mcp_${serverName}_${toolName}`;
54
+ export const getToolName = (toolName: string, serverName = BUILTIN_MCP_SERVER_NAME) => `mcp_${serverName}_${toolName}`;