fix(MCPService): 增加获取系统 PATH 的功能, 修复 process.env.PATH 无法获取系统PATH的问题 (#4766)
This commit is contained in:
parent
e13a43d82a
commit
352731827c
@ -1,5 +1,6 @@
|
|||||||
import os from 'node:os'
|
import os from 'node:os'
|
||||||
import path from 'node:path'
|
import path from 'node:path'
|
||||||
|
import fs from 'node:fs'
|
||||||
|
|
||||||
import { isLinux, isMac, isWin } from '@main/constant'
|
import { isLinux, isMac, isWin } from '@main/constant'
|
||||||
import { createInMemoryMCPServer } from '@main/mcpServers/factory'
|
import { createInMemoryMCPServer } from '@main/mcpServers/factory'
|
||||||
@ -13,7 +14,7 @@ import { nanoid } from '@reduxjs/toolkit'
|
|||||||
import { GetMCPPromptResponse, GetResourceResponse, MCPPrompt, MCPResource, MCPServer, MCPTool } from '@types'
|
import { GetMCPPromptResponse, GetResourceResponse, MCPPrompt, MCPResource, MCPServer, MCPTool } from '@types'
|
||||||
import { app } from 'electron'
|
import { app } from 'electron'
|
||||||
import Logger from 'electron-log'
|
import Logger from 'electron-log'
|
||||||
|
import { memoize } from 'lodash'
|
||||||
import { CacheService } from './CacheService'
|
import { CacheService } from './CacheService'
|
||||||
import { StreamableHTTPClientTransport, type StreamableHTTPClientTransportOptions } from './MCPStreamableHttpClient'
|
import { StreamableHTTPClientTransport, type StreamableHTTPClientTransportOptions } from './MCPStreamableHttpClient'
|
||||||
|
|
||||||
@ -184,7 +185,7 @@ class McpService {
|
|||||||
args,
|
args,
|
||||||
env: {
|
env: {
|
||||||
...getDefaultEnvironment(),
|
...getDefaultEnvironment(),
|
||||||
PATH: this.getEnhancedPath(process.env.PATH || ''),
|
PATH: await this.getEnhancedPath(process.env.PATH || ''),
|
||||||
...server.env
|
...server.env
|
||||||
},
|
},
|
||||||
stderr: 'pipe'
|
stderr: 'pipe'
|
||||||
@ -470,13 +471,93 @@ class McpService {
|
|||||||
return await cachedGetResource(server, uri)
|
return await cachedGetResource(server, uri)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private getSystemPath = memoize(async (): Promise<string> => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let command: string
|
||||||
|
let shell: string
|
||||||
|
|
||||||
|
if (process.platform === 'win32') {
|
||||||
|
shell = 'powershell.exe'
|
||||||
|
command = '$env:PATH'
|
||||||
|
} else {
|
||||||
|
// 尝试获取当前用户的默认 shell
|
||||||
|
|
||||||
|
let userShell = process.env.SHELL
|
||||||
|
if (!userShell) {
|
||||||
|
if (fs.existsSync('/bin/zsh')) {
|
||||||
|
userShell = '/bin/zsh'
|
||||||
|
} else if (fs.existsSync('/bin/bash')) {
|
||||||
|
userShell = '/bin/bash'
|
||||||
|
} else if (fs.existsSync('/bin/fish')) {
|
||||||
|
userShell = '/bin/fish'
|
||||||
|
} else {
|
||||||
|
userShell = '/bin/sh'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
shell = userShell
|
||||||
|
|
||||||
|
// 根据不同的 shell 构建不同的命令
|
||||||
|
if (userShell.includes('zsh')) {
|
||||||
|
shell = '/bin/zsh'
|
||||||
|
command =
|
||||||
|
'source /etc/zshenv 2>/dev/null || true; source ~/.zshenv 2>/dev/null || true; source /etc/zprofile 2>/dev/null || true; source ~/.zprofile 2>/dev/null || true; source /etc/zshrc 2>/dev/null || true; source ~/.zshrc 2>/dev/null || true; source /etc/zlogin 2>/dev/null || true; source ~/.zlogin 2>/dev/null || true; echo $PATH'
|
||||||
|
} else if (userShell.includes('bash')) {
|
||||||
|
shell = '/bin/bash'
|
||||||
|
command =
|
||||||
|
'source /etc/profile 2>/dev/null || true; source ~/.bash_profile 2>/dev/null || true; source ~/.bash_login 2>/dev/null || true; source ~/.profile 2>/dev/null || true; source ~/.bashrc 2>/dev/null || true; echo $PATH'
|
||||||
|
} else if (userShell.includes('fish')) {
|
||||||
|
shell = '/bin/fish'
|
||||||
|
command =
|
||||||
|
'source /etc/fish/config.fish 2>/dev/null || true; source ~/.config/fish/config.fish 2>/dev/null || true; source ~/.config/fish/config.local.fish 2>/dev/null || true; echo $PATH'
|
||||||
|
} else {
|
||||||
|
// 默认使用 zsh
|
||||||
|
shell = '/bin/zsh'
|
||||||
|
command =
|
||||||
|
'source /etc/zshenv 2>/dev/null || true; source ~/.zshenv 2>/dev/null || true; source /etc/zprofile 2>/dev/null || true; source ~/.zprofile 2>/dev/null || true; source /etc/zshrc 2>/dev/null || true; source ~/.zshrc 2>/dev/null || true; source /etc/zlogin 2>/dev/null || true; source ~/.zlogin 2>/dev/null || true; echo $PATH'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Using shell: ${shell} with command: ${command}`)
|
||||||
|
const child = require('child_process').spawn(shell, ['-c', command], {
|
||||||
|
env: { ...process.env },
|
||||||
|
cwd: app.getPath('home')
|
||||||
|
})
|
||||||
|
|
||||||
|
let path = ''
|
||||||
|
child.stdout.on('data', (data) => {
|
||||||
|
path += data.toString()
|
||||||
|
})
|
||||||
|
|
||||||
|
child.stderr.on('data', (data) => {
|
||||||
|
console.error('Error getting PATH:', data.toString())
|
||||||
|
})
|
||||||
|
|
||||||
|
child.on('close', (code) => {
|
||||||
|
if (code === 0) {
|
||||||
|
const trimmedPath = path.trim()
|
||||||
|
resolve(trimmedPath)
|
||||||
|
} else {
|
||||||
|
reject(new Error(`Failed to get system PATH, exit code: ${code}`))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get enhanced PATH including common tool locations
|
* Get enhanced PATH including common tool locations
|
||||||
*/
|
*/
|
||||||
private getEnhancedPath(originalPath: string): string {
|
private async getEnhancedPath(originalPath: string): Promise<string> {
|
||||||
|
let systemPath = ''
|
||||||
|
try {
|
||||||
|
systemPath = await this.getSystemPath()
|
||||||
|
} catch (error) {
|
||||||
|
Logger.error('[MCP] Failed to get system PATH:', error)
|
||||||
|
}
|
||||||
// 将原始 PATH 按分隔符分割成数组
|
// 将原始 PATH 按分隔符分割成数组
|
||||||
const pathSeparator = process.platform === 'win32' ? ';' : ':'
|
const pathSeparator = process.platform === 'win32' ? ';' : ':'
|
||||||
const existingPaths = new Set(originalPath.split(pathSeparator).filter(Boolean))
|
const existingPaths = new Set(
|
||||||
|
[...systemPath.split(pathSeparator), ...originalPath.split(pathSeparator)].filter(Boolean)
|
||||||
|
)
|
||||||
const homeDir = process.env.HOME || process.env.USERPROFILE || ''
|
const homeDir = process.env.HOME || process.env.USERPROFILE || ''
|
||||||
|
|
||||||
// 定义要添加的新路径
|
// 定义要添加的新路径
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user