@eamonboyle/mssql-mcp 1.6.0 → 2.0.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.
Files changed (122) hide show
  1. package/README.md +62 -12
  2. package/dist/apps/queryResultsApp.d.ts +18 -0
  3. package/dist/apps/queryResultsApp.d.ts.map +1 -0
  4. package/dist/apps/queryResultsApp.js +272 -0
  5. package/dist/apps/queryResultsApp.js.map +1 -0
  6. package/dist/checkNodeVersion.d.ts +2 -0
  7. package/dist/checkNodeVersion.d.ts.map +1 -0
  8. package/dist/checkNodeVersion.js +9 -0
  9. package/dist/checkNodeVersion.js.map +1 -0
  10. package/dist/config.d.ts +30 -2
  11. package/dist/config.d.ts.map +1 -1
  12. package/dist/config.js +66 -5
  13. package/dist/config.js.map +1 -1
  14. package/dist/confirmationMessage.d.ts +2 -0
  15. package/dist/confirmationMessage.d.ts.map +1 -0
  16. package/dist/confirmationMessage.js +105 -0
  17. package/dist/confirmationMessage.js.map +1 -0
  18. package/dist/db.d.ts +20 -0
  19. package/dist/db.d.ts.map +1 -1
  20. package/dist/db.js +118 -16
  21. package/dist/db.js.map +1 -1
  22. package/dist/filteredRead.js +0 -0
  23. package/dist/httpServer.d.ts +25 -0
  24. package/dist/httpServer.d.ts.map +1 -0
  25. package/dist/httpServer.js +128 -0
  26. package/dist/httpServer.js.map +1 -0
  27. package/dist/index.d.ts +1 -1
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +43 -395
  30. package/dist/index.js.map +1 -1
  31. package/dist/mcpResults.d.ts +1 -1
  32. package/dist/mcpResults.d.ts.map +1 -1
  33. package/dist/mcpResults.js +2 -2
  34. package/dist/mcpResults.js.map +1 -1
  35. package/dist/nodeVersion.d.ts +14 -0
  36. package/dist/nodeVersion.d.ts.map +1 -0
  37. package/dist/nodeVersion.js +23 -0
  38. package/dist/nodeVersion.js.map +1 -0
  39. package/dist/packageInfo.d.ts +3 -0
  40. package/dist/packageInfo.d.ts.map +1 -0
  41. package/dist/packageInfo.js +5 -0
  42. package/dist/packageInfo.js.map +1 -0
  43. package/dist/promptRegistry.d.ts +1 -1
  44. package/dist/promptRegistry.d.ts.map +1 -1
  45. package/dist/promptRegistry.js +1 -1
  46. package/dist/promptRegistry.js.map +1 -1
  47. package/dist/resourceRegistry.d.ts +3 -1
  48. package/dist/resourceRegistry.d.ts.map +1 -1
  49. package/dist/resourceRegistry.js +3 -2
  50. package/dist/resourceRegistry.js.map +1 -1
  51. package/dist/schema.js +0 -0
  52. package/dist/server.d.ts +5 -0
  53. package/dist/server.d.ts.map +1 -0
  54. package/dist/server.js +320 -0
  55. package/dist/server.js.map +1 -0
  56. package/dist/serverState.js +2 -4
  57. package/dist/serverState.js.map +1 -1
  58. package/dist/sql.js +0 -0
  59. package/dist/sqlErrors.d.ts +10 -0
  60. package/dist/sqlErrors.d.ts.map +1 -0
  61. package/dist/sqlErrors.js +32 -0
  62. package/dist/sqlErrors.js.map +1 -0
  63. package/dist/toolRegistry.d.ts +1 -1
  64. package/dist/toolRegistry.d.ts.map +1 -1
  65. package/dist/toolRegistry.js +1 -1
  66. package/dist/toolRegistry.js.map +1 -1
  67. package/dist/tools/AnalyzeTableTool.js +2 -4
  68. package/dist/tools/AnalyzeTableTool.js.map +1 -1
  69. package/dist/tools/CreateIndexTool.js +2 -4
  70. package/dist/tools/CreateIndexTool.js.map +1 -1
  71. package/dist/tools/CreateTableTool.js +2 -4
  72. package/dist/tools/CreateTableTool.js.map +1 -1
  73. package/dist/tools/DeleteDataTool.js +2 -4
  74. package/dist/tools/DeleteDataTool.js.map +1 -1
  75. package/dist/tools/DescribeDependenciesTool.js +2 -4
  76. package/dist/tools/DescribeDependenciesTool.js.map +1 -1
  77. package/dist/tools/DescribeObjectTool.js +2 -4
  78. package/dist/tools/DescribeObjectTool.js.map +1 -1
  79. package/dist/tools/DescribeRelationshipsTool.js +2 -4
  80. package/dist/tools/DescribeRelationshipsTool.js.map +1 -1
  81. package/dist/tools/DescribeTableTool.js +2 -4
  82. package/dist/tools/DescribeTableTool.js.map +1 -1
  83. package/dist/tools/DropTableTool.js +2 -4
  84. package/dist/tools/DropTableTool.js.map +1 -1
  85. package/dist/tools/ExplainQueryTool.d.ts.map +1 -1
  86. package/dist/tools/ExplainQueryTool.js +4 -6
  87. package/dist/tools/ExplainQueryTool.js.map +1 -1
  88. package/dist/tools/InsertDataTool.js +2 -4
  89. package/dist/tools/InsertDataTool.js.map +1 -1
  90. package/dist/tools/ListDatabasesTool.js +2 -4
  91. package/dist/tools/ListDatabasesTool.js.map +1 -1
  92. package/dist/tools/ListForeignKeysTool.js +2 -4
  93. package/dist/tools/ListForeignKeysTool.js.map +1 -1
  94. package/dist/tools/ListLargestTablesTool.js +2 -4
  95. package/dist/tools/ListLargestTablesTool.js.map +1 -1
  96. package/dist/tools/ListObjectsTool.js +2 -4
  97. package/dist/tools/ListObjectsTool.js.map +1 -1
  98. package/dist/tools/ListTableTool.js +2 -4
  99. package/dist/tools/ListTableTool.js.map +1 -1
  100. package/dist/tools/PreviewDeleteTool.js +2 -4
  101. package/dist/tools/PreviewDeleteTool.js.map +1 -1
  102. package/dist/tools/PreviewUpdateTool.js +2 -4
  103. package/dist/tools/PreviewUpdateTool.js.map +1 -1
  104. package/dist/tools/ReadDataTool.d.ts +15 -12
  105. package/dist/tools/ReadDataTool.d.ts.map +1 -1
  106. package/dist/tools/ReadDataTool.js +86 -64
  107. package/dist/tools/ReadDataTool.js.map +1 -1
  108. package/dist/tools/SearchDataTool.js +2 -4
  109. package/dist/tools/SearchDataTool.js.map +1 -1
  110. package/dist/tools/SummarizeSchemaTool.js +2 -4
  111. package/dist/tools/SummarizeSchemaTool.js.map +1 -1
  112. package/dist/tools/UpdateDataTool.js +2 -4
  113. package/dist/tools/UpdateDataTool.js.map +1 -1
  114. package/dist/validation.d.ts +26 -3
  115. package/dist/validation.d.ts.map +1 -1
  116. package/dist/validation.js +237 -85
  117. package/dist/validation.js.map +1 -1
  118. package/dist/writePreview.js +0 -0
  119. package/dist/writePreviewGrant.js +0 -0
  120. package/dist/writePreviewGrantStore.js +0 -0
  121. package/dist/writeSafety.js +0 -0
  122. package/package.json +29 -22
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4
4
  [![npm version](https://img.shields.io/npm/v/@eamonboyle/mssql-mcp.svg)](https://www.npmjs.com/package/@eamonboyle/mssql-mcp)
5
- [![Node.js 20+](https://img.shields.io/badge/node-%3E%3D20.0.0-brightgreen)](https://nodejs.org/)
5
+ [![Node.js 22+](https://img.shields.io/badge/node-%3E%3D22.0.0-brightgreen)](https://nodejs.org/)
6
6
  [![X: @eamonyo](https://img.shields.io/badge/X-%40eamonyo-000000?style=flat-square&logo=x&logoColor=white)](https://x.com/eamonyo)
7
7
 
8
8
  [![Add to Cursor](https://img.shields.io/badge/Add_to-Cursor-000000?style=for-the-badge&logo=cursor&logoColor=white)](https://cursor.com/en/install-mcp?name=mssql-local&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBlYW1vbmJveWxlL21zc3FsLW1jcCJdLCJlbnYiOnsiU0VSVkVSX05BTUUiOiJsb2NhbGhvc3QiLCJEQVRBQkFTRV9OQU1FIjoiQXBwREIiLCJEQVRBQkFTRVMiOiJBcHBEQixSZXBvcnRpbmdEQiIsIkRCX1VTRVIiOiJ5b3VyX3VzZXJuYW1lIiwiREJfUEFTU1dPUkQiOiJ5b3VyX3Bhc3N3b3JkIiwiVFJVU1RfU0VSVkVSX0NFUlRJRklDQVRFIjoidHJ1ZSIsIlJFQURPTkxZIjoiZmFsc2UiLCJFTkFCTEVfRERMIjoiZmFsc2UifX0=)
@@ -30,10 +30,12 @@ Supported clients include Cursor, VS Code, Claude Desktop, and other MCP-compati
30
30
 
31
31
  ### Prerequisites
32
32
 
33
- - Node.js 20 or newer
33
+ - Node.js 22 or newer (check with `node --version`)
34
34
  - Microsoft SQL Server
35
35
  - An MCP-compatible client
36
36
 
37
+ > **Still on Node.js 20?** Version 1.6.0 is the last release that runs on Node 20, which reached end-of-life in April 2026. Newer releases stop at startup with a message explaining this. Upgrade Node.js, or pin the older release in your MCP configuration with `npx -y @eamonboyle/mssql-mcp@1.6.0`.
38
+
37
39
  The recommended installation runs the published package directly:
38
40
 
39
41
  ```bash
@@ -112,11 +114,31 @@ The server validates these variables before starting. Missing or blank values pr
112
114
 
113
115
  | Variable | Accepted format | Purpose |
114
116
  | -------------------------- | ---------------------- | --------------------------------------------------------------------- |
115
- | `DB_USER` | Nonblank string | SQL authentication username |
116
- | `DB_PASSWORD` | Nonblank string | SQL authentication password |
117
+ | `DB_USER` | Nonblank string | SQL login (or NTLM) username; not used for Entra ID auth |
118
+ | `DB_PASSWORD` | Nonblank string | SQL login (or NTLM) password; not used for Entra ID auth |
117
119
 
118
120
  At least one database variable is required: set `DATABASE_NAME`, `DATABASES`, or both. With only `DATABASE_NAME`, that database is both the default and the allowlist. With only `DATABASES`, the first entry is the default. When both are set, `DATABASE_NAME` is used if it appears in `DATABASES`; otherwise the first allowed database is the runtime default.
119
121
 
122
+ ### Authentication
123
+
124
+ `SQL_AUTH_TYPE` selects how the server signs in to SQL Server. The default, `sql`, uses `DB_USER` and `DB_PASSWORD`.
125
+
126
+ | `SQL_AUTH_TYPE` | Also requires | Notes |
127
+ | ------------------------- | ---------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
128
+ | `sql` (default) | `DB_USER`, `DB_PASSWORD` | SQL Server login |
129
+ | `ntlm` | `DB_USER`, `DB_PASSWORD`, `DB_DOMAIN` | Windows domain account over NTLM; integrated (SSPI) auth of the current user is not supported |
130
+ | `azure-default` | Optional `AZURE_CLIENT_ID` | Microsoft Entra ID via `DefaultAzureCredential`: `az login`, managed identity, workload identity, environment credentials |
131
+ | `azure-service-principal` | `AZURE_CLIENT_ID`, `AZURE_CLIENT_SECRET`, `AZURE_TENANT_ID` | Entra ID app registration with a client secret |
132
+ | `azure-access-token` | `AZURE_ACCESS_TOKEN` | A pre-acquired Entra ID token; it is not refreshed, so restart the server when it expires |
133
+
134
+ Entra ID types default `ENCRYPT` to `true` and `TRUST_SERVER_CERTIFICATE` to `false`, because Azure SQL requires TLS and presents publicly trusted certificates. For Azure SQL with `azure-default` after `az login`:
135
+
136
+ ```text
137
+ SERVER_NAME=myserver.database.windows.net
138
+ DATABASE_NAME=mydb
139
+ SQL_AUTH_TYPE=azure-default
140
+ ```
141
+
120
142
  ### Hostname and port
121
143
 
122
144
  > Do not include the port in `SERVER_NAME`. Values such as `localhost,1434` are not supported by the Node.js `mssql` driver configuration used by this package. Set `SERVER_NAME` to the hostname and use `SERVER_PORT` separately.
@@ -152,8 +174,9 @@ Optional variables do not need empty placeholders. In-code defaults apply when t
152
174
  | ----------------------- | ----------------------------- | --------------------- | -------------------------------------------------------------- |
153
175
  | `SERVER_NAME` | Hostname | `localhost` | SQL Server hostname only |
154
176
  | `SERVER_PORT` | Integer from `1` to `65535` | Driver default `1433` | SQL Server TCP port; omitted from the driver config when unset |
155
- | `ENCRYPT` | `"true"` or `"false"` | `"false"` | Enable TLS encryption in the `mssql` driver |
156
- | `TRUST_SERVER_CERTIFICATE` | `"true"` or `"false"` | `"true"` | Trust the SQL Server certificate without validating its chain |
177
+ | `SQL_AUTH_TYPE` | See [Authentication](#authentication) | `sql` | SQL Server authentication method |
178
+ | `ENCRYPT` | `"true"` or `"false"` | `"false"` (`"true"` for Entra ID) | Enable TLS encryption in the `mssql` driver |
179
+ | `TRUST_SERVER_CERTIFICATE` | `"true"` or `"false"` | `"true"` (`"false"` for Entra ID) | Trust the SQL Server certificate without validating its chain |
157
180
  | `READONLY` | `"true"` or `"false"` | `"false"` | Remove write and DDL tools when enabled |
158
181
  | `ENABLE_DDL` | `"true"` or `"false"` | `"false"` | Allow registered DDL tools to execute |
159
182
  | `CONNECTION_TIMEOUT` | Positive integer seconds | `30` | SQL Server connection timeout |
@@ -165,6 +188,9 @@ Optional variables do not need empty placeholders. In-code defaults apply when t
165
188
  | `MCP_HTTP_HOST` | Host or IP string | `127.0.0.1` | Bind address for HTTP mode |
166
189
  | `MCP_HTTP_PORT` | Integer from `1` to `65535` | `3333` | Bind port for HTTP mode |
167
190
  | `MCP_BASE_URL` | Absolute HTTP or HTTPS URL | Unset | Public HTTP base advertised by the server; `/mcp` is appended |
191
+ | `MCP_HTTP_AUTH_TOKEN` | Nonblank string | Unset | Require `Authorization: Bearer <token>` on HTTP requests |
192
+ | `MCP_HTTP_ALLOWED_HOSTS`| Comma-separated hostnames | Loopback + bind host + `MCP_BASE_URL` host | Hostnames accepted in `Host`/`Origin` headers |
193
+ | `MCP_HTTP_ALLOW_UNAUTHENTICATED` | `"true"` or `"false"` | `"false"` | Allow a non-loopback `MCP_HTTP_HOST` without a token |
168
194
 
169
195
  Blank optional values use their documented defaults. Explicit nonblank invalid integers, booleans, ports, URLs, or transport names fail validation rather than falling back silently.
170
196
 
@@ -180,7 +206,7 @@ Blank optional values use their documented defaults. Explicit nonblank invalid i
180
206
 
181
207
  When writes are enabled:
182
208
 
183
- 1. `insert_data`, `update_data`, `delete_data`, and DDL tools require `confirmed: true` unless the client completes MCP elicitation.
209
+ 1. `insert_data`, `update_data`, `delete_data`, and DDL tools ask the user to confirm through MCP elicitation when the client supports it (Cursor, VS Code, Claude). Clients without elicitation must pass `confirmed: true`. Over HTTP, prompts work for 2026-07-28 clients; 2025-era HTTP clients must pass `confirmed: true` because the stateless transport cannot carry their elicitation round trip.
184
210
  2. `update_data` and `delete_data` require nonempty structured `filters`, not raw SQL WHERE text.
185
211
  3. With the default `REQUIRE_WRITE_PREVIEW=true`, call `preview_update` or `preview_delete` first and pass its `previewToken` to the matching write.
186
212
  4. Preview tokens expire after 10 minutes, are single-use, and are bound to the same tool, table, filters, and update payload.
@@ -206,7 +232,14 @@ The default endpoint is:
206
232
  http://127.0.0.1:3333/mcp
207
233
  ```
208
234
 
209
- An HTTP client must accept `application/json, text/event-stream`. Each HTTP request creates a fresh MCP server instance. Preview tokens use a process-wide store so they remain valid across requests to the same process.
235
+ The HTTP endpoint serves both the 2026-07-28 MCP protocol and 2025-era clients. A client must accept `application/json, text/event-stream`. Each HTTP request creates a fresh MCP server instance; preview tokens, stored query results, and query plans use process-wide stores, so they stay valid across requests to the same process.
236
+
237
+ HTTP security:
238
+
239
+ - Only `/mcp` is served. `Host` and `Origin` headers are checked against `MCP_HTTP_ALLOWED_HOSTS` (by default loopback names, the bind host, and the `MCP_BASE_URL` host) to block DNS-rebinding attacks from web pages.
240
+ - Set `MCP_HTTP_AUTH_TOKEN` to require `Authorization: Bearer <token>`.
241
+ - The server speaks plain HTTP. Off loopback, put a TLS-terminating reverse proxy in front so the bearer token and query results are encrypted, and set `MCP_BASE_URL` to its `https://` address. Startup logs a warning when a non-loopback bind has no `https://` `MCP_BASE_URL`.
242
+ - Binding `MCP_HTTP_HOST` to anything other than loopback fails at startup unless `MCP_HTTP_AUTH_TOKEN` is set, or `MCP_HTTP_ALLOW_UNAUTHENTICATED=true` acknowledges that another layer (reverse proxy, network policy) protects the endpoint.
210
243
 
211
244
  For a reverse proxy or externally published path, set `MCP_BASE_URL` to the public base without the final `/mcp` segment:
212
245
 
@@ -222,12 +255,15 @@ Cursor HTTP configuration:
222
255
  {
223
256
  "mcpServers": {
224
257
  "mssql-http": {
225
- "url": "http://127.0.0.1:3333/mcp"
258
+ "url": "http://127.0.0.1:3333/mcp",
259
+ "headers": { "Authorization": "Bearer ${env:MSSQL_MCP_TOKEN}" }
226
260
  }
227
261
  }
228
262
  }
229
263
  ```
230
264
 
265
+ Omit `headers` when `MCP_HTTP_AUTH_TOKEN` is not set.
266
+
231
267
  ## Tools
232
268
 
233
269
  | Tool | Mode | Purpose |
@@ -243,7 +279,7 @@ Cursor HTTP configuration:
243
279
  | `describe_relationships` | Read | Describe foreign keys involving one table |
244
280
  | `describe_dependencies` | Read | List objects that depend on an object |
245
281
  | `analyze_table` | Read | Return row counts, storage, and index details |
246
- | `read_data` | Read | Execute a validated SELECT query |
282
+ | `read_data` | Read | Execute a validated SELECT (or CTE) query in a rolled-back transaction |
247
283
  | `search_data` | Read | Search columns with parameterized LIKE predicates |
248
284
  | `explain_query` | Read | Generate an estimated SELECT execution plan |
249
285
  | `preview_update` | Read | Preview an update and issue a token when required |
@@ -270,9 +306,20 @@ Clients with MCP resource support can discover:
270
306
  - `mssql://database/{databaseName}/object/{schemaName}/{objectName}/dependencies`
271
307
  - `mssql://query-plan/{planId}`
272
308
  - `mssql://query-result/{resultId}`
309
+ - `ui://mssql/query-results.html` (MCP Apps view)
273
310
 
274
311
  Table and object listings are cached for 30 seconds. Query plan and large query result resources are temporary process-local artifacts.
275
312
 
313
+ ### Query results grid (MCP Apps)
314
+
315
+ `read_data` and `search_data` declare an [MCP Apps](https://modelcontextprotocol.io/extensions/apps) view. Hosts that support MCP Apps (Claude, VS Code, Cursor 2.6+, and others) render results as a sortable, filterable grid inline in the conversation. Other clients ignore the view and use the normal text and structured result.
316
+
317
+ ### read_data rules
318
+
319
+ `read_data` accepts one `SELECT` statement, optionally preceded by common table expressions (`WITH ...`). String literals, comments, and bracketed or quoted identifiers are ignored when checking for disallowed keywords, so `[Update]` columns or `'Update pending'` values are fine. Statements that modify data, execute code (`EXEC`, `sp_`/`xp_` procedures), declare variables, or read server identity (`@@` variables, `SUSER_SNAME()`) are rejected.
320
+
321
+ Every query also runs inside a transaction that is always rolled back, and results stream until `MAX_ROWS` rows have been read, at which point the query is cancelled and the result is marked `truncated`. SQL Server error messages (for example `Invalid column name`) are returned so the model can correct the query. Cancelling a tool call in the client cancels the running SQL request.
322
+
276
323
  Available prompts:
277
324
 
278
325
  - `explore_schema`
@@ -296,7 +343,7 @@ The repository includes a seeded SQL Server 2022 Docker environment:
296
343
  ```bash
297
344
  cp .env.example .env
298
345
  npm run db:up
299
- npm run test:e2e
346
+ npm run test:e2e # every tool over HTTP, then protocol checks (2026-07-28 + 2025 stdio)
300
347
  ```
301
348
 
302
349
  See [`docs/dev-database.md`](docs/dev-database.md) for database and E2E details and [`CONTRIBUTING.md`](CONTRIBUTING.md) for build, lint, and test commands.
@@ -308,6 +355,8 @@ See [`docs/dev-database.md`](docs/dev-database.md) for database and E2E details
308
355
  - `DDL_DISABLED`: set `ENABLE_DDL` to `"true"` only when DDL access is intended.
309
356
  - `PREVIEW_TOKEN_INVALID`: create a new matching preview and use its token once within 10 minutes.
310
357
  - stdio JSON parse errors: ensure scripts and dependencies write logs to stderr, not stdout.
358
+ - HTTP `403 Forbidden`: the request's `Host` or `Origin` is not in `MCP_HTTP_ALLOWED_HOSTS`; add the public hostname (or set `MCP_BASE_URL`).
359
+ - HTTP `401 Unauthorized`: send `Authorization: Bearer <MCP_HTTP_AUTH_TOKEN>`.
311
360
  - database rejected: add it to `DATABASES` and use the exact allowed name in `databaseName`.
312
361
 
313
362
  ## Security
@@ -316,7 +365,8 @@ See [`docs/dev-database.md`](docs/dev-database.md) for database and E2E details
316
365
  - Set `READONLY=true` whenever writes are unnecessary.
317
366
  - Keep `ENABLE_DDL=false` unless schema changes are explicitly needed.
318
367
  - Keep credentials out of source control and use your client's secret-input support or a secrets manager.
319
- - Bind HTTP mode to a trusted interface and add network authentication or isolation outside this package.
368
+ - Keep HTTP mode on loopback, or set `MCP_HTTP_AUTH_TOKEN` and `MCP_HTTP_ALLOWED_HOSTS` when exposing it. Prefer TLS termination at a reverse proxy.
369
+ - `read_data` validation and its rolled-back transaction are defense in depth; a least-privilege login is still the primary control.
320
370
  - Set `ENCRYPT=true` for TLS deployments and keep `TRUST_SERVER_CERTIFICATE=false` when the server certificate is publicly or privately trusted.
321
371
  - Report vulnerabilities through the [security policy](.github/SECURITY.md).
322
372
 
@@ -0,0 +1,18 @@
1
+ import type { McpServer } from "@modelcontextprotocol/server";
2
+ /**
3
+ * MCP Apps (io.modelcontextprotocol/ui) view that renders read_data and
4
+ * search_data results as an interactive grid in hosts that support it
5
+ * (Claude, VS Code, Cursor, …). Hosts without MCP Apps ignore the tool
6
+ * metadata and keep using the text/structured result.
7
+ */
8
+ export declare const QUERY_RESULTS_APP_URI = "ui://mssql/query-results.html";
9
+ export declare function buildQueryResultsHtml(): string;
10
+ export declare function registerQueryResultsApp(server: McpServer): void;
11
+ /** Tool `_meta` linking a tool to the query-results view (both key styles). */
12
+ export declare const queryResultsToolMeta: {
13
+ ui: {
14
+ resourceUri: string;
15
+ };
16
+ "ui/resourceUri": string;
17
+ };
18
+ //# sourceMappingURL=queryResultsApp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queryResultsApp.d.ts","sourceRoot":"","sources":["../../src/apps/queryResultsApp.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAE9D;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,kCAAkC,CAAC;AAqOrE,wBAAgB,qBAAqB,IAAI,MAAM,CAmB9C;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAuB/D;AAED,+EAA+E;AAC/E,eAAO,MAAM,oBAAoB;;;;;CAGhC,CAAC"}
@@ -0,0 +1,272 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { createRequire } from "node:module";
3
+ import { RESOURCE_MIME_TYPE, registerAppResource, } from "@modelcontextprotocol/ext-apps/server";
4
+ /**
5
+ * MCP Apps (io.modelcontextprotocol/ui) view that renders read_data and
6
+ * search_data results as an interactive grid in hosts that support it
7
+ * (Claude, VS Code, Cursor, …). Hosts without MCP Apps ignore the tool
8
+ * metadata and keep using the text/structured result.
9
+ */
10
+ export const QUERY_RESULTS_APP_URI = "ui://mssql/query-results.html";
11
+ const require = createRequire(import.meta.url);
12
+ /**
13
+ * Loads the self-contained ext-apps View runtime and rewrites its trailing
14
+ * `export{…}` into a local binding so it can be inlined into a single
15
+ * module script (hosts render the view from one HTML document).
16
+ */
17
+ function loadAppRuntime() {
18
+ const bundle = readFileSync(require.resolve("@modelcontextprotocol/ext-apps/app-with-deps"), "utf8");
19
+ const exportStart = bundle.lastIndexOf("export{");
20
+ if (exportStart === -1) {
21
+ throw new Error("Unexpected ext-apps bundle format: missing export list.");
22
+ }
23
+ const exportEnd = bundle.indexOf("}", exportStart);
24
+ const entries = bundle
25
+ .slice(exportStart + "export{".length, exportEnd)
26
+ .split(",")
27
+ .map((entry) => {
28
+ const [local, exported = local] = entry.trim().split(/\s+as\s+/);
29
+ return `${JSON.stringify(exported)}:${local}`;
30
+ });
31
+ return `${bundle.slice(0, exportStart)}const ExtApps={${entries.join(",")}};${bundle.slice(exportEnd + 1)}`;
32
+ }
33
+ const VIEW_STYLES = `
34
+ :root { color-scheme: light dark; }
35
+ * { box-sizing: border-box; }
36
+ body {
37
+ margin: 0;
38
+ font-family: var(--font-sans, system-ui, sans-serif);
39
+ font-size: var(--font-text-sm-size, 13px);
40
+ color: var(--color-text-primary, CanvasText);
41
+ background: var(--color-background-primary, Canvas);
42
+ }
43
+ header {
44
+ display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
45
+ padding: 8px 10px;
46
+ border-bottom: 1px solid var(--color-border-primary, #8884);
47
+ }
48
+ header .summary { flex: 1; color: var(--color-text-secondary, GrayText); }
49
+ .badge {
50
+ padding: 1px 6px; border-radius: 999px; font-size: 11px;
51
+ background: var(--color-background-warning, #f5a62333);
52
+ color: var(--color-text-warning, inherit);
53
+ }
54
+ input[type="search"] {
55
+ font: inherit; padding: 3px 8px; min-width: 160px;
56
+ color: inherit; background: transparent;
57
+ border: 1px solid var(--color-border-primary, #8886);
58
+ border-radius: var(--border-radius-sm, 4px);
59
+ }
60
+ .grid { overflow: auto; max-height: 480px; }
61
+ table { border-collapse: collapse; width: 100%; font-variant-numeric: tabular-nums; }
62
+ th, td {
63
+ padding: 4px 10px; text-align: left; white-space: nowrap;
64
+ border-bottom: 1px solid var(--color-border-secondary, #8882);
65
+ max-width: 360px; overflow: hidden; text-overflow: ellipsis;
66
+ }
67
+ th {
68
+ position: sticky; top: 0; cursor: pointer; user-select: none;
69
+ background: var(--color-background-secondary, Canvas);
70
+ font-weight: 600;
71
+ }
72
+ th[aria-sort="ascending"]::after { content: " ▲"; }
73
+ th[aria-sort="descending"]::after { content: " ▼"; }
74
+ td.null { color: var(--color-text-tertiary, GrayText); font-style: italic; }
75
+ td.num { text-align: right; }
76
+ .empty, .error { padding: 16px 10px; color: var(--color-text-secondary, GrayText); }
77
+ .error { color: var(--color-text-danger, #d33); }
78
+ `;
79
+ const VIEW_SCRIPT = `
80
+ const { App, applyDocumentTheme, applyHostStyleVariables, applyHostFonts } = ExtApps;
81
+ const MAX_RENDERED_ROWS = 1000;
82
+ const root = document.getElementById("root");
83
+ let rows = [];
84
+ let columns = [];
85
+ let meta = {};
86
+ let sort = { column: null, direction: 1 };
87
+ let filter = "";
88
+
89
+ function extractRows(payload) {
90
+ const data = payload && payload.data;
91
+ if (Array.isArray(data)) return data;
92
+ if (data && Array.isArray(data.rows)) return data.rows;
93
+ if (data && Array.isArray(data.data)) return data.data;
94
+ return [];
95
+ }
96
+
97
+ function formatCell(value) {
98
+ if (value === null || value === undefined) return { text: "NULL", cls: "null" };
99
+ if (typeof value === "number" || typeof value === "bigint") return { text: String(value), cls: "num" };
100
+ if (typeof value === "object") return { text: JSON.stringify(value), cls: "" };
101
+ return { text: String(value), cls: "" };
102
+ }
103
+
104
+ function el(tag, attrs, children) {
105
+ const node = document.createElement(tag);
106
+ for (const [key, value] of Object.entries(attrs || {})) {
107
+ if (key === "text") node.textContent = value;
108
+ else if (key.startsWith("on")) node.addEventListener(key.slice(2), value);
109
+ else node.setAttribute(key, value);
110
+ }
111
+ for (const child of children || []) node.append(child);
112
+ return node;
113
+ }
114
+
115
+ function visibleRows() {
116
+ let result = rows;
117
+ if (filter) {
118
+ const needle = filter.toLowerCase();
119
+ result = result.filter((row) =>
120
+ columns.some((column) => String(row[column] ?? "").toLowerCase().includes(needle))
121
+ );
122
+ }
123
+ if (sort.column !== null) {
124
+ const column = sort.column;
125
+ result = [...result].sort((a, b) => {
126
+ const left = a[column];
127
+ const right = b[column];
128
+ if (left === right) return 0;
129
+ if (left === null || left === undefined) return 1;
130
+ if (right === null || right === undefined) return -1;
131
+ return (left < right ? -1 : 1) * sort.direction;
132
+ });
133
+ }
134
+ return result;
135
+ }
136
+
137
+ function render() {
138
+ root.replaceChildren();
139
+ if (meta.error) {
140
+ root.append(el("div", { class: "error", text: meta.error }));
141
+ return;
142
+ }
143
+
144
+ const shown = visibleRows();
145
+ const rendered = shown.slice(0, MAX_RENDERED_ROWS);
146
+ const summaryParts = [rows.length + " row" + (rows.length === 1 ? "" : "s")];
147
+ if (filter) summaryParts.push(shown.length + " matching");
148
+ if (rendered.length < shown.length) summaryParts.push("showing first " + rendered.length);
149
+
150
+ const header = el("header", {}, [
151
+ el("span", { class: "summary", text: summaryParts.join(" · ") }),
152
+ ]);
153
+ if (meta.truncated) {
154
+ header.append(el("span", { class: "badge", text: "Truncated at MAX_ROWS", title: "More rows exist on the server" }));
155
+ }
156
+ header.append(
157
+ el("input", {
158
+ type: "search",
159
+ placeholder: "Filter rows",
160
+ value: filter,
161
+ "aria-label": "Filter rows",
162
+ oninput: (event) => {
163
+ filter = event.target.value;
164
+ render();
165
+ const input = root.querySelector("input[type=search]");
166
+ input.focus();
167
+ input.setSelectionRange(filter.length, filter.length);
168
+ },
169
+ })
170
+ );
171
+ root.append(header);
172
+
173
+ if (rows.length === 0) {
174
+ root.append(el("div", { class: "empty", text: meta.message || "No rows returned." }));
175
+ return;
176
+ }
177
+
178
+ const headRow = el("tr", {}, columns.map((column) => {
179
+ const ariaSort = sort.column === column ? (sort.direction === 1 ? "ascending" : "descending") : "none";
180
+ return el("th", {
181
+ text: column,
182
+ scope: "col",
183
+ "aria-sort": ariaSort,
184
+ onclick: () => {
185
+ sort = sort.column === column ? { column, direction: -sort.direction } : { column, direction: 1 };
186
+ render();
187
+ },
188
+ });
189
+ }));
190
+ const body = el("tbody", {}, rendered.map((row) =>
191
+ el("tr", {}, columns.map((column) => {
192
+ const cell = formatCell(row[column]);
193
+ return el("td", { class: cell.cls, text: cell.text, title: cell.text });
194
+ }))
195
+ ));
196
+ root.append(el("div", { class: "grid" }, [el("table", {}, [el("thead", {}, [headRow]), body])]));
197
+ }
198
+
199
+ function showResult(result) {
200
+ const payload = result && result.structuredContent;
201
+ if (!payload) {
202
+ meta = { error: "This result has no structured content to display." };
203
+ } else if (payload.success === false) {
204
+ meta = { error: payload.message || "The query failed." };
205
+ } else {
206
+ rows = extractRows(payload);
207
+ columns = rows.length > 0 ? Object.keys(rows[0]) : [];
208
+ meta = { truncated: payload.truncated === true, message: payload.message };
209
+ }
210
+ sort = { column: null, direction: 1 };
211
+ filter = "";
212
+ render();
213
+ }
214
+
215
+ function applyHostContext(context) {
216
+ if (!context) return;
217
+ if (context.theme) applyDocumentTheme(context.theme);
218
+ if (context.styles && context.styles.variables) applyHostStyleVariables(context.styles.variables);
219
+ if (context.styles && context.styles.css && context.styles.css.fonts) applyHostFonts(context.styles.css.fonts);
220
+ }
221
+
222
+ const app = new App({ name: "mssql-query-results", version: "1.0.0" }, {}, { autoResize: true });
223
+ app.ontoolresult = showResult;
224
+ app.onhostcontextchanged = applyHostContext;
225
+ root.append(el("div", { class: "empty", text: "Waiting for query results…" }));
226
+ await app.connect();
227
+ applyHostContext(app.getHostContext());
228
+ `;
229
+ let cachedHtml;
230
+ export function buildQueryResultsHtml() {
231
+ cachedHtml ??= `<!doctype html>
232
+ <html lang="en">
233
+ <head>
234
+ <meta charset="utf-8">
235
+ <meta name="viewport" content="width=device-width, initial-scale=1">
236
+ <title>Query results</title>
237
+ <style>${VIEW_STYLES}</style>
238
+ </head>
239
+ <body>
240
+ <div id="root"></div>
241
+ <script type="module">
242
+ ${loadAppRuntime()}
243
+ ${VIEW_SCRIPT}
244
+ </script>
245
+ </body>
246
+ </html>
247
+ `;
248
+ return cachedHtml;
249
+ }
250
+ export function registerQueryResultsApp(server) {
251
+ registerAppResource(server, "query_results_app", QUERY_RESULTS_APP_URI, {
252
+ title: "Query Results Grid",
253
+ description: "Interactive, sortable and filterable grid for read_data and search_data results.",
254
+ mimeType: RESOURCE_MIME_TYPE,
255
+ _meta: { ui: { prefersBorder: true } },
256
+ }, async () => ({
257
+ contents: [
258
+ {
259
+ uri: QUERY_RESULTS_APP_URI,
260
+ mimeType: RESOURCE_MIME_TYPE,
261
+ text: buildQueryResultsHtml(),
262
+ _meta: { ui: { prefersBorder: true } },
263
+ },
264
+ ],
265
+ }));
266
+ }
267
+ /** Tool `_meta` linking a tool to the query-results view (both key styles). */
268
+ export const queryResultsToolMeta = {
269
+ ui: { resourceUri: QUERY_RESULTS_APP_URI },
270
+ "ui/resourceUri": QUERY_RESULTS_APP_URI,
271
+ };
272
+ //# sourceMappingURL=queryResultsApp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queryResultsApp.js","sourceRoot":"","sources":["../../src/apps/queryResultsApp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=checkNodeVersion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checkNodeVersion.d.ts","sourceRoot":"","sources":["../src/checkNodeVersion.ts"],"names":[],"mappings":""}
@@ -0,0 +1,9 @@
1
+ // Imported first by index.ts so it runs before any dependency is evaluated.
2
+ // Logs to stderr only: stdout belongs to the stdio JSON-RPC stream.
3
+ import { nodeVersionError } from "./nodeVersion.js";
4
+ const versionError = nodeVersionError();
5
+ if (versionError) {
6
+ console.error(versionError);
7
+ process.exit(1);
8
+ }
9
+ //# sourceMappingURL=checkNodeVersion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"checkNodeVersion.js","sourceRoot":"","sources":["../src/checkNodeVersion.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,oEAAoE;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEpD,MAAM,YAAY,GAAG,gBAAgB,EAAE,CAAC;AACxC,IAAI,YAAY,EAAE,CAAC;IACjB,OAAO,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;IAC5B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC"}
package/dist/config.d.ts CHANGED
@@ -1,10 +1,32 @@
1
1
  type Environment = NodeJS.ProcessEnv;
2
2
  export type McpTransportMode = "stdio" | "http";
3
+ export declare const SQL_AUTH_TYPES: readonly ["sql", "ntlm", "azure-default", "azure-service-principal", "azure-access-token"];
4
+ export type SqlAuthType = (typeof SQL_AUTH_TYPES)[number];
5
+ export type SqlAuthConfig = {
6
+ type: "sql";
7
+ user: string;
8
+ password: string;
9
+ } | {
10
+ type: "ntlm";
11
+ user: string;
12
+ password: string;
13
+ domain: string;
14
+ } | {
15
+ type: "azure-default";
16
+ clientId?: string;
17
+ } | {
18
+ type: "azure-service-principal";
19
+ clientId: string;
20
+ clientSecret: string;
21
+ tenantId: string;
22
+ } | {
23
+ type: "azure-access-token";
24
+ token: string;
25
+ };
3
26
  export interface SqlConnectionConfig {
4
27
  serverName: string;
5
28
  serverPort?: number;
6
- dbUser: string;
7
- dbPassword: string;
29
+ auth: SqlAuthConfig;
8
30
  encrypt: boolean;
9
31
  trustServerCertificate: boolean;
10
32
  connectionTimeoutSeconds: number;
@@ -22,15 +44,21 @@ export interface EnvironmentConfig extends SqlConnectionConfig {
22
44
  mcpHttpHost: string;
23
45
  mcpHttpPort: number;
24
46
  mcpBaseUrl?: string;
47
+ mcpHttpAuthToken?: string;
48
+ mcpHttpAllowUnauthenticated: boolean;
49
+ mcpHttpAllowedHosts: string[];
25
50
  }
26
51
  export declare function configureRuntimeEnvironment(environment: EnvironmentConfig): void;
27
52
  export declare function parseDatabaseList(value: string | undefined): string[];
53
+ export declare function parseSqlAuthConfig(env?: Environment): SqlAuthConfig;
28
54
  export declare function parseSqlConnectionConfig(env?: Environment): SqlConnectionConfig;
29
55
  export declare function parseEnvironmentConfig(env?: Environment): EnvironmentConfig;
30
56
  export declare function getMaxRows(): number;
31
57
  export declare function getDefaultSearchLimit(): number;
32
58
  export declare function clampRowLimit(limit: unknown, fallback?: number): number;
33
59
  export declare function getMcpEndpointUrl(environment: Pick<EnvironmentConfig, "mcpBaseUrl" | "mcpHttpHost" | "mcpHttpPort">): string;
60
+ /** Brackets IPv6 literals (`::1` -> `[::1]`) for use in a URL authority. */
61
+ export declare function formatUrlHost(host: string): string;
34
62
  export declare function getMaxWriteRows(): number;
35
63
  export {};
36
64
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAQA,KAAK,WAAW,GAAG,MAAM,CAAC,UAAU,CAAC;AAErC,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,MAAM,CAAC;AAEhD,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,sBAAsB,EAAE,OAAO,CAAC;IAChC,wBAAwB,EAAE,MAAM,CAAC;IACjC,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,iBAAkB,SAAQ,mBAAmB;IAC5D,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,YAAY,EAAE,gBAAgB,CAAC;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAID,wBAAgB,2BAA2B,CACzC,WAAW,EAAE,iBAAiB,GAC7B,IAAI,CAKN;AAmHD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,EAAE,CASrE;AAED,wBAAgB,wBAAwB,CACtC,GAAG,GAAE,WAAyB,GAC7B,mBAAmB,CAuBrB;AAED,wBAAgB,sBAAsB,CACpC,GAAG,GAAE,WAAyB,GAC7B,iBAAiB,CAgDnB;AAeD,wBAAgB,UAAU,IAAI,MAAM,CAKnC;AAED,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,SAAe,GAAG,MAAM,CAa7E;AAED,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,IAAI,CACf,iBAAiB,EACjB,YAAY,GAAG,aAAa,GAAG,aAAa,CAC7C,GACA,MAAM,CAKR;AAED,wBAAgB,eAAe,IAAI,MAAM,CASxC"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAQA,KAAK,WAAW,GAAG,MAAM,CAAC,UAAU,CAAC;AAErC,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,MAAM,CAAC;AAEhD,eAAO,MAAM,cAAc,4FAMjB,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAE1D,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GAC/C;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAChE;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAC5C;IACE,IAAI,EAAE,yBAAyB,CAAC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;CAClB,GACD;IAAE,IAAI,EAAE,oBAAoB,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAElD,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,aAAa,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,sBAAsB,EAAE,OAAO,CAAC;IAChC,wBAAwB,EAAE,MAAM,CAAC;IACjC,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,iBAAkB,SAAQ,mBAAmB;IAC5D,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,YAAY,EAAE,gBAAgB,CAAC;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,2BAA2B,EAAE,OAAO,CAAC;IACrC,mBAAmB,EAAE,MAAM,EAAE,CAAC;CAC/B;AAID,wBAAgB,2BAA2B,CACzC,WAAW,EAAE,iBAAiB,GAC7B,IAAI,CAKN;AAmHD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,EAAE,CASrE;AAeD,wBAAgB,kBAAkB,CAChC,GAAG,GAAE,WAAyB,GAC7B,aAAa,CAoCf;AAED,wBAAgB,wBAAwB,CACtC,GAAG,GAAE,WAAyB,GAC7B,mBAAmB,CA0BrB;AAED,wBAAgB,sBAAsB,CACpC,GAAG,GAAE,WAAyB,GAC7B,iBAAiB,CAyDnB;AAeD,wBAAgB,UAAU,IAAI,MAAM,CAKnC;AAED,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,SAAe,GAAG,MAAM,CAa7E;AAED,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,IAAI,CACf,iBAAiB,EACjB,YAAY,GAAG,aAAa,GAAG,aAAa,CAC7C,GACA,MAAM,CAKR;AAED,4EAA4E;AAC5E,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,wBAAgB,eAAe,IAAI,MAAM,CASxC"}