diff --git a/docs/configuration/mcp-settings.mdx b/docs/configuration/mcp-settings.mdx
index 49cc9c6..7426a0e 100644
--- a/docs/configuration/mcp-settings.mdx
+++ b/docs/configuration/mcp-settings.mdx
@@ -259,6 +259,92 @@ MCPHub supports environment variable substitution using `${VAR_NAME}` syntax:
}
```
+### Proxy Configuration (proxychains4)
+
+MCPHub supports routing STDIO server network traffic through a proxy using **proxychains4**. This feature is available on **Linux and macOS only** (Windows is not supported).
+
+
+To use this feature, you must have `proxychains4` installed on your system:
+- **Debian/Ubuntu**: `apt install proxychains4`
+- **macOS**: `brew install proxychains-ng`
+- **Arch Linux**: `pacman -S proxychains-ng`
+
+
+#### Basic Proxy Configuration
+
+```json
+{
+ "mcpServers": {
+ "fetch-via-proxy": {
+ "command": "uvx",
+ "args": ["mcp-server-fetch"],
+ "proxy": {
+ "enabled": true,
+ "type": "socks5",
+ "host": "127.0.0.1",
+ "port": 1080
+ }
+ }
+ }
+}
+```
+
+#### Proxy Configuration Options
+
+| Field | Type | Default | Description |
+| ------------ | ------- | --------- | ------------------------------------------------ |
+| `enabled` | boolean | `false` | Enable/disable proxy routing |
+| `type` | string | `socks5` | Proxy protocol: `socks4`, `socks5`, or `http` |
+| `host` | string | - | Proxy server hostname or IP address |
+| `port` | number | - | Proxy server port |
+| `username` | string | - | Proxy authentication username (optional) |
+| `password` | string | - | Proxy authentication password (optional) |
+| `configPath` | string | - | Path to custom proxychains4 config file |
+
+#### Proxy with Authentication
+
+```json
+{
+ "mcpServers": {
+ "secure-server": {
+ "command": "npx",
+ "args": ["-y", "@example/mcp-server"],
+ "proxy": {
+ "enabled": true,
+ "type": "http",
+ "host": "proxy.example.com",
+ "port": 8080,
+ "username": "${PROXY_USER}",
+ "password": "${PROXY_PASSWORD}"
+ }
+ }
+ }
+}
+```
+
+#### Using Custom proxychains4 Configuration
+
+For advanced use cases, you can provide your own proxychains4 configuration file:
+
+```json
+{
+ "mcpServers": {
+ "custom-proxy-server": {
+ "command": "python",
+ "args": ["-m", "custom_mcp_server"],
+ "proxy": {
+ "enabled": true,
+ "configPath": "/etc/proxychains4/custom.conf"
+ }
+ }
+ }
+}
+```
+
+
+When `configPath` is specified, all other proxy settings (`type`, `host`, `port`, etc.) are ignored, and the custom configuration file is used directly.
+
+
{/* ### Custom Server Scripts
#### Local Python Server
diff --git a/examples/mcp_settings_with_env_vars.json b/examples/mcp_settings_with_env_vars.json
index 6a5701c..c36d4c6 100644
--- a/examples/mcp_settings_with_env_vars.json
+++ b/examples/mcp_settings_with_env_vars.json
@@ -31,6 +31,47 @@
"DATABASE_URL": "${DATABASE_URL}"
}
},
+ "example-stdio-with-proxy": {
+ "type": "stdio",
+ "command": "uvx",
+ "args": [
+ "mcp-server-fetch"
+ ],
+ "proxy": {
+ "enabled": true,
+ "type": "socks5",
+ "host": "${PROXY_HOST}",
+ "port": 1080
+ }
+ },
+ "example-stdio-with-auth-proxy": {
+ "type": "stdio",
+ "command": "npx",
+ "args": [
+ "-y",
+ "@example/mcp-server"
+ ],
+ "proxy": {
+ "enabled": true,
+ "type": "http",
+ "host": "${HTTP_PROXY_HOST}",
+ "port": 8080,
+ "username": "${PROXY_USERNAME}",
+ "password": "${PROXY_PASSWORD}"
+ }
+ },
+ "example-stdio-with-custom-proxy-config": {
+ "type": "stdio",
+ "command": "python",
+ "args": [
+ "-m",
+ "custom_mcp_server"
+ ],
+ "proxy": {
+ "enabled": true,
+ "configPath": "/etc/proxychains4/custom.conf"
+ }
+ },
"example-openapi-server": {
"type": "openapi",
"openapi": {
diff --git a/frontend/src/types/index.ts b/frontend/src/types/index.ts
index cfef4c8..ea68a7e 100644
--- a/frontend/src/types/index.ts
+++ b/frontend/src/types/index.ts
@@ -105,6 +105,17 @@ export interface Prompt {
enabled?: boolean;
}
+// Proxychains4 configuration for STDIO servers (Linux/macOS only)
+export interface ProxychainsConfig {
+ enabled?: boolean; // Enable/disable proxychains4 proxy routing
+ type?: 'socks4' | 'socks5' | 'http'; // Proxy protocol type
+ host?: string; // Proxy server hostname or IP address
+ port?: number; // Proxy server port
+ username?: string; // Proxy authentication username (optional)
+ password?: string; // Proxy authentication password (optional)
+ configPath?: string; // Path to custom proxychains4 configuration file (optional)
+}
+
// Server config types
export interface ServerConfig {
type?: 'stdio' | 'sse' | 'streamable-http' | 'openapi';
@@ -123,6 +134,8 @@ export interface ServerConfig {
resetTimeoutOnProgress?: boolean; // Reset timeout on progress notifications
maxTotalTimeout?: number; // Maximum total timeout in milliseconds
}; // MCP request options configuration
+ // Proxychains4 proxy configuration for STDIO servers (Linux/macOS only, Windows not supported)
+ proxy?: ProxychainsConfig;
// OAuth authentication for upstream MCP servers
oauth?: {
clientId?: string; // OAuth client ID
diff --git a/src/dao/ServerDaoDbImpl.ts b/src/dao/ServerDaoDbImpl.ts
index 12ce3d8..d24c9a2 100644
--- a/src/dao/ServerDaoDbImpl.ts
+++ b/src/dao/ServerDaoDbImpl.ts
@@ -38,6 +38,7 @@ export class ServerDaoDbImpl implements ServerDao {
prompts: entity.prompts,
options: entity.options,
oauth: entity.oauth,
+ proxy: entity.proxy,
openapi: entity.openapi,
});
return this.mapToServerConfig(server);
@@ -62,6 +63,7 @@ export class ServerDaoDbImpl implements ServerDao {
prompts: entity.prompts,
options: entity.options,
oauth: entity.oauth,
+ proxy: entity.proxy,
openapi: entity.openapi,
});
return server ? this.mapToServerConfig(server) : null;
@@ -140,6 +142,7 @@ export class ServerDaoDbImpl implements ServerDao {
prompts?: Record;
options?: Record;
oauth?: Record;
+ proxy?: Record;
openapi?: Record;
}): ServerConfigWithName {
return {
@@ -158,6 +161,7 @@ export class ServerDaoDbImpl implements ServerDao {
prompts: server.prompts,
options: server.options,
oauth: server.oauth,
+ proxy: server.proxy,
openapi: server.openapi,
};
}
diff --git a/src/db/entities/Server.ts b/src/db/entities/Server.ts
index bfdbb0c..2022c0d 100644
--- a/src/db/entities/Server.ts
+++ b/src/db/entities/Server.ts
@@ -59,6 +59,9 @@ export class Server {
@Column({ type: 'simple-json', nullable: true })
oauth?: Record;
+ @Column({ type: 'simple-json', nullable: true })
+ proxy?: Record;
+
@Column({ type: 'simple-json', nullable: true })
openapi?: Record;
diff --git a/src/services/mcpService.ts b/src/services/mcpService.ts
index 967193f..bd0a261 100644
--- a/src/services/mcpService.ts
+++ b/src/services/mcpService.ts
@@ -1,4 +1,6 @@
import os from 'os';
+import path from 'path';
+import fs from 'fs';
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import {
CallToolRequestSchema,
@@ -15,7 +17,7 @@ import {
StreamableHTTPClientTransportOptions,
} from '@modelcontextprotocol/sdk/client/streamableHttp.js';
import { createFetchWithProxy, getProxyConfigFromEnv } from './proxy.js';
-import { ServerInfo, ServerConfig, Tool } from '../types/index.js';
+import { ServerInfo, ServerConfig, Tool, ProxychainsConfig } from '../types/index.js';
import { expandEnvVars, replaceEnvVars, getNameSeparator } from '../config/index.js';
import config from '../config/index.js';
import { getGroup } from './sseService.js';
@@ -32,6 +34,150 @@ const servers: { [sessionId: string]: Server } = {};
import { setupClientKeepAlive } from './keepAliveService.js';
+/**
+ * Check if proxychains4 is available on the system (Linux/macOS only).
+ * Returns the path to proxychains4 if found, null otherwise.
+ */
+const findProxychains4 = (): string | null => {
+ // Windows is not supported
+ if (process.platform === 'win32') {
+ return null;
+ }
+
+ // Common proxychains4 binary paths
+ const possiblePaths = [
+ '/usr/bin/proxychains4',
+ '/usr/local/bin/proxychains4',
+ '/opt/homebrew/bin/proxychains4', // macOS Homebrew ARM
+ '/usr/local/Cellar/proxychains-ng/*/bin/proxychains4', // macOS Homebrew Intel
+ ];
+
+ for (const p of possiblePaths) {
+ if (fs.existsSync(p)) {
+ return p;
+ }
+ }
+
+ // Try to find in PATH
+ const pathEnv = process.env.PATH || '';
+ const pathDirs = pathEnv.split(path.delimiter);
+ for (const dir of pathDirs) {
+ const fullPath = path.join(dir, 'proxychains4');
+ if (fs.existsSync(fullPath)) {
+ return fullPath;
+ }
+ }
+
+ return null;
+};
+
+/**
+ * Generate a temporary proxychains4 configuration file.
+ * Returns the path to the generated config file.
+ */
+const generateProxychainsConfig = (
+ serverName: string,
+ proxyConfig: ProxychainsConfig,
+): string | null => {
+ // If a custom config path is provided, use it directly
+ if (proxyConfig.configPath) {
+ if (fs.existsSync(proxyConfig.configPath)) {
+ return proxyConfig.configPath;
+ }
+ console.warn(
+ `[${serverName}] Custom proxychains config not found: ${proxyConfig.configPath}`,
+ );
+ return null;
+ }
+
+ // Validate required fields
+ if (!proxyConfig.host || !proxyConfig.port) {
+ console.warn(`[${serverName}] Proxy host and port are required for proxychains4`);
+ return null;
+ }
+
+ const proxyType = proxyConfig.type || 'socks5';
+ const proxyLine = proxyConfig.username && proxyConfig.password
+ ? `${proxyType} ${proxyConfig.host} ${proxyConfig.port} ${proxyConfig.username} ${proxyConfig.password}`
+ : `${proxyType} ${proxyConfig.host} ${proxyConfig.port}`;
+
+ const configContent = `# Proxychains4 configuration for MCP server: ${serverName}
+# Generated by MCPHub
+
+strict_chain
+proxy_dns
+remote_dns_subnet 224
+tcp_read_time_out 15000
+tcp_connect_time_out 8000
+
+[ProxyList]
+${proxyLine}
+`;
+
+ // Create temp directory if needed
+ const tempDir = path.join(os.tmpdir(), 'mcphub-proxychains');
+ if (!fs.existsSync(tempDir)) {
+ fs.mkdirSync(tempDir, { recursive: true });
+ }
+
+ // Write config file
+ const configPath = path.join(tempDir, `${serverName.replace(/[^a-zA-Z0-9-_]/g, '_')}.conf`);
+ fs.writeFileSync(configPath, configContent, 'utf-8');
+ console.log(`[${serverName}] Generated proxychains4 config: ${configPath}`);
+
+ return configPath;
+};
+
+/**
+ * Wrap a command with proxychains4 if proxy is configured and available.
+ * Returns modified command and args if proxychains4 is used, original values otherwise.
+ */
+const wrapWithProxychains = (
+ serverName: string,
+ command: string,
+ args: string[],
+ proxyConfig?: ProxychainsConfig,
+): { command: string; args: string[] } => {
+ // Skip if proxy is not enabled or not configured
+ if (!proxyConfig?.enabled) {
+ return { command, args };
+ }
+
+ // Check platform - Windows is not supported
+ if (process.platform === 'win32') {
+ console.warn(
+ `[${serverName}] proxychains4 proxy is not supported on Windows, ignoring proxy configuration`,
+ );
+ return { command, args };
+ }
+
+ // Find proxychains4 binary
+ const proxychains4Path = findProxychains4();
+ if (!proxychains4Path) {
+ console.warn(
+ `[${serverName}] proxychains4 not found on system, install it with: apt install proxychains4 (Debian/Ubuntu) or brew install proxychains-ng (macOS)`,
+ );
+ return { command, args };
+ }
+
+ // Generate or get config file
+ const configPath = generateProxychainsConfig(serverName, proxyConfig);
+ if (!configPath) {
+ console.warn(`[${serverName}] Failed to setup proxychains4 configuration, skipping proxy`);
+ return { command, args };
+ }
+
+ // Wrap command with proxychains4
+ console.log(
+ `[${serverName}] Using proxychains4 proxy: ${proxyConfig.type || 'socks5'}://${proxyConfig.host}:${proxyConfig.port}`,
+ );
+
+ return {
+ command: proxychains4Path,
+ args: ['-f', configPath, command, ...args],
+ };
+};
+
export const initUpstreamServers = async (): Promise => {
// Initialize OAuth clients for servers with dynamic registration
await initializeAllOAuthClients();
@@ -209,11 +355,19 @@ export const createTransportFromConfig = async (name: string, conf: ServerConfig
env['npm_config_registry'] = systemConfig.install.npmRegistry;
}
- // Expand environment variables in command
+ // Apply proxychains4 wrapper if proxy is configured (Linux/macOS only)
+ const { command: finalCommand, args: finalArgs } = wrapWithProxychains(
+ name,
+ conf.command,
+ replaceEnvVars(conf.args) as string[],
+ conf.proxy,
+ );
+
+ // Create STDIO transport with potentially wrapped command
transport = new StdioClientTransport({
cwd: os.homedir(),
- command: conf.command,
- args: replaceEnvVars(conf.args) as string[],
+ command: finalCommand,
+ args: finalArgs,
env: env,
stderr: 'pipe',
});
diff --git a/src/types/index.ts b/src/types/index.ts
index e5e8186..e64a7af 100644
--- a/src/types/index.ts
+++ b/src/types/index.ts
@@ -270,6 +270,17 @@ export interface McpSettings {
bearerKeys?: BearerKey[]; // Bearer authentication keys (multi-key configuration)
}
+// Proxychains4 configuration for STDIO servers (Linux/macOS only)
+export interface ProxychainsConfig {
+ enabled?: boolean; // Enable/disable proxychains4 proxy routing
+ type?: 'socks4' | 'socks5' | 'http'; // Proxy protocol type
+ host?: string; // Proxy server hostname or IP address
+ port?: number; // Proxy server port
+ username?: string; // Proxy authentication username (optional)
+ password?: string; // Proxy authentication password (optional)
+ configPath?: string; // Path to custom proxychains4 configuration file (optional, overrides above settings)
+}
+
// Configuration details for an individual server
export interface ServerConfig {
type?: 'stdio' | 'sse' | 'streamable-http' | 'openapi'; // Type of server
@@ -285,6 +296,8 @@ export interface ServerConfig {
tools?: Record; // Tool-specific configurations with enable/disable state and custom descriptions
prompts?: Record; // Prompt-specific configurations with enable/disable state and custom descriptions
options?: Partial>; // MCP request options configuration
+ // Proxychains4 proxy configuration for STDIO servers (Linux/macOS only, Windows not supported)
+ proxy?: ProxychainsConfig;
// OAuth authentication for upstream MCP servers
oauth?: {
// Static client configuration (traditional OAuth flow)