From d5f8f65df04de36ef53a7ef92f8f14ffd5e11a51 Mon Sep 17 00:00:00 2001 From: Michael Bolin Date: Fri, 21 Nov 2025 13:43:56 -0800 Subject: [PATCH] feat: support login as an option on shell-tool-mcp --- .../exec-server/src/posix/escalate_server.rs | 19 ++++++++++++++----- codex-rs/exec-server/src/posix/mcp.rs | 10 +++------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/codex-rs/exec-server/src/posix/escalate_server.rs b/codex-rs/exec-server/src/posix/escalate_server.rs index 784562f2ff..d25409c839 100644 --- a/codex-rs/exec-server/src/posix/escalate_server.rs +++ b/codex-rs/exec-server/src/posix/escalate_server.rs @@ -23,6 +23,7 @@ use crate::posix::escalate_protocol::EscalateResponse; use crate::posix::escalate_protocol::SuperExecMessage; use crate::posix::escalate_protocol::SuperExecResult; use crate::posix::escalation_policy::EscalationPolicy; +use crate::posix::mcp::ExecParams; use crate::posix::socket::AsyncDatagramSocket; use crate::posix::socket::AsyncSocket; use codex_core::exec::ExecExpiration; @@ -47,9 +48,7 @@ impl EscalateServer { pub async fn exec( &self, - command: String, - env: HashMap, - workdir: PathBuf, + params: ExecParams, cancel_rx: CancellationToken, ) -> anyhow::Result { let (escalate_server, escalate_client) = AsyncDatagramSocket::pair()?; @@ -57,7 +56,7 @@ impl EscalateServer { client_socket.set_cloexec(false)?; let escalate_task = tokio::spawn(escalate_task(escalate_server, self.policy.clone())); - let mut env = env.clone(); + let mut env = std::env::vars().collect::>(); env.insert( ESCALATE_SOCKET_ENV_VAR.to_string(), client_socket.as_raw_fd().to_string(), @@ -73,11 +72,21 @@ impl EscalateServer { let sandbox_policy = SandboxPolicy::ReadOnly; let sandbox_cwd = PathBuf::from("/__NONEXISTENT__"); + let ExecParams { + command, + workdir, + timeout_ms: _, + login, + } = params; let result = process_exec_tool_call( codex_core::exec::ExecParams { command: vec![ self.bash_path.to_string_lossy().to_string(), - "-c".to_string(), + if login == Some(false) { + "-c".to_string() + } else { + "-lc".to_string() + }, command, ], cwd: PathBuf::from(&workdir), diff --git a/codex-rs/exec-server/src/posix/mcp.rs b/codex-rs/exec-server/src/posix/mcp.rs index b2f9b6de48..92368a32c2 100644 --- a/codex-rs/exec-server/src/posix/mcp.rs +++ b/codex-rs/exec-server/src/posix/mcp.rs @@ -41,6 +41,8 @@ pub struct ExecParams { pub workdir: String, /// The timeout for the command in milliseconds. pub timeout_ms: Option, + /// Launch Bash with -lc instead of -c: defaults to true. + pub login: Option, } #[derive(Debug, serde::Serialize, schemars::JsonSchema)] @@ -101,13 +103,7 @@ impl ExecTool { McpEscalationPolicy::new(self.policy, context, stopwatch.clone()), ); let result = escalate_server - .exec( - params.command, - // TODO: use ShellEnvironmentPolicy - std::env::vars().collect(), - PathBuf::from(¶ms.workdir), - cancel_token, - ) + .exec(params, cancel_token) .await .map_err(|e| McpError::internal_error(e.to_string(), None))?; Ok(CallToolResult::success(vec![Content::json(