Skip to content

stdio: logs and driver dumps leak onto stdout and break MCP JSON-RPC clients #492

Description

@Mochxd

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:

  1. Appium @appium/support / npmlog output interleaved with stdio JSON-RPC.
  2. Verbose tool wrapper logs in src/tools/index.ts.
  3. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions