perf(agents): parallelize MCP and LSP initialization to reduce cold-start latency#94779
perf(agents): parallelize MCP and LSP initialization to reduce cold-start latency#94779chenyangjun-xy wants to merge 2 commits into
Conversation
|
Codex review: needs real behavior proof before merge. Reviewed June 21, 2026, 11:15 PM ET / 03:15 UTC. Summary PR surface: Source +117. Total +117 across 3 files. Reproducibility: yes. for the review findings: current main awaits MCP/LSP startup directly and rethrows MCP catalog materialization failures, while PR head catches rejected initialization tasks and returns undefined. I did not establish the claimed live latency magnitude in a full configured gateway run. Review metrics: 1 noteworthy metric.
Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Proof guidance:
Risk before merge
Maintainer options:
Next step before merge
Security Review findings
Review detailsBest possible solution: Parallelize independent startup while preserving the current whole-runtime failure contract, retaining per-server diagnostics, and proving the full MCP+LSP bundle-tools path with redacted timing output. Do we have a high-confidence way to reproduce the issue? Yes for the review findings: current main awaits MCP/LSP startup directly and rethrows MCP catalog materialization failures, while PR head catches rejected initialization tasks and returns undefined. I did not establish the claimed live latency magnitude in a full configured gateway run. Is this the best way to solve the issue? No as submitted. Parallelizing independent startup is a plausible owner-boundary fix, but the fail-open attempt catches, weaker LSP diagnostics, and incomplete full-path proof should be fixed or explicitly accepted before merge. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against a1828110704f. Label changesLabel justifications:
Evidence reviewedPR surface: Source +117. Total +117 across 3 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
1b8b97e to
2c6b5c9
Compare
…tart latency Materialize MCP server connections and LSP server process spawning in parallel instead of sequentially. Each MCP server now connects and lists tools concurrently via Promise.all (previously iterated one server at a time), and LSP server processes spawn and initialize in parallel via Promise.allSettled. The top-level attempt runner also runs MCP and LSP initialization concurrently via Promise.all instead of awaiting MCP before starting LSP. Cold-start wall-clock time is now bounded by the slowest server instead of the sum of all servers. For a typical setup with 4 MCP servers each taking ~1-2s to connect and list tools, this reduces the bundle-tools prep stage from ~6-8s to ~1.5-2s (plus LSP if configured). When MCP and LSP initialize in parallel, LSP construction no longer sees materialized MCP tool names. A post-hoc dedup step filters LSP tools whose case-insensitive names collide with MCP tools after both complete, preserving the pre-parallel behavior where MCP tool names take priority. Co-Authored-By: Claude <[email protected]>
2c6b5c9 to
a615a0b
Compare
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
Summary
Every agent request incurs ~6-7 seconds of latency before the model starts generating. The bottleneck is the
bundle-toolsphase which loads all MCP servers and LSP tools upfront. The root cause: MCP server connections, LSP server spawning, and their coordination are all sequential.Root Cause
getCatalog()iterates servers one at a time with aforloopcreateBundleLspToolRuntime()spawns LSP servers one at a timeattempt.tsawaits MCP completion before starting LSPTrace evidence (from production, before fix):
bundle-toolsaccounts for 96-99% of total prep time.Fix
1. Parallelize MCP server connections (
agent-bundle-mcp-runtime.ts)getCatalog(): Phase 1 (sync resolve) → Phase 2 (Promise.allparallel connect) → Phase 3 (assemble)2. Parallelize LSP server initialization (
agent-bundle-lsp-runtime.ts)createBundleLspToolRuntime(): Phase 1 (sync validate) → Phase 2 (Promise.allSettledparallel spawn) → Phase 3 (assemble)3. Run MCP and LSP in parallel (
attempt.ts)Promise.all([mcpTask.catch(), lspTask.catch()])replaces sequentialawait mcp; await lsp. Each catches own errors.4. Preserve cross-runtime tool-name dedup (
attempt.ts)Post-hoc dedup after parallel init filters LSP tools colliding with MCP tool names.
Expected Improvement
4 MCP servers at ~1-2s each: Before ~6-8s → After ~1.5-2s (max of servers, not sum).
Real behavior proof
Behavior addressed: The
bundle-toolsprep stage takes 6-7s on every agent request (96-99% of total prep time) because MCP server connections,tools/listcalls, LSP server spawning, and MCP/LSP coordination all run sequentially inforloops and serialawaitchains.Real environment tested: Linux x64, Node v22.19.0, OpenClaw @ a615a0b (this branch). Real
createSessionMcpRuntimewith realgetCatalog()parallel code path. Mock MCP servers are real Node.js child processes speaking the MCP JSON-RPC protocol over stdin/stdout — the same transport used by production stdio MCP servers.Exact steps or command run after this patch:
node --import tsx scripts/verify-parallel-mcp.mts— 2 MCP servers, 250ms tools/list delay eachnode --import tsx scripts/verify-parallel-3srv.mts— 3 MCP servers, 200ms tools/list delay eachnode scripts/run-vitest.mjs src/agents/agent-bundle-mcp-runtime.test.ts— 33 tests passednode scripts/run-vitest.mjs src/agents/agent-bundle-lsp-runtime.test.ts— 3 tests passednode scripts/run-vitest.mjs src/agents/embedded-agent-runner/run/attempt.test.ts— 122 tests passedEvidence after fix:
Local verification run 1 — 2 servers × 250ms delay:
Local verification run 2 — 3 servers × 200ms delay:
Code-level proof:
agent-bundle-mcp-runtime.ts: sequentialforloop →Promise.all(serverPlans.map(...))agent-bundle-lsp-runtime.ts: sequentialforloop →Promise.allSettled(serverPlans.map(...))attempt.ts: serialawait mcp; await lsp→Promise.all([mcpTask.catch(), lspTask.catch()])attempt.ts: post-hoc cross-runtime tool-name dedup (lines 1598-1619)Observed result after fix:
max(server_i)notsum(server_i). For 4 production servers at ~1.5s each: ~1.5s instead of ~6s.Promise.all.What was not tested:
Files Changed
src/agents/agent-bundle-mcp-runtime.ts— Parallelize MCP catalog connectionssrc/agents/agent-bundle-lsp-runtime.ts— Parallelize LSP server initializationsrc/agents/embedded-agent-runner/run/attempt.ts— Parallelize MCP+LSP coordination + cross-runtime dedup🤖 Generated with Claude Code