From 5170914a7a49dd8e31947291bd0aaaa8dace3679 Mon Sep 17 00:00:00 2001 From: mika kuns Date: Mon, 1 Jun 2026 15:51:44 +0200 Subject: [PATCH] feat(installer): optionally register ClaudeDo MCP server with Claude Add an install step and welcome-page opt-in that registers the ClaudeDo external MCP server with the Claude CLI. Failures are non-fatal and surface the manual command so a missing or old CLI never blocks the install. Co-Authored-By: Claude Opus 4.7 --- src/ClaudeDo.Installer/App.xaml.cs | 2 + src/ClaudeDo.Installer/Core/InstallContext.cs | 4 ++ .../Pages/InstallPage/InstallPageViewModel.cs | 1 + .../Pages/WelcomePage/WelcomePageView.xaml | 8 ++++ .../Pages/WelcomePage/WelcomePageViewModel.cs | 2 + .../Steps/RegisterMcpStep.cs | 47 +++++++++++++++++++ 6 files changed, 64 insertions(+) create mode 100644 src/ClaudeDo.Installer/Steps/RegisterMcpStep.cs diff --git a/src/ClaudeDo.Installer/App.xaml.cs b/src/ClaudeDo.Installer/App.xaml.cs index 424d658..1df27e0 100644 --- a/src/ClaudeDo.Installer/App.xaml.cs +++ b/src/ClaudeDo.Installer/App.xaml.cs @@ -209,6 +209,8 @@ public partial class App : Application sc.AddSingleton(sp => sp.GetRequiredService()); sc.AddSingleton(); sc.AddSingleton(); + sc.AddSingleton(); + sc.AddSingleton(sp => sp.GetRequiredService()); sc.AddSingleton(); sc.AddSingleton(sp => sp.GetRequiredService()); sc.AddSingleton(); diff --git a/src/ClaudeDo.Installer/Core/InstallContext.cs b/src/ClaudeDo.Installer/Core/InstallContext.cs index e11f4fa..920b0ba 100644 --- a/src/ClaudeDo.Installer/Core/InstallContext.cs +++ b/src/ClaudeDo.Installer/Core/InstallContext.cs @@ -32,4 +32,8 @@ public sealed class InstallContext // InstallPage public bool CreateDesktopShortcut { get; set; } = true; + + // WelcomePage — register the external MCP endpoint with the Claude CLI. + public bool RegisterMcpWithClaude { get; set; } = true; + public int ExternalMcpPort { get; set; } = 47_822; } diff --git a/src/ClaudeDo.Installer/Pages/InstallPage/InstallPageViewModel.cs b/src/ClaudeDo.Installer/Pages/InstallPage/InstallPageViewModel.cs index 3d6edad..bef1e7e 100644 --- a/src/ClaudeDo.Installer/Pages/InstallPage/InstallPageViewModel.cs +++ b/src/ClaudeDo.Installer/Pages/InstallPage/InstallPageViewModel.cs @@ -148,6 +148,7 @@ public partial class InstallPageViewModel : ObservableObject, IInstallerPage _serviceProvider.GetRequiredService(), // Migrates the legacy service away and (re)registers the logon task. _serviceProvider.GetRequiredService(), + _serviceProvider.GetRequiredService(), _serviceProvider.GetRequiredService(), _serviceProvider.GetRequiredService(), // Refresh the bundled uninstaller exe + Add/Remove-Programs version so a diff --git a/src/ClaudeDo.Installer/Pages/WelcomePage/WelcomePageView.xaml b/src/ClaudeDo.Installer/Pages/WelcomePage/WelcomePageView.xaml index 7ad82e4..03ebbce 100644 --- a/src/ClaudeDo.Installer/Pages/WelcomePage/WelcomePageView.xaml +++ b/src/ClaudeDo.Installer/Pages/WelcomePage/WelcomePageView.xaml @@ -32,6 +32,14 @@ + + + diff --git a/src/ClaudeDo.Installer/Pages/WelcomePage/WelcomePageViewModel.cs b/src/ClaudeDo.Installer/Pages/WelcomePage/WelcomePageViewModel.cs index 0f2c791..66619c3 100644 --- a/src/ClaudeDo.Installer/Pages/WelcomePage/WelcomePageViewModel.cs +++ b/src/ClaudeDo.Installer/Pages/WelcomePage/WelcomePageViewModel.cs @@ -24,6 +24,7 @@ public partial class WelcomePageViewModel : ObservableObject, IInstallerPage [ObservableProperty] private string _heading = "Install ClaudeDo"; [ObservableProperty] private string _subheading = "Set the installation directory and continue."; [ObservableProperty] private bool _installDirEditable = true; + [ObservableProperty] private bool _registerMcp = true; public WelcomePageViewModel(InstallContext context) { @@ -62,6 +63,7 @@ public partial class WelcomePageViewModel : ObservableObject, IInstallerPage public Task ApplyAsync() { _context.InstallDirectory = InstallDirectory; + _context.RegisterMcpWithClaude = RegisterMcp; return Task.CompletedTask; } diff --git a/src/ClaudeDo.Installer/Steps/RegisterMcpStep.cs b/src/ClaudeDo.Installer/Steps/RegisterMcpStep.cs new file mode 100644 index 0000000..cb7817d --- /dev/null +++ b/src/ClaudeDo.Installer/Steps/RegisterMcpStep.cs @@ -0,0 +1,47 @@ +using ClaudeDo.Installer.Core; + +namespace ClaudeDo.Installer.Steps; + +public sealed class RegisterMcpStep : IInstallStep +{ + private const string ServerName = "claudedo"; + + public string Name => "Register MCP with Claude"; + + public async Task ExecuteAsync(InstallContext ctx, IProgress progress, CancellationToken ct) + { + if (!ctx.RegisterMcpWithClaude) + { + progress.Report("Skipped (not selected)"); + return StepResult.Ok(); + } + + var url = $"http://127.0.0.1:{ctx.ExternalMcpPort}/mcp"; + + // Drop any prior registration first so a re-run (e.g. update, changed port) + // overwrites cleanly instead of erroring on a duplicate name. + progress.Report($"Removing existing '{ServerName}' MCP registration (if any)..."); + await ProcessRunner.RunAsync(ctx.ClaudeBin, $"mcp remove --scope user {ServerName}", null, progress, ct); + + progress.Report($"Registering '{ServerName}' MCP server at {url}..."); + var (exit, output) = await ProcessRunner.RunAsync( + ctx.ClaudeBin, + $"mcp add --transport http --scope user {ServerName} {url}", + null, progress, ct); + + // Non-fatal: a missing/old Claude CLI must never block the install. Surface the + // manual command so the user can register it themselves later. + if (exit != 0) + { + progress.Report( + $"Could not register MCP automatically (claude exited {exit}). " + + $"Run manually: claude mcp add --transport http --scope user {ServerName} {url}"); + } + else + { + progress.Report("MCP server registered with Claude."); + } + + return StepResult.Ok(); + } +}