Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Comments

feat: fast DevServer startup with convention-based discovery, instant MCP, and hot reconnection#22704

Open
carldebilly wants to merge 56 commits intomasterfrom
dev/cdb/devserver-discovery
Open

feat: fast DevServer startup with convention-based discovery, instant MCP, and hot reconnection#22704
carldebilly wants to merge 56 commits intomasterfrom
dev/cdb/devserver-discovery

Conversation

@carldebilly
Copy link
Member

Summary

Problem: Every DevServer startup pays a 10-30s MSBuild evaluation tax for add-in discovery. In MCP mode, AI tools take 15-40s to become available.

Solution: Convention-based.targets parsing replaces MSBuild evaluation (<200ms). MCP server starts instantly with cached tool definitions (<1s). Hot reconnection survives Host crashes without MCP client restart.

Scope: 73 files changed, ~12.9K lines added across discovery, MCP proxy, tests, and specs.

Performance Gains

MetricBeforeAfter
Add-in discovery10-30s (MSBuild)<200ms (convention-based)
MCP time tolist_tools15-40s<1s (cached)
MCP time to functional tools15-40s<5s
Host crash recoveryManual restartAutomatic (hot reconnection)

What's Changed

Convention-Based Add-In Discovery

  • TargetsAddInResolver: Direct.targets XML parsing from NuGet cache — replaces 10-30s MSBuild evaluation with <200ms resolution. Handles MSBuild property substitution ($(TargetFramework),$(MSBuildThisFileDirectory), etc.)
  • ManifestAddInResolver: Forward-compatibledevserver-addin.json manifest lookup (priority 1 in resolution chain) with version gating
  • ProjectAssetsParser: Third-party add-in discovery viaproject.assets.json — finds transitive NuGet packages that ship DevServer add-ins
  • DotNetVersionCache: Cacheddotnet --version with 24h TTL andglobal.json file-hash invalidation
  • --addins flag on Host for pre-resolved add-in paths (backward-compatible: absence = MSBuild fallback)
  • Discovery priority chain: manifest →.targets → MSBuild fallback

Instant MCP Startup

  • MCP STDIO server starts immediately and returns cached tool definitions (<1s)
  • Host launch happens in background — doesn't block MCP startup
  • 30s bounded timeouts on upstream operations
  • Structured error responses with remediation hints for tools called before Host is ready

Direct Host Launch & Instance Reuse

  • CLI launches Host directly (2-process chain instead of 3 — bypasses controller process)
  • AmbientRegistry reuse: detects existing DevServer instances by port/PID, connects instead of spawning duplicates
  • .csproj.user generation moved CLI-side

Hot Reconnection

  • Automatic Host relaunch on crash — MCP client never needs restart
  • ConnectionState state machine:Initializing → Discovering → Launching → Connecting → Connected, plusReconnecting,Degraded,Shutdown
  • Max 3 reconnection attempts before enteringDegraded state (MCP stays alive with health info)

Health & Diagnostics

  • uno_health built-in tool +uno://health MCP resource — always available, even before Host is ready
  • DiscoveryIssueMapper: maps discovery failures to structuredValidationIssue with codes, severity, and remediation hints
  • MCPServerInfo declaration for protocol compliance
  • Capability-based client detection (replaces hardcoded client name lists)

Reliability & Race Condition Fixes

  • Lock-free TCS management viaVolatile.Read /Interlocked.Exchange on upstream connection
  • ResettableStartOnceGuard for failed startup retry (Interlocked.CompareExchange)
  • Process handle leak prevention viaDisposeAndClearProcess helper
  • Health polling for attached (reused) DevServer instances
  • Stale connection disposal when TCS reset races with connection completion
  • Readiness short-circuit when Host process exits during probe

MCP SDK Upgrade

  • ModelContextProtocol SDK0.4.1 → 0.8.0

Architecture Overview

MCP Client (IDE/AI)    │ stdio    ▼┌──────────────────────┐│  McpStdioServer      │  ← Instant start, cached tools│  (STDIO protocol)    │└──────┬───────────────┘       │┌──────▼───────────────┐│ ProxyLifecycleManager│  ← Orchestrates full lifecycle│  ├─ ToolListManager  │     (discovery → launch → connect → reconnect)│  ├─ HealthService    ││  └─ DevServerMonitor │└──────┬───────────────┘       │┌──────▼───────────────┐│  McpUpstreamClient   │  ← Lock-free HTTP/SSE connection│  (HTTP+SSE)          │└──────┬───────────────┘       │ HTTP       ▼┌──────────────────────┐│  DevServer Host      │  ← Launched directly by CLI│  (--addins flag)     │└──────────────────────┘

ConnectionState Machine

Initializing → Discovering → Launching → Connecting → Connected                                  ↑                       │                                  │    (crash detected)    │                                  │         ↓              │                                  └── Reconnecting ←───────┘                                          │                                    (max retries)                                          ↓                                       Degraded ──→ Shutdown

Add-In Discovery Chain

1. devserver-addin.json manifest    (instant, explicit)2. .targets file XML parsing        (<200ms, convention-based)3. MSBuild evaluation               (10-30s, fallback safety net)

Key New Components

ComponentResponsibility
ProxyLifecycleManagerTop-level MCP lifecycle orchestrator
McpUpstreamClientLock-free HTTP connection to upstream DevServer
McpStdioServerMCP stdio protocol handlers (tools, resources, health)
DevServerMonitorProcess lifecycle + readiness monitoring
HealthServiceHealth reports + validation issue aggregation
ToolListManagerTool cache with file persistence + upstream sync
MonitorDecisionsPure testable decision logic extracted from monitor
StartOnceGuardResettable guard for one-shot operations with retry
UnoToolsLocatorSDK discovery orchestration
TargetsAddInResolver.targets file parsing with MSBuild property resolution
ManifestAddInResolverdevserver-addin.json resolution with version gating
ProjectAssetsParserproject.assets.json parsing for transitive add-ins
DiscoveryIssueMapperMaps discovery errors → health issue codes
DotNetVersionCacheCacheddotnet --version with 24h TTL
AmbientRegistryDetects and reuses running DevServer instances

Refactoring

  • McpProxy split into 5 focused classes:ProxyLifecycleManager,McpUpstreamClient,McpStdioServer,HealthService,ToolListManager
  • McpClientProxy renamed toMcpUpstreamClient for clarity
  • Test class split into 8 targeted test files with XML docs and[Description] attributes

Test Coverage

  • 258 unit tests passing (0 failures)
  • Test coverage areas:TargetsAddInResolver,ManifestAddInResolver,ProjectAssetsParser,McpUpstreamClient,DevServerMonitor,HealthService,ConnectionState,DiscoveryIssueMapper,MonitorDecisions,ToolCacheFile,EntryPoint regression,DotNetVersionCache,NuGetCacheHelper,ConfigurationExtensions
  • PowerShell backward-compatibility test suite (run-devserver-compat-tests.ps1)
  • Azure DevOps CI integration

Backward Compatibility

  • No breaking changes to Host launch — IDE extensions (VS, Rider, VS Code) work unchanged
  • No breaking changes to CLI commands (start,stop,list,disco,login)
  • MSBuild fallback remains as safety net for older SDKs or unrecognized project structures
  • Graceful degradation for Uno SDK 5.x/6.x (version gating in manifest resolver)
  • Cross-platform path handling (Windows, macOS, Linux)

Specification

  • Full spec:specs/001-fast-devserver-startup/spec.md with 8 appendices (A–H)
  • Known limitations documented inspecs/001-fast-devserver-startup/known-limitations.md

Test plan

  • 258 unit tests pass (dotnet test on DevServer.Tests)
  • Manual:uno-devserver start launches Host with--addins flag
  • Manual: MCPlist_tools returns cached tools in <1s
  • Manual: Kill Host process → MCP reconnects automatically
  • Manual:uno_health tool returns structured health info
  • Manual: IDE extensions (VS/Rider/VS Code) continue to work unchanged
  • CI: Azure DevOps pipeline passes

Replace MSBuild-based add-in discovery (2x dotnet build, 10-30s) with direct .targets XML parsing from the NuGet cache (~110ms).- Add TargetsAddInResolver that parses packages.json and buildTransitive/*.targets- Fix NUGET_PACKAGES="" producing dangerous relative paths in GetNuGetCachePaths- Add --addins flag to Host to skip MSBuild discovery when paths are pre-resolved- Forward --addins from controller to child server process- Resolve add-ins in CLI start and MCP paths before launching the host- Add --addins-only flag to disco command for pipe-friendly output- Show add-ins section with discovery method and duration in disco output- Add 18 unit tests for TargetsAddInResolver
…fixes- Add DotNetVersionCache to avoid repeated `dotnet --version` subprocess  calls during startup (disk cache with 24h TTL + global.json sdk.version  invalidation key)- Integrate cache into UnoToolsLocator and register in DI- Add EntryPoint regression tests to lock VS extension reflection-probed  type names and constructor signatures- Fix MCP notification name in dev-server.md (tools/list_changed)- Add missing tools to using-the-uno-mcps.md (uno_app_start, Business tier)- Add --mcp-wait-tools-list to Antigravity setup guide- Add antigravity to ClientsWithoutListUpdateSupport in McpProxy- Create devserver-agent.md and reference it in AGENTS.md
… diagnostics- Enable tool cache unconditionally in --mcp-app mode for < 1s first list_tools- Add 30s bounded timeout to list_tools and EnsureRootsInitialized (no more infinite blocking)- Fix McpClientProxy TCS completion on connection error (prevents permanent deadlock)- Fix DisposeAsync hang by canceling TCS before awaiting client disposal- Remove incorrect ResourceUpdatedNotificationParams deserialization for ToolListChanged- Always invoke toolListChanged callback even with 0 tools to unblock waiters- Return structured MCP error responses for premature tool calls instead of exceptions- Add uno_health built-in tool with HealthReport model for startup diagnostics- Add 17 unit tests covering serialization, timeout patterns, and cache integration
…overyAdd 17 unit tests (addins flag parsing, controller forwarding, NuGetcache path guard) and 5 PowerShell integration test functions (discoJSON output, addins-only, cleanup, Host --addins flag, package content).
Upgrade ModelContextProtocol SDK from 0.4.1 to 0.8.0. Add uno://healthMCP resource, HealthReport fields (UnoSdkVersion, DiscoveryDurationMs),cache invalidation metadata (workspace hash, SDK version), and atomiccache writes.
- Link AmbientRegistry and CsprojUserGenerator sources into CLI project- Check AmbientRegistry for existing DevServer before launching- Write .csproj.user files CLI-side before server launch- Launch Host directly without --command start (2-process chain)- Manage long-running server process lifecycle and cleanup- Call StopMonitoringAsync on MCP proxy shutdown- Add Phase 1b unit tests for AmbientRegistry and direct launch args- Document IDEChannel single-connection limitation
- TCS resettable via ResetConnectionAsync (bugs 1+4)- Monitor loop continues after ServerStarted, raises ServerCrashed (bug 2)- Notification handler awaits async callback (bug 3)- Add 11 regression and bug-exposing tests
Extract health reporting into a dedicated HealthService class:- BuildHealthReport(), BuildHealthToolResponse()- HealthTool static Tool definition- HealthResourceUri constantMcpProxy now delegates all health logic to HealthService via DI.
Extract tool caching and list operations into ToolListManager:- GetCachedTools(), PersistToolCacheIfNeeded(), RefreshCachedToolsFromUpstreamAsync()- ListToolsWithTimeoutAsync(), FetchToolsFromUpstreamAsync(), AppendBuiltInTools()- InitializeToolCachePath(), MarkShouldRefresh()HealthService now uses ToolListManager.CachedToolCount directly.
Pure rename for clarity — McpUpstreamClient better describes its roleas the connection to the upstream DevServer MCP host.
Extract MCP Host building and handler registration into McpStdioServer:- BuildHost() constructs the stdio MCP server with all 4 handlers- Lifecycle-specific behavior injected via delegates- McpProxy now calls BuildHost() then wires callbacks and runs
McpProxy now only contains lifecycle orchestration (roots, DevServerstartup, cache priming, event wiring). The new name reflects its role.
- Split Given_McpProxy into 5 test classes matching production classes  (Given_HealthService, Given_ToolCacheFile, Given_McpUpstreamClient,  Given_DevServerMonitor, Given_McpStdioServer)- Add XML doc comments on test classes with <see cref> to tested class- Add MSTest [Description] on non-trivial test methods- Rename mcpClientProxy parameter to mcpUpstreamClient in all classes- Replace "MCP proxy" with "MCP bridge" / "stdio server" in docs and logs- Remove Phase 1b/1c-1 references from code comments- Add [Retry(2)] on intermittent DevServer process tests
Add observational state machine to ProxyLifecycleManager that tracksConnectionState transitions driven by DevServerMonitor events:- ServerStarted -> Connecting- toolListChanged -> Connected (resets reconnection counter)- ServerCrashed -> Reconnecting (with ResetConnectionAsync) or Degraded  after 3 failed reconnection attempts- ServerFailed -> DegradedMcpStdioServer now returns a contextual error message when tools arecalled during reconnection vs initial startup.
Cover TCS reset pattern (crash -> reset -> reconnect cycle), reconnectioncounter reset on success, max attempts leading to Degraded state,Degraded not being terminal, and HealthReport roundtrip withReconnecting/Degraded ConnectionState.
Add ASCII state diagram in ProxyLifecycleManager next to the statefields, showing all transitions with their triggering events and thetwo separate retry counters.Enrich ConnectionState.cs with detailed <remarks> block describingevent-to-state mapping, counter semantics, and per-member XML summarieson each enum value.
ServerLaunching event fires after process start, before health-check wait.Shutdown state is set in the finally block for guaranteed cleanup transition.
Configure ServerInfo with name="uno-devserver" and assembly versionso clients see a named server in the initialize response.
Remove stale ClientsWithoutListUpdateSupport blacklist. Instead, waitfor upstream tools when no cache exists (universal), return cached toolsimmediately when available. Add HasCachedTools property to ToolListManager.
Align ServerInfo and HealthReport on the same versioning pattern asCliManager.ShowBanner, using AssemblyInformationalVersionAttributeto get the SemVer version instead of the 4-part assembly version.
Cover Launching/Shutdown roundtrips in HealthReport, ServerInfoversion extraction pattern, and ServerLaunching event sequence.
Refactor RunMonitor() to use DiscoverAsync() directly instead ofResolveHostExecutableAsync(), storing the full DiscoveryInfo forhealth reporting. StartProcess() now reuses cached add-ins fromthe discovery result instead of re-calling DiscoverAsync().
Static mapper that converts DiscoveryInfo nullable fields intoValidationIssue[] for health reports. Maps GlobalJsonNotFound,UnoSdkNotInGlobalJson, SdkNotInCache, PackagesJsonNotFound,DevServerPackageNotCached, HostBinaryNotFound, DotNetNotFound.
@unodevops
Copy link
Contributor

🤖 Your WebAssembly Skia Sample App stage site is ready! Visit it here:https://unowasmprstaging.z20.web.core.windows.net/pr-22704/wasm-skia-net9/index.html

@unodevops
Copy link
Contributor

🤖 Your Docs stage site is ready! Visit it here:https://unodocsprstaging.z13.web.core.windows.net/pr-22704/docs/index.html

Copy link
Contributor

CopilotAI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 77 out of 78 changed files in this pull request and generated 3 comments.


💡Add Copilot custom instructions for smarter, more guided reviews.Learn how to get started.

@unodevops
Copy link
Contributor

⚠️⚠️ The build197560 has failed on Uno.UI - docs.

@unodevops
Copy link
Contributor

⚠️⚠️ The build197559 has failed on Uno.UI - CI.

CopilotAI review requested due to automatic review settingsFebruary 20, 2026 21:43
Copy link
Contributor

CopilotAI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 78 out of 80 changed files in this pull request and generated no new comments.


💡Add Copilot custom instructions for smarter, more guided reviews.Learn how to get started.

@unodevops
Copy link
Contributor

🤖 Your WebAssembly Skia Sample App stage site is ready! Visit it here:https://unowasmprstaging.z20.web.core.windows.net/pr-22704/wasm-skia-net9/index.html

@unodevops
Copy link
Contributor

🤖 Your Docs stage site is ready! Visit it here:https://unodocsprstaging.z13.web.core.windows.net/pr-22704/docs/index.html

@unodevops
Copy link
Contributor

🤖 Your WebAssembly Skia Sample App stage site is ready! Visit it here:https://unowasmprstaging.z20.web.core.windows.net/pr-22704/wasm-skia-net9/index.html

@unodevops
Copy link
Contributor

🤖 Your Docs stage site is ready! Visit it here:https://unodocsprstaging.z13.web.core.windows.net/pr-22704/docs/index.html

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

Reviewers

Copilot code reviewCopilotCopilot left review comments

@nickrandolphnickrandolphAwaiting requested review from nickrandolph

@kazo0kazo0Awaiting requested review from kazo0

@jeromelabanjeromelabanAwaiting requested review from jeromelaban

@dr1rrbdr1rrbAwaiting requested review from dr1rrb

At least 1 approving review is required to merge this pull request.

Assignees

@carldebillycarldebilly

Labels

area/buildCategorizes an issue or PR as relevant to build infrastructurekind/documentationkind/enhancementNew feature or request

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

2 participants

@carldebilly@unodevops

[8]ページ先頭

©2009-2026 Movatter.jp