apache/shardingsphere · error · MCPInvalidRequestException

Cross-schema SQL is not supported for database `%s`: `%s`.

Error message

Cross-schema SQL is not supported for database `%s`: `%s`.

What it means

MCPSQLExecutionFacade.checkCrossSchemaSql rejects statements that reference objects outside the target database's schema when the database capability does not use BEST_EFFORT schema semantics: for every referenced object that is qualified (or a namespace target) and whose first identifier does not match the metadata schema, it throws MCPInvalidRequestException naming the database and object. This keeps each MCP execution pinned to the schema selected via the database/schema arguments.

Source

Thrown at mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/MCPSQLExecutionFacade.java:116

    private SQLExecutionResult executeInternal(final SQLExecutionRequest executionRequest, final ClassificationResult classificationResult,
                                               final MCPDatabaseCapability databaseCapability) {
        ShardingSpherePreconditions.checkContains(databaseCapability.getSupportedStatementClasses(), classificationResult.getStatementClass(),
                StatementClassNotSupportedException::new);
        checkCrossSchemaSql(executionRequest, databaseCapability, classificationResult);
        return switch (classificationResult.getStatementClass()) {
            case TRANSACTION_CONTROL, SAVEPOINT -> transactionStatementExecutor.execute(
                    executionRequest.getSessionId(), executionRequest.getDatabase(), databaseCapability, classificationResult);
            case QUERY, EXPLAIN, DML, DDL, DCL -> statementExecutor.execute(executionRequest, classificationResult, databaseCapability);
        };
    }
    
    private void checkCrossSchemaSql(final SQLExecutionRequest executionRequest, final MCPDatabaseCapability databaseCapability, final ClassificationResult classificationResult) {
        if (SchemaExecutionSemantics.BEST_EFFORT == databaseCapability.getSchemaExecutionSemantics()) {
            return;
        }
        for (SQLStatementObjectName each : classificationResult.getReferencedObjects()) {
            if (isCrossSchemaReference(each, executionRequest.getDatabase(), databaseCapability.getIdentifierContext())) {
                throw new MCPInvalidRequestException(String.format("Cross-schema SQL is not supported for database `%s`: `%s`.", executionRequest.getDatabase(), each.getObjectName()));
            }
        }
    }
    
    private boolean isCrossSchemaReference(final SQLStatementObjectName objectName, final String databaseName, final DatabaseIdentifierContext identifierContext) {
        return (objectName.isQualified() || objectName.isNamespaceTarget())
                && !identifierContext.matchesMetaData(IdentifierScope.SCHEMA, databaseName,
                        new IdentifierValue(objectName.getFirstIdentifier(), objectName.getFirstIdentifierQuoteCharacter()));
    }
}

View on GitHub (pinned to e952770a21)

Solutions

  1. Remove schema qualifiers from the SQL and rely on the database/schema tool arguments to select the target schema.
  2. Or pass the database/schema arguments matching the qualified prefix so the reference resolves to the target schema.
  3. Create or refresh metadata so the referenced schema is visible to the target database, if cross-schema access is intended.
  4. If cross-schema execution is a hard requirement, use a database type whose capability declares BEST_EFFORT schema semantics.

Example fix

// before
await tools.call('database_gateway_execute_query', { sql: 'SELECT * FROM sales_schema.orders WHERE id = 1', schema: 'reporting' }); // cross-schema -> error

// after
await tools.call('database_gateway_execute_query', { sql: 'SELECT * FROM orders WHERE id = 1', schema: 'sales_schema' });
Defensive patterns

Strategy: validation

Validate before calling

// Reject qualified names that don't match the selected schema before sending
function usesForeignSchema(sql, targetSchema) {
  const refs = sql.match(/\b(from|join|into|update|table)\s+([A-Za-z_][\w$]*(\.[A-Za-z_][\w$]*)+)/gi) ?? [];
  return refs.some(r => {
    const qualifier = r.split(/\s+/)[1].split('.')[0];
    return qualifier.toLowerCase() !== String(targetSchema).toLowerCase();
  });
}
if (usesForeignSchema(sql, schema)) throw new Error('Cross-schema reference in SQL; select the right schema argument instead.');

Type guard

function isSchemaQualified(name) {
  return /^[A-Za-z_][\w$]*\.[A-Za-z_][\w$]*$/.test(name.trim());
}

Try / catch

try {
  return await tools.call('database_gateway_execute_query', { sql, database, schema });
} catch (e) {
  if (/Cross-schema SQL is not supported/.test(e.message)) {
    const { objectName } = parseCrossSchemaObject(e.message);
    return tools.call('database_gateway_execute_query', { sql: sql.replaceAll(objectName, unqualify(objectName)), database, schema: qualifierOf(objectName) });
  }
  throw e;
}

Prevention

When it happens

Trigger: Executing SQL like SELECT * FROM other_schema.users or INSERT INTO db2.orders ... through the MCP execution tools when the resolved database's SchemaExecutionSemantics is not BEST_EFFORT and the qualified prefix does not resolve to the target schema in metadata.

Common situations: Cross-schema joins or fully-qualified object names copied from existing application SQL; multi-tenant databases where each MCP session is bound to one schema; database name vs schema name confusion (e.g. using the catalog name as prefix on engines where they differ).

Related errors


AI-assisted analysis of apache/shardingsphere@e952770a21 (2026-08-14). Data as JSON: /api/errors/1c228e94c9ae7e53. Report an issue: GitHub.