@lobehub/chat 1.109.0 → 1.110.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 (100) hide show
  1. package/.cursor/rules/i18n.mdc +1 -2
  2. package/CHANGELOG.md +59 -0
  3. package/README.md +1 -1
  4. package/README.zh-CN.md +1 -1
  5. package/apps/desktop/electron-builder.js +22 -0
  6. package/apps/desktop/src/main/controllers/McpInstallCtr.ts +153 -0
  7. package/apps/desktop/src/main/controllers/index.ts +19 -0
  8. package/apps/desktop/src/main/core/App.ts +46 -0
  9. package/apps/desktop/src/main/core/infrastructure/IoCContainer.ts +4 -0
  10. package/apps/desktop/src/main/core/infrastructure/ProtocolManager.ts +256 -0
  11. package/apps/desktop/src/main/types/protocol.ts +60 -0
  12. package/apps/desktop/src/main/utils/__tests__/protocol.test.ts +203 -0
  13. package/apps/desktop/src/main/utils/protocol.ts +210 -0
  14. package/changelog/v1.json +21 -0
  15. package/locales/ar/models.json +6 -0
  16. package/locales/ar/plugin.json +196 -136
  17. package/locales/ar/providers.json +3 -0
  18. package/locales/bg-BG/models.json +6 -0
  19. package/locales/bg-BG/plugin.json +204 -144
  20. package/locales/bg-BG/providers.json +3 -0
  21. package/locales/de-DE/models.json +6 -0
  22. package/locales/de-DE/plugin.json +176 -116
  23. package/locales/de-DE/providers.json +3 -0
  24. package/locales/en-US/models.json +6 -0
  25. package/locales/en-US/plugin.json +192 -132
  26. package/locales/en-US/providers.json +3 -0
  27. package/locales/es-ES/models.json +6 -0
  28. package/locales/es-ES/plugin.json +203 -143
  29. package/locales/es-ES/providers.json +3 -0
  30. package/locales/fa-IR/models.json +6 -0
  31. package/locales/fa-IR/plugin.json +155 -95
  32. package/locales/fa-IR/providers.json +3 -0
  33. package/locales/fr-FR/models.json +6 -0
  34. package/locales/fr-FR/plugin.json +161 -101
  35. package/locales/fr-FR/providers.json +3 -0
  36. package/locales/it-IT/models.json +6 -0
  37. package/locales/it-IT/plugin.json +193 -133
  38. package/locales/it-IT/providers.json +3 -0
  39. package/locales/ja-JP/models.json +6 -0
  40. package/locales/ja-JP/plugin.json +195 -135
  41. package/locales/ja-JP/providers.json +3 -0
  42. package/locales/ko-KR/models.json +6 -0
  43. package/locales/ko-KR/plugin.json +163 -103
  44. package/locales/ko-KR/providers.json +3 -0
  45. package/locales/nl-NL/models.json +6 -0
  46. package/locales/nl-NL/plugin.json +211 -151
  47. package/locales/nl-NL/providers.json +3 -0
  48. package/locales/pl-PL/models.json +6 -0
  49. package/locales/pl-PL/plugin.json +171 -111
  50. package/locales/pl-PL/providers.json +3 -0
  51. package/locales/pt-BR/models.json +6 -0
  52. package/locales/pt-BR/plugin.json +180 -120
  53. package/locales/pt-BR/providers.json +3 -0
  54. package/locales/ru-RU/models.json +6 -0
  55. package/locales/ru-RU/plugin.json +191 -131
  56. package/locales/ru-RU/providers.json +3 -0
  57. package/locales/tr-TR/models.json +6 -0
  58. package/locales/tr-TR/plugin.json +187 -127
  59. package/locales/tr-TR/providers.json +3 -0
  60. package/locales/vi-VN/models.json +6 -0
  61. package/locales/vi-VN/plugin.json +152 -92
  62. package/locales/vi-VN/providers.json +3 -0
  63. package/locales/zh-CN/models.json +6 -0
  64. package/locales/zh-CN/plugin.json +60 -0
  65. package/locales/zh-CN/providers.json +3 -0
  66. package/locales/zh-TW/models.json +6 -0
  67. package/locales/zh-TW/plugin.json +157 -97
  68. package/locales/zh-TW/providers.json +3 -0
  69. package/package.json +2 -1
  70. package/packages/electron-client-ipc/src/events/index.ts +5 -2
  71. package/packages/electron-client-ipc/src/events/protocol.ts +29 -0
  72. package/packages/electron-client-ipc/src/types/index.ts +1 -0
  73. package/packages/electron-client-ipc/src/types/mcpInstall.ts +19 -0
  74. package/packages/types/src/plugins/mcp.ts +38 -1
  75. package/packages/types/src/plugins/protocol.ts +166 -0
  76. package/src/app/[variants]/(main)/chat/_layout/Desktop/index.tsx +4 -1
  77. package/src/app/[variants]/(main)/discover/(detail)/mcp/[slug]/features/Sidebar/ActionButton/index.tsx +1 -2
  78. package/src/components/KeyValueEditor/index.tsx +4 -2
  79. package/src/config/aiModels/aihubmix.ts +465 -30
  80. package/src/config/aiModels/anthropic.ts +27 -1
  81. package/src/config/aiModels/groq.ts +40 -4
  82. package/src/config/aiModels/qwen.ts +24 -2
  83. package/src/features/MCP/MCPInstallProgress/index.tsx +1 -1
  84. package/src/features/PluginDevModal/MCPManifestForm/index.tsx +30 -36
  85. package/src/features/PluginStore/McpList/List/Item.tsx +1 -1
  86. package/src/features/ProtocolUrlHandler/InstallPlugin/ConfigDisplay.tsx +211 -0
  87. package/src/features/ProtocolUrlHandler/InstallPlugin/CustomPluginInstallModal.tsx +228 -0
  88. package/src/features/ProtocolUrlHandler/InstallPlugin/OfficialPluginInstallModal/Detail.tsx +44 -0
  89. package/src/features/ProtocolUrlHandler/InstallPlugin/OfficialPluginInstallModal/index.tsx +105 -0
  90. package/src/features/ProtocolUrlHandler/InstallPlugin/index.tsx +55 -0
  91. package/src/features/ProtocolUrlHandler/InstallPlugin/types.ts +45 -0
  92. package/src/features/ProtocolUrlHandler/index.tsx +30 -0
  93. package/src/libs/model-runtime/anthropic/index.ts +15 -2
  94. package/src/libs/model-runtime/utils/modelParse.ts +2 -2
  95. package/src/libs/model-runtime/utils/streams/ollama.test.ts +97 -51
  96. package/src/libs/model-runtime/utils/streams/ollama.ts +4 -0
  97. package/src/locales/default/plugin.ts +60 -0
  98. package/src/store/tool/slices/mcpStore/action.ts +127 -1
  99. package/src/store/tool/slices/mcpStore/initialState.ts +8 -13
  100. package/src/store/tool/slices/mcpStore/selectors.ts +13 -0
@@ -18,24 +18,36 @@ import {
18
18
  CheckMcpInstallResult,
19
19
  MCPErrorInfo,
20
20
  MCPInstallProgress,
21
+ MCPInstallStep,
21
22
  MCPPluginListParams,
23
+ McpConnectionParams,
22
24
  } from '@/types/plugins';
23
25
  import { sleep } from '@/utils/sleep';
24
26
  import { setNamespace } from '@/utils/storeDebug';
25
27
 
26
28
  import { ToolStore } from '../../store';
27
- import { MCPInstallStep, MCPStoreState } from './initialState';
29
+ import { MCPStoreState } from './initialState';
28
30
 
29
31
  const n = setNamespace('mcpStore');
30
32
 
33
+ // 测试连接结果类型
34
+ export interface TestMcpConnectionResult {
35
+ error?: string;
36
+ manifest?: LobeChatPluginManifest;
37
+ success: boolean;
38
+ }
39
+
31
40
  export interface PluginMCPStoreAction {
32
41
  cancelInstallMCPPlugin: (identifier: string) => Promise<void>;
42
+ cancelMcpConnectionTest: (identifier: string) => void;
33
43
  installMCPPlugin: (
34
44
  identifier: string,
35
45
  options?: { config?: Record<string, any>; resume?: boolean; skipDepsCheck?: boolean },
36
46
  ) => Promise<boolean | undefined>;
37
47
  loadMoreMCPPlugins: () => void;
38
48
  resetMCPPluginList: (keywords?: string) => void;
49
+ // 测试连接相关方法
50
+ testMcpConnection: (params: McpConnectionParams) => Promise<TestMcpConnectionResult>;
39
51
  uninstallMCPPlugin: (identifier: string) => Promise<void>;
40
52
  updateMCPInstallProgress: (identifier: string, progress: MCPInstallProgress | undefined) => void;
41
53
  useFetchMCPPluginList: (params: MCPPluginListParams) => SWRResponse<PluginListResponse>;
@@ -68,6 +80,25 @@ export const createMCPPluginStoreSlice: StateCreator<
68
80
  get().updateInstallLoadingState(identifier, undefined);
69
81
  },
70
82
 
83
+ // 取消 MCP 连接测试
84
+ cancelMcpConnectionTest: (identifier) => {
85
+ const abortController = get().mcpTestAbortControllers[identifier];
86
+ if (abortController) {
87
+ abortController.abort();
88
+
89
+ // 清理状态
90
+ set(
91
+ produce((draft: MCPStoreState) => {
92
+ draft.mcpTestLoading[identifier] = false;
93
+ delete draft.mcpTestAbortControllers[identifier];
94
+ delete draft.mcpTestErrors[identifier];
95
+ }),
96
+ false,
97
+ n('cancelMcpConnectionTest'),
98
+ );
99
+ }
100
+ },
101
+
71
102
  installMCPPlugin: async (identifier, options = {}) => {
72
103
  const { resume = false, config, skipDepsCheck } = options;
73
104
  let plugin = mcpStoreSelectors.getPluginById(identifier)(get());
@@ -438,6 +469,101 @@ export const createMCPPluginStoreSlice: StateCreator<
438
469
  );
439
470
  },
440
471
 
472
+ // 测试 MCP 连接
473
+ testMcpConnection: async (params) => {
474
+ const { identifier, connection, metadata } = params;
475
+
476
+ // 创建 AbortController 用于取消测试
477
+ const abortController = new AbortController();
478
+
479
+ // 存储 AbortController 并设置加载状态
480
+ set(
481
+ produce((draft: MCPStoreState) => {
482
+ draft.mcpTestAbortControllers[identifier] = abortController;
483
+ draft.mcpTestLoading[identifier] = true;
484
+ draft.mcpTestErrors[identifier] = '';
485
+ }),
486
+ false,
487
+ n('testMcpConnection/start'),
488
+ );
489
+
490
+ try {
491
+ let manifest: LobeChatPluginManifest;
492
+
493
+ if (connection.type === 'http') {
494
+ if (!connection.url) {
495
+ throw new Error('URL is required for HTTP connection');
496
+ }
497
+
498
+ manifest = await mcpService.getStreamableMcpServerManifest(
499
+ {
500
+ auth: connection.auth,
501
+ headers: connection.headers,
502
+ identifier,
503
+ metadata,
504
+ url: connection.url,
505
+ },
506
+ abortController.signal,
507
+ );
508
+ } else if (connection.type === 'stdio') {
509
+ if (!connection.command) {
510
+ throw new Error('Command is required for STDIO connection');
511
+ }
512
+
513
+ manifest = await mcpService.getStdioMcpServerManifest(
514
+ {
515
+ args: connection.args,
516
+ command: connection.command,
517
+ env: connection.env,
518
+ name: identifier,
519
+ },
520
+ metadata,
521
+ abortController.signal,
522
+ );
523
+ } else {
524
+ throw new Error('Invalid MCP connection type');
525
+ }
526
+
527
+ // 检查是否已被取消
528
+ if (abortController.signal.aborted) {
529
+ return { error: 'Test cancelled', success: false };
530
+ }
531
+
532
+ // 清理状态
533
+ set(
534
+ produce((draft: MCPStoreState) => {
535
+ draft.mcpTestLoading[identifier] = false;
536
+ delete draft.mcpTestAbortControllers[identifier];
537
+ delete draft.mcpTestErrors[identifier];
538
+ }),
539
+ false,
540
+ n('testMcpConnection/success'),
541
+ );
542
+
543
+ return { manifest, success: true };
544
+ } catch (error) {
545
+ // 如果是因为取消导致的错误,静默处理
546
+ if (abortController.signal.aborted) {
547
+ return { error: 'Test cancelled', success: false };
548
+ }
549
+
550
+ const errorMessage = error instanceof Error ? error.message : String(error);
551
+
552
+ // 设置错误状态
553
+ set(
554
+ produce((draft: MCPStoreState) => {
555
+ draft.mcpTestLoading[identifier] = false;
556
+ draft.mcpTestErrors[identifier] = errorMessage;
557
+ delete draft.mcpTestAbortControllers[identifier];
558
+ }),
559
+ false,
560
+ n('testMcpConnection/error'),
561
+ );
562
+
563
+ return { error: errorMessage, success: false };
564
+ }
565
+ },
566
+
441
567
  uninstallMCPPlugin: async (identifier) => {
442
568
  await pluginService.uninstallPlugin(identifier);
443
569
  await get().refreshPlugins();
@@ -2,19 +2,6 @@ import { PluginItem } from '@lobehub/market-sdk';
2
2
 
3
3
  import { MCPInstallProgressMap } from '@/types/plugins';
4
4
 
5
- /* eslint-disable typescript-sort-keys/string-enum */
6
- export enum MCPInstallStep {
7
- FETCHING_MANIFEST = 'FETCHING_MANIFEST',
8
- CHECKING_INSTALLATION = 'CHECKING_INSTALLATION',
9
- DEPENDENCIES_REQUIRED = 'DEPENDENCIES_REQUIRED',
10
- GETTING_SERVER_MANIFEST = 'GETTING_SERVER_MANIFEST',
11
- CONFIGURATION_REQUIRED = 'CONFIGURATION_REQUIRED',
12
- INSTALLING_PLUGIN = 'INSTALLING_PLUGIN',
13
- COMPLETED = 'COMPLETED',
14
- ERROR = 'Error',
15
- }
16
- /* eslint-enable */
17
-
18
5
  export interface MCPStoreState {
19
6
  activeMCPIdentifier?: string;
20
7
  categories: string[];
@@ -25,6 +12,10 @@ export interface MCPStoreState {
25
12
  mcpInstallProgress: MCPInstallProgressMap;
26
13
  mcpPluginItems: PluginItem[];
27
14
  mcpSearchKeywords?: string;
15
+ // 测试连接相关状态
16
+ mcpTestAbortControllers: Record<string, AbortController>;
17
+ mcpTestErrors: Record<string, string>;
18
+ mcpTestLoading: Record<string, boolean>;
28
19
  searchLoading?: boolean;
29
20
  tags?: string[];
30
21
  totalCount?: number;
@@ -37,4 +28,8 @@ export const initialMCPStoreState: MCPStoreState = {
37
28
  mcpInstallAbortControllers: {},
38
29
  mcpInstallProgress: {},
39
30
  mcpPluginItems: [],
31
+ // 测试连接相关状态初始化
32
+ mcpTestAbortControllers: {},
33
+ mcpTestErrors: {},
34
+ mcpTestLoading: {},
40
35
  };
@@ -49,11 +49,24 @@ const isMCPInstallInProgress = (id: string) => (s: ToolStoreState) => {
49
49
  return !!progress && !progress.needsConfig && progress.step !== 'Error';
50
50
  };
51
51
 
52
+ // 测试连接相关选择器
53
+ const isMCPConnectionTesting = (id: string) => (s: ToolStoreState) => s.mcpTestLoading[id] || false;
54
+
55
+ const getMCPConnectionTestError = (id: string) => (s: ToolStoreState) => s.mcpTestErrors[id];
56
+
57
+ const getMCPConnectionTestState = (id: string) => (s: ToolStoreState) => ({
58
+ error: s.mcpTestErrors[id],
59
+ loading: s.mcpTestLoading[id] || false,
60
+ });
61
+
52
62
  export const mcpStoreSelectors = {
53
63
  activeMCPPluginIdentifier,
64
+ getMCPConnectionTestError,
65
+ getMCPConnectionTestState,
54
66
  getMCPInstallProgress,
55
67
  getMCPPluginRequiringConfig,
56
68
  getPluginById,
69
+ isMCPConnectionTesting,
57
70
  isMCPInstallInProgress,
58
71
  isMCPInstalling,
59
72
  isMCPPluginRequiringConfig,