diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7732715..c3564b9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,14 +1,19 @@ -name: CI +name: Build on: push: branches: [main] pull_request: - branches: [main] + branches: [main, dev] + release: + types: [created, published] + +permissions: + contents: write jobs: build-and-test: - runs-on: ubuntu-latest + runs-on: windows-latest steps: - uses: actions/checkout@v4 @@ -34,3 +39,51 @@ jobs: - name: Run tests run: dotnet test tests/PlanViewer.Core.Tests/PlanViewer.Core.Tests.csproj -c Release --no-build --verbosity normal + + - name: Get version + id: version + shell: pwsh + run: | + $version = ([xml](Get-Content src/PlanViewer.App/PlanViewer.App.csproj)).Project.PropertyGroup.Version | Where-Object { $_ } + echo "VERSION=$version" >> $env:GITHUB_OUTPUT + + - name: Publish App + run: dotnet publish src/PlanViewer.App/PlanViewer.App.csproj -c Release -o publish/App + + - name: Publish CLI + run: dotnet publish src/PlanViewer.Cli/PlanViewer.Cli.csproj -c Release -o publish/Cli + + - name: Package release artifacts + if: github.event_name == 'release' + shell: pwsh + run: | + $version = "${{ steps.version.outputs.VERSION }}" + New-Item -ItemType Directory -Force -Path releases + + # App ZIP + if (Test-Path 'README.md') { Copy-Item 'README.md' 'publish/App/' } + if (Test-Path 'LICENSE') { Copy-Item 'LICENSE' 'publish/App/' } + Compress-Archive -Path 'publish/App/*' -DestinationPath "releases/PerformanceStudio-$version.zip" -Force + + # CLI ZIP + if (Test-Path 'LICENSE') { Copy-Item 'LICENSE' 'publish/Cli/' } + Compress-Archive -Path 'publish/Cli/*' -DestinationPath "releases/PerformanceStudioCli-$version.zip" -Force + + - name: Generate checksums + if: github.event_name == 'release' + shell: pwsh + run: | + $checksums = Get-ChildItem releases/*.zip | ForEach-Object { + $hash = (Get-FileHash $_.FullName -Algorithm SHA256).Hash.ToLower() + "$hash $($_.Name)" + } + $checksums | Out-File -FilePath releases/SHA256SUMS.txt -Encoding utf8 + Write-Host "Checksums:" + $checksums | ForEach-Object { Write-Host $_ } + + - name: Upload release assets + if: github.event_name == 'release' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh release upload ${{ github.event.release.tag_name }} releases/*.zip releases/SHA256SUMS.txt --clobber diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8f8390e..ee7999f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,6 @@ -# Contributing to SQL Performance Studio +# Contributing to Performance Studio -Thank you for your interest in contributing to SQL Performance Studio! This guide will help you get started. +Thank you for your interest in contributing to Performance Studio! This guide will help you get started. ## Reporting Issues diff --git a/README.md b/README.md index f8f3da1..b6d582e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# SQL Performance Studio +# Performance Studio -A cross-platform SQL Server execution plan analyzer. Parses `.sqlplan` XML, identifies performance problems, suggests missing indexes, and provides actionable warnings — from the command line or a desktop GUI. +A cross-platform SQL Server execution plan analyzer with built-in MCP server for AI-assisted analysis. Parses `.sqlplan` XML, identifies performance problems, suggests missing indexes, and provides actionable warnings — from the command line or a desktop GUI. Built for developers and DBAs who want fast, automated plan analysis without clicking through SSMS. @@ -139,7 +139,7 @@ planview analyze ./queries/ --server sql2022 --database StackOverflow2013 \ ``` Batch mode produces three files per query: -- `query_name.sqlplan` — the raw execution plan XML (openable in SSMS or the SQL Performance Studio GUI) +- `query_name.sqlplan` — the raw execution plan XML (openable in SSMS or the Performance Studio GUI) - `query_name.analysis.json` — structured analysis with warnings, missing indexes, and operator tree - `query_name.analysis.txt` — human-readable text report @@ -240,6 +240,7 @@ Features: - **Copy Repro Script** — extracts parameters, SET options, and query text into a runnable `sp_executesql` script - **Get Actual Plan** — connect to a server and re-execute the query to capture runtime stats - **Query Store Analysis** — connect to a server and analyze top queries by CPU, duration, or reads +- **MCP Server** — built-in Model Context Protocol server for AI-assisted plan analysis (opt-in) - Dark theme ```bash @@ -248,14 +249,14 @@ dotnet run --project src/PlanViewer.App ## SSMS Extension -A VSIX extension that adds **"Open in SQL Performance Studio"** to the execution plan right-click context menu in SSMS 18-22. +A VSIX extension that adds **"Open in Performance Studio"** to the execution plan right-click context menu in SSMS 18-22. ### How it works 1. Right-click on any execution plan in SSMS -2. Click "Open in SQL Performance Studio" +2. Click "Open in Performance Studio" 3. The extension extracts the plan XML via reflection and saves it to a temp file -4. SQL Performance Studio opens with the plan loaded +4. Performance Studio opens with the plan loaded ### Installation @@ -267,13 +268,55 @@ A VSIX extension that adds **"Open in SQL Performance Studio"** to the execution ### First run -On first use, if SQL Performance Studio isn't found automatically, the extension will prompt you to locate `PlanViewer.App.exe`. The path is saved to the registry (`HKCU\SOFTWARE\DarlingData\SQLPerformanceStudio\InstallPath`) so you only need to do this once. +On first use, if Performance Studio isn't found automatically, the extension will prompt you to locate `PlanViewer.App.exe`. The path is saved to the registry (`HKCU\SOFTWARE\DarlingData\SQLPerformanceStudio\InstallPath`) so you only need to do this once. The extension searches for the app in this order: 1. Registry key (set automatically after first browse) 2. System PATH 3. Common install locations (`%LOCALAPPDATA%\Programs\SQLPerformanceStudio\`, `Program Files`, etc.) +## MCP Server (LLM Integration) + +The desktop GUI includes an embedded [Model Context Protocol](https://modelcontextprotocol.io) server that exposes loaded execution plans and Query Store data to LLM clients like Claude Code and Cursor. + +### Setup + +1. Enable the MCP server in `~/.planview/settings.json`: + +```json +{ + "mcp_enabled": true, + "mcp_port": 5152 +} +``` + +2. Register with Claude Code: + +``` +claude mcp add --transport streamable-http --scope user performance-studio http://localhost:5152/ +``` + +3. Open a new Claude Code session and ask questions like: + - "What plans are loaded in the application?" + - "Analyze the execution plan and tell me what's wrong" + - "Are there any missing index suggestions?" + - "Compare these two plans — which is better?" + - "Fetch the top 10 queries by CPU from Query Store" + +### Available Tools + +13 tools for plan analysis and Query Store data: + +| Category | Tools | +|---|---| +| Discovery | `list_plans`, `get_connections` | +| Plan Analysis | `analyze_plan`, `get_plan_summary`, `get_plan_warnings`, `get_missing_indexes`, `get_plan_parameters`, `get_expensive_operators`, `get_plan_xml`, `compare_plans`, `get_repro_script` | +| Query Store | `check_query_store`, `get_query_store_top` | + +Plan analysis tools work on plans loaded in the app (via file open, paste, query execution, or Query Store fetch). Query Store tools use a built-in read-only DMV query — no arbitrary SQL can be executed. + +The MCP server binds to `localhost` only and does not accept remote connections. Disabled by default. + ## Project Structure ``` diff --git a/SECURITY.md b/SECURITY.md index a02e642..5a54ea9 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,7 +2,7 @@ ## Reporting a Vulnerability -If you discover a security vulnerability in SQL Performance Studio, please report it responsibly. +If you discover a security vulnerability in Performance Studio, please report it responsibly. **Do not open a public GitHub issue for security vulnerabilities.** @@ -26,7 +26,7 @@ This policy applies to: ## Security Best Practices -When using SQL Performance Studio: +When using Performance Studio: - Use Windows Authentication where possible when connecting to SQL Server - Use dedicated accounts with minimal required permissions diff --git a/screenshots/.gitkeep b/screenshots/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/PlanViewer.App/AboutWindow.axaml b/src/PlanViewer.App/AboutWindow.axaml index 8c30608..8f5b51e 100644 --- a/src/PlanViewer.App/AboutWindow.axaml +++ b/src/PlanViewer.App/AboutWindow.axaml @@ -1,8 +1,8 @@ - @@ -46,8 +46,24 @@ TextDecorations="Underline"/> - - + + + + + + + + + +