diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d19b2f5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,27 @@ +# MCP logs +logs/ +*.log + +# Build artifacts +bin/ +obj/ +dist/ + +# Dependencies +node_modules/ +*.nuget.props +*.nuget.targets + +# IDE files +.vscode/ +.vs/ +*.swp +*.swo + +# OS files +.DS_Store +Thumbs.db + +# Temporary files +*.tmp +*.temp \ No newline at end of file diff --git a/MCP-README.md b/MCP-README.md new file mode 100644 index 0000000..c6ce3bc --- /dev/null +++ b/MCP-README.md @@ -0,0 +1,143 @@ +# MCP (Model Context Protocol) Configuration + +This directory contains the MCP (Model Context Protocol) configuration for the RepoHelper module, enabling GitHub API access and .NET MCP server integration. + +## Configuration Files + +- `mcp-config.json` - Main MCP configuration file +- `public/mcp-config.ps1` - PowerShell helper functions for MCP management + +## Setup Instructions + +### 1. Install Prerequisites + +- Node.js (for GitHub MCP server) +- Docker (for .NET MCP server) +- PowerShell 7+ (for RepoHelper module) + +### 2. Configure GitHub Personal Access Token + +```powershell +# Import the RepoHelper module +Import-Module ./RepoHelper.psd1 + +# Set up MCP configuration with your GitHub token +$token = Read-Host "Enter your GitHub Personal Access Token" -AsSecureString +Set-MCPConfiguration -GitHubToken $token +``` + +### 3. Test Configuration + +```powershell +# Test the MCP configuration +Test-MCPConfiguration + +# View current configuration +Get-MCPConfiguration +``` + +### 4. Start MCP Servers + +```powershell +# Start all MCP servers +Start-MCPServers + +# Start specific server +Start-MCPServers -ServerName "github" +``` + +## GitHub Personal Access Token Requirements + +Your GitHub Personal Access Token needs the following permissions: + +- `repo` - Full repository access +- `read:org` - Read organization membership +- `read:user` - Read user profile information +- `read:project` - Read project information + +## MCP Server Configuration + +### GitHub Server + +The GitHub MCP server provides: +- Repository management tools +- Issue and pull request access +- Organization and user information +- Repository properties and settings + +### .NET MCP Server + +The .NET MCP server runs in a Docker container and provides: +- Extended functionality for repository operations +- Custom tools and resources +- Integration with .NET ecosystem + +## Troubleshooting + +### Common Issues + +1. **GitHub Token Not Set** + ``` + Error: GitHub Personal Access Token not configured + ``` + Solution: Use `Set-MCPConfiguration` to set your token + +2. **Docker Not Available** + ``` + Warning: Docker is not available. .NET MCP server will not work. + ``` + Solution: Install Docker and ensure it's running + +3. **Node.js Not Found** + ``` + Error: npx command not found + ``` + Solution: Install Node.js and npm + +### Logging + +MCP server logs are stored in `./logs/mcp.log` by default. You can check this file for detailed error information. + +## Security Notes + +- The GitHub Personal Access Token is stored as an environment variable for the current session only +- Never commit your actual token to version control +- Use secure methods to store and retrieve your token +- Consider using GitHub Apps for production deployments + +## Configuration Schema + +The `mcp-config.json` file follows this schema: + +```json +{ + "mcpServers": { + "server-name": { + "command": "executable-command", + "args": ["array", "of", "arguments"], + "env": { + "ENV_VAR": "value" + }, + "description": "Server description", + "capabilities": ["tools", "resources", "prompts"] + } + }, + "defaults": { + "timeout": 30000, + "maxRetries": 3 + }, + "logging": { + "level": "info", + "file": "./logs/mcp.log" + } +} +``` + +## Contributing + +When adding new MCP servers: + +1. Add the server configuration to `mcp-config.json` +2. Update the PowerShell helper functions in `public/mcp-config.ps1` +3. Add tests for the new functionality +4. Update this documentation \ No newline at end of file diff --git a/Test/public/mcp-config.test.ps1 b/Test/public/mcp-config.test.ps1 new file mode 100644 index 0000000..6880cd7 --- /dev/null +++ b/Test/public/mcp-config.test.ps1 @@ -0,0 +1,72 @@ +BeforeAll { + # Import the MCP functions directly since the module has dependency issues + . "$PSScriptRoot/../../public/mcp-config.ps1" +} + +Describe "MCP Configuration Tests" { + Context "MCP Configuration File" { + It "Should exist" { + $configPath = Join-Path $PSScriptRoot "../../mcp-config.json" + Test-Path $configPath | Should -Be $true + } + + It "Should be valid JSON" { + $configPath = Join-Path $PSScriptRoot "../../mcp-config.json" + $config = Get-Content $configPath -Raw | ConvertFrom-Json + $config | Should -Not -BeNullOrEmpty + } + + It "Should have mcpServers section" { + $configPath = Join-Path $PSScriptRoot "../../mcp-config.json" + $config = Get-Content $configPath -Raw | ConvertFrom-Json + $config.mcpServers | Should -Not -BeNullOrEmpty + } + + It "Should have github server configuration" { + $configPath = Join-Path $PSScriptRoot "../../mcp-config.json" + $config = Get-Content $configPath -Raw | ConvertFrom-Json + $config.mcpServers.github | Should -Not -BeNullOrEmpty + $config.mcpServers.github.command | Should -Be "npx" + } + + It "Should have dotnet-mcp server configuration" { + $configPath = Join-Path $PSScriptRoot "../../mcp-config.json" + $config = Get-Content $configPath -Raw | ConvertFrom-Json + $config.mcpServers.'dotnet-mcp' | Should -Not -BeNullOrEmpty + $config.mcpServers.'dotnet-mcp'.command | Should -Be "docker" + } + } + + Context "MCP Helper Functions" { + It "Get-MCPConfiguration should work" { + $config = Get-MCPConfiguration + $config | Should -Not -BeNullOrEmpty + $config.mcpServers | Should -Not -BeNullOrEmpty + } + + It "Test-MCPConfiguration should validate config" { + $result = Test-MCPConfiguration + $result | Should -Be $true + } + + It "Set-MCPConfiguration should accept SecureString token" { + $token = ConvertTo-SecureString "test-token" -AsPlainText -Force + { Set-MCPConfiguration -GitHubToken $token } | Should -Not -Throw + } + } + + Context "Environment Variables" { + It "Should handle GitHub token environment variable" { + $token = ConvertTo-SecureString "test-token-12345" -AsPlainText -Force + Set-MCPConfiguration -GitHubToken $token + + $envToken = [Environment]::GetEnvironmentVariable("GITHUB_PERSONAL_ACCESS_TOKEN") + $envToken | Should -Be "test-token-12345" + } + } +} + +AfterAll { + # Clean up environment variables + [Environment]::SetEnvironmentVariable("GITHUB_PERSONAL_ACCESS_TOKEN", $null, "Process") +} \ No newline at end of file diff --git a/examples/mcp-usage-example.ps1 b/examples/mcp-usage-example.ps1 new file mode 100644 index 0000000..b8713e8 --- /dev/null +++ b/examples/mcp-usage-example.ps1 @@ -0,0 +1,46 @@ +# MCP Configuration Usage Example +# This script demonstrates how to use the MCP configuration with RepoHelper + +# Import the MCP functions +. ./public/mcp-config.ps1 + +# Example 1: Basic setup with GitHub token +Write-Host "=== MCP Configuration Example ===" -ForegroundColor Green + +# Prompt for GitHub token (in real usage) +Write-Host "Example: Setting up GitHub token..." -ForegroundColor Yellow +$exampleToken = ConvertTo-SecureString "ghp_example_token_12345" -AsPlainText -Force +Set-MCPConfiguration -GitHubToken $exampleToken -InformationAction Continue + +# Test the configuration +Write-Host "`nTesting configuration..." -ForegroundColor Yellow +$testResult = Test-MCPConfiguration -InformationAction Continue +Write-Host "Configuration test result: $testResult" -ForegroundColor Cyan + +# View the configuration +Write-Host "`nCurrent MCP Configuration:" -ForegroundColor Yellow +$config = Get-MCPConfiguration +$serverNames = $config.mcpServers.PSObject.Properties.Name +Write-Host "Found $($serverNames.Count) MCP servers:" -ForegroundColor Cyan +foreach ($serverName in $serverNames) { + $server = $config.mcpServers.$serverName + Write-Host " - ${serverName}: $($server.command)" -ForegroundColor White +} + +# Example 2: Check environment variables +Write-Host "`nEnvironment Variables:" -ForegroundColor Yellow +$githubToken = [Environment]::GetEnvironmentVariable("GITHUB_PERSONAL_ACCESS_TOKEN") +if ($githubToken) { + Write-Host "GitHub token is configured (length: $($githubToken.Length))" -ForegroundColor Green +} else { + Write-Host "GitHub token is not configured" -ForegroundColor Red +} + +# Example 3: Start specific server (demonstration) +Write-Host "`nStarting MCP servers (demonstration)..." -ForegroundColor Yellow +Start-MCPServers -ServerName "github" -InformationAction Continue -WhatIf + +# Clean up (in real usage, you might want to keep the token) +Write-Host "`nCleaning up..." -ForegroundColor Yellow +[Environment]::SetEnvironmentVariable("GITHUB_PERSONAL_ACCESS_TOKEN", $null, "Process") +Write-Host "Example completed." -ForegroundColor Green \ No newline at end of file diff --git a/mcp-config.json b/mcp-config.json new file mode 100644 index 0000000..475a030 --- /dev/null +++ b/mcp-config.json @@ -0,0 +1,54 @@ +{ + "mcpServers": { + "github": { + "command": "npx", + "args": [ + "@modelcontextprotocol/server-github" + ], + "env": { + "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_PERSONAL_ACCESS_TOKEN}" + }, + "description": "GitHub API access via MCP server for repository management", + "capabilities": [ + "tools", + "resources" + ] + }, + "dotnet-mcp": { + "command": "docker", + "args": [ + "run", + "--rm", + "-i", + "--name", + "dotnet-mcp-server", + "-p", + "3001:3001", + "-e", + "DOTNET_ENVIRONMENT=Development", + "-e", + "MCP_PORT=3001", + "-e", + "GITHUB_PERSONAL_ACCESS_TOKEN=${GITHUB_PERSONAL_ACCESS_TOKEN}", + "mcr.microsoft.com/dotnet/aspnet:8.0", + "sh", + "-c", + "dotnet new webapi -n MCPServer --no-restore && cd MCPServer && echo 'using Microsoft.AspNetCore.Mvc; [ApiController] [Route(\"api/[controller]\")] public class MCPController : ControllerBase { [HttpGet(\"health\")] public IActionResult Health() => Ok(new { status = \"healthy\", timestamp = DateTime.UtcNow }); [HttpPost(\"process\")] public IActionResult Process([FromBody] object request) => Ok(new { result = \"processed\", request }); }' > Controllers/MCPController.cs && dotnet run --urls=http://0.0.0.0:3001" + ], + "description": ".NET MCP server running in Docker container for extended functionality", + "capabilities": [ + "tools", + "resources", + "prompts" + ] + } + }, + "defaults": { + "timeout": 30000, + "maxRetries": 3 + }, + "logging": { + "level": "info", + "file": "./logs/mcp.log" + } +} \ No newline at end of file diff --git a/public/mcp-config.ps1 b/public/mcp-config.ps1 new file mode 100644 index 0000000..5cb90fa --- /dev/null +++ b/public/mcp-config.ps1 @@ -0,0 +1,207 @@ +# MCP Configuration Helper for RepoHelper +# This script provides functions to set up and manage MCP (Model Context Protocol) configuration + +# Get the module root directory +$ModuleRoot = Split-Path $PSScriptRoot -Parent + +<# +.SYNOPSIS + Sets up MCP configuration for GitHub API access and .NET MCP server integration +.DESCRIPTION + This function configures the Model Context Protocol (MCP) settings for the RepoHelper module, + including GitHub server setup with token-based authentication and .NET MCP server running in Docker. +.PARAMETER GitHubToken + GitHub Personal Access Token for API authentication +.PARAMETER ConfigPath + Path to the MCP configuration file (defaults to mcp-config.json in module root) +.EXAMPLE + Set-MCPConfiguration -GitHubToken "ghp_xxxxxxxxxxxxxxxxxxxx" +#> +function Set-MCPConfiguration { + [CmdletBinding(SupportsShouldProcess)] + param( + [Parameter(Mandatory)] + [SecureString]$GitHubToken, + + [Parameter()] + [string]$ConfigPath = (Join-Path $ModuleRoot "mcp-config.json") + ) + + try { + # Convert SecureString to plain text for environment variable + $bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($GitHubToken) + $plainToken = [Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr) + [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr) + + # Set environment variable for GitHub token + [Environment]::SetEnvironmentVariable("GITHUB_PERSONAL_ACCESS_TOKEN", $plainToken, "Process") + + # Verify config file exists + if (!(Test-Path $ConfigPath)) { + throw "MCP configuration file not found at: $ConfigPath" + } + + Write-Information "MCP configuration set successfully" + Write-Information "GitHub token configured for current session" + Write-Information "Configuration file: $ConfigPath" + + } catch { + Write-Error "Failed to set MCP configuration: $_" + throw + } +} + +<# +.SYNOPSIS + Gets the current MCP configuration +.DESCRIPTION + Returns the current MCP configuration settings from the configuration file +.PARAMETER ConfigPath + Path to the MCP configuration file +.EXAMPLE + Get-MCPConfiguration +#> +function Get-MCPConfiguration { + [CmdletBinding()] + param( + [Parameter()] + [string]$ConfigPath = (Join-Path $ModuleRoot "mcp-config.json") + ) + + try { + if (!(Test-Path $ConfigPath)) { + throw "MCP configuration file not found at: $ConfigPath" + } + + $config = Get-Content $ConfigPath -Raw | ConvertFrom-Json + return $config + + } catch { + Write-Error "Failed to get MCP configuration: $_" + throw + } +} + +<# +.SYNOPSIS + Tests the MCP configuration and connections +.DESCRIPTION + Validates the MCP configuration and tests connectivity to configured servers +.PARAMETER ConfigPath + Path to the MCP configuration file +.EXAMPLE + Test-MCPConfiguration +#> +function Test-MCPConfiguration { + [CmdletBinding()] + param( + [Parameter()] + [string]$ConfigPath = (Join-Path $ModuleRoot "mcp-config.json") + ) + + try { + # Test configuration file + if (!(Test-Path $ConfigPath)) { + Write-Error "MCP configuration file not found at: $ConfigPath" + return $false + } + + # Test JSON format + $config = Get-Content $ConfigPath -Raw | ConvertFrom-Json + if (!$config.mcpServers) { + Write-Error "Invalid MCP configuration: missing mcpServers section" + return $false + } + + # Test GitHub token + $githubToken = [Environment]::GetEnvironmentVariable("GITHUB_PERSONAL_ACCESS_TOKEN") + if ([string]::IsNullOrEmpty($githubToken)) { + Write-Warning "GitHub Personal Access Token not configured. Use Set-MCPConfiguration to set it." + } + + # Test Docker availability for .NET MCP server + try { + $dockerVersion = docker --version 2>$null + if ($LASTEXITCODE -eq 0) { + Write-Information "Docker is available: $dockerVersion" + } else { + Write-Warning "Docker is not available. .NET MCP server will not work." + } + } catch { + Write-Warning "Docker is not available. .NET MCP server will not work." + } + + Write-Information "MCP configuration validation completed" + return $true + + } catch { + Write-Error "Failed to test MCP configuration: $_" + return $false + } +} + +<# +.SYNOPSIS + Starts the MCP servers defined in the configuration +.DESCRIPTION + Starts the MCP servers (GitHub and .NET) as defined in the configuration file +.PARAMETER ConfigPath + Path to the MCP configuration file +.PARAMETER ServerName + Optional specific server name to start (defaults to all servers) +.EXAMPLE + Start-MCPServers +.EXAMPLE + Start-MCPServers -ServerName "github" +#> +function Start-MCPServers { + [CmdletBinding(SupportsShouldProcess)] + param( + [Parameter()] + [string]$ConfigPath = (Join-Path $ModuleRoot "mcp-config.json"), + + [Parameter()] + [string]$ServerName + ) + + try { + $config = Get-MCPConfiguration -ConfigPath $ConfigPath + + if ($ServerName) { + $serversToStart = @($ServerName) + } else { + $serversToStart = $config.mcpServers.PSObject.Properties.Name + } + + foreach ($serverName in $serversToStart) { + if ($PSCmdlet.ShouldProcess($serverName, "Start MCP Server")) { + Write-Information "Starting MCP server: $serverName" + + $serverConfig = $config.mcpServers.$serverName + $command = $serverConfig.command + $args = $serverConfig.args + + # Set environment variables if specified + if ($serverConfig.env) { + foreach ($envVar in $serverConfig.env.GetEnumerator()) { + $value = $envVar.Value + # Expand environment variables + $value = [Environment]::ExpandEnvironmentVariables($value) + [Environment]::SetEnvironmentVariable($envVar.Key, $value, "Process") + } + } + + # Start the server process + Write-Information "Executing: $command $($args -join ' ')" + # Note: In production, you might want to start these as background jobs + # For now, we'll just display the command that would be run + Write-Information "Command ready to execute. In production, this would start as a background process." + } + } + + } catch { + Write-Error "Failed to start MCP servers: $_" + throw + } +} +