apache/shardingsphere · error · MCPUnsupportedSQLStatementException
Statement is not supported by the MCP contract.
Error message
Statement is not supported by the MCP contract.
What it means
Thrown by SQLStatementScanner.extractLeadingKeyword as MCPUnsupportedSQLStatementException when the scanner cannot extract any leading alphabetic keyword from the statement. If the first visible token starts with a non-letter (digit, punctuation, paren) or the statement has no visible tokens at all, keyword extraction yields an empty span and the statement is declared unsupported.
Source
Thrown at mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/SQLStatementScanner.java:106
return sql;
}
SQLStatementScanner scan(final String sql) {
return new SQLStatementScanner(lexerClass, parserClass, sql);
}
String leadingSql() {
return sql.substring(visibleTokens.isEmpty() ? sql.length() : visibleTokens.get(0).getStartIndex()).trim();
}
String extractLeadingKeyword() {
int startIndex = visibleTokens.isEmpty() ? sql.length() : visibleTokens.get(0).getStartIndex();
int stopIndex = startIndex;
while (stopIndex < sql.length() && Character.isLetter(sql.charAt(stopIndex))) {
stopIndex++;
}
if (startIndex == stopIndex) {
throw new MCPUnsupportedSQLStatementException();
}
return sql.substring(startIndex, stopIndex).toUpperCase(Locale.ENGLISH);
}
boolean containsExecutableComment() {
return executableComment;
}
private boolean containsExecutableComment(final String sql, final List<Token> tokens, final boolean lineCommentsHandledByLexer) {
int nextIndex = 0;
int skippedCommentEnd = -1;
for (int index = 0; index < tokens.size(); index++) {
Token each = tokens.get(index);
if (each.getStartIndex() <= skippedCommentEnd) {
continue;
}
if (each.getStartIndex() > nextIndex && containsExecutableCommentMarker(sql.substring(nextIndex, each.getStartIndex()))) {
return true;View on GitHub (pinned to e952770a21)
Solutions
- Rewrite the statement so it begins with a SQL keyword: unwrap `(SELECT ...)` to `SELECT ...`, drop leading literals
- Ensure the payload actually contains a statement, not only comments or whitespace
- If you need expression evaluation, wrap it as `SELECT <expr>` before submitting
Example fix
-- before (SELECT * FROM t_order) LIMIT 10 -- after SELECT * FROM t_order LIMIT 10
Defensive patterns
Strategy: validation
Validate before calling
// Require the first non-space, non-comment character to be a letter
String stripped = sql.strip();
if (stripped.isEmpty() || !Character.isLetter(stripped.charAt(0))) {
throw new IllegalArgumentException("Statement must start with a SQL keyword; wrap expressions in SELECT");
} Try / catch
try {
executeSql(sql);
} catch (MCPUnsupportedSQLStatementException e) {
executeSql("SELECT " + sql.strip().replaceFirst("^\\(|\\)$", "")); // normalize leading keyword
} Prevention
- Always prefix expression-only payloads with SELECT
- Unwrap parenthesized statements before submission
When it happens
Trigger: visibleTokens is empty (comment-only or whitespace-only input), or the character at the first visible token's start index is not a letter — e.g. `(SELECT 1)`, `123 + 1`, `@x`, `$func$ ...`, `"quoted" ...` as the leading text. startIndex == stopIndex triggers the throw.
Common situations: Statements wrapped in parentheses for precedence; expressions starting with literals or variables; empty/comment-only payloads sent by an agent loop; strings whose leading quote/backtick survives as the first token (also caught separately by delimiter validation).
Related errors
- Only one SQL statement is allowed.
- Metadata introspection SQL should use MCP metadata resources
- Statement is not a transaction command.
- Locking read statements such as SELECT ... FOR UPDATE are no
- %s execution_mode is required.
AI-assisted analysis of apache/shardingsphere@e952770a21 (2026-08-14).
Data as JSON: /api/errors/9ba823324d7a95fd.
Report an issue: GitHub.