codex_wrapper/command/
mcp_server.rs1use crate::Codex;
5use crate::command::CodexCommand;
6use crate::error::Result;
7use crate::exec::{self, CommandOutput};
8
9#[derive(Debug, Clone, Default)]
11pub struct McpServerCommand {
12 config_overrides: Vec<String>,
13 enabled_features: Vec<String>,
14 disabled_features: Vec<String>,
15}
16
17impl McpServerCommand {
18 #[must_use]
19 pub fn new() -> Self {
20 Self::default()
21 }
22
23 #[must_use]
24 pub fn config(mut self, key_value: impl Into<String>) -> Self {
25 self.config_overrides.push(key_value.into());
26 self
27 }
28
29 #[must_use]
30 pub fn enable(mut self, feature: impl Into<String>) -> Self {
31 self.enabled_features.push(feature.into());
32 self
33 }
34
35 #[must_use]
36 pub fn disable(mut self, feature: impl Into<String>) -> Self {
37 self.disabled_features.push(feature.into());
38 self
39 }
40}
41
42impl CodexCommand for McpServerCommand {
43 type Output = CommandOutput;
44
45 fn args(&self) -> Vec<String> {
46 let mut args = vec!["mcp-server".into()];
47 for v in &self.config_overrides {
48 args.push("-c".into());
49 args.push(v.clone());
50 }
51 for v in &self.enabled_features {
52 args.push("--enable".into());
53 args.push(v.clone());
54 }
55 for v in &self.disabled_features {
56 args.push("--disable".into());
57 args.push(v.clone());
58 }
59 args
60 }
61
62 async fn execute(&self, codex: &Codex) -> Result<CommandOutput> {
63 exec::run_codex(codex, self.args()).await
64 }
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70
71 #[test]
72 fn mcp_server_args() {
73 assert_eq!(McpServerCommand::new().args(), vec!["mcp-server"]);
74 }
75
76 #[test]
77 fn mcp_server_with_config_args() {
78 let args = McpServerCommand::new()
79 .config("model=\"gpt-5\"")
80 .enable("web-search")
81 .args();
82 assert_eq!(
83 args,
84 vec![
85 "mcp-server",
86 "-c",
87 "model=\"gpt-5\"",
88 "--enable",
89 "web-search"
90 ]
91 );
92 }
93}