dbatools-mcp-server 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 DataPlat contributors
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 DataPlat contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,160 +1,160 @@
1
- # dbatools-mcp-server
2
-
3
- A [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server for the [dbatools](https://dbatools.io) PowerShell module.
4
-
5
- Exposes dbatools commands as MCP tools so AI assistants (GitHub Copilot, Claude, etc.) can discover, explain, and execute dbatools commands directly — with all metadata sourced from dbatools' own **comment-based help**.
6
-
7
- ---
8
-
9
- ## Features
10
-
11
- - **`list_dbatools_commands`** — search commands by verb, noun, keyword, or risk level
12
- - **`get_dbatools_command_help`** — full normalized help (synopsis, parameters, examples) from `Get-Help -Full`
13
- - **`invoke_dbatools_command`** — execute any dbatools command with safe parameter validation, risk gating, and structured JSON output
14
- - **`check_dbatools_environment`** — verify PowerShell + dbatools installation, index freshness, and version alignment
15
- - **Version mismatch detection** — warns when installed dbatools version differs from the indexed version
16
- - **Safe mode** — non-readonly commands require explicit `confirm: true` to execute
17
- - **SQL Authentication support** — pass `SqlCredential: { username, password }` for SQL auth instances
18
-
19
- ---
20
-
21
- ## Prerequisites
22
-
23
- - [Node.js](https://nodejs.org/) 20+
24
- - [PowerShell 7+](https://github.com/PowerShell/PowerShell/releases) (`pwsh`)
25
- - [dbatools](https://dbatools.io/download) PowerShell module
26
-
27
- ```powershell
28
- Install-Module dbatools -Scope CurrentUser
29
- ```
30
-
31
- ---
32
-
33
- ## Quick Start
34
-
35
- ```powershell
36
- # 1. Clone the repo
37
- git clone https://github.com/Dataplat/dbatools-mcp-server.git
38
- cd dbatools-mcp-server
39
-
40
- # 2. Install Node dependencies
41
- npm install
42
-
43
- # 3. Generate the help index from your local dbatools installation
44
- npm run refresh-help
45
-
46
- # 4. Build
47
- npm run build
48
- ```
49
-
50
- Then open the folder in VS Code — the `.vscode/mcp.json` file automatically registers the MCP server.
51
-
52
- ---
53
-
54
- ## Connecting to VS Code
55
-
56
- The included [`.vscode/mcp.json`](.vscode/mcp.json) registers the server as a local STDIO MCP server.
57
- Open this folder in VS Code and the server will appear in the GitHub Copilot MCP panel.
58
-
59
- ```json
60
- {
61
- "servers": {
62
- "dbatools": {
63
- "type": "stdio",
64
- "command": "node",
65
- "args": ["${workspaceFolder}/dist/server.js"],
66
- "env": {
67
- "DBATOOLS_SAFE_MODE": "true",
68
- "MAX_OUTPUT_ROWS": "100",
69
- "COMMAND_TIMEOUT_SECONDS": "60"
70
- }
71
- }
72
- }
73
- }
74
- ```
75
-
76
- ---
77
-
78
- ## Configuration
79
-
80
- All settings are controlled via environment variables (set in `.vscode/mcp.json` or your shell):
81
-
82
- | Variable | Default | Description |
83
- |---|---|---|
84
- | `PWSH_EXE` | `pwsh` | Path to PowerShell executable |
85
- | `DBATOOLS_SAFE_MODE` | `true` | When `true`, non-readonly commands require `confirm: true` |
86
- | `MAX_OUTPUT_ROWS` | `100` | Maximum rows returned per command execution |
87
- | `COMMAND_TIMEOUT_SECONDS` | `60` | Seconds before PowerShell process is killed |
88
-
89
- ---
90
-
91
- ## Refreshing the Help Index
92
-
93
- The help index (`generated/dbatools-help.json`) is generated from your locally installed dbatools module.
94
- Re-run whenever dbatools is updated:
95
-
96
- ```powershell
97
- Update-Module dbatools -Scope CurrentUser
98
- npm run refresh-help
99
- ```
100
-
101
- The server detects version mismatches at runtime and warns you when the index is stale.
102
-
103
- ---
104
-
105
- ## Risk Levels
106
-
107
- Commands are automatically classified by verb:
108
-
109
- | Risk Level | Verbs | Behavior |
110
- |---|---|---|
111
- | `readonly` | Get, Test, Find, Compare, … | Always allowed |
112
- | `change` | Set, New, Add, Copy, Enable, … | Requires `confirm: true` in safe mode |
113
- | `destructive` | Remove, Drop, Disable, Reset, … | Requires `confirm: true` in safe mode |
114
-
115
- ---
116
-
117
- ## SQL Authentication
118
-
119
- For SQL-auth-only instances (e.g. Docker), pass credentials via the `SqlCredential` parameter:
120
-
121
- ```json
122
- {
123
- "SqlInstance": "localhost,1433",
124
- "SqlCredential": { "username": "<SqlLogin>", "password": "YourPassword" }
125
- }
126
- ```
127
-
128
- ---
129
-
130
- ## Project Structure
131
-
132
- ```
133
- dbatools-mcp-server/
134
- ├── src/
135
- │ ├── server.ts # MCP server entry point, tool definitions
136
- │ ├── powershell.ts # PowerShell process runner, health checks, version detection
137
- │ ├── help-indexer.ts # Help manifest loader and command search
138
- │ ├── tool-registry.ts # Risk classification, safe argument builder
139
- │ └── types.ts # Shared TypeScript interfaces
140
- ├── scripts/
141
- │ └── refresh-help.ps1 # Generates generated/dbatools-help.json
142
- ├── generated/ # Help index (gitignored, generated locally)
143
- ├── .vscode/
144
- │ └── mcp.json # VS Code MCP local server registration
145
- └── dist/ # Compiled output (gitignored)
146
- ```
147
-
148
- ---
149
-
150
- ## Contributing
151
-
152
- Contributions are welcome! Please open an issue first for significant changes.
153
-
154
- This project follows the same community spirit as [dbatools](https://github.com/dataplat/dbatools).
155
-
156
- ---
157
-
158
- ## License
159
-
160
- [MIT](LICENSE) — © 2026 DataPlat contributors
1
+ # dbatools-mcp-server
2
+
3
+ A [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server for the [dbatools](https://dbatools.io) PowerShell module.
4
+
5
+ Exposes dbatools commands as MCP tools so AI assistants (GitHub Copilot, Claude, etc.) can discover, explain, and execute dbatools commands directly — with all metadata sourced from dbatools' own **comment-based help**.
6
+
7
+ ---
8
+
9
+ ## Features
10
+
11
+ - **`list_dbatools_commands`** — search commands by verb, noun, keyword, or risk level
12
+ - **`get_dbatools_command_help`** — full normalized help (synopsis, parameters, examples) from `Get-Help -Full`
13
+ - **`invoke_dbatools_command`** — execute any dbatools command with safe parameter validation, risk gating, and structured JSON output
14
+ - **`check_dbatools_environment`** — verify PowerShell + dbatools installation, index freshness, and version alignment
15
+ - **Version mismatch detection** — warns when installed dbatools version differs from the indexed version
16
+ - **Safe mode** — non-readonly commands require explicit `confirm: true` to execute
17
+ - **SQL Authentication support** — pass `SqlCredential: { username, password }` for SQL auth instances
18
+
19
+ ---
20
+
21
+ ## Prerequisites
22
+
23
+ - [Node.js](https://nodejs.org/) 20+
24
+ - [PowerShell 7+](https://github.com/PowerShell/PowerShell/releases) (`pwsh`)
25
+ - [dbatools](https://dbatools.io/download) PowerShell module
26
+
27
+ ```powershell
28
+ Install-Module dbatools -Scope CurrentUser
29
+ ```
30
+
31
+ ---
32
+
33
+ ## Quick Start
34
+
35
+ ```powershell
36
+ # 1. Clone the repo
37
+ git clone https://github.com/Dataplat/dbatools-mcp-server.git
38
+ cd dbatools-mcp-server
39
+
40
+ # 2. Install Node dependencies
41
+ npm install
42
+
43
+ # 3. Generate the help index from your local dbatools installation
44
+ npm run refresh-help
45
+
46
+ # 4. Build
47
+ npm run build
48
+ ```
49
+
50
+ Then open the folder in VS Code — the `.vscode/mcp.json` file automatically registers the MCP server.
51
+
52
+ ---
53
+
54
+ ## Connecting to VS Code
55
+
56
+ The included [`.vscode/mcp.json`](.vscode/mcp.json) registers the server as a local STDIO MCP server.
57
+ Open this folder in VS Code and the server will appear in the GitHub Copilot MCP panel.
58
+
59
+ ```json
60
+ {
61
+ "servers": {
62
+ "dbatools": {
63
+ "type": "stdio",
64
+ "command": "node",
65
+ "args": ["${workspaceFolder}/dist/server.js"],
66
+ "env": {
67
+ "DBATOOLS_SAFE_MODE": "true",
68
+ "MAX_OUTPUT_ROWS": "100",
69
+ "COMMAND_TIMEOUT_SECONDS": "60"
70
+ }
71
+ }
72
+ }
73
+ }
74
+ ```
75
+
76
+ ---
77
+
78
+ ## Configuration
79
+
80
+ All settings are controlled via environment variables (set in `.vscode/mcp.json` or your shell):
81
+
82
+ | Variable | Default | Description |
83
+ |---|---|---|
84
+ | `PWSH_EXE` | `pwsh` | Path to PowerShell executable |
85
+ | `DBATOOLS_SAFE_MODE` | `true` | When `true`, non-readonly commands require `confirm: true` |
86
+ | `MAX_OUTPUT_ROWS` | `100` | Maximum rows returned per command execution |
87
+ | `COMMAND_TIMEOUT_SECONDS` | `60` | Seconds before PowerShell process is killed |
88
+
89
+ ---
90
+
91
+ ## Refreshing the Help Index
92
+
93
+ The help index (`generated/dbatools-help.json`) is generated from your locally installed dbatools module.
94
+ Re-run whenever dbatools is updated:
95
+
96
+ ```powershell
97
+ Update-Module dbatools -Scope CurrentUser
98
+ npm run refresh-help
99
+ ```
100
+
101
+ The server detects version mismatches at runtime and warns you when the index is stale.
102
+
103
+ ---
104
+
105
+ ## Risk Levels
106
+
107
+ Commands are automatically classified by verb:
108
+
109
+ | Risk Level | Verbs | Behavior |
110
+ |---|---|---|
111
+ | `readonly` | Get, Test, Find, Compare, … | Always allowed |
112
+ | `change` | Set, New, Add, Copy, Enable, … | Requires `confirm: true` in safe mode |
113
+ | `destructive` | Remove, Drop, Disable, Reset, … | Requires `confirm: true` in safe mode |
114
+
115
+ ---
116
+
117
+ ## SQL Authentication
118
+
119
+ For SQL-auth-only instances (e.g. Docker), pass credentials via the `SqlCredential` parameter:
120
+
121
+ ```json
122
+ {
123
+ "SqlInstance": "localhost,1433",
124
+ "SqlCredential": { "username": "<SqlLogin>", "password": "YourPassword" }
125
+ }
126
+ ```
127
+
128
+ ---
129
+
130
+ ## Project Structure
131
+
132
+ ```
133
+ dbatools-mcp-server/
134
+ ├── src/
135
+ │ ├── server.ts # MCP server entry point, tool definitions
136
+ │ ├── powershell.ts # PowerShell process runner, health checks, version detection
137
+ │ ├── help-indexer.ts # Help manifest loader and command search
138
+ │ ├── tool-registry.ts # Risk classification, safe argument builder
139
+ │ └── types.ts # Shared TypeScript interfaces
140
+ ├── scripts/
141
+ │ └── refresh-help.ps1 # Generates generated/dbatools-help.json
142
+ ├── generated/ # Help index (gitignored, generated locally)
143
+ ├── .vscode/
144
+ │ └── mcp.json # VS Code MCP local server registration
145
+ └── dist/ # Compiled output (gitignored)
146
+ ```
147
+
148
+ ---
149
+
150
+ ## Contributing
151
+
152
+ Contributions are welcome! Please open an issue first for significant changes.
153
+
154
+ This project follows the same community spirit as [dbatools](https://github.com/dataplat/dbatools).
155
+
156
+ ---
157
+
158
+ ## License
159
+
160
+ [MIT](LICENSE) — © 2026 DataPlat contributors
@@ -1,3 +1,3 @@
1
- # This directory is created by scripts/refresh-help.ps1
2
- # dbatools-help.json is generated locally and is intentionally gitignored.
3
- # Run: npm run refresh-help
1
+ # This directory is created by scripts/refresh-help.ps1
2
+ # dbatools-help.json is generated locally and is intentionally gitignored.
3
+ # Run: npm run refresh-help
package/package.json CHANGED
@@ -1,66 +1,66 @@
1
- {
2
- "name": "dbatools-mcp-server",
3
- "mcpName": "io.github.dataplat/dbatools-mcp-server",
4
- "version": "0.1.0",
5
- "description": "MCP server for the dbatools PowerShell module — exposes dbatools commands as MCP tools driven by comment-based help",
6
- "keywords": [
7
- "dbatools",
8
- "mcp",
9
- "sql server",
10
- "powershell",
11
- "database"
12
- ],
13
- "repository": {
14
- "type": "git",
15
- "url": "https://github.com/dataplat/dbatools-mcp-server.git"
16
- },
17
- "license": "MIT",
18
- "type": "module",
19
- "files": [
20
- "dist",
21
- "generated/.gitkeep",
22
- "scripts/refresh-help.ps1"
23
- ],
24
- "bin": {
25
- "dbatools-mcp-server": "./dist/server.js"
26
- },
27
- "scripts": {
28
- "build": "tsc",
29
- "dev": "tsx src/server.ts",
30
- "start": "node dist/server.js",
31
- "refresh-help": "pwsh -NonInteractive -File scripts/refresh-help.ps1",
32
- "test": "node --experimental-vm-modules node_modules/.bin/jest --passWithNoTests"
33
- },
34
- "dependencies": {
35
- "@modelcontextprotocol/sdk": "^1.10.0",
36
- "zod": "^3.24.0"
37
- },
38
- "devDependencies": {
39
- "@types/jest": "^29.5.0",
40
- "@types/node": "^22.0.0",
41
- "jest": "^29.7.0",
42
- "ts-jest": "^29.2.0",
43
- "tsx": "^4.19.0",
44
- "typescript": "^5.7.0"
45
- },
46
- "jest": {
47
- "preset": "ts-jest/presets/default-esm",
48
- "extensionsToTreatAsEsm": [
49
- ".ts"
50
- ],
51
- "moduleNameMapper": {
52
- "^(\\.{1,2}/.*)\\.js$": "$1"
53
- },
54
- "transform": {
55
- "^.+\\.tsx?$": [
56
- "ts-jest",
57
- {
58
- "useESM": true
59
- }
60
- ]
61
- }
62
- },
63
- "engines": {
64
- "node": ">=20.0.0"
65
- }
66
- }
1
+ {
2
+ "name": "dbatools-mcp-server",
3
+ "mcpName": "io.github.dataplat/dbatools-mcp-server",
4
+ "version": "0.2.0",
5
+ "description": "MCP server for dbatools — exposes SQL Server management commands as MCP tools",
6
+ "keywords": [
7
+ "dbatools",
8
+ "mcp",
9
+ "sql server",
10
+ "powershell",
11
+ "database"
12
+ ],
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "https://github.com/dataplat/dbatools-mcp-server.git"
16
+ },
17
+ "license": "MIT",
18
+ "type": "module",
19
+ "files": [
20
+ "dist",
21
+ "generated/.gitkeep",
22
+ "scripts/refresh-help.ps1"
23
+ ],
24
+ "bin": {
25
+ "dbatools-mcp-server": "./dist/server.js"
26
+ },
27
+ "scripts": {
28
+ "build": "tsc",
29
+ "dev": "tsx src/server.ts",
30
+ "start": "node dist/server.js",
31
+ "refresh-help": "pwsh -NonInteractive -File scripts/refresh-help.ps1",
32
+ "test": "node --experimental-vm-modules node_modules/.bin/jest --passWithNoTests"
33
+ },
34
+ "dependencies": {
35
+ "@modelcontextprotocol/sdk": "^1.10.0",
36
+ "zod": "^3.24.0"
37
+ },
38
+ "devDependencies": {
39
+ "@types/jest": "^29.5.0",
40
+ "@types/node": "^22.0.0",
41
+ "jest": "^29.7.0",
42
+ "ts-jest": "^29.2.0",
43
+ "tsx": "^4.19.0",
44
+ "typescript": "^5.7.0"
45
+ },
46
+ "jest": {
47
+ "preset": "ts-jest/presets/default-esm",
48
+ "extensionsToTreatAsEsm": [
49
+ ".ts"
50
+ ],
51
+ "moduleNameMapper": {
52
+ "^(\\.{1,2}/.*)\\.js$": "$1"
53
+ },
54
+ "transform": {
55
+ "^.+\\.tsx?$": [
56
+ "ts-jest",
57
+ {
58
+ "useESM": true
59
+ }
60
+ ]
61
+ }
62
+ },
63
+ "engines": {
64
+ "node": ">=20.0.0"
65
+ }
66
+ }
@@ -1,192 +1,192 @@
1
- <#
2
- .SYNOPSIS
3
- Generates generated/dbatools-help.json by extracting comment-based help from
4
- every command in the locally installed dbatools module.
5
-
6
- .DESCRIPTION
7
- Run this script whenever dbatools is installed or updated.
8
- Output is consumed by the MCP server at startup and cached for the session.
9
-
10
- Usage: npm run refresh-help
11
- pwsh -File scripts/refresh-help.ps1
12
-
13
- .PARAMETER OutputPath
14
- Override the output file path (default: <repo-root>/generated/dbatools-help.json)
15
-
16
- .PARAMETER MaxCommands
17
- Limit to N commands for quick development iterations (0 = all commands)
18
- #>
19
- [CmdletBinding()]
20
- param(
21
- [string]$OutputPath = "",
22
- [int]$MaxCommands = 0
23
- )
24
-
25
- $ErrorActionPreference = 'Stop'
26
- $InformationPreference = 'Continue'
27
-
28
- # ---------------------------------------------------------------------------
29
- # Resolve paths
30
- # ---------------------------------------------------------------------------
31
- $ScriptDir = Split-Path -Parent $PSCommandPath
32
- $RepoRoot = Split-Path -Parent $ScriptDir
33
- $OutputDir = Join-Path $RepoRoot 'generated'
34
- $DefaultOut = Join-Path $OutputDir 'dbatools-help.json'
35
-
36
- if ($OutputPath -eq "") { $OutputPath = $DefaultOut }
37
-
38
- if (-not (Test-Path $OutputDir)) {
39
- New-Item -ItemType Directory -Path $OutputDir | Out-Null
40
- Write-Information "Created directory: $OutputDir"
41
- }
42
-
43
- # ---------------------------------------------------------------------------
44
- # Verify dbatools
45
- # ---------------------------------------------------------------------------
46
- $module = Get-Module -ListAvailable -Name dbatools |
47
- Sort-Object Version -Descending |
48
- Select-Object -First 1
49
-
50
- if (-not $module) {
51
- Write-Error "dbatools is not installed.`nRun: Install-Module dbatools -Scope CurrentUser"
52
- exit 1
53
- }
54
-
55
- Write-Information "Found dbatools $($module.Version) at $($module.ModuleBase)"
56
- Write-Information "Importing module..."
57
- Import-Module dbatools -ErrorAction Stop
58
-
59
- # ---------------------------------------------------------------------------
60
- # Enumerate commands
61
- # ---------------------------------------------------------------------------
62
- $commands = Get-Command -Module dbatools | Sort-Object Name
63
-
64
- if ($MaxCommands -gt 0) {
65
- $commands = $commands | Select-Object -First $MaxCommands
66
- Write-Warning "MaxCommands=$MaxCommands — indexing a subset only."
67
- }
68
-
69
- $total = $commands.Count
70
- Write-Information "Indexing $total commands..."
71
-
72
- # ---------------------------------------------------------------------------
73
- # Risk classification helpers
74
- # ---------------------------------------------------------------------------
75
- $ReadonlyVerbs = @('Get','Test','Find','Measure','Select','Show','Watch','Compare','Search','Resolve')
76
- $DestructiveVerbs = @('Remove','Drop','Delete','Uninstall','Revoke','Disable','Reset')
77
-
78
- function Get-RiskLevel([string]$verb) {
79
- if ($ReadonlyVerbs -contains $verb) { return 'readonly' }
80
- if ($DestructiveVerbs -contains $verb) { return 'destructive' }
81
- return 'change'
82
- }
83
-
84
- # ---------------------------------------------------------------------------
85
- # Help extraction loop
86
- # ---------------------------------------------------------------------------
87
- $index = [System.Collections.Specialized.OrderedDictionary]::new()
88
- $failures = 0
89
- $counter = 0
90
-
91
- foreach ($cmd in $commands) {
92
- $counter++
93
- if ($counter % 100 -eq 0) {
94
- Write-Information " $counter / $total ($([Math]::Round($counter/$total*100))%)"
95
- }
96
-
97
- try {
98
- $help = Get-Help $cmd.Name -Full -ErrorAction SilentlyContinue
99
-
100
- # --- Parameters ---------------------------------------------------
101
- $params = [System.Collections.Generic.List[hashtable]]::new()
102
- if ($help.parameters -and $help.parameters.parameter) {
103
- foreach ($p in $help.parameters.parameter) {
104
- $desc = if ($p.description) {
105
- ($p.description | ForEach-Object { $_.Text }) -join ' '
106
- } else { '' }
107
-
108
- $aliasArr = if ($p.aliases -and $p.aliases -ne 'None') {
109
- @($p.aliases -split ',\s*' | Where-Object { $_ -ne '' })
110
- } else { @() }
111
-
112
- $params.Add([ordered]@{
113
- name = [string]$p.name
114
- type = if ($p.type -and $p.type.name) { [string]$p.type.name } else { 'Object' }
115
- required = ($p.required -eq 'true')
116
- aliases = $aliasArr
117
- pipelineInput = ($p.pipelineInput -and $p.pipelineInput -ne 'false')
118
- description = $desc.Trim()
119
- defaultValue = if ($p.defaultValue) { [string]$p.defaultValue } else { $null }
120
- })
121
- }
122
- }
123
-
124
- # --- Examples -----------------------------------------------------
125
- $examples = [System.Collections.Generic.List[hashtable]]::new()
126
- if ($help.examples -and $help.examples.example) {
127
- foreach ($ex in $help.examples.example) {
128
- $remarks = if ($ex.remarks) {
129
- ($ex.remarks | ForEach-Object { $_.Text }) -join ' '
130
- } else { '' }
131
-
132
- $examples.Add([ordered]@{
133
- title = ([string]($ex.title ?? '')).TrimStart('-').Trim()
134
- code = ([string]($ex.code ?? '')).Trim()
135
- remarks = $remarks.Trim()
136
- })
137
- }
138
- }
139
-
140
- # --- Related links ------------------------------------------------
141
- $links = @()
142
- if ($help.relatedLinks -and $help.relatedLinks.navigationLink) {
143
- $links = @(
144
- $help.relatedLinks.navigationLink |
145
- ForEach-Object { if ($_.uri) { $_.uri } elseif ($_.linkText) { $_.linkText } } |
146
- Where-Object { $_ -and $_ -ne '' }
147
- )
148
- }
149
-
150
- # --- Synopsis / Description ---------------------------------------
151
- $synopsis = if ($help.Synopsis) { $help.Synopsis.Trim() } else { '' }
152
-
153
- $description = if ($help.description) {
154
- ($help.description | ForEach-Object { $_.Text }) -join ' '
155
- } else { '' }
156
-
157
- $index[$cmd.Name] = [ordered]@{
158
- name = $cmd.Name
159
- verb = $cmd.Verb
160
- noun = $cmd.Noun
161
- synopsis = $synopsis
162
- description = $description.Trim()
163
- parameters = $params.ToArray()
164
- examples = $examples.ToArray()
165
- relatedLinks = $links
166
- tags = @()
167
- riskLevel = Get-RiskLevel $cmd.Verb
168
- }
169
- }
170
- catch {
171
- $failures++
172
- Write-Warning "[$counter/$total] Failed to get help for $($cmd.Name): $_"
173
- }
174
- }
175
-
176
- # ---------------------------------------------------------------------------
177
- # Write manifest
178
- # ---------------------------------------------------------------------------
179
- $manifest = [ordered]@{
180
- generatedAt = (Get-Date -Format 'o')
181
- dbatoolsVersion = $module.Version.ToString()
182
- commandCount = $index.Count
183
- commands = $index
184
- }
185
-
186
- $manifest | ConvertTo-Json -Depth 12 | Set-Content -Path $OutputPath -Encoding UTF8
187
-
188
- Write-Information ""
189
- Write-Information "Done! Indexed $($index.Count) commands -> $OutputPath"
190
- if ($failures -gt 0) {
191
- Write-Warning "$failures command(s) failed to index (see warnings above)."
192
- }
1
+ <#
2
+ .SYNOPSIS
3
+ Generates generated/dbatools-help.json by extracting comment-based help from
4
+ every command in the locally installed dbatools module.
5
+
6
+ .DESCRIPTION
7
+ Run this script whenever dbatools is installed or updated.
8
+ Output is consumed by the MCP server at startup and cached for the session.
9
+
10
+ Usage: npm run refresh-help
11
+ pwsh -File scripts/refresh-help.ps1
12
+
13
+ .PARAMETER OutputPath
14
+ Override the output file path (default: <repo-root>/generated/dbatools-help.json)
15
+
16
+ .PARAMETER MaxCommands
17
+ Limit to N commands for quick development iterations (0 = all commands)
18
+ #>
19
+ [CmdletBinding()]
20
+ param(
21
+ [string]$OutputPath = "",
22
+ [int]$MaxCommands = 0
23
+ )
24
+
25
+ $ErrorActionPreference = 'Stop'
26
+ $InformationPreference = 'Continue'
27
+
28
+ # ---------------------------------------------------------------------------
29
+ # Resolve paths
30
+ # ---------------------------------------------------------------------------
31
+ $ScriptDir = Split-Path -Parent $PSCommandPath
32
+ $RepoRoot = Split-Path -Parent $ScriptDir
33
+ $OutputDir = Join-Path $RepoRoot 'generated'
34
+ $DefaultOut = Join-Path $OutputDir 'dbatools-help.json'
35
+
36
+ if ($OutputPath -eq "") { $OutputPath = $DefaultOut }
37
+
38
+ if (-not (Test-Path $OutputDir)) {
39
+ New-Item -ItemType Directory -Path $OutputDir | Out-Null
40
+ Write-Information "Created directory: $OutputDir"
41
+ }
42
+
43
+ # ---------------------------------------------------------------------------
44
+ # Verify dbatools
45
+ # ---------------------------------------------------------------------------
46
+ $module = Get-Module -ListAvailable -Name dbatools |
47
+ Sort-Object Version -Descending |
48
+ Select-Object -First 1
49
+
50
+ if (-not $module) {
51
+ Write-Error "dbatools is not installed.`nRun: Install-Module dbatools -Scope CurrentUser"
52
+ exit 1
53
+ }
54
+
55
+ Write-Information "Found dbatools $($module.Version) at $($module.ModuleBase)"
56
+ Write-Information "Importing module..."
57
+ Import-Module dbatools -ErrorAction Stop
58
+
59
+ # ---------------------------------------------------------------------------
60
+ # Enumerate commands
61
+ # ---------------------------------------------------------------------------
62
+ $commands = Get-Command -Module dbatools | Sort-Object Name
63
+
64
+ if ($MaxCommands -gt 0) {
65
+ $commands = $commands | Select-Object -First $MaxCommands
66
+ Write-Warning "MaxCommands=$MaxCommands — indexing a subset only."
67
+ }
68
+
69
+ $total = $commands.Count
70
+ Write-Information "Indexing $total commands..."
71
+
72
+ # ---------------------------------------------------------------------------
73
+ # Risk classification helpers
74
+ # ---------------------------------------------------------------------------
75
+ $ReadonlyVerbs = @('Get','Test','Find','Measure','Select','Show','Watch','Compare','Search','Resolve')
76
+ $DestructiveVerbs = @('Remove','Drop','Delete','Uninstall','Revoke','Disable','Reset')
77
+
78
+ function Get-RiskLevel([string]$verb) {
79
+ if ($ReadonlyVerbs -contains $verb) { return 'readonly' }
80
+ if ($DestructiveVerbs -contains $verb) { return 'destructive' }
81
+ return 'change'
82
+ }
83
+
84
+ # ---------------------------------------------------------------------------
85
+ # Help extraction loop
86
+ # ---------------------------------------------------------------------------
87
+ $index = [System.Collections.Specialized.OrderedDictionary]::new()
88
+ $failures = 0
89
+ $counter = 0
90
+
91
+ foreach ($cmd in $commands) {
92
+ $counter++
93
+ if ($counter % 100 -eq 0) {
94
+ Write-Information " $counter / $total ($([Math]::Round($counter/$total*100))%)"
95
+ }
96
+
97
+ try {
98
+ $help = Get-Help $cmd.Name -Full -ErrorAction SilentlyContinue
99
+
100
+ # --- Parameters ---------------------------------------------------
101
+ $params = [System.Collections.Generic.List[hashtable]]::new()
102
+ if ($help.parameters -and $help.parameters.parameter) {
103
+ foreach ($p in $help.parameters.parameter) {
104
+ $desc = if ($p.description) {
105
+ ($p.description | ForEach-Object { $_.Text }) -join ' '
106
+ } else { '' }
107
+
108
+ $aliasArr = if ($p.aliases -and $p.aliases -ne 'None') {
109
+ @($p.aliases -split ',\s*' | Where-Object { $_ -ne '' })
110
+ } else { @() }
111
+
112
+ $params.Add([ordered]@{
113
+ name = [string]$p.name
114
+ type = if ($p.type -and $p.type.name) { [string]$p.type.name } else { 'Object' }
115
+ required = ($p.required -eq 'true')
116
+ aliases = $aliasArr
117
+ pipelineInput = ($p.pipelineInput -and $p.pipelineInput -ne 'false')
118
+ description = $desc.Trim()
119
+ defaultValue = if ($p.defaultValue) { [string]$p.defaultValue } else { $null }
120
+ })
121
+ }
122
+ }
123
+
124
+ # --- Examples -----------------------------------------------------
125
+ $examples = [System.Collections.Generic.List[hashtable]]::new()
126
+ if ($help.examples -and $help.examples.example) {
127
+ foreach ($ex in $help.examples.example) {
128
+ $remarks = if ($ex.remarks) {
129
+ ($ex.remarks | ForEach-Object { $_.Text }) -join ' '
130
+ } else { '' }
131
+
132
+ $examples.Add([ordered]@{
133
+ title = ([string]($ex.title ?? '')).TrimStart('-').Trim()
134
+ code = ([string]($ex.code ?? '')).Trim()
135
+ remarks = $remarks.Trim()
136
+ })
137
+ }
138
+ }
139
+
140
+ # --- Related links ------------------------------------------------
141
+ $links = @()
142
+ if ($help.relatedLinks -and $help.relatedLinks.navigationLink) {
143
+ $links = @(
144
+ $help.relatedLinks.navigationLink |
145
+ ForEach-Object { if ($_.uri) { $_.uri } elseif ($_.linkText) { $_.linkText } } |
146
+ Where-Object { $_ -and $_ -ne '' }
147
+ )
148
+ }
149
+
150
+ # --- Synopsis / Description ---------------------------------------
151
+ $synopsis = if ($help.Synopsis) { $help.Synopsis.Trim() } else { '' }
152
+
153
+ $description = if ($help.description) {
154
+ ($help.description | ForEach-Object { $_.Text }) -join ' '
155
+ } else { '' }
156
+
157
+ $index[$cmd.Name] = [ordered]@{
158
+ name = $cmd.Name
159
+ verb = $cmd.Verb
160
+ noun = $cmd.Noun
161
+ synopsis = $synopsis
162
+ description = $description.Trim()
163
+ parameters = $params.ToArray()
164
+ examples = $examples.ToArray()
165
+ relatedLinks = $links
166
+ tags = @()
167
+ riskLevel = Get-RiskLevel $cmd.Verb
168
+ }
169
+ }
170
+ catch {
171
+ $failures++
172
+ Write-Warning "[$counter/$total] Failed to get help for $($cmd.Name): $_"
173
+ }
174
+ }
175
+
176
+ # ---------------------------------------------------------------------------
177
+ # Write manifest
178
+ # ---------------------------------------------------------------------------
179
+ $manifest = [ordered]@{
180
+ generatedAt = (Get-Date -Format 'o')
181
+ dbatoolsVersion = $module.Version.ToString()
182
+ commandCount = $index.Count
183
+ commands = $index
184
+ }
185
+
186
+ $manifest | ConvertTo-Json -Depth 12 | Set-Content -Path $OutputPath -Encoding UTF8
187
+
188
+ Write-Information ""
189
+ Write-Information "Done! Indexed $($index.Count) commands -> $OutputPath"
190
+ if ($failures -gt 0) {
191
+ Write-Warning "$failures command(s) failed to index (see warnings above)."
192
+ }