@lobehub/chat 1.84.7 → 1.84.8

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 CHANGED
@@ -2,6 +2,31 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ### [Version 1.84.8](https://github.com/lobehub/lobe-chat/compare/v1.84.7...v1.84.8)
6
+
7
+ <sup>Released on **2025-04-29**</sup>
8
+
9
+ #### 🐛 Bug Fixes
10
+
11
+ - **misc**: Fix stdio mcp server env issue.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### What's fixed
19
+
20
+ - **misc**: Fix stdio mcp server env issue, closes [#7648](https://github.com/lobehub/lobe-chat/issues/7648) ([bad222a](https://github.com/lobehub/lobe-chat/commit/bad222a))
21
+
22
+ </details>
23
+
24
+ <div align="right">
25
+
26
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
27
+
28
+ </div>
29
+
5
30
  ### [Version 1.84.7](https://github.com/lobehub/lobe-chat/compare/v1.84.6...v1.84.7)
6
31
 
7
32
  <sup>Released on **2025-04-29**</sup>
@@ -1,5 +1,5 @@
1
1
  import { ElectronAppState } from '@lobechat/electron-client-ipc';
2
- import { app, systemPreferences } from 'electron';
2
+ import { app, shell, systemPreferences } from 'electron';
3
3
  import { macOS } from 'electron-is';
4
4
  import { readFileSync, writeFileSync } from 'node:fs';
5
5
  import { join } from 'node:path';
@@ -49,6 +49,11 @@ export default class SystemController extends ControllerModule {
49
49
  return systemPreferences.isTrustedAccessibilityClient(true);
50
50
  }
51
51
 
52
+ @ipcClientEvent('openExternalLink')
53
+ openExternalLink(url: string) {
54
+ return shell.openExternal(url);
55
+ }
56
+
52
57
  /**
53
58
  * 更新应用语言设置
54
59
  */
@@ -34,12 +34,23 @@ export const setupRouteInterceptors = function () {
34
34
  try {
35
35
  const url = new URL(link.href);
36
36
 
37
+ // 检查是否为外部链接
38
+ if (url.origin !== window.location.origin) {
39
+ console.log(`[preload] Intercepted external link click:`, url.href);
40
+ // 阻止默认的链接跳转行为
41
+ e.preventDefault();
42
+ e.stopPropagation();
43
+ // 调用主进程处理外部链接
44
+ await invoke('openExternalLink', url.href);
45
+ return false; // 明确阻止后续处理
46
+ }
47
+
48
+ // 如果不是外部链接,则继续处理内部路由拦截逻辑
37
49
  // 使用共享配置检查是否需要拦截
38
50
  const matchedRoute = findMatchingRoute(url.pathname);
39
51
 
40
- // 如果是需要拦截的路径,立即阻止默认行为
52
+ // 如果是需要拦截的路径
41
53
  if (matchedRoute) {
42
- // 检查当前页面是否已经在目标路径下,如果是则不拦截
43
54
  const currentPath = window.location.pathname;
44
55
  const isAlreadyInTargetPage = currentPath.startsWith(matchedRoute.pathPrefix);
45
56
 
@@ -55,7 +66,18 @@ export const setupRouteInterceptors = function () {
55
66
  return false;
56
67
  }
57
68
  } catch (err) {
58
- console.error('[preload] Link interception error:', err);
69
+ // 处理可能的 URL 解析错误或其他问题
70
+ // 例如 mailto:, tel: 等协议会导致 new URL() 抛出错误
71
+ if (err instanceof TypeError && err.message.includes('Invalid URL')) {
72
+ console.log(
73
+ '[preload] Non-HTTP link clicked, allowing default browser behavior:',
74
+ link.href,
75
+ );
76
+ // 对于非 HTTP/HTTPS 链接,允许浏览器默认处理
77
+ // 不需要 e.preventDefault() 或 invoke
78
+ } else {
79
+ console.error('[preload] Link interception error:', err);
80
+ }
59
81
  }
60
82
  }
61
83
  },
package/changelog/v1.json CHANGED
@@ -1,4 +1,13 @@
1
1
  [
2
+ {
3
+ "children": {
4
+ "fixes": [
5
+ "Fix stdio mcp server env issue."
6
+ ]
7
+ },
8
+ "date": "2025-04-29",
9
+ "version": "1.84.8"
10
+ },
2
11
  {
3
12
  "children": {
4
13
  "fixes": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "1.84.7",
3
+ "version": "1.84.8",
4
4
  "description": "Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
5
5
  "keywords": [
6
6
  "framework",
@@ -3,6 +3,7 @@ import { ElectronAppState } from '../types';
3
3
  export interface SystemDispatchEvents {
4
4
  checkSystemAccessibility: () => boolean | undefined;
5
5
  getDesktopAppState: () => ElectronAppState;
6
+ openExternalLink: (url: string) => void;
6
7
  /**
7
8
  * 更新应用语言设置
8
9
  * @param locale 语言设置
@@ -165,10 +165,10 @@ const MCPManifestForm = ({ form, isEditMode }: MCPManifestFormProps) => {
165
165
  } else if (mcp.type === 'stdio') {
166
166
  if (!mcp.command) throw new Error(t('dev.mcp.command.required'));
167
167
  if (!mcp.args) throw new Error(t('dev.mcp.args.required'));
168
- data = await mcpService.getStdioMcpServerManifest(id, mcp.command, mcp.args, {
169
- avatar,
170
- description,
171
- });
168
+ data = await mcpService.getStdioMcpServerManifest(
169
+ { ...mcp, name: id },
170
+ { avatar, description },
171
+ );
172
172
  } else {
173
173
  throw new Error('Invalid MCP type'); // Internal error
174
174
  }
@@ -5,6 +5,7 @@ import {
5
5
  } from '@modelcontextprotocol/sdk/client/stdio.js';
6
6
  import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
7
7
  import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.d.ts';
8
+ import type { Progress } from '@modelcontextprotocol/sdk/types.js';
8
9
  import debug from 'debug';
9
10
 
10
11
  import { MCPClientParams, McpTool } from './types';
@@ -46,10 +47,20 @@ export class MCPClient {
46
47
  }
47
48
  }
48
49
 
49
- async initialize() {
50
+ async initialize(options: { onProgress?: (progress: Progress) => void } = {}) {
50
51
  log('Initializing MCP connection...');
51
- await this.mcp.connect(this.transport);
52
- log('MCP connection initialized.');
52
+
53
+ try {
54
+ await this.mcp.connect(this.transport, { onprogress: options.onProgress });
55
+ log('MCP connection initialized.');
56
+ } catch (e) {
57
+ if ((e as any).code === -32_000) {
58
+ throw new Error('Fail to connecting MCP Server, please check your configuration.');
59
+ }
60
+
61
+ log('MCP connection failed:', e);
62
+ throw e;
63
+ }
53
64
  }
54
65
 
55
66
  async disconnect() {
@@ -1,3 +1,4 @@
1
+ import debug from 'debug';
1
2
  import { z } from 'zod';
2
3
 
3
4
  import { isServerMode } from '@/const/version';
@@ -5,9 +6,12 @@ import { passwordProcedure } from '@/libs/trpc/edge';
5
6
  import { authedProcedure, router } from '@/libs/trpc/lambda';
6
7
  import { mcpService } from '@/server/services/mcp';
7
8
 
9
+ const log = debug('lobe-mcp:router');
10
+
8
11
  const stdioParamsSchema = z.object({
9
12
  args: z.array(z.string()).optional().default([]),
10
13
  command: z.string().min(1),
14
+ env: z.any().optional(),
11
15
  metadata: z
12
16
  .object({
13
17
  avatar: z.string().optional(),
@@ -22,10 +26,9 @@ const mcpProcedure = isServerMode ? authedProcedure : passwordProcedure;
22
26
 
23
27
  export const mcpRouter = router({
24
28
  getStdioMcpServerManifest: mcpProcedure.input(stdioParamsSchema).query(async ({ input }) => {
25
- return await mcpService.getStdioMcpServerManifest(
26
- { args: input.args, command: input.command, name: input.name },
27
- input.metadata,
28
- );
29
+ log('getStdioMcpServerManifest input: %O', input);
30
+
31
+ return await mcpService.getStdioMcpServerManifest(input, input.metadata);
29
32
  }),
30
33
 
31
34
  /* eslint-disable sort-keys-fix/sort-keys-fix */
@@ -119,7 +119,11 @@ class MCPService {
119
119
  // }
120
120
 
121
121
  const client = new MCPClient(params);
122
- await client.initialize(); // Initialization logic should be within MCPClient
122
+ await client.initialize({
123
+ onProgress: (progress) => {
124
+ log(`New client initializing... ${progress.progress}/${progress.total}`);
125
+ },
126
+ }); // Initialization logic should be within MCPClient
123
127
  this.clients.set(key, client);
124
128
  log(`New client initialized and cached for key: ${key}`);
125
129
  return client;
@@ -129,7 +133,7 @@ class MCPService {
129
133
  throw new TRPCError({
130
134
  cause: error,
131
135
  code: 'INTERNAL_SERVER_ERROR',
132
- message: `Failed to initialize MCP client: ${(error as Error).message}`,
136
+ message: `Failed to initialize MCP client, reason: ${(error as Error).message}`,
133
137
  });
134
138
  }
135
139
  }
@@ -181,6 +185,7 @@ class MCPService {
181
185
  const tools = await this.listTools({
182
186
  args: params.args,
183
187
  command: params.command,
188
+ env: params.env,
184
189
  name: params.name,
185
190
  type: 'stdio',
186
191
  });
@@ -40,17 +40,15 @@ class MCPService {
40
40
  }
41
41
 
42
42
  async getStdioMcpServerManifest(
43
- identifier: string,
44
- command: string,
45
- args?: string[],
43
+ stdioParams: {
44
+ args?: string[];
45
+ command: string;
46
+ env?: Record<string, string>;
47
+ name: string;
48
+ },
46
49
  metadata?: CustomPluginMetadata,
47
50
  ) {
48
- return desktopClient.mcp.getStdioMcpServerManifest.query({
49
- args: args,
50
- command,
51
- metadata,
52
- name: identifier,
53
- });
51
+ return desktopClient.mcp.getStdioMcpServerManifest.query({ ...stdioParams, metadata });
54
52
  }
55
53
  }
56
54
 
@@ -22,6 +22,7 @@ export interface CustomPluginParams {
22
22
  */
23
23
  mcp?: {
24
24
  args?: string[];
25
+ env?: Record<string, string>;
25
26
  command?: string;
26
27
  type: 'http' | 'stdio';
27
28
  url?: string;