Skip to content

feat(sqlserver): surface informational messages (STATISTICS, PRINT) in query results#307

Open
esetnik wants to merge 2 commits intobytebase:mainfrom
esetnik:feat/sqlserver-statistics-messages
Open

feat(sqlserver): surface informational messages (STATISTICS, PRINT) in query results#307
esetnik wants to merge 2 commits intobytebase:mainfrom
esetnik:feat/sqlserver-statistics-messages

Conversation

@esetnik
Copy link
Copy Markdown

@esetnik esetnik commented Apr 8, 2026

Summary

SQL Server emits informational messages via the TDS protocol for SET STATISTICS TIME/IO output, PRINT statements, and warnings. The mssql driver's Request object exposes these through info events, but they were previously discarded.

This change captures those messages during query execution and includes them in the response when present, enabling MCP clients to access query performance statistics and diagnostic output.

Motivation

When using DBHub as an MCP server to analyze SQL Server query performance, there's currently no way to see SET STATISTICS TIME ON or SET STATISTICS IO ON output — the tool only returns result set rows. This forces users to work around the limitation with DECLARE @start timing variables or DMV queries, which provide less detail than the native statistics output.

With this change, running:

SET STATISTICS TIME ON;
SELECT TOP 10 * FROM users;
SET STATISTICS TIME OFF;

...will include the CPU/elapsed time breakdown in the response's messages array alongside the result rows.

Changes

  • src/connectors/interface.ts: Add optional messages?: string[] field to SQLResult
  • src/connectors/sqlserver/index.ts: Listen for info events on the Request object before executing queries, collect messages, and include them in the result when present
  • src/tools/execute-sql.ts: Pass messages through to the MCP tool response when non-empty

Notes

  • The change is backward-compatible — messages is optional and only included when non-empty
  • Only the SQL Server connector is affected; other connectors continue to return the same SQLResult shape
  • The mssql package's Request.on('info') event covers all SQL Server informational messages (severity < 10): statistics, print output, warnings, etc.

…n query results

SQL Server emits informational messages via the TDS protocol for
SET STATISTICS TIME/IO output, PRINT statements, and warnings.
The mssql driver's Request object exposes these through 'info' events,
but they were previously discarded.

This change captures those messages during query execution and includes
them in the response when present, enabling MCP clients to access
query performance statistics and diagnostic output.

Changes:
- Add optional `messages` field to SQLResult interface
- Listen for 'info' events on SQL Server Request before execution
- Include non-empty messages array in execute_sql tool response
Copilot AI review requested due to automatic review settings April 8, 2026 18:36
@esetnik esetnik requested a review from tianzhou as a code owner April 8, 2026 18:36
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds support for surfacing SQL Server informational messages (e.g., SET STATISTICS TIME/IO, PRINT, warnings) by capturing mssql Request info events during execution and returning them to MCP clients when present.

Changes:

  • Extend SQLResult with an optional messages?: string[] field for informational DB messages.
  • Capture SQL Server Request info events during query execution and include them in the connector result.
  • Pass messages through the execute_sql tool response when non-empty.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
src/connectors/interface.ts Adds optional messages to the shared SQLResult contract.
src/connectors/sqlserver/index.ts Collects SQL Server informational messages via Request.on('info') and returns them in SQLResult.
src/tools/execute-sql.ts Includes messages in the tool response payload when provided by the connector.

…ture

Adds three tests covering the new messages behavior:
- PRINT output is captured and returned in messages array
- SET STATISTICS TIME output contains CPU/elapsed timing info
- messages field is absent when no informational messages are emitted
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

Comment on lines 630 to 632
return {
rows: result.recordset || [],
rowCount: result.rowsAffected[0] || 0,
Copy link

Copilot AI Apr 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rowCount is derived from result.rowsAffected[0], which is incorrect for multi-statement batches (e.g. SET STATISTICS TIME ON; SELECT ...; SET STATISTICS TIME OFF; or PRINT ...; SELECT ...;). In those cases the first statement often affects 0 rows, so count will be reported as 0 even when recordset contains rows. Consider computing rowCount based on the returned recordset (for SELECT) and/or using the last entry in rowsAffected (or summing it) to reflect the statement(s) that actually produced the returned rows.

Suggested change
return {
rows: result.recordset || [],
rowCount: result.rowsAffected[0] || 0,
const rows = result.recordset || [];
const rowCount = rows.length > 0
? rows.length
: (result.rowsAffected && result.rowsAffected.length > 0
? result.rowsAffected[result.rowsAffected.length - 1] || 0
: 0);
return {
rows,
rowCount,

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants