Skip to content

fix: make stdio bridge command timeout configurable (default 5m) - #1320

Merged
Scriptwonder merged 2 commits into
betafrom
fix/stdio-configurable-command-timeout
Aug 7, 2026
Merged

fix: make stdio bridge command timeout configurable (default 5m)#1320
Scriptwonder merged 2 commits into
betafrom
fix/stdio-configurable-command-timeout

Conversation

@andriy-coplay

@andriy-coplay andriy-coplay commented Aug 7, 2026

Copy link
Copy Markdown

Problem

Long-running tool calls on the stdio transport (asset imports, run_tests, batched manage_gameobject/execute_code, etc.) are cut off ~30–90s into execution and can never finish. In the Unity console the bridge visibly restarts on alternating ports:

MCP-FOR-UNITY: StdioBridgeHost started on port 6400 ...
MCP-FOR-UNITY: StdioBridgeHost started on port 6402 ...

Root cause

On the stdio path the timeout is hardcoded on both hops, with no way to raise it (unlike the WebSocket transport, where WebSocketTransportClient reads a per-call timeout off the wire at WebSocketTransportClient.cs:605):

Hop Value Location
Unity command execution + frame I/O 30s StdioBridgeHost.FrameIOTimeoutMs = 30000 (const)
Socket receive 60s StdioBridgeHost client.ReceiveTimeout = 60000
Stale-command eviction 60s () StdioBridgeHost staleThresholdMs
Python socket recv (per attempt) 30s ServerConfig.connection_timeout = 30.0
Python cross-retry ceiling 90s ServerConfig.command_total_timeout = 90.0

When the 30s/90s cap fires, the Python client closes the socket and re-sends the command on a fresh connection; the new connection makes Unity force-close the prior client and re-listen — the restart/port-churn seen above.

Fix

Make all three configurable, defaulting to 5 minutes (from the historical 30s), with env-var overrides. Invalid or non-positive values fall back to the default so a bad override can't disable the timeout.

C# — StdioBridgeHost.cs

  • FrameIOTimeoutMs: 30000 → default 300000, override UNITY_MCP_STDIO_COMMAND_TIMEOUT_MS. Changed from const to a static readonly resolved once at load.
  • client.ReceiveTimeout now Math.Max(60000, FrameIOTimeoutMs) so it never fires before the command timeout.
  • staleThresholdMs kept at 2× FrameIOTimeoutMs (was a const, now a local since the operand is no longer compile-time constant).

Python — core/config.py

  • connection_timeout: 30.0 → default 300.0, override UNITY_MCP_CONNECTION_TIMEOUT.
  • command_total_timeout: 90.0 → default 600.0 (kept above connection_timeout), override UNITY_MCP_COMMAND_TOTAL_TIMEOUT.
  • Added a small _env_float helper that ignores invalid/non-positive values.

Tests

  • Updated test_core_infrastructure_characterization.py to assert the new defaults (connection_timeout == 300.0, command_total_timeout == 600.0).

Notes / testing

  • Env-var parsing + fallback for config.py verified in isolation (defaults 300.0/600.0; a valid override applies; a bad value falls back). The repo's pytest collection currently fails on an unrelated missing tomli import in core/telemetry.py, so the full suite wasn't run in this environment.
  • C# is header/behaviour-only; no signature changes. Not compiled against Unity in this environment.
  • Naming follows the existing UNITY_MCP_* env-var convention (UNITY_MCP_TIMEOUT, UNITY_MCP_DISABLE_TELEMETRY, UNITY_MCP_ALLOW_BATCH, …).

Summary by CodeRabbit

  • New Features

    • Added configurable timeout settings through environment variables for bridge, connection, and command operations.
    • Increased default connection, command, and bridge timeouts to support longer-running operations.
    • Client receive and stale-command handling now adapt to the configured bridge timeout.
    • Invalid, missing, non-positive, or non-finite timeout values automatically fall back to safe defaults.
  • Tests

    • Expanded coverage for default, valid override, and invalid timeout configurations.

Long-running tool calls (asset imports, test runs, batched edits) were
cut off ~30-90s into execution, so the task could never finish. On the
stdio transport this was governed by hardcoded values on both hops:

- Unity side: StdioBridgeHost.FrameIOTimeoutMs (30s const) capped every
  command's execution and frame I/O; on timeout the client reconnected
  and re-sent, which force-closed the prior client and made the bridge
  restart on a new port (the repeated "StdioBridgeHost started on port
  6400/6402" churn).
- Server side: ServerConfig.connection_timeout (30s socket recv) and
  command_total_timeout (90s cross-retry ceiling) cut the command off
  first.

Unlike the WebSocket transport (WebSocketTransportClient reads a per-call
timeout off the wire), the stdio bridge had no way to raise these.

Make all three configurable with a 5-minute default:
- FrameIOTimeoutMs: 30s -> 300s, env UNITY_MCP_STDIO_COMMAND_TIMEOUT_MS.
  ReceiveTimeout now scales with it (max(60s, timeout)).
- connection_timeout: 30s -> 300s, env UNITY_MCP_CONNECTION_TIMEOUT.
- command_total_timeout: 90s -> 600s, env UNITY_MCP_COMMAND_TOTAL_TIMEOUT.

Invalid/non-positive env values fall back to the default so a bad
override can't disable the timeout. Updates the config characterization
test to the new defaults.
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 7b743fe5-39dc-47cc-860f-99fd1cfd3664

📥 Commits

Reviewing files that changed from the base of the PR and between d8d06cb and 7997788.

📒 Files selected for processing (2)
  • Server/src/core/config.py
  • Server/tests/test_core_infrastructure_characterization.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • Server/src/core/config.py

📝 Walkthrough

Walkthrough

The change makes Unity stdio bridge and server timeouts configurable through environment variables. It adds validated fallback values, derives related bridge thresholds from the configured timeout, and expands timeout configuration tests.

Changes

Timeout configuration

Layer / File(s) Summary
Server timeout configuration
Server/src/core/config.py, Server/tests/test_core_infrastructure_characterization.py
The server accepts positive, finite environment overrides for connection and total-command timeouts. It uses 300- and 600-second fallback defaults. Tests cover defaults, valid overrides, and invalid values.
Stdio timeout propagation
MCPForUnity/Editor/Services/Transport/Transports/StdioBridgeHost.cs
The Unity stdio bridge reads UNITY_MCP_STDIO_COMMAND_TIMEOUT_MS with a five-minute fallback. Client receive timeouts and stale-command eviction thresholds derive from the configured value.

Estimated code review effort: 2 (Simple) | ~15 minutes

Possibly related PRs

Suggested labels: bug

Suggested reviewers: scriptwonder

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely identifies the main change: making the stdio bridge command timeout configurable with a five-minute default.
Description check ✅ Passed The description clearly explains the problem, root cause, implementation, configuration variables, tests, and known test limitations.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/stdio-configurable-command-timeout

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
Server/tests/test_core_infrastructure_characterization.py (1)

664-665: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add coverage for the new environment paths.

The updated test covers only fallback defaults. Add cases for valid overrides and invalid, zero, negative, and non-finite values.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Server/tests/test_core_infrastructure_characterization.py` around lines 664 -
665, Extend the configuration tests around the connection_timeout and
command_total_timeout assertions to cover environment-variable overrides,
including valid values and invalid, zero, negative, and non-finite inputs.
Verify valid overrides are applied and each disallowed value preserves the
fallback defaults.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Server/src/core/config.py`:
- Around line 16-20: Update _env_float to require math.isfinite(value) in
addition to the existing positive-value check before returning an environment
override. Non-finite inputs such as inf and overflowed values must use the
existing fallback path for MCP timeout settings.

In `@Server/tests/test_core_infrastructure_characterization.py`:
- Around line 664-665: Update the default-value test around ServerConfig() to
remove both environment variables controlling connection_timeout and
command_total_timeout with monkeypatch.delenv(..., raising=False) before
constructing the configuration, then retain the existing default assertions.

---

Nitpick comments:
In `@Server/tests/test_core_infrastructure_characterization.py`:
- Around line 664-665: Extend the configuration tests around the
connection_timeout and command_total_timeout assertions to cover
environment-variable overrides, including valid values and invalid, zero,
negative, and non-finite inputs. Verify valid overrides are applied and each
disallowed value preserves the fallback defaults.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 926d20a0-607f-42a9-b299-9bbb114bb9ad

📥 Commits

Reviewing files that changed from the base of the PR and between 9f84072 and d8d06cb.

📒 Files selected for processing (3)
  • MCPForUnity/Editor/Services/Transport/Transports/StdioBridgeHost.cs
  • Server/src/core/config.py
  • Server/tests/test_core_infrastructure_characterization.py

Comment thread Server/src/core/config.py Outdated
Comment thread Server/tests/test_core_infrastructure_characterization.py
@andriy-coplay andriy-coplay self-assigned this Aug 7, 2026
Address CodeRabbit review on #1320:

- _env_float now requires math.isfinite(value): "inf"/"Infinity"/"1e309"/
  "nan" are positive-or-parseable but would produce unusable socket/timeout
  behaviour, so they now fall back to the default like other invalid input.
- test_config_default_values clears the two env vars first so ambient env
  can't mask the defaults.
- Added coverage for valid overrides and for invalid/zero/negative/
  non-finite values falling back to defaults.
@andriy-coplay

Copy link
Copy Markdown
Author

Thanks @coderabbitai — addressed in 7997788:

  • Non-finite values (major): _env_float now requires math.isfinite(value), so inf / Infinity / 1e309 / nan fall back to the default alongside the existing invalid/non-positive handling.
  • Env-robust default test: test_config_default_values now monkeypatch.delenvs UNITY_MCP_CONNECTION_TIMEOUT and UNITY_MCP_COMMAND_TOTAL_TIMEOUT before constructing ServerConfig().
  • Override coverage: added test_timeout_env_overrides_are_honored (valid values applied) and a parametrized test_timeout_env_invalid_values_fall_back covering 0 / -5 / abc / "" / inf / Infinity / 1e309 / nan.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

@andriy-coplay Thanks. The changes address the concern.

_env_float now rejects non-finite values, and the test coverage verifies both clean defaults and environment overrides.

🐇 ✅


If you found this review helpful, would you consider giving us a shout-out on X?

Thank you for using CodeRabbit!

You are interacting with an AI system.

@Scriptwonder
Scriptwonder merged commit 270463c into beta Aug 7, 2026
6 of 7 checks passed
@Scriptwonder
Scriptwonder deleted the fix/stdio-configurable-command-timeout branch August 7, 2026 18:38
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.

3 participants