@lobehub/chat 1.109.1 → 1.110.1
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.
- package/.cursor/rules/i18n.mdc +1 -2
- package/CHANGELOG.md +50 -0
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/apps/desktop/electron-builder.js +22 -0
- package/apps/desktop/src/main/controllers/McpInstallCtr.ts +153 -0
- package/apps/desktop/src/main/controllers/index.ts +19 -0
- package/apps/desktop/src/main/core/App.ts +46 -0
- package/apps/desktop/src/main/core/infrastructure/IoCContainer.ts +4 -0
- package/apps/desktop/src/main/core/infrastructure/ProtocolManager.ts +256 -0
- package/apps/desktop/src/main/types/protocol.ts +60 -0
- package/apps/desktop/src/main/utils/__tests__/protocol.test.ts +203 -0
- package/apps/desktop/src/main/utils/protocol.ts +210 -0
- package/changelog/v1.json +18 -0
- package/locales/ar/plugin.json +196 -136
- package/locales/bg-BG/plugin.json +204 -144
- package/locales/de-DE/plugin.json +176 -116
- package/locales/en-US/plugin.json +192 -132
- package/locales/es-ES/plugin.json +203 -143
- package/locales/fa-IR/plugin.json +155 -95
- package/locales/fr-FR/plugin.json +161 -101
- package/locales/it-IT/plugin.json +193 -133
- package/locales/ja-JP/plugin.json +195 -135
- package/locales/ko-KR/plugin.json +163 -103
- package/locales/nl-NL/plugin.json +211 -151
- package/locales/pl-PL/plugin.json +171 -111
- package/locales/pt-BR/plugin.json +180 -120
- package/locales/ru-RU/plugin.json +191 -131
- package/locales/tr-TR/plugin.json +187 -127
- package/locales/vi-VN/plugin.json +152 -92
- package/locales/zh-CN/plugin.json +60 -0
- package/locales/zh-TW/plugin.json +157 -97
- package/package.json +2 -1
- package/packages/electron-client-ipc/src/events/index.ts +5 -2
- package/packages/electron-client-ipc/src/events/protocol.ts +29 -0
- package/packages/electron-client-ipc/src/types/index.ts +1 -0
- package/packages/electron-client-ipc/src/types/mcpInstall.ts +19 -0
- package/packages/types/src/plugins/mcp.ts +38 -1
- package/packages/types/src/plugins/protocol.ts +166 -0
- package/src/app/[variants]/(main)/chat/_layout/Desktop/index.tsx +4 -1
- package/src/app/[variants]/(main)/discover/(detail)/mcp/[slug]/features/Sidebar/ActionButton/index.tsx +1 -2
- package/src/components/KeyValueEditor/index.tsx +4 -2
- package/src/features/ChatItem/index.tsx +25 -2
- package/src/features/MCP/MCPInstallProgress/index.tsx +1 -1
- package/src/features/PluginDevModal/MCPManifestForm/index.tsx +30 -36
- package/src/features/PluginStore/McpList/List/Item.tsx +1 -1
- package/src/features/ProtocolUrlHandler/InstallPlugin/ConfigDisplay.tsx +211 -0
- package/src/features/ProtocolUrlHandler/InstallPlugin/CustomPluginInstallModal.tsx +228 -0
- package/src/features/ProtocolUrlHandler/InstallPlugin/OfficialPluginInstallModal/Detail.tsx +44 -0
- package/src/features/ProtocolUrlHandler/InstallPlugin/OfficialPluginInstallModal/index.tsx +105 -0
- package/src/features/ProtocolUrlHandler/InstallPlugin/index.tsx +55 -0
- package/src/features/ProtocolUrlHandler/InstallPlugin/types.ts +45 -0
- package/src/features/ProtocolUrlHandler/index.tsx +30 -0
- package/src/locales/default/plugin.ts +60 -0
- package/src/store/tool/slices/mcpStore/action.ts +127 -1
- package/src/store/tool/slices/mcpStore/initialState.ts +8 -13
- 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 {
|
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,
|