Skip to content

Commit 8a5ff0c

Browse files
committed
feat: Add configurable verbose error mode for AI debugging
Problem: Error messages were intentionally sanitized for security, making it impossible for AI agents to debug SQL command failures. Solution: Added VERBOSE_ERRORS environment variable that exposes full error details when enabled while keeping secure defaults. Features: - New errorHandler utility with formatError() and formatSqlError() - SQL error details: number, state, class, lineNumber, serverName - Stack traces and original error context - Query context in error messages - Secure by default (VERBOSE_ERRORS not set) - Comprehensive error logging to console Usage: Set VERBOSE_ERRORS=true in MCP env config to enable full errors Files Added: - src/utils/errorHandler.ts (error formatting utilities) - VERBOSE_ERRORS.md (complete documentation) Files Modified: - src/index.ts (use formatError in main handler) - src/tools/ReadDataTool.ts (use formatSqlError for SQL errors) Benefits: ✅ AI agents can debug SQL syntax errors ✅ Full error context for troubleshooting ✅ Toggle on/off without code changes ✅ Secure defaults for production Ready for PR to upstream microsoft/SQL-AI-samples
1 parent f723313 commit 8a5ff0c

File tree

4 files changed

+364
-15
lines changed

4 files changed

+364
-15
lines changed

MssqlMcp/Node/VERBOSE_ERRORS.md

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
# Enhanced Error Handling for MSSQL MCP Server
2+
3+
## Problem
4+
5+
The original MSSQL MCP server intentionally hides error details for security reasons, making it impossible for AI agents to debug SQL commands. Errors like this:
6+
7+
```
8+
Failed to execute query: Database query execution failed
9+
```
10+
11+
Provide no actionable information for debugging.
12+
13+
## Solution
14+
15+
Added configurable **VERBOSE_ERRORS** mode that exposes full error details when enabled, while keeping secure defaults for production.
16+
17+
## Usage
18+
19+
### Enable Verbose Errors
20+
21+
Set the `VERBOSE_ERRORS` environment variable to `true` in your MCP configuration:
22+
23+
**~/.mcp.json:**
24+
```json
25+
{
26+
"mcpServers": {
27+
"mssql_analytics": {
28+
"command": "node",
29+
"args": ["/path/to/SQL-AI-samples/MssqlMcp/Node/dist/index.js"],
30+
"env": {
31+
"SERVER_NAME": "your-server.database.windows.net",
32+
"DATABASE_NAME": "your-database",
33+
"READONLY": "true",
34+
"VERBOSE_ERRORS": "true"
35+
}
36+
}
37+
}
38+
}
39+
```
40+
41+
### Error Output Comparison
42+
43+
**Before (Production Mode - VERBOSE_ERRORS not set):**
44+
```json
45+
{
46+
"success": false,
47+
"message": "Failed to execute query: Database query execution failed",
48+
"error": "SQL_EXECUTION_FAILED"
49+
}
50+
```
51+
52+
**After (Verbose Mode - VERBOSE_ERRORS=true):**
53+
```json
54+
{
55+
"success": false,
56+
"message": "Failed to execute query: Invalid column name 'nonexistent_column'.",
57+
"error": "SQL_EXECUTION_FAILED",
58+
"details": {
59+
"code": "EREQUEST",
60+
"number": 207,
61+
"state": 1,
62+
"class": 16,
63+
"lineNumber": 1,
64+
"serverName": "your-server",
65+
"procName": "",
66+
"stack": "RequestError: Invalid column name 'nonexistent_column'.\n at..."
67+
}
68+
}
69+
```
70+
71+
## Benefits
72+
73+
### For AI Agents
74+
- **Full SQL error details**: Error number, state, line number
75+
- **Stack traces**: Complete error context for debugging
76+
- **Query context**: See which query failed (truncated for safety)
77+
- **Actionable feedback**: AI can identify and fix SQL syntax errors
78+
79+
### For Developers
80+
- **Debug mode**: Toggle verbose errors on/off without code changes
81+
- **Secure by default**: Production mode hides sensitive details
82+
- **Comprehensive logging**: All errors logged to console regardless of mode
83+
84+
## Error Information Exposed
85+
86+
When `VERBOSE_ERRORS=true`, the following details are included:
87+
88+
| Field | Description | Example |
89+
|-------|-------------|---------|
90+
| `code` | Error code | "EREQUEST" |
91+
| `number` | SQL error number | 207 |
92+
| `state` | SQL error state | 1 |
93+
| `class` | SQL error severity | 16 |
94+
| `lineNumber` | Line number in SQL | 1 |
95+
| `serverName` | Database server | "your-server.database.windows.net" |
96+
| `procName` | Stored procedure name | "" |
97+
| `stack` | Full stack trace | "RequestError: Invalid..." |
98+
| `originalError` | Original error object | {...} |
99+
100+
## Security Considerations
101+
102+
### Production Mode (Default)
103+
- ✅ Hides internal error details
104+
- ✅ Only shows safe patterns ("Invalid object name", "Invalid column name")
105+
- ✅ Prevents information leakage
106+
- ✅ Suitable for production environments
107+
108+
### Verbose Mode (VERBOSE_ERRORS=true)
109+
- ⚠️ Exposes full error details
110+
- ⚠️ May reveal schema information
111+
- ⚠️ May expose server details
112+
- ✅ Excellent for development and debugging
113+
- ✅ Required for AI-assisted SQL debugging
114+
115+
**Recommendation**: Only enable `VERBOSE_ERRORS=true` in:
116+
- Development environments
117+
- Testing/debugging sessions
118+
- Read-only database connections
119+
- Trusted environments where you control the AI agent
120+
121+
## Implementation Details
122+
123+
### Files Modified
124+
125+
1. **src/utils/errorHandler.ts** (NEW)
126+
- `formatError()`: General error formatting with verbose mode
127+
- `formatSqlError()`: SQL-specific error formatting
128+
- `isVerboseErrorMode()`: Check environment variable
129+
130+
2. **src/index.ts**
131+
- Updated main error handler to use `formatError()`
132+
133+
3. **src/tools/ReadDataTool.ts**
134+
- Updated catch block to use `formatSqlError()`
135+
- Extracts query before try/catch for error context
136+
137+
### Testing
138+
139+
Test verbose error mode with an intentional error:
140+
141+
```typescript
142+
// This will fail with verbose details
143+
const result = await callMCPTool('mcp__mssql_analytics__read_data', {
144+
query: 'SELECT nonexistent_column FROM nonexistent_table'
145+
});
146+
147+
console.log(JSON.stringify(result, null, 2));
148+
```
149+
150+
**Expected Output (VERBOSE_ERRORS=true):**
151+
```json
152+
{
153+
"success": false,
154+
"message": "Failed to execute query: Invalid object name 'nonexistent_table'.",
155+
"error": "SQL_EXECUTION_FAILED",
156+
"details": {
157+
"code": "EREQUEST",
158+
"number": 208,
159+
"state": 1,
160+
"class": 16,
161+
"lineNumber": 1,
162+
"serverName": "...",
163+
"stack": "..."
164+
}
165+
}
166+
```
167+
168+
## Future Enhancements
169+
170+
Potential improvements for this feature:
171+
172+
1. **Granular verbosity levels**:
173+
- `VERBOSE_ERRORS=minimal`: Show error message only
174+
- `VERBOSE_ERRORS=normal`: Show message + error codes
175+
- `VERBOSE_ERRORS=full`: Show everything (current behavior)
176+
177+
2. **Apply to all tools**: Currently only applied to ReadDataTool and main handler. Could extend to:
178+
- UpdateDataTool
179+
- InsertDataTool
180+
- CreateTableTool
181+
- etc.
182+
183+
3. **Structured error codes**: Standardize error codes across all tools
184+
185+
4. **Error categorization**: Group errors by type (syntax, permission, connection, etc.)
186+
187+
## Contributing
188+
189+
To open a PR with this feature:
190+
191+
1. Fork the repository
192+
2. Create a feature branch: `git checkout -b feature/verbose-errors`
193+
3. Commit changes with clear messages
194+
4. Add tests demonstrating error visibility
195+
5. Update main README with VERBOSE_ERRORS documentation
196+
6. Open PR against upstream
197+
198+
---
199+
200+
*Last Updated: November 12, 2025*
201+
*Status: Ready for Testing & PR*

MssqlMcp/Node/src/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,11 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
138138
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
139139
};
140140
} catch (error) {
141+
// Enhanced error handling with configurable verbosity
142+
const { formatError } = await import("./utils/errorHandler.js");
143+
const errorDetails = formatError(error, `call tool '${name}'`, 'TOOL_EXECUTION_FAILED');
141144
return {
142-
content: [{ type: "text", text: `Error occurred: ${error}` }],
145+
content: [{ type: "text", text: JSON.stringify(errorDetails, null, 2) }],
143146
isError: true,
144147
};
145148
}

MssqlMcp/Node/src/tools/ReadDataTool.ts

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -204,8 +204,8 @@ export class ReadDataTool implements Tool {
204204
* @returns Query execution result
205205
*/
206206
async run(params: any) {
207+
const { query } = params; // Extract query before try/catch for error handler access
207208
try {
208-
const { query } = params;
209209

210210
// Validate the query for security issues
211211
const validation = this.validateQuery(query);
@@ -241,19 +241,9 @@ export class ReadDataTool implements Tool {
241241
};
242242

243243
} catch (error) {
244-
console.error("Error executing query:", error);
245-
246-
// Don't expose internal error details to prevent information leakage
247-
const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
248-
const safeErrorMessage = errorMessage.includes('Invalid object name')
249-
? errorMessage
250-
: 'Database query execution failed';
251-
252-
return {
253-
success: false,
254-
message: `Failed to execute query: ${safeErrorMessage}`,
255-
error: 'QUERY_EXECUTION_FAILED'
256-
};
244+
// Use enhanced error handler with configurable verbosity
245+
const { formatSqlError } = await import('../utils/errorHandler.js');
246+
return formatSqlError(error, query);
257247
}
258248
}
259249
}

0 commit comments

Comments
 (0)