Skip to content

Conversation

@vmlinuzx
Copy link

@vmlinuzx vmlinuzx commented Jan 22, 2026

Summary

Fixes the infinite JSON parse error loop that makes OpenCode unrecoverable when using the /playwright skill.

Problem

When Playwright MCP outputs non-JSON-RPC data to stdout (npm download progress, browser console logs, debug output), the MCP SDK's JSON parser throws repeatedly in a while(true) loop, flooding the system with thousands of errors per second and causing OpenCode to freeze.

Root Cause

The MCP SDK's stdio transport (@modelcontextprotocol/sdk) has a processReadBuffer() method with this pattern:

while (true) {
  try {
    const message = this._readBuffer.readMessage();
    if (message === null) break;
    this.onmessage?.(message);
  } catch (error) {
    this.onerror?.(error);  // Error is caught but loop CONTINUES
  }
}

When garbage hits stdout, each line throws, the error is reported, and the loop continues - creating a denial-of-service on the error handler.

Solution

1. Suppress npm output (quick fix)

Added --yes --quiet flags to npx in the playwright skill config to prevent npm from outputting download progress.

2. Error rate limiting (defensive fix)

Added error rate limiting to SkillMcpManager:

  • Tracks errors per client with sliding 1-second window
  • If >50 errors occur within 1 second, automatically kills the MCP client
  • Subsequent operations on killed clients throw a descriptive error explaining what happened

Changes

File Changes
src/features/builtin-skills/skills.ts Added --yes --quiet to npx args
src/features/skill-mcp-manager/manager.ts Added ErrorRateTracker, error rate limiting logic
src/features/skill-mcp-manager/manager.test.ts Added 2 tests for error rate limiting
docs/issues/playwright-mcp-infinite-loop.md Full root cause analysis and documentation

Test Results

bun test src/features/skill-mcp-manager/manager.test.ts
30 pass, 0 fail

Notes

The pre-existing type errors in session-manager/tools.test.ts, skill-mcp/tools.test.ts, and skill/tools.test.ts are unrelated to this change (missing metadata and ask properties in ToolContext).


Summary by cubic

Prevents the Playwright MCP from flooding errors and freezing OpenCode by suppressing noisy stdout and terminating runaway clients when error rates spike.

  • Bug Fixes
    • Added --yes --quiet to npx in the Playwright skill to suppress npm/npx output.
    • Implemented error rate limiting in SkillMcpManager; kill client if >50 errors occur within 1 second and return a clear error.
    • Added unit tests for the limiting behavior and documented the root cause.

Written for commit d05e11a. Summary will update on new commits.

When Playwright MCP outputs non-JSON-RPC data to stdout (npm download
progress, browser console logs), the MCP SDK's JSON parser throws
repeatedly in a while(true) loop, flooding the system with errors and
causing OpenCode to become unresponsive.

Changes:
- Add --yes --quiet flags to npx in playwright skill config to suppress
  npm output
- Implement error rate limiting in SkillMcpManager: if >50 errors occur
  within 1 second, the MCP client is automatically killed
- Add descriptive error message when a killed client is detected
- Add unit tests for error rate limiting behavior
- Add issue documentation with full root cause analysis

Fixes the infinite JSON parse error loop that made OpenCode unrecoverable
when using the /playwright skill.
@github-actions
Copy link
Contributor

Thank you for your contribution! Before we can merge this PR, we need you to sign our Contributor License Agreement (CLA).

To sign the CLA, please comment on this PR with:

I have read the CLA Document and I hereby sign the CLA

This is a one-time requirement. Once signed, all your future contributions will be automatically accepted.


I have read the CLA Document and I hereby sign the CLA


DC seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You can retrigger this bot by commenting recheck in this Pull Request. Posted by the CLA Assistant Lite bot.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d05e11ad27

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +324 to +325
const originalOnerror = transport.onerror
transport.onerror = (error: Error) => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Install rate limiter before client.connect

The error‑rate wrapper is installed only after client.connect(transport) completes; any non‑JSON stdout that appears during the initial handshake (e.g., npx download progress or early Playwright logs) will still hit the SDK’s unbounded onerror loop before this handler is attached. That means the original freeze can still happen during startup, which is the most likely time for npm noise. Consider wiring the transport.onerror wrapper before calling client.connect so startup errors are also rate‑limited.

Useful? React with 👍 / 👎.

Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 4 files

Confidence score: 5/5

  • Automated review surfaced no issues in the provided summaries.
  • No files require special attention.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant