mirror of
https://github.com/t8y2/dbx.git
synced 2026-10-19 16:16:45 +00:00
153 lines
6.4 KiB
PowerShell
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
|