Today I published version 2.2.0, five days after 2.0.0. It is a smaller release than 2.0.0, but an important one if you use Codex, or if you run an agent without a person watching it.
It is live on GitHub and on npm as swipium@2.2.0.
In short: Swipium now works properly with Codex and in headless runs, speaks the newest MCP protocol, and gives the AI leaner results it actually reads. If you are new to the project, the 1.0.0 launch post explains what Swipium is, and the 2.0.0 post covers the last big release. The docs cover setup.
It works with Codex and headless agents
Before: Codex does not pass your shell's environment to MCP servers. Test credentials like SWIPIUM_TEST_PASSWORD and the Android SDK path went missing, silently, and the run failed in confusing ways. And agents running unattended, like codex exec or claude -p, cannot show a person a consent prompt. They answer it automatically, so boots, installs, and builds were refused every single time.
Now: swipium init codex writes the line that tells Codex which variables to pass through, and qa_doctor checks it when it runs under Codex. For unattended runs, the person operating the agent can pre-approve specific actions in the server config:
[mcp_servers.swipium]
env = { SWIPIUM_CONSENT_PREAPPROVE = "prepare_plan,install_app" }
The list only accepts exact action names, and it is only read from the server environment, never from a file in the repository. Every approval is still single-use and logged with the exact command it ran. Actions that run repository code, like building from source or starting Metro, need a second, explicit opt-in, SWIPIUM_CONSENT_PREAPPROVE_RUN_CODE=1. When a prompt is answered automatically, Swipium tells the agent about pre-approval instead of letting it retry in a loop. A real decline from a person is never nudged that way.
Why: 2.0.0 introduced Swipium CI Pipelines, and a pipeline has nobody there to click "approve". The operator decides in advance what is fine, and a cloned repository can never decide it for them.
It speaks the newest MCP protocol
Before: Swipium only spoke the 2025 revisions of MCP.
Now: it also speaks MCP 2026-07-28, next to 2025-06-18 and 2025-11-25, and picks the right one automatically from the client's first message. Claude Code 2.1.285 and later connect on the new revision, and Codex keeps using 2025-06-18. If you use Claude Code, there is nothing to configure.
On the new revision, consent prompts still go to the person, never to the model. The answer is tied to the exact tool call, its arguments, and the session, so it cannot be forged or reused: if it is, nothing runs. I verified this in headless runs and at the protocol level.
Why: clients are moving to the new revision, and Swipium should not be the reason a connection fails.
Leaner results the AI actually reads
This one surprised me.
Before: a tool result has two parts: human-readable text and a structured part. Claude Code and Codex show the model the structured part, not the text. Swipium put its summary and its next-step hints, like "call qa_report", in the text, so the model never saw them.
Now: the summary and next steps are in the structured part. Screen element lists are compact one-line entries, about 40% smaller:
@e3 [button] "Log in" #login_btn [40,200][1040,245] (focused)
The tool list sent to the AI is about 9% smaller (69.6 KB to 63.5 KB), and the server instructions went from 2,518 to 1,900 characters, so they now fit within Claude Code's 2,048-character limit.
If a script of yours reads element lists, they changed shape. Pass responseMode: "verbose" to keep the old format.
Why: the same lesson as 1.5.0 and 2.0.0. The agent works better with less to read, as long as what it reads is the right thing.
It fits inside client timeouts
Before: a status poll could wait up to 120 seconds, and Codex cuts a tool call off after 60 seconds by default. Building WebDriverAgent for iOS or cold-booting a simulator could block a single call for minutes.
Now: waits and status polls end within about 50 seconds. Long work, like building WebDriverAgent, runs in the background as a job the agent polls, and a simulator boot that takes longer reports "booting" instead of blocking. A few long operations, such as running a full flow or a large iOS install, can still take longer, which is why swipium init codex keeps a longer tool timeout in the Codex config.
Cancel means cancel
Before: stopping a request stopped the answer, not the work. The polling behind it kept running until its deadline, and the server stayed alive after the client closed. A cancelled mobile audit could leave the device offline, because it had turned on airplane mode to test resilience.
Now: stopping a request stops the work behind it, closing the client shuts the server down cleanly, and a cancelled audit restores the device network. Cancelled runs are not recorded as failures either.
Lighter and more secure under the hood
Swipium now runs on version 2 of the MCP TypeScript SDK. A production install went from 100 packages to 21, and it picks up the SDK's fix for a regular-expression denial-of-service bug (GHSA-cqwc-fm46-7fff). Swipium also stopped patching private parts of the SDK, which makes future upgrades safer.
The test suite went from 901 to 1,116 tests, with new tests that run the real server over stdio for both protocol eras. Before publishing, I ran it end to end with Claude Code and Codex, including the headless consent and pre-approval paths. The tool surface did not change: still 55 tools and 5 prompts.
Upgrading from 2.0
Update and restart your MCP client. If you use Codex, rerun swipium init codex and add the line it prints. If a script reads element lists, pass responseMode: "verbose". If your agent waited on one long iOS call, it now needs to poll for "booting" or "starting" to finish. The full upgrade checklist is in the changelog.
Thoughts
While working on 2.0.0, I realized I was quite behind on the MCP architecture side, and I already knew about some bugs, which I fixed in this version.
For the next versions, my idea is to work more on the MCP side and on better communication with agents, rather than on specific tools. This version is already a good improvement: I used it while testing another project, and it does feel faster and more accurate, although there is still a way to go.