Files
dbx/scripts/dbx-mcp-check.ps1

153 lines
6.4 KiB
PowerShell

<#
.SYNOPSIS
Manually verify the dbx-mcp stdio handshake paths on Windows.
.DESCRIPTION
Runs the four paths that matter after the MCP protocol work:
1. bare `server/discover` (no _meta) -> -32601, the legacy fallback signal
2. `initialize` at 2025-11-25 -> legacy stateful session
3. `server/discover` with _meta -> advertises 2026-07-28
4. `tools/call` with no initialize -> served statelessly
.EXAMPLE
.\dbx-mcp-check.ps1 -Binary .\target\debug\dbx-mcp.exe
.EXAMPLE
# against your real DBX connections
.\dbx-mcp-check.ps1 -Binary .\target\debug\dbx-mcp.exe -DataDir "$env:APPDATA\com.dbx.app"
#>
param(
[string]$Binary = ".\target\debug\dbx-mcp.exe",
[string]$DataDir = "",
[int]$TimeoutMs = 15000
)
$ErrorActionPreference = "Stop"
if (-not (Test-Path $Binary)) {
Write-Error "binary not found: $Binary`nBuild it first:`n cargo build -p dbx-mcp --no-default-features --features sqlite-bundled"
}
$Binary = (Resolve-Path $Binary).Path
$explicitDataDir = [bool]$DataDir
if (-not $DataDir) {
$DataDir = Join-Path $env:TEMP ("dbx-mcp-check-" + [guid]::NewGuid().ToString("N").Substring(0, 8))
New-Item -ItemType Directory -Force -Path $DataDir | Out-Null
}
elseif (-not (Test-Path -LiteralPath $DataDir)) {
Write-Error "data directory does not exist: $DataDir`nPass -DataDir only with a directory that contains dbx.db, or omit it to test with an empty store."
}
elseif (-not (Test-Path -LiteralPath (Join-Path $DataDir "dbx.db")) -and -not (Test-Path -LiteralPath (Join-Path $DataDir "storage.db"))) {
Write-Warning "no dbx.db found in $DataDir; dbx_list_connections may report no connections"
}
$DataDir = (Resolve-Path -LiteralPath $DataDir).Path
$env:DBX_DATA_DIR = $DataDir
$env:RUST_LOG = "warn"
$meta = @{
"io.modelcontextprotocol/protocolVersion" = "2026-07-28"
"io.modelcontextprotocol/clientInfo" = @{ name = "manual-check"; version = "0" }
"io.modelcontextprotocol/clientCapabilities" = @{}
}
$failures = New-Object System.Collections.Generic.List[string]
$proc = $null
function Invoke-Mcp {
param([hashtable]$Message, [switch]$NoReply)
$line = ($Message | ConvertTo-Json -Depth 12 -Compress)
$proc.StandardInput.WriteLine($line)
$proc.StandardInput.Flush()
if ($NoReply) { return $null }
$read = $proc.StandardOutput.ReadLineAsync()
if (-not $read.Wait($TimeoutMs)) {
$proc.Kill()
throw "timed out waiting for a reply to '$($Message.method)'; stderr: $($proc.StandardError.ReadToEnd())"
}
return ($read.Result | ConvertFrom-Json)
}
function Invoke-Request {
param([int]$Id, [string]$Method, [hashtable]$Params)
$paramsJson = ($Params | ConvertTo-Json -Depth 12 -Compress)
if (-not $paramsJson -or $paramsJson -eq "{}") { $paramsJson = "{}" }
$raw = "{`"jsonrpc`":`"2.0`",`"id`":$Id,`"method`":`"$Method`",`"params`":$paramsJson}"
$proc.StandardInput.WriteLine($raw)
$proc.StandardInput.Flush()
$read = $proc.StandardOutput.ReadLineAsync()
if (-not $read.Wait($TimeoutMs)) {
$proc.Kill()
throw "timed out waiting for '$Method'; stderr: $($proc.StandardError.ReadToEnd())"
}
return ($read.Result | ConvertFrom-Json)
}
function Invoke-Notification {
param([string]$Method)
$proc.StandardInput.WriteLine("{`"jsonrpc`":`"2.0`",`"method`":`"$Method`"}")
$proc.StandardInput.Flush()
}
try {
$proc = New-Object System.Diagnostics.Process
$proc.StartInfo.FileName = $Binary
$proc.StartInfo.UseShellExecute = $false
$proc.StartInfo.RedirectStandardInput = $true
$proc.StartInfo.RedirectStandardOutput = $true
$proc.StartInfo.RedirectStandardError = $true
$proc.StartInfo.CreateNoWindow = $true
[void]$proc.Start()
# 1. Bare discovery probe: agents older than the final 2026 lifecycle read
# -32601 as "this server is legacy, use initialize".
$bare = Invoke-Request -Id 1 -Method "server/discover" -Params @{}
$code = $bare.error.code
Write-Host "[1] bare server/discover -> error $code (expected -32601)"
if ($code -ne -32601) { $failures.Add("bare probe returned $code, expected -32601") }
# 2. Legacy initialize still negotiates a pre-2026 version.
$init = Invoke-Request -Id 2 -Method "initialize" -Params @{
protocolVersion = "2025-11-25"
capabilities = @{}
clientInfo = @{ name = "manual-check"; version = "0" }
}
$version = $init.result.protocolVersion
$server = $init.result.serverInfo.name
Write-Host "[2] initialize 2025-11-25 -> protocolVersion=$version serverInfo=$server"
if ($version -ne "2025-11-25" -or $server -ne "dbx") { $failures.Add("legacy initialize returned $($init | ConvertTo-Json -Compress)") }
Invoke-Notification -Method "notifications/initialized"
$tools = (Invoke-Request -Id 3 -Method "tools/list" -Params @{}).result.tools
Write-Host " legacy tools/list -> $($tools.Count) tools"
if (-not $tools -or $tools.Count -eq 0) { $failures.Add("legacy tools/list returned no tools") }
# 3. A well-formed probe must reach the SDK and advertise 2026-07-28.
$discover = Invoke-Request -Id 4 -Method "server/discover" -Params @{ _meta = $meta }
$versions = $discover.result.supportedVersions
Write-Host "[3] server/discover + _meta -> versions=$($versions -join ', ')"
$infoName = $discover.result._meta."io.modelcontextprotocol/serverInfo".name
Write-Host " serverInfo=$infoName ttlMs=$($discover.result.ttlMs) cacheScope=$($discover.result.cacheScope)"
if ($versions -notcontains "2026-07-28") { $failures.Add("discovery did not advertise 2026-07-28") }
# 4. Stateless tools/call: no initialize at all, metadata per request.
$call = Invoke-Request -Id 5 -Method "tools/call" -Params @{
name = "dbx_list_connections"
arguments = @{}
_meta = $meta
}
$text = $call.result.content[0].text
Write-Host "[4] stateless tools/call -> isError=$($call.result.isError) text='$($text -replace "`r?`n", ' ')'"
if ($call.result.isError) { $failures.Add("stateless tools/call failed: $($call | ConvertTo-Json -Compress)") }
}
finally {
if ($proc) {
try { if (-not $proc.HasExited) { $proc.Kill() } } catch { }
}
}
if ($failures.Count -gt 0) {
Write-Host "`nFAILED:" -ForegroundColor Red
$failures | ForEach-Object { Write-Host " - $_" -ForegroundColor Red }
exit 1
}
Write-Host "`nAll checks passed." -ForegroundColor Green
exit 0