diff --git a/Dockerfile b/Dockerfile index 200d539..0d89081 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,25 +9,9 @@ RUN apt-get update && apt-get install -y curl gnupg git \ RUN npm install -g pnpm -ENV MCP_DATA_DIR=/app/data -ENV MCP_SERVERS_DIR=$MCP_DATA_DIR/servers -ENV MCP_NPM_DIR=$MCP_SERVERS_DIR/npm -ENV MCP_PYTHON_DIR=$MCP_SERVERS_DIR/python -ENV PNPM_HOME=$MCP_DATA_DIR/pnpm -ENV NPM_CONFIG_PREFIX=$MCP_DATA_DIR/npm-global -ENV NPM_CONFIG_CACHE=$MCP_DATA_DIR/npm-cache -ENV UV_TOOL_DIR=$MCP_DATA_DIR/uv/tools -ENV UV_CACHE_DIR=$MCP_DATA_DIR/uv/cache -ENV PATH=$PNPM_HOME:$NPM_CONFIG_PREFIX/bin:$UV_TOOL_DIR/bin:$PATH -RUN mkdir -p \ - $PNPM_HOME \ - $NPM_CONFIG_PREFIX/bin \ - $NPM_CONFIG_PREFIX/lib/node_modules \ - $NPM_CONFIG_CACHE \ - $UV_TOOL_DIR \ - $UV_CACHE_DIR \ - $MCP_NPM_DIR \ - $MCP_PYTHON_DIR && \ +ENV PNPM_HOME=/usr/local/share/pnpm +ENV PATH=$PNPM_HOME:$PATH +RUN mkdir -p $PNPM_HOME && \ pnpm add -g @amap/amap-maps-mcp-server @playwright/mcp@latest tavily-mcp@latest @modelcontextprotocol/server-github @modelcontextprotocol/server-slack ARG INSTALL_EXT=false diff --git a/entrypoint.sh b/entrypoint.sh index 7e077df..d4f7382 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -1,27 +1,5 @@ #!/bin/bash -DATA_DIR=${MCP_DATA_DIR:-/app/data} -SERVERS_DIR=${MCP_SERVERS_DIR:-$DATA_DIR/servers} -NPM_SERVER_DIR=${MCP_NPM_DIR:-$SERVERS_DIR/npm} -PYTHON_SERVER_DIR=${MCP_PYTHON_DIR:-$SERVERS_DIR/python} -PNPM_HOME=${PNPM_HOME:-$DATA_DIR/pnpm} -NPM_CONFIG_PREFIX=${NPM_CONFIG_PREFIX:-$DATA_DIR/npm-global} -NPM_CONFIG_CACHE=${NPM_CONFIG_CACHE:-$DATA_DIR/npm-cache} -UV_TOOL_DIR=${UV_TOOL_DIR:-$DATA_DIR/uv/tools} -UV_CACHE_DIR=${UV_CACHE_DIR:-$DATA_DIR/uv/cache} - -mkdir -p \ - "$PNPM_HOME" \ - "$NPM_CONFIG_PREFIX/bin" \ - "$NPM_CONFIG_PREFIX/lib/node_modules" \ - "$NPM_CONFIG_CACHE" \ - "$UV_TOOL_DIR" \ - "$UV_CACHE_DIR" \ - "$NPM_SERVER_DIR" \ - "$PYTHON_SERVER_DIR" - -export PATH="$PNPM_HOME:$NPM_CONFIG_PREFIX/bin:$UV_TOOL_DIR/bin:$PATH" - NPM_REGISTRY=${NPM_REGISTRY:-https://registry.npmjs.org/} echo "Setting npm registry to ${NPM_REGISTRY}" npm config set registry "$NPM_REGISTRY" diff --git a/src/services/mcpService.ts b/src/services/mcpService.ts index 801e4da..85a6729 100644 --- a/src/services/mcpService.ts +++ b/src/services/mcpService.ts @@ -1,6 +1,4 @@ -import fs from 'fs'; import os from 'os'; -import path from 'path'; import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { CallToolRequestSchema, @@ -33,77 +31,6 @@ const servers: { [sessionId: string]: Server } = {}; const serverDao = getServerDao(); -const ensureDirExists = (dir: string | undefined): string => { - if (!dir) { - throw new Error('Directory path is undefined'); - } - if (!fs.existsSync(dir)) { - fs.mkdirSync(dir, { recursive: true }); - } - return dir; -}; - -const getDataRootDir = (): string => { - return ensureDirExists(process.env.MCP_DATA_DIR || path.join(process.cwd(), 'data')); -}; - -const getServersStorageRoot = (): string => { - return ensureDirExists(process.env.MCP_SERVERS_DIR || path.join(getDataRootDir(), 'servers')); -}; - -const getNpmBaseDir = (): string => { - return ensureDirExists(process.env.MCP_NPM_DIR || path.join(getServersStorageRoot(), 'npm')); -}; - -const getPythonBaseDir = (): string => { - return ensureDirExists( - process.env.MCP_PYTHON_DIR || path.join(getServersStorageRoot(), 'python'), - ); -}; - -const getNpmCacheDir = (): string => { - return ensureDirExists(process.env.NPM_CONFIG_CACHE || path.join(getDataRootDir(), 'npm-cache')); -}; - -const getNpmPrefixDir = (): string => { - const dir = ensureDirExists( - process.env.NPM_CONFIG_PREFIX || path.join(getDataRootDir(), 'npm-global'), - ); - ensureDirExists(path.join(dir, 'bin')); - ensureDirExists(path.join(dir, 'lib', 'node_modules')); - return dir; -}; - -const getUvCacheDir = (): string => { - return ensureDirExists(process.env.UV_CACHE_DIR || path.join(getDataRootDir(), 'uv', 'cache')); -}; - -const getUvToolDir = (): string => { - const dir = ensureDirExists(process.env.UV_TOOL_DIR || path.join(getDataRootDir(), 'uv', 'tools')); - ensureDirExists(path.join(dir, 'bin')); - return dir; -}; - -const getServerInstallDir = (serverName: string, kind: 'npm' | 'python'): string => { - const baseDir = kind === 'npm' ? getNpmBaseDir() : getPythonBaseDir(); - return ensureDirExists(path.join(baseDir, serverName)); -}; - -const prependToPath = (currentPath: string, dir: string): string => { - if (!dir) { - return currentPath; - } - const delimiter = path.delimiter; - const segments = currentPath ? currentPath.split(delimiter) : []; - if (segments.includes(dir)) { - return currentPath; - } - return currentPath ? `${dir}${delimiter}${currentPath}` : dir; -}; - -const NODE_COMMANDS = new Set(['npm', 'npx', 'pnpm', 'yarn', 'node', 'bun', 'bunx']); -const PYTHON_COMMANDS = new Set(['uv', 'uvx', 'python', 'pip', 'pip3', 'pipx']); - // Helper function to set up keep-alive ping for SSE connections const setupKeepAlive = (serverInfo: ServerInfo, serverConfig: ServerConfig): void => { // Only set up keep-alive for SSE connections @@ -286,7 +213,7 @@ export const createTransportFromConfig = async (name: string, conf: ServerConfig ...(process.env as Record), ...replaceEnvVars(conf.env || {}), }; - env['PATH'] = expandEnvVars(env['PATH'] || process.env.PATH || ''); + env['PATH'] = expandEnvVars(process.env.PATH as string) || ''; const settings = loadSettings(); // Add UV_DEFAULT_INDEX and npm_config_registry if needed @@ -308,52 +235,9 @@ export const createTransportFromConfig = async (name: string, conf: ServerConfig env['npm_config_registry'] = settings.systemConfig.install.npmRegistry; } - // Ensure stdio servers use persistent directories under /app/data (or configured override) - let workingDirectory = os.homedir(); - const commandLower = conf.command.toLowerCase(); - - if (NODE_COMMANDS.has(commandLower)) { - const serverDir = getServerInstallDir(name, 'npm'); - workingDirectory = serverDir; - - const npmCacheDir = getNpmCacheDir(); - const npmPrefixDir = getNpmPrefixDir(); - - if (!env['npm_config_cache']) { - env['npm_config_cache'] = npmCacheDir; - } - if (!env['NPM_CONFIG_CACHE']) { - env['NPM_CONFIG_CACHE'] = env['npm_config_cache']; - } - - if (!env['npm_config_prefix']) { - env['npm_config_prefix'] = npmPrefixDir; - } - if (!env['NPM_CONFIG_PREFIX']) { - env['NPM_CONFIG_PREFIX'] = env['npm_config_prefix']; - } - - env['PATH'] = prependToPath(env['PATH'], path.join(env['npm_config_prefix'], 'bin')); - } else if (PYTHON_COMMANDS.has(commandLower)) { - const serverDir = getServerInstallDir(name, 'python'); - workingDirectory = serverDir; - - const uvCacheDir = getUvCacheDir(); - const uvToolDir = getUvToolDir(); - - if (!env['UV_CACHE_DIR']) { - env['UV_CACHE_DIR'] = uvCacheDir; - } - if (!env['UV_TOOL_DIR']) { - env['UV_TOOL_DIR'] = uvToolDir; - } - - env['PATH'] = prependToPath(env['PATH'], path.join(env['UV_TOOL_DIR'], 'bin')); - } - // Expand environment variables in command transport = new StdioClientTransport({ - cwd: workingDirectory, + cwd: os.homedir(), command: conf.command, args: replaceEnvVars(conf.args) as string[], env: env,