Skip to main content

mcp_stdio_proxy/
config.rs

1use anyhow::Result;
2use serde::Deserialize;
3use std::env;
4use std::fs::File;
5use std::path::Path;
6
7/// The default config file
8const DEFAULT_CONFIG_YAML: &str = include_str!("../config.yml");
9
10/// config.yml 中 mirror 段的结构
11#[derive(Debug, Deserialize, Clone, Default)]
12pub struct MirrorYamlConfig {
13    #[serde(default)]
14    pub npm_registry: String,
15    #[serde(default)]
16    pub pypi_index_url: String,
17}
18
19#[derive(Debug, Deserialize, Clone)]
20pub struct AppConfig {
21    pub server: ServerConfig,
22    pub log: LogConfig,
23    #[serde(default)]
24    pub mirror: MirrorYamlConfig,
25}
26#[derive(Debug, Deserialize, Clone)]
27pub struct ServerConfig {
28    /// The port to listen on for incoming connections
29    pub port: u16,
30}
31#[derive(Debug, Deserialize, Clone)]
32pub struct LogConfig {
33    /// The log level to use
34    pub level: String,
35    /// The path to the log file
36    pub path: String,
37    /// The number of log files to retain (default: 20)
38    #[serde(default = "default_retain_days")]
39    pub retain_days: u32,
40}
41
42/// Default log files to retain
43fn default_retain_days() -> u32 {
44    5
45}
46
47impl AppConfig {
48    /// Load the config file from the following sources:
49    /// 1. /app/config.yml
50    /// 2. config.yml
51    /// 3. BOT_SERVER_CONFIG environment variable
52    ///
53    /// Environment variables can override config values:
54    /// - MCP_PROXY_PORT: Override server port
55    /// - MCP_PROXY_LOG_DIR: Override log directory path
56    /// - MCP_PROXY_LOG_LEVEL: Override log level
57    pub fn load_config() -> Result<Self> {
58        let mut config = match (
59            File::open("/app/config.yml"),
60            File::open("config.yml"),
61            env::var("BOT_SERVER_CONFIG"),
62        ) {
63            (Ok(file), _, _) => serde_yaml::from_reader(file),
64            (_, Ok(file), _) => serde_yaml::from_reader(file),
65            (_, _, Ok(file_path)) => serde_yaml::from_reader(File::open(file_path)?),
66            _ => {
67                // 如果都没有,则使用默认配置
68                serde_yaml::from_str::<AppConfig>(DEFAULT_CONFIG_YAML)
69            }
70        }?;
71
72        // 环境变量覆盖配置(优先级最高)
73        if let Ok(port) = env::var("MCP_PROXY_PORT")
74            && let Ok(port_num) = port.parse::<u16>()
75        {
76            config.server.port = port_num;
77        }
78
79        if let Ok(log_dir) = env::var("MCP_PROXY_LOG_DIR") {
80            config.log.path = log_dir;
81        }
82
83        if let Ok(log_level) = env::var("MCP_PROXY_LOG_LEVEL") {
84            config.log.level = log_level;
85        }
86
87        Ok(config)
88    }
89
90    pub fn log_path_init(&self) -> Result<()> {
91        let log_path = &self.log.path;
92
93        // 获取日志文件的父目录
94        if let Some(parent) = Path::new(log_path).parent()
95            && !parent.exists()
96        {
97            std::fs::create_dir_all(parent)?;
98        }
99        Ok(())
100    }
101}