mecatui/mecated startup blocks up to 30s on a single unreachable MCP server
Nobody has claimed this yet.
- Dominant language
- Go
- Stars
- 152
- Forks
- 16
- Avg merge
- 14h 48m
- Merged PRs (30d)
- 536
Description
Summary
mecatui/mecated startup (app.Build) blocks synchronously on connecting
every MCP server before the embedded server (and therefore the TUI) becomes
usable. If any single MCP server is unreachable — a network blip, a wrong URL,
a crashed/corrupted local ToolHive workload — startup stalls for the full,
hardcoded defaultConnectTimeout (30s), even when every other server connects
in milliseconds. There is no way to configure this timeout down, no
degrade-and-continue path, and no visible progress during the wait, so from
the outside a single dead MCP server is indistinguishable from a hung/broken
build.
Reproduction (what we hit)
Root-caused via a private --diagnostics-log capture. Timestamped evidence:
time=2026-09-18T10:41:59.302+02:00 ← last line before the gap
time=2026-09-18T10:42:29.319+02:00 level=WARN msg="MCP server unreachable; skipping" name=github reason=unavailable
time=2026-09-18T10:42:29.320+02:00 level=WARN msg="MCP server unreachable; skipping" name=toolhive-doc-mcp-remote reason=unavailable
time=2026-09-18T10:42:29.320+02:00 level=INFO msg="MCP servers connected" servers=6 tools=39
That's a 30.017s gap, matching defaultConnectTimeout = 30 * time.Second in
internal/adapter/mcp/mcp.go:57 to the millisecond. Everything else in the
build (session store, permission config, agent defs, LLM provider, skills,
memory, Team/Parallel/Schedule tools, scheduler) completed in under 300ms
total — this one stalled connection is the entire startup delay.
In our case the underlying cause was a corrupted Docker overlay2 layer for
the ToolHive-managed github MCP server container (thv status github /
docker rm both failed with input/output error / read-only file system
against the Docker Desktop VM disk) — but the mecatl-side behavior is the
real issue: this class of failure (one unreachable MCP server) will always
cost every user a 30s freeze on mecatui/mecated startup, for any reason a
server can be down.
Why this matters
internal/adapter/mcp/mcp.goNewManagerconnects servers concurrently
under a bounded semaphore, butBuild()still callswg.Wait()and does
not return until every server has connected or timed out
(internal/adapter/mcp/mcp.go~L1258). One dead server holds back the
other N that connected in milliseconds.defaultConnectTimeout(30s) is a hardcoded constant with no CLI flag or
settings.yamlknob — not even for local/loopback ToolHive servers where
30s is enormous relative to a real connect.- There's no degrade-and-continue path: MCP tool mounting happens once during
buildCatalog(Phase A of catalog construction), so there's no way to
bring up the core tool set immediately and attach straggler MCP servers'
tools later if/when they connect. - Nothing is emitted to the user during the wait to explain why startup is
frozen — from the outside, a hung MCP server and a genuinely broken build
look identical, which is what made this hard to diagnose in the first
place.
Suggested direction (not prescriptive — open to design review)
- Make the per-server (and/or overall) MCP connect timeout configurable
(CLI flag +settings.yaml), so an operator with known-flaky or
loopback-only servers can tighten it. - Consider connecting MCP servers in the background after the embedded
server/TUI is otherwise ready, surfacing tools as each server comes
online instead of gating the wholeBuild()on the slowest one. This is
a bigger architectural change (catalog assembly currently assumes a
build-once snapshot) and would need its own design pass. - At minimum, emit a visible "connecting to MCP server(s): X, Y, Z..."
diagnostic/status line the moment connects start, so a long wait is
attributable in real time instead of only after the fact viadiag.
🤖 Generated with Claude Code
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in internal/adapter/mcp/mcp.go, reading defaultConnectTimeout, NewManager, Build, and the buildCatalog Phase A path to understand where MCP connections gate startup. Done should be defined by design review, but the issue calls for a configurable timeout, visible connection status, or startup that no longer waits for one unreachable server.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100