@lobehub/lobehub 2.0.0-next.46 → 2.0.0-next.47
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/CHANGELOG.md +25 -0
- package/changelog/v1.json +9 -0
- package/package.json +1 -1
- package/packages/database/src/models/file.ts +15 -1
- package/packages/database/src/repositories/aiInfra/index.test.ts +1 -1
- package/packages/database/src/repositories/dataExporter/index.test.ts +1 -1
- package/packages/database/src/repositories/tableViewer/index.test.ts +1 -1
- package/packages/types/src/aiProvider.ts +1 -1
- package/packages/types/src/document/index.ts +38 -38
- package/packages/types/src/exportConfig.ts +15 -15
- package/packages/types/src/generation/index.ts +5 -5
- package/packages/types/src/openai/chat.ts +15 -15
- package/packages/types/src/plugins/mcp.ts +29 -29
- package/packages/types/src/plugins/protocol.ts +43 -43
- package/packages/types/src/search.ts +4 -4
- package/packages/types/src/tool/plugin.ts +3 -3
- package/src/app/(backend)/f/[id]/route.ts +55 -0
- package/src/envs/app.ts +4 -3
- package/src/features/Conversation/components/VirtualizedList/index.tsx +2 -1
- package/src/features/PluginsUI/Render/MCPType/index.tsx +26 -6
- package/src/server/routers/desktop/mcp.ts +23 -8
- package/src/server/routers/tools/mcp.ts +24 -4
- package/src/server/services/file/impls/local.ts +4 -1
- package/src/server/services/file/index.ts +96 -1
- package/src/server/services/mcp/contentProcessor.ts +101 -0
- package/src/server/services/mcp/index.test.ts +52 -10
- package/src/server/services/mcp/index.ts +29 -26
- package/src/services/session/index.ts +0 -14
- package/src/utils/server/routeVariants.test.ts +340 -0
|
@@ -21,7 +21,7 @@ export enum MCPInstallStep {
|
|
|
21
21
|
/* eslint-enable */
|
|
22
22
|
export interface CheckMcpInstallParams {
|
|
23
23
|
/**
|
|
24
|
-
*
|
|
24
|
+
* Installation details
|
|
25
25
|
*/
|
|
26
26
|
installationDetails: {
|
|
27
27
|
packageName?: string;
|
|
@@ -29,11 +29,11 @@ export interface CheckMcpInstallParams {
|
|
|
29
29
|
setupSteps?: string[];
|
|
30
30
|
};
|
|
31
31
|
/**
|
|
32
|
-
*
|
|
32
|
+
* Installation method
|
|
33
33
|
*/
|
|
34
34
|
installationMethod: string;
|
|
35
35
|
/**
|
|
36
|
-
*
|
|
36
|
+
* System dependencies
|
|
37
37
|
*/
|
|
38
38
|
systemDependencies?: SystemDependency[];
|
|
39
39
|
}
|
|
@@ -41,12 +41,12 @@ export interface CheckMcpInstallParams {
|
|
|
41
41
|
export interface CheckMcpInstallResult {
|
|
42
42
|
allDependenciesMet?: boolean;
|
|
43
43
|
/**
|
|
44
|
-
*
|
|
44
|
+
* Check results for all deployment options
|
|
45
45
|
*/
|
|
46
46
|
allOptions?: Array<{
|
|
47
47
|
allDependenciesMet?: boolean;
|
|
48
48
|
/**
|
|
49
|
-
*
|
|
49
|
+
* Connection information for subsequent connection use
|
|
50
50
|
*/
|
|
51
51
|
connection?: {
|
|
52
52
|
args?: string[];
|
|
@@ -66,11 +66,11 @@ export interface CheckMcpInstallResult {
|
|
|
66
66
|
}>;
|
|
67
67
|
}>;
|
|
68
68
|
/**
|
|
69
|
-
*
|
|
69
|
+
* Configuration schema, elevated to top level for easy access
|
|
70
70
|
*/
|
|
71
71
|
configSchema?: any;
|
|
72
72
|
/**
|
|
73
|
-
*
|
|
73
|
+
* Connection information for subsequent connection use
|
|
74
74
|
*/
|
|
75
75
|
connection?: {
|
|
76
76
|
args?: string[];
|
|
@@ -79,28 +79,28 @@ export interface CheckMcpInstallResult {
|
|
|
79
79
|
url?: string;
|
|
80
80
|
};
|
|
81
81
|
/**
|
|
82
|
-
*
|
|
82
|
+
* Error information if detection fails
|
|
83
83
|
*/
|
|
84
84
|
error?: string;
|
|
85
85
|
/**
|
|
86
|
-
*
|
|
86
|
+
* Whether this is the recommended option
|
|
87
87
|
*/
|
|
88
88
|
isRecommended?: boolean;
|
|
89
89
|
/**
|
|
90
|
-
*
|
|
90
|
+
* Whether configuration is needed (e.g. API key, etc.)
|
|
91
91
|
*/
|
|
92
92
|
needsConfig?: boolean;
|
|
93
93
|
/**
|
|
94
|
-
*
|
|
94
|
+
* Plugin installation detection result
|
|
95
95
|
*/
|
|
96
96
|
packageInstalled?: boolean;
|
|
97
97
|
platform: string;
|
|
98
98
|
/**
|
|
99
|
-
*
|
|
99
|
+
* Whether the detection result is successful
|
|
100
100
|
*/
|
|
101
101
|
success: boolean;
|
|
102
102
|
/**
|
|
103
|
-
*
|
|
103
|
+
* System dependency detection results
|
|
104
104
|
*/
|
|
105
105
|
systemDependencies?: Array<{
|
|
106
106
|
error?: string;
|
|
@@ -119,12 +119,12 @@ export interface MCPErrorInfoMetadata {
|
|
|
119
119
|
errorLog?: string;
|
|
120
120
|
|
|
121
121
|
/**
|
|
122
|
-
*
|
|
122
|
+
* Original error message
|
|
123
123
|
*/
|
|
124
124
|
originalError?: string;
|
|
125
125
|
|
|
126
126
|
/**
|
|
127
|
-
* MCP
|
|
127
|
+
* MCP connection parameters
|
|
128
128
|
*/
|
|
129
129
|
params?: {
|
|
130
130
|
args?: string[];
|
|
@@ -132,7 +132,7 @@ export interface MCPErrorInfoMetadata {
|
|
|
132
132
|
type?: string;
|
|
133
133
|
};
|
|
134
134
|
/**
|
|
135
|
-
*
|
|
135
|
+
* Process-related information
|
|
136
136
|
*/
|
|
137
137
|
process?: {
|
|
138
138
|
exitCode?: number;
|
|
@@ -140,31 +140,31 @@ export interface MCPErrorInfoMetadata {
|
|
|
140
140
|
};
|
|
141
141
|
|
|
142
142
|
/**
|
|
143
|
-
*
|
|
143
|
+
* Step where the error occurred
|
|
144
144
|
*/
|
|
145
145
|
step?: string;
|
|
146
146
|
|
|
147
147
|
/**
|
|
148
|
-
*
|
|
148
|
+
* Timestamp
|
|
149
149
|
*/
|
|
150
150
|
timestamp?: number;
|
|
151
151
|
}
|
|
152
152
|
/**
|
|
153
|
-
*
|
|
153
|
+
* Structured error information
|
|
154
154
|
*/
|
|
155
155
|
export interface MCPErrorInfo {
|
|
156
156
|
/**
|
|
157
|
-
*
|
|
157
|
+
* Core error message (user-friendly brief description)
|
|
158
158
|
*/
|
|
159
159
|
message: string;
|
|
160
160
|
|
|
161
161
|
/**
|
|
162
|
-
*
|
|
162
|
+
* Structured error metadata
|
|
163
163
|
*/
|
|
164
164
|
metadata?: MCPErrorInfoMetadata;
|
|
165
165
|
|
|
166
166
|
/**
|
|
167
|
-
*
|
|
167
|
+
* Error type
|
|
168
168
|
*/
|
|
169
169
|
type: MCPErrorType;
|
|
170
170
|
}
|
|
@@ -174,7 +174,7 @@ export interface MCPInstallProgress {
|
|
|
174
174
|
configSchema?: any;
|
|
175
175
|
// connection info from checkInstallation
|
|
176
176
|
connection?: any;
|
|
177
|
-
//
|
|
177
|
+
// Structured error information, displayed when installation fails
|
|
178
178
|
errorInfo?: MCPErrorInfo;
|
|
179
179
|
manifest?: any;
|
|
180
180
|
// LobeChatPluginManifest
|
|
@@ -182,12 +182,12 @@ export interface MCPInstallProgress {
|
|
|
182
182
|
// 0-100
|
|
183
183
|
progress: number;
|
|
184
184
|
step: MCPInstallStep;
|
|
185
|
-
//
|
|
185
|
+
// System dependency detection results, displayed when dependencies need to be installed
|
|
186
186
|
systemDependencies?: Array<{
|
|
187
187
|
error?: string;
|
|
188
188
|
installInstructions?: {
|
|
189
|
-
current?: string; //
|
|
190
|
-
manual?: string; //
|
|
189
|
+
current?: string; // Installation command for the current system
|
|
190
|
+
manual?: string; // Manual installation command
|
|
191
191
|
};
|
|
192
192
|
installed: boolean;
|
|
193
193
|
meetRequirement: boolean;
|
|
@@ -206,16 +206,16 @@ export interface McpConnection {
|
|
|
206
206
|
token?: string;
|
|
207
207
|
type: 'none' | 'bearer' | 'oauth2';
|
|
208
208
|
};
|
|
209
|
-
// STDIO
|
|
209
|
+
// STDIO connection parameters
|
|
210
210
|
command?: string;
|
|
211
211
|
env?: Record<string, string>;
|
|
212
212
|
headers?: Record<string, string>;
|
|
213
213
|
type: 'http' | 'stdio';
|
|
214
|
-
// HTTP
|
|
214
|
+
// HTTP connection parameters
|
|
215
215
|
url?: string;
|
|
216
216
|
}
|
|
217
217
|
|
|
218
|
-
//
|
|
218
|
+
// Test connection parameter type
|
|
219
219
|
export interface McpConnectionParams {
|
|
220
220
|
connection: McpConnection;
|
|
221
221
|
identifier: string;
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Protocol source type
|
|
3
3
|
*/
|
|
4
4
|
export enum ProtocolSource {
|
|
5
|
-
/**
|
|
5
|
+
/** Community contribution */
|
|
6
6
|
COMMUNITY = 'community',
|
|
7
|
-
/**
|
|
7
|
+
/** Developer custom */
|
|
8
8
|
DEVELOPER = 'developer',
|
|
9
|
-
/** GitHub
|
|
9
|
+
/** GitHub official */
|
|
10
10
|
GITHUB_OFFICIAL = 'github_official',
|
|
11
|
-
/**
|
|
11
|
+
/** Official LobeHub marketplace */
|
|
12
12
|
OFFICIAL = 'official',
|
|
13
|
-
/**
|
|
13
|
+
/** Third-party marketplace */
|
|
14
14
|
THIRD_PARTY = 'third_party',
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
|
-
* MCP Schema - stdio
|
|
18
|
+
* MCP Schema - stdio configuration type
|
|
19
19
|
*/
|
|
20
20
|
export interface McpStdioConfig {
|
|
21
21
|
args?: string[];
|
|
@@ -25,7 +25,7 @@ export interface McpStdioConfig {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
|
-
* MCP Schema - http
|
|
28
|
+
* MCP Schema - http configuration type
|
|
29
29
|
*/
|
|
30
30
|
export interface McpHttpConfig {
|
|
31
31
|
headers?: Record<string, string>;
|
|
@@ -34,74 +34,74 @@ export interface McpHttpConfig {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
|
-
* MCP Schema
|
|
37
|
+
* MCP Schema configuration type
|
|
38
38
|
*/
|
|
39
39
|
export type McpConfig = McpStdioConfig | McpHttpConfig;
|
|
40
40
|
|
|
41
41
|
/**
|
|
42
|
-
* MCP Schema
|
|
43
|
-
*
|
|
42
|
+
* MCP Schema object
|
|
43
|
+
* Conforms to RFC 0001 definition
|
|
44
44
|
*/
|
|
45
45
|
export interface McpSchema {
|
|
46
|
-
/**
|
|
46
|
+
/** Plugin author */
|
|
47
47
|
author: string;
|
|
48
|
-
/**
|
|
48
|
+
/** Plugin configuration */
|
|
49
49
|
config: McpConfig;
|
|
50
|
-
/**
|
|
50
|
+
/** Plugin description */
|
|
51
51
|
description: string;
|
|
52
|
-
/**
|
|
52
|
+
/** Plugin homepage */
|
|
53
53
|
homepage?: string;
|
|
54
|
-
/**
|
|
54
|
+
/** Plugin icon */
|
|
55
55
|
icon?: string;
|
|
56
|
-
/**
|
|
56
|
+
/** Plugin unique identifier, must match the id parameter in the URL */
|
|
57
57
|
identifier: string;
|
|
58
|
-
/**
|
|
58
|
+
/** Plugin name */
|
|
59
59
|
name: string;
|
|
60
|
-
/**
|
|
60
|
+
/** Plugin version (semver) */
|
|
61
61
|
version: string;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
/**
|
|
65
|
-
* RFC 0001
|
|
65
|
+
* RFC 0001 protocol parameters
|
|
66
66
|
* lobehub://plugin/install?id=xxx&schema=xxx&marketId=xxx&meta_*=xxx
|
|
67
67
|
*/
|
|
68
68
|
export interface McpInstallProtocolParamsRFC {
|
|
69
|
-
/**
|
|
69
|
+
/** Optional UI display metadata, prefixed with meta_ */
|
|
70
70
|
[key: `meta_${string}`]: string | undefined;
|
|
71
|
-
/**
|
|
71
|
+
/** Unique identifier of the plugin */
|
|
72
72
|
id: string;
|
|
73
|
-
/**
|
|
73
|
+
/** Unique identifier of the Marketplace providing this plugin */
|
|
74
74
|
marketId?: string;
|
|
75
|
-
/** Base64URL
|
|
75
|
+
/** Base64URL encoded MCP Schema object */
|
|
76
76
|
schema: string;
|
|
77
|
-
/**
|
|
77
|
+
/** Plugin type, fixed as 'mcp' for MCP */
|
|
78
78
|
type: 'mcp';
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
/**
|
|
82
|
-
*
|
|
82
|
+
* Protocol URL parsing result
|
|
83
83
|
*/
|
|
84
84
|
export interface ProtocolUrlParsed {
|
|
85
|
-
/**
|
|
85
|
+
/** Action type (e.g.: 'install') */
|
|
86
86
|
action: 'install' | 'configure' | 'update';
|
|
87
|
-
/**
|
|
87
|
+
/** Parsed parameters */
|
|
88
88
|
params: {
|
|
89
89
|
id: string;
|
|
90
90
|
marketId?: string;
|
|
91
91
|
type: string;
|
|
92
92
|
};
|
|
93
|
-
/** MCP Schema
|
|
93
|
+
/** MCP Schema object */
|
|
94
94
|
schema: McpSchema;
|
|
95
|
-
/**
|
|
95
|
+
/** Protocol source */
|
|
96
96
|
source: ProtocolSource;
|
|
97
|
-
/**
|
|
97
|
+
/** Plugin type (e.g.: 'mcp') */
|
|
98
98
|
type: 'mcp' | 'plugin';
|
|
99
|
-
/** URL
|
|
99
|
+
/** URL type (e.g.: 'plugin') */
|
|
100
100
|
urlType: string;
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
/**
|
|
104
|
-
*
|
|
104
|
+
* Installation confirmation dialog information
|
|
105
105
|
*/
|
|
106
106
|
export interface InstallConfirmationInfo {
|
|
107
107
|
dependencies?: string[];
|
|
@@ -125,42 +125,42 @@ export interface InstallConfirmationInfo {
|
|
|
125
125
|
url?: string;
|
|
126
126
|
};
|
|
127
127
|
type: ProtocolSource;
|
|
128
|
-
verified: boolean; //
|
|
128
|
+
verified: boolean; // Whether it's a verified source
|
|
129
129
|
};
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
/**
|
|
133
|
-
*
|
|
133
|
+
* Protocol handler interface
|
|
134
134
|
*/
|
|
135
135
|
export interface ProtocolHandler {
|
|
136
136
|
/**
|
|
137
|
-
*
|
|
137
|
+
* Handle protocol URL
|
|
138
138
|
*/
|
|
139
139
|
handle(
|
|
140
140
|
parsed: ProtocolUrlParsed,
|
|
141
141
|
): Promise<{ error?: string; success: boolean; targetWindow?: string }>;
|
|
142
142
|
|
|
143
143
|
/**
|
|
144
|
-
*
|
|
144
|
+
* Supported actions
|
|
145
145
|
*/
|
|
146
146
|
readonly supportedActions: string[];
|
|
147
147
|
|
|
148
148
|
/**
|
|
149
|
-
*
|
|
149
|
+
* Protocol type
|
|
150
150
|
*/
|
|
151
151
|
readonly type: string;
|
|
152
152
|
}
|
|
153
153
|
|
|
154
154
|
/**
|
|
155
|
-
*
|
|
155
|
+
* Protocol routing configuration
|
|
156
156
|
*/
|
|
157
157
|
export interface ProtocolRouteConfig {
|
|
158
|
-
/**
|
|
158
|
+
/** Action type */
|
|
159
159
|
action: string;
|
|
160
|
-
/**
|
|
160
|
+
/** Target path (relative to window base path) */
|
|
161
161
|
targetPath?: string;
|
|
162
|
-
/**
|
|
162
|
+
/** Target window */
|
|
163
163
|
targetWindow: 'chat' | 'settings';
|
|
164
|
-
/**
|
|
164
|
+
/** Protocol type */
|
|
165
165
|
type: string;
|
|
166
166
|
}
|
|
@@ -4,16 +4,16 @@ export type SearchMode = 'off' | 'auto' | 'on';
|
|
|
4
4
|
|
|
5
5
|
export enum ModelSearchImplement {
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
7
|
+
* Model has built-in search functionality
|
|
8
|
+
* Similar to search modes of models like Jina, PPLX, transparent to the caller
|
|
9
9
|
*/
|
|
10
10
|
Internal = 'internal',
|
|
11
11
|
/**
|
|
12
|
-
*
|
|
12
|
+
* Uses parameter toggle approach, e.g. Qwen, Google, OpenRouter, search results in
|
|
13
13
|
*/
|
|
14
14
|
Params = 'params',
|
|
15
15
|
/**
|
|
16
|
-
*
|
|
16
|
+
* Uses tool calling approach
|
|
17
17
|
*/
|
|
18
18
|
Tool = 'tool',
|
|
19
19
|
}
|
|
@@ -19,7 +19,7 @@ export interface CustomPluginParams {
|
|
|
19
19
|
|
|
20
20
|
/* eslint-disable sort-keys-fix/sort-keys-fix , typescript-sort-keys/interface */
|
|
21
21
|
/**
|
|
22
|
-
* TODO:
|
|
22
|
+
* TODO: Temporary solution, needs major refactoring in the future
|
|
23
23
|
*/
|
|
24
24
|
mcp?: {
|
|
25
25
|
args?: string[];
|
|
@@ -27,13 +27,13 @@ export interface CustomPluginParams {
|
|
|
27
27
|
command?: string;
|
|
28
28
|
type: 'http' | 'stdio';
|
|
29
29
|
url?: string;
|
|
30
|
-
//
|
|
30
|
+
// Added authentication configuration support
|
|
31
31
|
auth?: {
|
|
32
32
|
type: 'none' | 'bearer' | 'oauth2';
|
|
33
33
|
token?: string; // Bearer Token
|
|
34
34
|
accessToken?: string; // OAuth2 Access Token
|
|
35
35
|
};
|
|
36
|
-
//
|
|
36
|
+
// Added headers configuration support
|
|
37
37
|
headers?: Record<string, string>;
|
|
38
38
|
};
|
|
39
39
|
avatar?: string;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import debug from 'debug';
|
|
2
|
+
|
|
3
|
+
import { FileModel } from '@/database/models/file';
|
|
4
|
+
import { getServerDB } from '@/database/server';
|
|
5
|
+
import { FileService } from '@/server/services/file';
|
|
6
|
+
|
|
7
|
+
const log = debug('lobe-file:proxy');
|
|
8
|
+
|
|
9
|
+
type Params = Promise<{ id: string }>;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* File proxy service
|
|
13
|
+
* GET /f/:id
|
|
14
|
+
*
|
|
15
|
+
* Features:
|
|
16
|
+
* - Query database to get file record (without userId filter for public access)
|
|
17
|
+
* - Generate access URL based on platform (desktop → local file, web → S3 presigned URL)
|
|
18
|
+
* - Return 302 redirect
|
|
19
|
+
*/
|
|
20
|
+
export const GET = async (_req: Request, segmentData: { params: Params }) => {
|
|
21
|
+
try {
|
|
22
|
+
const params = await segmentData.params;
|
|
23
|
+
const { id } = params;
|
|
24
|
+
|
|
25
|
+
log('File proxy request: %s', id);
|
|
26
|
+
|
|
27
|
+
// Get database connection
|
|
28
|
+
const db = await getServerDB();
|
|
29
|
+
|
|
30
|
+
// Query file record without userId filter (public access)
|
|
31
|
+
const file = await FileModel.getFileById(db, id);
|
|
32
|
+
|
|
33
|
+
if (!file) {
|
|
34
|
+
log('File not found: %s', id);
|
|
35
|
+
return new Response('File not found', {
|
|
36
|
+
status: 404,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Create file service with file owner's userId
|
|
41
|
+
const fileService = new FileService(db, file.userId);
|
|
42
|
+
|
|
43
|
+
// Web: Generate S3 presigned URL (5 minutes expiry)
|
|
44
|
+
const redirectUrl = await fileService.createPreSignedUrlForPreview(file.url, 300);
|
|
45
|
+
log('Web S3 presigned URL generated (expires in 5 min)');
|
|
46
|
+
|
|
47
|
+
// Return 302 redirect
|
|
48
|
+
return Response.redirect(redirectUrl, 302);
|
|
49
|
+
} catch (error) {
|
|
50
|
+
console.error('File proxy error:', error);
|
|
51
|
+
return new Response('Internal server error', {
|
|
52
|
+
status: 500,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
};
|
package/src/envs/app.ts
CHANGED
|
@@ -18,7 +18,9 @@ const APP_URL = process.env.APP_URL
|
|
|
18
18
|
? process.env.APP_URL
|
|
19
19
|
: isInVercel
|
|
20
20
|
? vercelUrl
|
|
21
|
-
: '
|
|
21
|
+
: process.env.NODE_ENV === 'development'
|
|
22
|
+
? 'http://localhost:3010'
|
|
23
|
+
: 'http://localhost:3210';
|
|
22
24
|
|
|
23
25
|
// INTERNAL_APP_URL is used for server-to-server calls to bypass CDN/proxy
|
|
24
26
|
// Falls back to APP_URL if not set
|
|
@@ -37,7 +39,6 @@ export const getAppConfig = () => {
|
|
|
37
39
|
},
|
|
38
40
|
server: {
|
|
39
41
|
ACCESS_CODES: z.any(z.string()).optional(),
|
|
40
|
-
|
|
41
42
|
AGENTS_INDEX_URL: z.string().url(),
|
|
42
43
|
|
|
43
44
|
DEFAULT_AGENT_CONFIG: z.string(),
|
|
@@ -46,7 +47,7 @@ export const getAppConfig = () => {
|
|
|
46
47
|
PLUGINS_INDEX_URL: z.string().url(),
|
|
47
48
|
PLUGIN_SETTINGS: z.string().optional(),
|
|
48
49
|
|
|
49
|
-
APP_URL: z.string()
|
|
50
|
+
APP_URL: z.string(),
|
|
50
51
|
INTERNAL_APP_URL: z.string().optional(),
|
|
51
52
|
VERCEL_EDGE_CONFIG: z.string().optional(),
|
|
52
53
|
MIDDLEWARE_REWRITE_THROUGH_LOCAL: z.boolean().optional(),
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
+
import isEqual from 'fast-deep-equal';
|
|
3
4
|
import {
|
|
4
5
|
ReactNode,
|
|
5
6
|
forwardRef,
|
|
@@ -132,6 +133,6 @@ const VirtualizedList = memo<VirtualizedListProps>(({ mobile, dataSource, itemCo
|
|
|
132
133
|
</WideScreenContainer>
|
|
133
134
|
</VirtuosoContext>
|
|
134
135
|
);
|
|
135
|
-
});
|
|
136
|
+
}, isEqual);
|
|
136
137
|
|
|
137
138
|
export default VirtualizedList;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Markdown } from '@lobehub/ui';
|
|
1
|
+
import { Image, Markdown } from '@lobehub/ui';
|
|
2
2
|
import { memo } from 'react';
|
|
3
3
|
import { Flexbox } from 'react-layout-kit';
|
|
4
4
|
|
|
@@ -21,14 +21,22 @@ const MCPType = memo<MCPTypeProps>(({ pluginState, arguments: args }) => {
|
|
|
21
21
|
|
|
22
22
|
const { content } = pluginState;
|
|
23
23
|
|
|
24
|
+
const hasImage = content.some((item) => item.type === 'image');
|
|
24
25
|
return (
|
|
25
|
-
<Flexbox
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
<Flexbox
|
|
27
|
+
gap={8}
|
|
28
|
+
style={
|
|
29
|
+
!hasImage ? { maxHeight: 400, overflow: 'scroll', padding: 8, width: '100%' } : undefined
|
|
30
|
+
}
|
|
31
|
+
>
|
|
32
|
+
{args && (
|
|
33
|
+
<div>
|
|
34
|
+
<Arguments arguments={args} />
|
|
35
|
+
</div>
|
|
36
|
+
)}
|
|
29
37
|
<Flexbox>
|
|
30
38
|
<Flexbox>
|
|
31
|
-
{content.map((item) => {
|
|
39
|
+
{content.map((item, index) => {
|
|
32
40
|
switch (item.type) {
|
|
33
41
|
case 'text': {
|
|
34
42
|
return (
|
|
@@ -38,6 +46,18 @@ const MCPType = memo<MCPTypeProps>(({ pluginState, arguments: args }) => {
|
|
|
38
46
|
);
|
|
39
47
|
}
|
|
40
48
|
|
|
49
|
+
case 'image': {
|
|
50
|
+
return (
|
|
51
|
+
<Image
|
|
52
|
+
alt="MCP content"
|
|
53
|
+
height={'auto'}
|
|
54
|
+
key={`image-${index}`}
|
|
55
|
+
src={item.data}
|
|
56
|
+
width={'100%'}
|
|
57
|
+
/>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
41
61
|
default: {
|
|
42
62
|
return null;
|
|
43
63
|
}
|
|
@@ -2,8 +2,12 @@ import { GetStreamableMcpServerManifestInputSchema } from '@lobechat/types';
|
|
|
2
2
|
import debug from 'debug';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
|
|
5
|
+
import { ToolCallContent } from '@/libs/mcp';
|
|
5
6
|
import { authedProcedure, router } from '@/libs/trpc/lambda';
|
|
7
|
+
import { serverDatabase } from '@/libs/trpc/lambda/middleware';
|
|
8
|
+
import { FileService } from '@/server/services/file';
|
|
6
9
|
import { mcpService } from '@/server/services/mcp';
|
|
10
|
+
import { processContentBlocks } from '@/server/services/mcp/contentProcessor';
|
|
7
11
|
|
|
8
12
|
const log = debug('lobe-mcp:router');
|
|
9
13
|
|
|
@@ -22,7 +26,13 @@ const stdioParamsSchema = z.object({
|
|
|
22
26
|
type: z.literal('stdio').default('stdio'),
|
|
23
27
|
});
|
|
24
28
|
|
|
25
|
-
const mcpProcedure = authedProcedure
|
|
29
|
+
const mcpProcedure = authedProcedure.use(serverDatabase).use(async ({ ctx, next }) => {
|
|
30
|
+
return next({
|
|
31
|
+
ctx: {
|
|
32
|
+
fileService: new FileService(ctx.serverDB, ctx.userId),
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
});
|
|
26
36
|
|
|
27
37
|
export const mcpRouter = router({
|
|
28
38
|
getStdioMcpServerManifest: mcpProcedure.input(stdioParamsSchema).query(async ({ input }) => {
|
|
@@ -85,13 +95,18 @@ export const mcpRouter = router({
|
|
|
85
95
|
toolName: z.string(),
|
|
86
96
|
}),
|
|
87
97
|
)
|
|
88
|
-
.mutation(async ({ input }) => {
|
|
89
|
-
//
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
98
|
+
.mutation(async ({ input, ctx }) => {
|
|
99
|
+
// Create a closure that binds fileService and userId to processContentBlocks
|
|
100
|
+
const boundProcessContentBlocks = async (blocks: ToolCallContent[]) =>
|
|
101
|
+
processContentBlocks(blocks, ctx.fileService);
|
|
102
|
+
|
|
103
|
+
// Pass the validated params, toolName, args, and bound processContentBlocks to the service
|
|
104
|
+
return await mcpService.callTool({
|
|
105
|
+
clientParams: { ...input.params, env: input.env },
|
|
106
|
+
toolName: input.toolName,
|
|
107
|
+
argsStr: input.args,
|
|
108
|
+
processContentBlocks: boundProcessContentBlocks,
|
|
109
|
+
});
|
|
95
110
|
}),
|
|
96
111
|
|
|
97
112
|
validMcpServerInstallable: mcpProcedure
|