Skip to content

Diagnose recursive OpenCode MCP config timeouts#410

Open
baron wants to merge 2 commits into
wt/opencode-acp-timeoutfrom
wt/opencode-recursive-mcp-guidance
Open

Diagnose recursive OpenCode MCP config timeouts#410
baron wants to merge 2 commits into
wt/opencode-acp-timeoutfrom
wt/opencode-recursive-mcp-guidance

Conversation

@baron

@baron baron commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Summary

Follow-up to #407 for #117. Thanks to @jpmurray for isolating the root cause: OpenCode can load RepoPrompt/RepoPrompt CE MCP entries from its global config during opencode acp startup, recursively launch RepoPrompt CE, and block session/new until RepoPrompt CE reports a startup timeout.

This PR keeps the existing upgrade guidance, but adds a targeted best-effort diagnostic when the startup timeout may be caused by that recursive MCP config:

  • checks OpenCode's global config path ($XDG_CONFIG_HOME/opencode/opencode.json or $HOME/.config/opencode/opencode.json) only after an ACP startup timeout
  • detects suspicious top-level mcp entries whose key or nested values reference RepoPrompt/RepoPrompt CE
  • reports only the config path and suspicious MCP keys, not config contents
  • advises backing up the config and removing/disabling those entries, or temporarily setting "mcp": {}
  • preserves cancellation semantics in OpenCode model-discovery bootstrap while continuing to normalize other bootstrap errors

The app still does not edit OpenCode config automatically.

Validation

  • make dev-format
  • make dev-lint
  • make dev-test FILTER=OpenCodeACPLaunchResolverTests
  • make dev-test-list
  • python3 Scripts/test_suite_optimizer.py verify-ledger --ledger Scripts/Fixtures/test-suite-contract-ledger.tsv
  • make dev-swift-build PRODUCT=RepoPrompt
  • .agents/skills/rpce-contribution-check/scripts/preflight.sh commit
  • .agents/skills/rpce-contribution-check/scripts/preflight.sh push

Stack

Stacked on #407 / wt/opencode-acp-timeout.

Comment on lines 133 to +136
if error is OpenCodeACPLaunchResolutionError || error is ExecutableFileIdentityError {
return AIProviderError.invalidConfiguration(detail: error.localizedDescription)
}
if let guidance = Self.openCodeACPStartupGuidance(for: error) {
if let guidance = Self.openCodeACPStartupGuidance(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bug: The recursiveMCPConfigGuidance() closure is eagerly evaluated for all errors in normalizeError, causing unnecessary filesystem I/O even when the result is discarded for non-startup errors.
Severity: MEDIUM

Suggested Fix

Modify openCodeACPStartupGuidance to accept recursiveMCPConfigGuidance as an escaping closure (@escaping @Sendable () -> String?). Call the closure inside the function, only after the guard check for the error type has passed. In normalizeError, pass the closure itself, not its result.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location:
Sources/RepoPrompt/Infrastructure/AI/Providers/OpenCode/OpenCodeACPAgentProvider.swift#L133-L136

Potential issue: The `normalizeError` function calls `recursiveMCPConfigGuidance()` as
an argument to `openCodeACPStartupGuidance`. This causes the closure to be evaluated
immediately, triggering synchronous filesystem I/O (checking for config files, reading
them, and parsing JSON) for every error processed. However, `openCodeACPStartupGuidance`
only uses the result for specific startup timeout errors, discarding it for all other
error types. This leads to unnecessary, potentially expensive I/O operations in a hot
path, such as during `session/prompt` timeouts, which degrades performance. This
contradicts the PR's intent to perform this check only for startup timeouts.

Did we get this right? 👍 / 👎 to inform future reviews.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Good catch — this was valid. Fixed in c99f229 by passing the diagnostic closure through lazily and invoking it only after the startup-timeout guard passes. I also strengthened the non-startup timeout test so session/prompt normalization asserts the recursive MCP config diagnostic is not called.

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