mcp: accept foreign absolute cwd for remote stdio (#29493)

## Why

Remote stdio MCP servers can run in an environment whose path convention
differs from the Codex host. A Windows cwd such as
`C:\Users\openai\share` is absolute for the executor but was rejected by
a POSIX orchestrator.

Built on #29501, now merged, which only clarifies the host-native
`PathUri` constructor name.

## What changed

- Deserialize MCP cwd values as `LegacyAppPathString` so config does not
apply host path rules.
- Interpret that spelling as host-native for local launches and convert
it to `PathUri` at executor launch.
- Skip host filesystem and command resolution checks for remote stdio in
`codex doctor`.
- Add host-independent config and executor-boundary coverage using the
foreign path convention for each test platform.

## Validation

- `just test -p codex-utils-path-uri -p codex-config -p codex-mcp -p
codex-rmcp-client` (408 passed)
- `just test -p codex-cli -p codex-rmcp-client` (372 passed)
- `cargo check --workspace --tests`
- `just test` (11,311 passed; 43 unrelated environment/timing failures)
- `just fix -p codex-cli -p codex-config -p codex-core -p codex-mcp -p
codex-mcp-extension -p codex-rmcp-client -p codex-tui`
This commit is contained in:
Adam Perry @ OpenAI
2026-06-22 18:33:51 -07:00
committed by GitHub
Unverified
parent 3310fc8ae5
commit 67009bc53f
20 changed files with 250 additions and 162 deletions
+11 -5
View File
@@ -7,6 +7,7 @@ use serde::Deserialize;
use serde::Serialize;
use serde::Serializer;
use std::fmt;
use std::path::Path;
use thiserror::Error;
use ts_rs::TS;
@@ -18,10 +19,10 @@ use ts_rs::TS;
///
/// When converting from [`PathUri`], "native" refers to the supplied
/// [`PathConvention`], which may be foreign to the operating system running
/// this process. The inner string is private so path-producing code must convert
/// from [`AbsolutePathBuf`] or use [`Self::from_path_uri`] instead of bypassing
/// the intended conversion boundary. Non-UTF-8 paths are converted to UTF-8
/// lossily because this API value is serialized as a JSON string.
/// this process. The inner string is private so path-producing code must use a
/// path conversion method instead of bypassing the intended conversion
/// boundary. Non-UTF-8 paths are converted to UTF-8 lossily because this API
/// value is serialized as a JSON string.
///
/// Deserialization accepts any UTF-8 string without interpreting or validating
/// it. That unrestricted construction path is intentionally available only to
@@ -35,9 +36,14 @@ use ts_rs::TS;
pub struct LegacyAppPathString(String);
impl LegacyAppPathString {
/// Preserves path text without interpreting it using the current host.
pub fn from_path(path: &Path) -> Self {
Self(path.to_string_lossy().into_owned())
}
/// Renders an absolute path using the current host's path convention.
pub fn from_abs_path(path: &AbsolutePathBuf) -> Self {
Self(path.to_string_lossy().into_owned())
Self::from_path(path.as_path())
}
/// Renders a path URI using the requested native path convention.