$ErrorActionPreference = "Stop" Set-StrictMode -Version Latest $repo = (Resolve-Path -LiteralPath (Join-Path $PSScriptRoot "..")).Path $expectedTools = @( "win_helper_version", "win_helper_self_check", "win_helper_scan_windows", "win_helper_dump_uia" ) $tempRoot = Join-Path ([System.IO.Path]::GetTempPath()) ("isphere-go-mcp-verify-" + [guid]::NewGuid().ToString("N")) $goMcpExe = Join-Path $tempRoot "isphere-mcp.exe" $harnessDir = Join-Path $repo ("runs\go-mcp-harness-" + [guid]::NewGuid().ToString("N")) $harnessMain = Join-Path $harnessDir "main.go" function Assert-True([bool]$Condition, [string]$Message) { if (-not $Condition) { throw $Message } } function Invoke-Step([string]$Name, [scriptblock]$Body) { Write-Host "## $Name" & $Body } try { New-Item -ItemType Directory -Force -Path $tempRoot | Out-Null New-Item -ItemType Directory -Force -Path $harnessDir | Out-Null Push-Location $repo try { Invoke-Step "build C# helper" { & powershell -NoProfile -ExecutionPolicy Bypass -File (Join-Path $repo "scripts\build-win-helper.ps1") | Out-Host if ($LASTEXITCODE -ne 0) { throw "build-win-helper.ps1 failed with exit code $LASTEXITCODE" } } Invoke-Step "build Go MCP binary" { & go build -o $goMcpExe ./cmd/isphere-mcp if ($LASTEXITCODE -ne 0) { throw "go build ./cmd/isphere-mcp failed with exit code $LASTEXITCODE" } Assert-True (Test-Path -LiteralPath $goMcpExe) "Go MCP binary was not created: $goMcpExe" } } finally { Pop-Location } Invoke-Step "write temporary SDK harness" { @" package main import ( "context" "encoding/json" "fmt" "os" "reflect" "sort" "strings" "time" "github.com/modelcontextprotocol/go-sdk/mcp" "isphere-ai-bridge/internal/mcpserver" ) var expectedTools = []string{ "win_helper_version", "win_helper_self_check", "win_helper_scan_windows", "win_helper_dump_uia", } var forbiddenTerms = []string{"send", "search", "file", "login", "conversation", "upload", "download", "receive", "autologin"} func main() { ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) defer cancel() serverTransport, clientTransport := mcp.NewInMemoryTransports() server := mcpserver.NewServer() serverErr := make(chan error, 1) go func() { serverErr <- server.Run(ctx, serverTransport) }() client := mcp.NewClient(&mcp.Implementation{Name: "verify-go-mcp", Version: "0.1.0"}, nil) session, err := client.Connect(ctx, clientTransport, nil) if err != nil { fail("initialize/connect", err) } defer func() { _ = session.Close() cancel() select { case <-serverErr: case <-time.After(2 * time.Second): fail("server shutdown", fmt.Errorf("server did not stop")) } }() listResult, err := session.ListTools(ctx, &mcp.ListToolsParams{}) if err != nil { fail("tools/list", err) } toolNames := make([]string, 0, len(listResult.Tools)) for _, tool := range listResult.Tools { toolNames = append(toolNames, tool.Name) lower := strings.ToLower(tool.Name) for _, term := range forbiddenTerms { if strings.Contains(lower, term) { fail("tools/list", fmt.Errorf("forbidden action term %q found in tool %q", term, tool.Name)) } } } sort.Strings(toolNames) want := append([]string(nil), expectedTools...) sort.Strings(want) if len(toolNames) != 4 || !reflect.DeepEqual(toolNames, want) { fail("tools/list", fmt.Errorf("tool names = %#v, want %#v", toolNames, want)) } callResult, err := session.CallTool(ctx, &mcp.CallToolParams{Name: "win_helper_version", Arguments: map[string]any{}}) if err != nil { fail("tools/call win_helper_version", err) } if callResult.IsError { fail("tools/call win_helper_version", fmt.Errorf("tool returned isError=true: %#v", callResult.Content)) } structured, ok := callResult.StructuredContent.(map[string]any) if !ok { payload, _ := json.Marshal(callResult.StructuredContent) if err := json.Unmarshal(payload, &structured); err != nil { fail("tools/call win_helper_version", fmt.Errorf("structuredContent was not object: %T", callResult.StructuredContent)) } } if structured["ok"] != true { fail("tools/call win_helper_version", fmt.Errorf("ok = %#v, want true", structured["ok"])) } data, ok := structured["data"].(map[string]any) if !ok { fail("tools/call win_helper_version", fmt.Errorf("data missing or not object: %#v", structured["data"])) } helperName, _ := data["helper_name"].(string) if helperName != "ISphereWinHelper" { fail("tools/call win_helper_version", fmt.Errorf("helper_name = %q, want ISphereWinHelper", helperName)) } result := map[string]any{ "ok": true, "transport": "sdk_in_memory", "initialized": true, "tool_count": len(toolNames), "tools": toolNames, "helper_name": helperName, "real_isphere_login_required": false, "python_runtime_required": false, "action_tools_present": false, } encoded, _ := json.Marshal(result) fmt.Println(string(encoded)) } func fail(step string, err error) { payload, _ := json.Marshal(map[string]any{"ok": false, "step": step, "error": err.Error()}) fmt.Fprintln(os.Stderr, string(payload)) os.Exit(1) } "@ | Set-Content -LiteralPath $harnessMain -Encoding UTF8 } $harnessJson = $null Invoke-Step "run MCP SDK harness initialize/tools/list/tools/call" { Push-Location $harnessDir try { $output = & go run . if ($LASTEXITCODE -ne 0) { throw "go run SDK harness failed with exit code $LASTEXITCODE" } $output | ForEach-Object { Write-Host $_ } $lastLine = @($output | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }) | Select-Object -Last 1 $script:harnessJson = $lastLine | ConvertFrom-Json } finally { Pop-Location } } Assert-True ($script:harnessJson.ok -eq $true) "SDK harness did not return ok=true" Assert-True ($script:harnessJson.helper_name -eq "ISphereWinHelper") "SDK harness helper_name mismatch: $($script:harnessJson.helper_name)" Assert-True ($script:harnessJson.tool_count -eq 4) "SDK harness tool_count mismatch: $($script:harnessJson.tool_count)" [ordered]@{ ok = $true verification = "go_mcp_sdk_harness" go_mcp_binary_built = (Test-Path -LiteralPath $goMcpExe) helper_name = $script:harnessJson.helper_name tool_count = $script:harnessJson.tool_count tools = $script:harnessJson.tools python_runtime_required = $false real_isphere_login_required = $false action_tools_present = $false } | ConvertTo-Json -Depth 8 -Compress } finally { if (Test-Path -LiteralPath $tempRoot) { Remove-Item -LiteralPath $tempRoot -Recurse -Force } if (Test-Path -LiteralPath $harnessDir) { Remove-Item -LiteralPath $harnessDir -Recurse -Force } }