Summary
Cursor (and other strict stdio MCP clients) fail to parse Appium MCP traffic even when tools themselves succeed (isError: false). Non-JSON-RPC bytes are appearing on stdout.
This is not the same as #491 (Android alert custom-button W3C element id). That is a real functional bug; this issue is transport pollution.
Symptoms (Cursor user-appium-mcp)
On connect:
createClient completed ... connected=false
error=Unexpected non-whitespace character after JSON at position 4 (line 1 column 5)
During tool calls (tools often still return success):
Client error: Unexpected token '<', "<XCUIEleme"... is not valid JSON
Client error: Unexpected token 'E', " ELEMENT: '"... is not valid JSON
Client error: Unexpected token ''', " 'element-6"... is not valid JSON
Client error: Unexpected token 'e', " error: 'no"... is not valid JSON
The same Cursor log stream also shows Appium logger lines mixed into the MCP process:
info appium-mcp [TOOL START] appium_find_element { strategy: 'accessibility id', selector: '...' }
info appium-mcp {"tool":"generate_locators","durationMs":1433,"isError":false}
Page-source XML (<AppiumAUT>, <XCUIElementType...>) and util.inspect-style WebDriver payloads (ELEMENT:, 'element-6066-...', error: 'no such element') are being parsed as JSON-RPC frames.
Root cause
MCP stdio requires stdout to contain only JSON-RPC. Anything else (npmlog info ... lines, WDIO protocol dumps, XML, stack traces) breaks the client parser.
Prior work did not fully close this:
- #6 / #26 moved
console.log to the Appium logger, but did not guarantee stdio stdout stays clean.
- #282 added per-tool
[TOOL START] and duration JSON logs. Those lines match the Cursor errors exactly.
- #444 routed FastMCP logs through the Appium logger. It does not stop Appium/npmlog or WebDriver client dumps if those still reach stdout.
Likely remaining emitters:
- Appium
@appium/support / npmlog output interleaved with stdio JSON-RPC.
- Verbose tool wrapper logs in
src/tools/index.ts.
- WebDriver / WDIO client
logLevel defaulting to info, which dumps page source and element/error objects.
Expected
With transportType: 'stdio', stdout is only JSON-RPC. Diagnostic logs go to stderr (or are off by default).
Environment
- Client: Cursor MCP (
user-appium-mcp)
- Transport: stdio
- Server: appium-mcp (local / mainline)
- iOS XCUITest session (XML page source in the parse errors)
Related
Summary
Cursor (and other strict stdio MCP clients) fail to parse Appium MCP traffic even when tools themselves succeed (
isError: false). Non-JSON-RPC bytes are appearing on stdout.This is not the same as #491 (Android alert custom-button W3C element id). That is a real functional bug; this issue is transport pollution.
Symptoms (Cursor
user-appium-mcp)On connect:
During tool calls (tools often still return success):
The same Cursor log stream also shows Appium logger lines mixed into the MCP process:
Page-source XML (
<AppiumAUT>,<XCUIElementType...>) andutil.inspect-style WebDriver payloads (ELEMENT:,'element-6066-...',error: 'no such element') are being parsed as JSON-RPC frames.Root cause
MCP stdio requires stdout to contain only JSON-RPC. Anything else (npmlog
info ...lines, WDIO protocol dumps, XML, stack traces) breaks the client parser.Prior work did not fully close this:
console.logto the Appium logger, but did not guarantee stdio stdout stays clean.[TOOL START]and duration JSON logs. Those lines match the Cursor errors exactly.Likely remaining emitters:
@appium/support/ npmlog output interleaved with stdio JSON-RPC.src/tools/index.ts.logLeveldefaulting toinfo, which dumps page source and element/error objects.Expected
With
transportType: 'stdio', stdout is only JSON-RPC. Diagnostic logs go to stderr (or are off by default).Environment
user-appium-mcp)Related