This guide provides step-by-step instructions for extracting MCP server functionality from AiStudio4 into a standalone WPF application while maximizing code sharing between both applications.
MaxsAiStudio/
├── AiStudio4.Core/ # Shared library project
│ ├── Interfaces/
│ ├── Models/
│ ├── Services/
│ ├── Tools/
│ ├── Exceptions/
│ └── Configuration/
├── AiStudio4/ # Main WPF application
├── AiStudio4.McpManager/ # Standalone MCP Manager WPF app
│ ├── Views/
│ ├── ViewModels/
│ ├── Services/
│ └── App.xaml
└── AiStudio4.sln # Updated solution file
- Create new Class Library project:
AiStudio4.Core - Target framework:
net9.0-windows - Add to solution file
- Add these packages to AiStudio4.Core.csproj:
<ItemGroup>
<PackageReference Include="ModelContextProtocol.Client" Version="*" />
<PackageReference Include="ModelContextProtocol.Protocol" Version="*" />
<PackageReference Include="Newtonsoft.Json" Version="*" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="*" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="*" />
</ItemGroup>- Move these files from
AiStudio4/Core/Interfaces/toAiStudio4.Core/Interfaces/:-
IMcpService.cs -
ITool.cs -
IToolExecutor.cs -
IToolService.cs -
IToolProcessorService.cs -
IBuiltinToolService.cs -
IBuiltInToolExtraPropertiesService.cs
-
- Create new
IConfigurationService.cs
- Move these files from
AiStudio4/Core/Models/toAiStudio4.Core/Models/:-
McpServerDefinition.cs -
ToolModels.cs -
ToolResponse.cs -
ToolResponseItem.cs -
ContentBlock.cs -
ContentType.cs -
BuiltinToolResult.cs
-
- Move these files from
AiStudio4/Core/Exceptions/toAiStudio4.Core/Exceptions/:-
McpCommunicationException.cs
-
- Create
AiStudio4.Core/Helpers/PathHelper.cs(extract path-related methods)
- Move
AiStudio4/Services/McpService.cstoAiStudio4.Core/Services/ - Update namespace to
AiStudio4.Core.Services - Update all imports
- Move these files to
AiStudio4.Core/Tools/:-
BaseToolImplementation.cs -
ToolRequestBuilder.cs -
ToolGuids.cs
-
- Review each tool in
AiStudio4/Core/Tools/and categorize:
Can Move to Core (no UI dependencies):
- File system tools (ReadFilesTool, CreateNewFileTool, etc.)
- Git tools (GitStatusTool, GitCommitTool, etc.)
- Search tools (FileSearchTool, FileRegExSearchTool)
- URL tools (RetrieveTextFromUrlTool)
- Most Azure DevOps tools
- Most GitHub tools
Must Stay in AiStudio4 (UI/WPF dependencies):
- ThinkAndAwaitUserInputTool
- PresentResultsAndAwaitUserInputTool
- WindowsSandboxTool
- Any tools that show dialogs or interact with UI
- For each standalone-compatible tool:
- Move to
AiStudio4.Core/Tools/[Category]/ - Update namespace
- Remove any UI-specific code
- Add logging instead of UI notifications
- Move to
- Create
AiStudio4.Core/Extensions/ServiceCollectionExtensions.cs:
using Microsoft.Extensions.DependencyInjection;
using AiStudio4.Core.Interfaces;
using AiStudio4.Core.Services;
namespace AiStudio4.Core.Extensions
{
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddMcpCore(this IServiceCollection services)
{
services.AddSingleton<IMcpService, McpService>();
return services;
}
public static IServiceCollection AddCoreTools(this IServiceCollection services)
{
// Register all core tools
services.AddTransient<ITool, ReadFilesTool>();
services.AddTransient<ITool, CreateNewFileTool>();
// ... add all other core tools
return services;
}
}
}- Update AiStudio4.csproj target framework to
net9.0-windows
- In AiStudio4.csproj:
<ItemGroup>
<ProjectReference Include="..\AiStudio4.Core\AiStudio4.Core.csproj" />
</ItemGroup>- Update all files that reference moved classes:
- Change
using AiStudio4.Core.Interfacestousing AiStudio4.Core.Interfaces - Update all other namespace references
- Change
- In
AiStudio4/Core/DependencyInjection.cs:
services.AddMcpCore();
services.AddCoreTools();
// Add UI-specific tools
services.AddTransient<ITool, ThinkAndAwaitUserInputTool>();
// ... other UI tools- Create new WPF Application:
AiStudio4.McpManager - Target framework:
net9.0-windows - Add to solution
- In AiStudio4.McpManager.csproj:
<ItemGroup>
<ProjectReference Include="..\AiStudio4.Core\AiStudio4.Core.csproj" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="*" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="*" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="*" />
<PackageReference Include="ModernWpfUI" Version="*" />
<PackageReference Include="Serilog.Extensions.Hosting" Version="*" />
<PackageReference Include="Serilog.Sinks.Console" Version="*" />
<PackageReference Include="Serilog.Sinks.File" Version="*" />
</ItemGroup>- Create
AiStudio4.McpManager/App.xaml:
<Application x:Class="AiStudio4.McpManager.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ui="http://schemas.modernwpf.com/2019">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ui:ThemeResources />
<ui:XamlControlsResources />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>- Create
AiStudio4.McpManager/App.xaml.cs:
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Serilog;
using System.Windows;
using AiStudio4.Core.Extensions;
using AiStudio4.McpManager.Views;
using AiStudio4.McpManager.ViewModels;
using AiStudio4.McpManager.Services;
namespace AiStudio4.McpManager
{
public partial class App : Application
{
private readonly IHost _host;
public App()
{
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Information()
.WriteTo.Console()
.WriteTo.File("logs/mcp-manager-.txt", rollingInterval: RollingInterval.Day)
.CreateLogger();
_host = Host.CreateDefaultBuilder()
.UseSerilog()
.ConfigureServices((context, services) =>
{
// Add configuration service
services.AddSingleton<IConfigurationService, WpfConfigurationService>();
// Add core MCP services
services.AddMcpCore();
services.AddCoreTools();
// Add WPF services
services.AddSingleton<MainWindow>();
services.AddSingleton<MainViewModel>();
services.AddTransient<ServerConfigViewModel>();
services.AddTransient<ToolConfigViewModel>();
// Add application services
services.AddSingleton<IDialogService, WpfDialogService>();
services.AddSingleton<INavigationService, NavigationService>();
})
.Build();
}
protected override async void OnStartup(StartupEventArgs e)
{
await _host.StartAsync();
var mainWindow = _host.Services.GetRequiredService<MainWindow>();
mainWindow.Show();
base.OnStartup(e);
}
protected override async void OnExit(ExitEventArgs e)
{
using (_host)
{
await _host.StopAsync();
}
Log.CloseAndFlush();
base.OnExit(e);
}
}
}- Create
AiStudio4.McpManager/Views/MainWindow.xaml:
<mah:MetroWindow x:Class="AiStudio4.McpManager.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
Title="AiStudio4 MCP Manager" Height="600" Width="900">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Toolbar -->
<ToolBar Grid.Row="0">
<Button Command="{Binding AddServerCommand}" Content="Add Server" />
<Button Command="{Binding RefreshCommand}" Content="Refresh" />
<Separator />
<Button Command="{Binding ConfigureToolsCommand}" Content="Configure Tools" />
</ToolBar>
<!-- Main Content -->
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="300"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- Server List -->
<GroupBox Grid.Column="0" Header="MCP Servers" Margin="5">
<ListBox ItemsSource="{Binding Servers}"
SelectedItem="{Binding SelectedServer}">
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderBrush="LightGray" BorderThickness="0,0,0,1" Padding="5">
<StackPanel>
<TextBlock Text="{Binding Name}" FontWeight="Bold"/>
<TextBlock Text="{Binding Command}" Foreground="Gray" FontSize="11"/>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Status: " FontSize="11"/>
<TextBlock Text="{Binding Status}"
Foreground="{Binding StatusColor}"
FontSize="11"/>
</StackPanel>
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</GroupBox>
<!-- Server Details -->
<GroupBox Grid.Column="1" Header="Server Details" Margin="5">
<ScrollViewer>
<ContentControl Content="{Binding SelectedServerView}"/>
</ScrollViewer>
</GroupBox>
</Grid>
</Grid>
</mah:MetroWindow>- Create
AiStudio4.McpManager/ViewModels/MainViewModel.cs - Create
AiStudio4.McpManager/ViewModels/ServerViewModel.cs - Create
AiStudio4.McpManager/ViewModels/ToolConfigViewModel.cs - Create
AiStudio4.McpManager/ViewModels/ToolPropertyViewModel.cs
- Create
AiStudio4.McpManager/Views/ToolConfigurationDialog.xaml - Create corresponding view model and code-behind
- Create
AiStudio4.McpManager/Views/ToolExtraPropertiesDialog.xaml - Create corresponding view model and code-behind
- Create
AiStudio4.Core/Interfaces/IConfigurationService.cs
- Move
AiStudio4/InjectedDependencies/BuiltInToolExtraPropertiesService.cstoAiStudio4.Core/Services/ - Update to use IConfigurationService for paths
- Create
AiStudio4.McpManager/Services/WpfConfigurationService.cs
- Create
AiStudio4.McpManager/Services/WpfDialogService.cs - Implement IDialogService interface
- Create
AiStudio4.McpManager/Views/ServerDetailsView.xaml - Create corresponding view model
- Create server configuration dialog
- Create input dialog for simple text input
- Create confirmation dialogs
- Create
AiStudio4.McpManager/Views/MainWindow.xaml.cs
- Ensure both apps use the same configuration directory
- Verify both apps read/write to the same files:
-
builtinToolExtraProps.json -
mcpServers.json - Configuration path:
%APPDATA%/AiStudio4/Config/
-
- Ensure both apps read/write to the same mcpServers.json file
- Test that changes in one app are reflected in the other
- Verify tool extra properties are shared
- Verify all moved tools work in both applications
- Test MCP server connections from both apps
- Validate tool extra properties configuration
- Run the MCP Manager standalone
- Test server management (add, edit, delete, start, stop)
- Test tool configuration UI
- Verify all tools are accessible through UI
- Test all dialog boxes and forms
- Verify MVVM patterns work correctly
- Test data binding and commands
- Modify build_and_release.ps1 to build both projects
- Create separate release packages for each
- Structure release packages:
AiStudio4-Release/
├── AiStudio4.exe # Main app
├── AiStudio4.Core.dll # Shared library
└── Other dependencies...
AiStudio4.McpManager-Release/
├── AiStudio4.McpManager.exe # MCP Manager
├── AiStudio4.Core.dll # Shared library
└── Other dependencies...
- Ensure both projects build correctly
- Test release builds
- Path Compatibility: Ensure PathHelper works correctly in both apps
- Logging: Both apps should log to separate files
- Tool Discovery: Implement proper tool registration in both apps
- Error Handling: Ensure UI-specific error handling is isolated
- Configuration Sharing: Use the same config file locations
- Version Synchronization: Keep both apps version-synchronized
- All core interfaces moved to AiStudio4.Core
- All shared models moved to AiStudio4.Core
- MCP service extracted to core library
- Standalone-compatible tools moved to core
- Service registration extensions created
- Main app updated to use shared core
- WPF MCP Manager application created
- Tool configuration UI implemented
- Shared configuration working between apps
- All tests passing
- Build scripts updated
- Documentation updated
After implementation:
- Update documentation for both applications
- Create separate README files
- Update CI/CD pipelines
- Plan migration strategy for existing users
- Create user guides for the new MCP Manager