Skip to content

mcp: server entries with a "timeout" field are silently dropped from the normalized config #50807

Closed

Description

@chuangye-gu

Summary

In 2.0.13, adding timeout to an MCP server entry silently removes that entire MCP server from the normalized config. The field is documented in the schema for both local and remote servers, so there is no way to raise the 5s default tool-discovery timeout — which makes slow MCP servers intermittently fail with Request timed out.

Environment

  • opencode version: 2.0.13 (opencode --version → opencode v2.0.13), channel=latest local=false
  • OS: Linux a100server 5.4.0-42-generic #46-Ubuntu SMP Fri Jul 10 00:24:02 UTC 2020 x86_64
  • Terminal: TERM=xterm-256color, COLORTERM=truecolor
  • Shell: /bin/bash
  • Install/channel: curl -fsSL https://opencode.ai/v2/install | bash (V2, ~/.opencode/bin/opencode)
  • Active plugins: none

Reproduction

  1. Add a timeout to any MCP server entry, e.g. a remote one:
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "servers": {
      "demo": {
        "type": "remote",
        "url": "https://api.githubcopilot.com/mcp/",
        "headers": { "Authorization": "Bearer {env:GITHUB_PERSONAL_ACCESS_TOKEN}" },
        "timeout": 60000
      }
    }
  }
}
  1. Run opencode debug config.
  2. demo (here: mcp.servers.github) is not in the output — the whole server is gone.

Same result for a local server: add "timeout": 60000 to an existing local entry and it disappears from opencode debug config too.

Removing timeout makes the server come back. Deterministic across repeated runs; no error is shown on the CLI, only a WARN in the log:

level=WARN message="configuration normalization diagnostic" source=~/.config/opencode/opencode.json path=$.mcp.servers.github kind=invalid action="skipped malformed recognized value"

Fields that are not dropped (so this is specific to timeout): oauth: false and enabled: true on a remote server are both accepted.

Expected Behavior

timeout should be accepted (it is part of the published schema and the embedded schema), or, if unsupported in this build, the field should be ignored/reported while keeping the server configured. The server must not be silently discarded.

Actual Behavior

The entire MCP server entry is dropped from the normalized config. opencode mcp list then shows only the remaining servers.

Schema at https://opencode.ai/config.json claims both variants support it:

  • McpLocalConfig.timeout — "Timeout in ms for MCP server requests. Defaults to 5000 (5 seconds) if not specified."
  • McpRemoteConfig.timeout — same description.

There also appears to be schema divergence inside the 2.0.13 binary: the embedded JSON schema lists timeout under McpLocalConfig but not under McpRemoteConfig, while the runtime Effect schema defines it for both (McpRemoteConfig also gets enabled and oauth). Regardless of which one the normalizer uses, both variants are dropped in practice.

Additional Context

  • Impact: the default 5s tool-discovery timeout cannot be raised. A remote MCP server whose initialize → notifications/initialized → tools/list handshake takes ~4.4s (52 tools, 124KB payload) returned ✗ ... failed: Request timed out. from opencode mcp list, while the identical handshake done manually with curl succeeded (initialize 0.78s, initialized 0.72s, tools/list 4.53s). With no way to set a longer timeout this is flaky/unfixable from config.
  • Workaround: none for the timeout itself. (The specific remote server I was debugging was ultimately fixed by adding oauth: false to disable OAuth auto-detection, which is a separate issue — but timeout could not be used to make slow handshakes reliable.)
  • Related, possibly same-area issues: Support per-server MCP execution timeout in config #23096 (per-server MCP timeout, notes mcp.<server>.timeout controls tool discovery with a 5s default), Documentation for MCP timeout configuration doesn't match schema #23648 (schema vs docs wording), mcp: Windows service registers zero MCP servers from global config #50710 (Windows service registers zero MCP servers from global config).

Activity

  1. chuangye-gu commented on Sep 23, 2026

    @chuangye-gu
    Author

    Reopening — the fix never landed, and the completed state here was misleading.

    A fix was submitted for this: #50810 (fix(config): retain MCP timeout entries, +36/−10 including a test). It was closed by the compliance bot, not by a maintainer — the PR description was missing the required template sections and wasn't updated within the 2-hour window. It was never merged, and the author hasn't re-submitted.

    Mainline is still pre-fix: packages/opencode/src/config/v2-compat.ts is at blob 9e4e0bf540, which is exactly the before side of #50810's diff (index 9e4e0bf54089..40f5f64d75a8), with no commits touching that file since 2026-08-27. So this reproduces on 2.0.13 and 2.0.14.

    Why it isn't cosmetic: the 5s default MCP request timeout can't be raised, so a remote MCP server with a slow handshake fails intermittently with Request timed out. I measured tools/list against a remote MCP server at 1.6–8.0s over 6 runs, and opencode mcp list fails whenever it exceeds 5s.

    For reference, the patch in #50810 is small and looks correct: let Timeout accept a plain PositiveInt alongside the {startup, request, catalog, execution} struct, and add a typeof input === "number" branch in lowerTimeout() (plus relax the global-timeout guard).

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

Metadata

Metadata

Assignees

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