build-ios-apps starts multiple XcodeBuildMCP instances on unsupported Linux hosts, causing severe memory pressure

Resolved 💬 2 comments Opened Jul 15, 2026 by tnt2ray Closed Jul 15, 2026
### Component

Codex App Server / plugin runtime / MCP lifecycle

### Versions

- Codex CLI / App Server: `0.144.1`
- Codex Desktop client observed in logs: `26.707.72221`
- `build-ios-apps` plugin: `0.1.2`
- `xcodebuildmcp`: `2.6.2`
- Node.js: `24.18.0`
- npm: `11.18.0`

### Environment

- Debian GNU/Linux 13 (trixie), x86_64
- KVM virtual machine
- 1 vCPU
- 1.9 GiB RAM
- Initially 1 GiB swap
- No Xcode or iOS Simulator; neither can run on this host

### Summary

The `build-ios-apps` plugin eagerly starts XcodeBuildMCP on a Debian Linux
host, even when the user request, repository, selected skill, and actual tool
usage have no relationship to iOS, macOS, Swift, Xcode, or Simulator.

A separate XcodeBuildMCP process tree is created for multiple Codex threads and
subagents. Six concurrent instances were initially observed, consuming
approximately 1.2 GiB on a host with only 1.9 GiB RAM.

No XcodeBuildMCP tool was ever called.

The MCP processes were started while Codex initialized the MCP manager and
enumerated the available tool list, before the model selected a skill or tool.

Uninstalling the plugin reported success and briefly removed its cache, but the
running App Server subsequently recreated the plugin cache and started new
XcodeBuildMCP processes.

### Evidence that project code did not start the MCP

Every XcodeBuildMCP process was a direct descendant of Codex App Server:

```text
codex app-server
└─ npm exec xcodebuildmcp@latest mcp
   └─ sh -c xcodebuildmcp mcp
      └─ node .../xcodebuildmcp mcp

The observed process environment included:

npm_config_user_agent=npm/11.18.0 node/v24.18.0 linux x64
XCODEBUILDMCP_ENABLED_WORKFLOWS=simulator,ui-automation,debugging,logging

The project did not contain or execute an xcodebuildmcp command.

The affected threads were working on unrelated tasks, including:

  • Markdown-based examination question import
  • SQL concurrency review
  • Release/delta review
  • Linux SSH and memory-pressure investigation

Evidence that no skill or Xcode tool triggered it

I scanned all available active and archived rollout JSONL files.

Results:

Actual mcp__XcodeBuildMCP__* tool calls: 0
build-ios-apps skill reads/triggers: 0

No iOS/macOS skill was selected or read before these processes started.

Internal startup path shown by Codex logs

Codex logs show that XcodeBuildMCP was started during thread/session
initialization:

thread_spawn
→ session_init
→ session_init.mcp_manager_init
→ new{server_name=xcodebuildmcp}
→ start_server_task

During turn initialization, Codex eagerly enumerated all plugin MCP tools:

run_turn
→ build_skills_and_plugins
→ list_all_tools
→ server_name=xcodebuildmcp
→ tool_count=44

Representative trace messages:

session_init.mcp_manager_init:
new{server_name=xcodebuildmcp}:
start_server_task{server_name=xcodebuildmcp}
text
build_skills_and_plugins:list_all_tools:
listed MCP server tools while building tool list
server_name=xcodebuildmcp
tool_count=44
text
list_all_tools:
waiting for MCP server tools while building tool list
server_name=xcodebuildmcp
has_cached_tools=false
startup_complete=true

This happens before any Xcode tool invocation and independently of task
relevance.

Unbounded per-thread/subagent multiplication

Multiple unrelated root threads and subagent threads each initialized their own
MCP manager and started a separate XcodeBuildMCP process tree.

Three confirmed subagents were performing unrelated review tasks:

/root/final_delta_review
/root/sql_concurrency_review
/root/release_delta_review

Each had:

XcodeBuildMCP tool calls: 0
iOS/macOS skill triggers: 0

Despite that, their creation times aligned with new XcodeBuildMCP process
start times.

The initial observation showed six simultaneous process trees. The wrappers and
Node processes together consumed approximately 1.2 GiB.

Resource impact

Before terminating the duplicate MCP processes:

RAM:        1.9 GiB total
Available:  approximately 300 MiB
Swap used: approximately 450–700 MiB
I/O wait:  observed as high as 57%

systemd-journald repeatedly logged:

Under memory pressure, flushing caches.

The three preceding abnormal boots contained respectively:

78 memory-pressure events
5 memory-pressure events
16 memory-pressure events

The host repeatedly became unresponsive over SSH during high CPU, memory, and
swap pressure. The journal ended abruptly without a normal shutdown sequence.

After terminating six XcodeBuildMCP instances:

Available memory increased to approximately 1.4 GiB
System load dropped substantially
XcodeBuildMCP process count became 0

This strongly correlates the unnecessary MCP instances with the host-wide
resource exhaustion, although there was no explicit kernel OOM kill.

Plugin uninstall does not stop or invalidate the runtime state

I ran:

codex plugin remove build-ios-apps@openai-curated-remote --json

The command reported success:

{
  "pluginId": "build-ios-apps@openai-curated-remote",
  "name": "build-ios-apps",
  "marketplaceName": "openai-curated-remote"
}

Immediately afterward:

  • The plugin cache directory was absent.
  • Plugin references were absent from ~/.codex/config.toml.
  • Four existing XcodeBuildMCP process trees had to be terminated manually.

However, while the same App Server remained running:

  • npm recorded nine additional npm exec xcodebuildmcp@latest mcp starts.
  • The build-ios-apps/0.1.2 plugin cache directory reappeared.
  • New XcodeBuildMCP processes appeared again.
  • During preparation of this report, two XcodeBuildMCP process trees were

running again.

  • No XcodeBuildMCP tool had been called.

This suggests that the running App Server, Desktop-injected plugin state, or
another active runtime state can re-materialize a locally uninstalled plugin.
The exact ownership of that state is not visible from the client logs.

Steps to reproduce

  1. Run Codex App Server on a Linux host.
  2. Install or enable build-ios-apps@openai-curated-remote.
  3. Open a thread with a task unrelated to iOS/macOS, such as editing Markdown.
  4. Observe the process tree:

``text
npm exec xcodebuildmcp@latest mcp
``

  1. Inspect Codex logs and observe:

``text
session_init.mcp_manager_init
new{server_name=xcodebuildmcp}
start_server_task
list_all_tools
``

  1. Confirm that no mcp__XcodeBuildMCP__* tool was invoked.
  2. Spawn or resume several unrelated threads/subagents.
  3. Observe additional independent XcodeBuildMCP process trees.
  4. Run codex plugin remove build-ios-apps@openai-curated-remote.
  5. Keep the existing App Server running and continue unrelated turns.
  6. Observe the plugin cache and XcodeBuildMCP processes reappear.

Expected behavior

  1. build-ios-apps and XcodeBuildMCP should be unavailable on non-macOS hosts,

or the runtime should verify OS/Xcode compatibility before starting them.

  1. Plugin MCP servers should not start merely because Codex enumerates the

global tool list when the platform is unsupported.

  1. A plugin MCP should not create an unbounded local process tree for every

unrelated thread or subagent.

  1. MCP instances should be shared where safe, constrained, lazily started, or

reclaimed when idle.

  1. Uninstalling a plugin should:
  • invalidate it in the running App Server;
  • terminate its child MCP processes;
  • prevent its cache from being recreated;
  • prevent subsequent turns from restarting it.
  1. Unsupported MCP servers should not consume CPU, RAM, swap, or network

resources.

Actual behavior

  • XcodeBuildMCP starts on Debian Linux.
  • Startup occurs during MCP manager/tool-list initialization.
  • No related skill or tool call is required.
  • Multiple threads and subagents create multiple process trees.
  • Six instances consumed most of a 2 GiB host.
  • The host experienced severe memory pressure and SSH unresponsiveness.
  • Plugin removal did not terminate existing processes.
  • The running system recreated the plugin cache and started the MCP again.

Severity

High for low-memory local or remote Codex hosts.

An unusable, platform-specific plugin can consume most system memory without
ever being called, and parallel agent work amplifies the issue enough to make
the entire host unresponsive.

Suggested areas to investigate

  • Platform filtering for plugin manifests and MCP servers
  • session_init.mcp_manager_init
  • build_skills_and_plugins:list_all_tools
  • Per-thread MCP connection-manager ownership
  • Plugin MCP process reuse and idle cleanup
  • Plugin uninstall invalidation in a running App Server
  • Desktop/plugin-state synchronization after CLI uninstall
  • Automatic cache re-materialization

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗