@@ -137,24 +137,185 @@ jobs:
137137
138138 Write-Host "`n=== All tests passed ===" -ForegroundColor Green
139139
140- - name : Test Proxy startup
140+ - name : Test Proxy JSON-RPC communication
141141 shell : pwsh
142142 run : |
143143 $ErrorActionPreference = "Stop"
144144
145- Write-Host "=== Testing Proxy ===" -ForegroundColor Cyan
145+ Write-Host "=== Testing Proxy JSON-RPC ===" -ForegroundColor Cyan
146146 $proxyPath = Get-MCPProxyPath
147147
148+ # Start Proxy process with redirected stdin/stdout
149+ $psi = [System.Diagnostics.ProcessStartInfo]::new()
150+ $psi.FileName = $proxyPath
151+ $psi.RedirectStandardInput = $true
152+ $psi.RedirectStandardOutput = $true
153+ $psi.RedirectStandardError = $true
154+ $psi.UseShellExecute = $false
155+ $psi.CreateNoWindow = $true
156+
157+ $process = [System.Diagnostics.Process]::Start($psi)
158+
159+ function Send-JsonRpc {
160+ param([string]$Json)
161+ $process.StandardInput.WriteLine($Json)
162+ $process.StandardInput.Flush()
163+ Start-Sleep -Milliseconds 500
164+
165+ # Read available output
166+ $output = ""
167+ while ($process.StandardOutput.Peek() -ge 0) {
168+ $output += [char]$process.StandardOutput.Read()
169+ }
170+ return $output
171+ }
172+
173+ try {
174+ # Test 1: Initialize
175+ Write-Host "`n=== Test 1: Initialize ===" -ForegroundColor Yellow
176+ $initRequest = '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}'
177+ $response = Send-JsonRpc $initRequest
178+ Write-Host "Response: $response"
179+
180+ if ($response -match '"protocolVersion"') {
181+ Write-Host "Initialize: PASSED" -ForegroundColor Green
182+ } else {
183+ throw "Initialize failed - no protocolVersion in response"
184+ }
185+
186+ # Send initialized notification
187+ $process.StandardInput.WriteLine('{"jsonrpc":"2.0","method":"notifications/initialized"}')
188+ $process.StandardInput.Flush()
189+ Start-Sleep -Milliseconds 200
190+
191+ # Test 2: List tools
192+ Write-Host "`n=== Test 2: List Tools ===" -ForegroundColor Yellow
193+ $listRequest = '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}'
194+ $response = Send-JsonRpc $listRequest
195+ Write-Host "Response: $response"
196+
197+ if ($response -match '"get_current_location"' -and $response -match '"invoke_expression"' -and $response -match '"start_powershell_console"') {
198+ Write-Host "List Tools: PASSED" -ForegroundColor Green
199+ } else {
200+ throw "List Tools failed - expected tools not found"
201+ }
202+
203+ Write-Host "`n=== All JSON-RPC tests passed ===" -ForegroundColor Green
204+
205+ } finally {
206+ if (-not $process.HasExited) {
207+ $process.Kill()
208+ }
209+ $process.Dispose()
210+ }
211+
212+ - name : Test Named Pipe communication
213+ shell : pwsh
214+ run : |
215+ $ErrorActionPreference = "Stop"
216+
217+ Write-Host "=== Testing Named Pipe Communication ===" -ForegroundColor Cyan
218+
219+ # Start a background pwsh process with PowerShell.MCP imported
220+ Write-Host "Starting background pwsh with PowerShell.MCP..."
221+ $bgPsi = [System.Diagnostics.ProcessStartInfo]::new()
222+ $bgPsi.FileName = "pwsh"
223+ $bgPsi.Arguments = "-NoProfile -NoExit -Command `"Import-Module PowerShell.MCP; while (`$true) { Start-Sleep -Seconds 1 }`""
224+ $bgPsi.UseShellExecute = $false
225+ $bgPsi.CreateNoWindow = $true
226+ $bgPsi.RedirectStandardInput = $true
227+ $bgPsi.RedirectStandardOutput = $true
228+ $bgPsi.RedirectStandardError = $true
229+
230+ $bgProcess = [System.Diagnostics.Process]::Start($bgPsi)
231+ Write-Host "Background pwsh PID: $($bgProcess.Id)"
232+
233+ # Wait for Named Pipe server to be ready
234+ Write-Host "Waiting for Named Pipe server..."
235+ $pipeName = "PowerShell.MCP.$($bgProcess.Id)"
236+ $pipeReady = $false
237+ for ($i = 0; $i -lt 30; $i++) {
238+ Start-Sleep -Milliseconds 500
239+ if ($IsWindows) {
240+ $pipeReady = Test-Path "\\.\pipe\$pipeName"
241+ } else {
242+ $pipeReady = Test-Path "/tmp/CoreFxPipe_$pipeName"
243+ }
244+ if ($pipeReady) {
245+ Write-Host "Named Pipe ready after $($i * 500)ms"
246+ break
247+ }
248+ }
249+
250+ if (-not $pipeReady) {
251+ $bgProcess.Kill()
252+ throw "Named Pipe server did not start within 15 seconds"
253+ }
254+
255+ # Start Proxy
148256 Write-Host "Starting Proxy..."
149- $process = Start-Process -FilePath $proxyPath -PassThru
257+ $proxyPath = Get-MCPProxyPath
258+ $psi = [System.Diagnostics.ProcessStartInfo]::new()
259+ $psi.FileName = $proxyPath
260+ $psi.RedirectStandardInput = $true
261+ $psi.RedirectStandardOutput = $true
262+ $psi.RedirectStandardError = $true
263+ $psi.UseShellExecute = $false
264+ $psi.CreateNoWindow = $true
150265
151- Start-Sleep -Seconds 2
266+ $process = [System.Diagnostics.Process]::Start($psi)
152267
153- if ($process.HasExited) {
154- Write-Host "Proxy exited with code: $($process.ExitCode)" -ForegroundColor Red
155- throw "Proxy exited unexpectedly"
156- } else {
157- Write-Host "Proxy is running (PID: $($process.Id))" -ForegroundColor Green
158- Stop-Process -Id $process.Id -Force
159- Write-Host "Proxy stopped successfully" -ForegroundColor Green
268+ function Send-JsonRpc {
269+ param([string]$Json, [int]$WaitMs = 2000)
270+ $process.StandardInput.WriteLine($Json)
271+ $process.StandardInput.Flush()
272+ Start-Sleep -Milliseconds $WaitMs
273+
274+ $output = ""
275+ while ($process.StandardOutput.Peek() -ge 0) {
276+ $output += [char]$process.StandardOutput.Read()
277+ }
278+ return $output
279+ }
280+
281+ try {
282+ # Initialize
283+ $initRequest = '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}'
284+ $null = Send-JsonRpc $initRequest
285+ $process.StandardInput.WriteLine('{"jsonrpc":"2.0","method":"notifications/initialized"}')
286+ $process.StandardInput.Flush()
287+ Start-Sleep -Milliseconds 200
288+
289+ # Test: invoke_expression with Get-Date
290+ Write-Host "`n=== Test: invoke_expression (Get-Date) ===" -ForegroundColor Yellow
291+ $invokeRequest = '{"jsonrpc":"2.0","id":10,"method":"tools/call","params":{"name":"invoke_expression","arguments":{"pipeline":"Get-Date -Format yyyy-MM-dd"}}}'
292+ $response = Send-JsonRpc $invokeRequest 3000
293+ Write-Host "Response: $response"
294+
295+ $today = Get-Date -Format "yyyy-MM-dd"
296+ if ($response -match $today) {
297+ Write-Host "invoke_expression (Get-Date): PASSED - Got today's date" -ForegroundColor Green
298+ } else {
299+ throw "invoke_expression failed - expected date $today not found in response"
300+ }
301+
302+ # Test: get_current_location
303+ Write-Host "`n=== Test: get_current_location ===" -ForegroundColor Yellow
304+ $locRequest = '{"jsonrpc":"2.0","id":11,"method":"tools/call","params":{"name":"get_current_location","arguments":{}}}'
305+ $response = Send-JsonRpc $locRequest 3000
306+ Write-Host "Response: $response"
307+
308+ if ($response -match '"current_location"' -or $response -match '"system"') {
309+ Write-Host "get_current_location: PASSED" -ForegroundColor Green
310+ } else {
311+ throw "get_current_location failed - no location info in response"
312+ }
313+
314+ Write-Host "`n=== All Named Pipe tests passed ===" -ForegroundColor Green
315+
316+ } finally {
317+ if (-not $process.HasExited) { $process.Kill() }
318+ $process.Dispose()
319+ if (-not $bgProcess.HasExited) { $bgProcess.Kill() }
320+ $bgProcess.Dispose()
160321 }
0 commit comments