mcp_stdio_proxy/client/support/
args.rs1use clap::Parser;
6use std::collections::HashMap;
7use std::path::PathBuf;
8
9#[derive(Parser, Debug, Clone)]
13pub struct LoggingArgs {
14 #[arg(long, default_value = "false", help = "启用详细诊断模式,追踪连接生命周期和超时问题(默认启用)")]
16 pub diagnostic: bool,
17
18 #[arg(long, help = "日志输出目录,将自动生成日志文件名")]
20 pub log_dir: Option<PathBuf>,
21
22 #[arg(long, conflicts_with = "log_dir", help = "日志文件完整路径")]
24 pub log_file: Option<PathBuf>,
25
26 #[arg(
31 long,
32 env = "OTEL_EXPORTER_OTLP_ENDPOINT",
33 help = "OTLP 追踪端点 (如 http://localhost:4317)"
34 )]
35 pub otlp_endpoint: Option<String>,
36
37 #[arg(
39 long,
40 default_value = "mcp-proxy",
41 help = "追踪服务名称(用于 Jaeger 等追踪后端标识)"
42 )]
43 pub service_name: String,
44}
45
46
47#[derive(Parser, Debug)]
49#[command(name = "mcp-proxy")]
50#[command(version = env!("CARGO_PKG_VERSION"))]
51#[command(about = "MCP 协议转换代理工具", long_about = None)]
52pub struct Cli {
53 #[command(subcommand)]
54 pub command: Option<Commands>,
55
56 #[arg(value_name = "URL", help = "MCP 服务的 URL 地址(直接模式)")]
58 pub url: Option<String>,
59
60 #[arg(short, long, global = true)]
62 pub verbose: bool,
63
64 #[arg(short, long, global = true)]
66 pub quiet: bool,
67}
68
69#[derive(clap::Subcommand, Debug)]
70pub enum Commands {
71 Convert(ConvertArgs),
73
74 Check(CheckArgs),
76
77 Detect(DetectArgs),
79
80 Proxy(crate::client::proxy_server::ProxyArgs),
82}
83
84#[derive(Parser, Debug, Clone)]
86pub struct ConvertArgs {
87 #[arg(value_name = "URL", help = "MCP 服务的 URL 地址")]
89 pub url: Option<String>,
90
91 #[arg(long, conflicts_with = "config_file", help = "MCP 服务配置 JSON")]
93 pub config: Option<String>,
94
95 #[arg(long, conflicts_with = "config", help = "MCP 服务配置文件路径")]
97 pub config_file: Option<PathBuf>,
98
99 #[arg(short, long, help = "MCP 服务名称(多服务配置时必需)")]
101 pub name: Option<String>,
102
103 #[arg(long, value_enum, help = "指定远程服务协议类型(不指定则自动检测)")]
105 pub protocol: Option<crate::client::proxy_server::ProxyProtocol>,
106
107 #[arg(short, long, help = "认证 header")]
109 pub auth: Option<String>,
110
111 #[arg(short = 'H', long, value_parser = parse_key_val, help = "自定义 HTTP headers (KEY=VALUE 格式)")]
113 pub header: Vec<(String, String)>,
114
115 #[arg(long, default_value = "0", help = "重试次数,0 表示无限重试")]
117 pub retries: u32,
118
119 #[arg(long, value_delimiter = ',', help = "工具白名单(逗号分隔),只允许指定的工具")]
121 pub allow_tools: Option<Vec<String>>,
122
123 #[arg(long, value_delimiter = ',', help = "工具黑名单(逗号分隔),排除指定的工具")]
125 pub deny_tools: Option<Vec<String>>,
126
127 #[arg(long, default_value = "30", help = "客户端 ping 间隔(秒),0 表示禁用")]
129 pub ping_interval: u64,
130
131 #[arg(long, default_value = "10", help = "客户端 ping 超时(秒),超时则认为连接断开")]
133 pub ping_timeout: u64,
134
135 #[command(flatten)]
137 pub logging: LoggingArgs,
138}
139
140#[derive(Parser, Debug)]
142pub struct CheckArgs {
143 #[arg(value_name = "URL")]
145 pub url: String,
146
147 #[arg(short, long)]
149 pub auth: Option<String>,
150
151 #[arg(long, default_value = "10")]
153 pub timeout: u64,
154}
155
156#[derive(Parser, Debug)]
158pub struct DetectArgs {
159 #[arg(value_name = "URL")]
161 pub url: String,
162
163 #[arg(short, long)]
165 pub auth: Option<String>,
166}
167
168pub fn parse_key_val(s: &str) -> Result<(String, String), String> {
170 let pos = s.find('=')
171 .ok_or_else(|| format!("无效的 KEY=VALUE 格式: {}", s))?;
172 Ok((s[..pos].to_string(), s[pos + 1..].to_string()))
173}