Skip the stdio child-process transport on watchOS
watchOS hides execv the same way tvOS does, so nix under process-wrap doesn't compile there. Gate the rmcp child-process feature, the TokioChildProcess import and the Transport::Stdio arm on any(tvos, watchos). Http stays available on both. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Seto Elkahfi committed
Oct 16, 2026 at 09:17 UTC
db0039c6dd97a5c4332cbd32d5652c8e9479a50f
2 files changed
+14
-14
crates/ed-mcp/Cargo.toml
+4
-4
@@ -24,10 +24,10 @@ serde_json.workspace = true
24
anyhow.workspace = true
25
tracing.workspace = true
26
27
-# Spawning an MCP server as a child process needs `exec`, which Apple hides on tvOS (`libc`
28
-# has no `execv` there, so `nix` under `process-wrap` doesn't compile). The stdio transport
29
-# is everywhere else.
30
-[target.'cfg(not(target_os = "tvos"))'.dependencies]
27
+# Spawning an MCP server as a child process needs `exec`, which Apple hides on tvOS and
28
+# watchOS (`libc` has no `execv` there, so `nix` under `process-wrap` doesn't compile). The
29
+# stdio transport is everywhere else.
30
+[target.'cfg(not(any(target_os = "tvos", target_os = "watchos")))'.dependencies]
31
rmcp = { workspace = true, features = ["transport-child-process"] }
32
33
[features]
crates/ed-mcp/src/lib.rs
+10
-10
@@ -35,7 +35,7 @@ use rmcp::model::{
35
};
36
use rmcp::service::{NotificationContext, PeerRequestOptions, RequestContext, RunningService};
37
use rmcp::transport::StreamableHttpClientTransport;
38
-#[cfg(not(target_os = "tvos"))]
38
+#[cfg(not(any(target_os = "tvos", target_os = "watchos")))]
39
use rmcp::transport::TokioChildProcess;
40
use rmcp::transport::streamable_http_client::StreamableHttpClientTransportConfig;
41
use rmcp::{ClientHandler, ErrorData as McpError, RoleClient, ServiceExt};
@@ -144,12 +144,12 @@ pub enum Transport {
144
/// Start `command args…` with extra environment variables and talk over its stdio.
145
///
146
/// Stdio is only available on platforms that can spawn a child process.
147
- /// On `target_os = "tvos"` the OS does not allow apps to create other
148
- /// processes, so this variant is **not** supported on tvOS builds: the
149
- /// matching arm in [`Connection::connect_with`] returns an error at
150
- /// runtime instead of compiling out the variant. Use [`Transport::Http`]
151
- /// for tvOS; if you only know the transport at runtime, branch on the
152
- /// current `target_os` before constructing a `Stdio` spec.
147
+ /// On `target_os = "tvos"` and `target_os = "watchos"` the OS does not allow
148
+ /// apps to create other processes, so this variant is **not** supported on
149
+ /// tvOS or watchOS builds: the matching arm in [`Connection::connect_with`]
150
+ /// returns an error at runtime instead of compiling out the variant. Use
151
+ /// [`Transport::Http`] there; if you only know the transport at runtime,
152
+ /// branch on the current `target_os` before constructing a `Stdio` spec.
153
Stdio {
154
command: PathBuf,
155
args: Vec<String>,
@@ -360,7 +360,7 @@ impl Connection {
360
elicitation,
361
};
362
let handshake = match &spec.transport {
363
- #[cfg(not(target_os = "tvos"))]
363
+ #[cfg(not(any(target_os = "tvos", target_os = "watchos")))]
364
Transport::Stdio { command, args, env } => {
365
let mut cmd = tokio::process::Command::new(command);
366
cmd.args(args).envs(env.iter().map(|(k, v)| (k, v)));
@@ -368,8 +368,8 @@ impl Connection {
368
.with_context(|| format!("starting {}", command.display()))?;
369
tokio::time::timeout(timeout, handler.serve(transport)).await
370
}
371
- // tvOS can't start a process, so there is no stdio transport to offer.
372
- #[cfg(target_os = "tvos")]
371
+ // tvOS and watchOS can't start a process, so there is no stdio transport to offer.
372
+ #[cfg(any(target_os = "tvos", target_os = "watchos"))]
373
Transport::Stdio { command, .. } => {
374
bail!(
375
"can't start {}: this platform can't run MCP servers as processes",