@aliyun-rds/supabase-mcp-server 1.0.7 → 1.0.8
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.
- package/dist/index.js +85 -19
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -813,6 +813,13 @@ var SelfhostedSupabaseClient = class _SelfhostedSupabaseClient {
|
|
|
813
813
|
isRpcAvailable() {
|
|
814
814
|
return this.rpcFunctionExists;
|
|
815
815
|
}
|
|
816
|
+
/**
|
|
817
|
+
* Sets the RPC function availability status.
|
|
818
|
+
* Called after successfully installing the execute_sql function.
|
|
819
|
+
*/
|
|
820
|
+
setRpcAvailable(available) {
|
|
821
|
+
this.rpcFunctionExists = available;
|
|
822
|
+
}
|
|
816
823
|
/**
|
|
817
824
|
* Gets the authentication mode this client was created with.
|
|
818
825
|
*/
|
|
@@ -865,6 +872,9 @@ import { z } from "zod";
|
|
|
865
872
|
import { exec } from "node:child_process";
|
|
866
873
|
import { promisify } from "node:util";
|
|
867
874
|
var execAsync = promisify(exec);
|
|
875
|
+
function isSqlErrorResponse(result) {
|
|
876
|
+
return result.error !== void 0;
|
|
877
|
+
}
|
|
868
878
|
function handleSqlResponse(result, schema) {
|
|
869
879
|
if ("error" in result) {
|
|
870
880
|
throw new Error(`SQL Error (${result.error.code}): ${result.error.message}`);
|
|
@@ -1277,7 +1287,22 @@ var getDatabaseStatsTool = {
|
|
|
1277
1287
|
stats_reset::text
|
|
1278
1288
|
FROM pg_stat_database
|
|
1279
1289
|
`;
|
|
1280
|
-
const
|
|
1290
|
+
const getBgWriterStatsSqlPg17 = `
|
|
1291
|
+
SELECT
|
|
1292
|
+
(SELECT num_timed::text FROM pg_stat_checkpointer) as checkpoints_timed,
|
|
1293
|
+
(SELECT num_requested::text FROM pg_stat_checkpointer) as checkpoints_req,
|
|
1294
|
+
(SELECT write_time FROM pg_stat_checkpointer) as checkpoint_write_time,
|
|
1295
|
+
(SELECT sync_time FROM pg_stat_checkpointer) as checkpoint_sync_time,
|
|
1296
|
+
(SELECT buffers_written::text FROM pg_stat_checkpointer) as buffers_checkpoint,
|
|
1297
|
+
buffers_clean::text,
|
|
1298
|
+
maxwritten_clean::text,
|
|
1299
|
+
NULL::text as buffers_backend,
|
|
1300
|
+
NULL::text as buffers_backend_fsync,
|
|
1301
|
+
buffers_alloc::text,
|
|
1302
|
+
stats_reset::text
|
|
1303
|
+
FROM pg_stat_bgwriter
|
|
1304
|
+
`;
|
|
1305
|
+
const getBgWriterStatsSqlPg16 = `
|
|
1281
1306
|
SELECT
|
|
1282
1307
|
checkpoints_timed::text,
|
|
1283
1308
|
checkpoints_req::text,
|
|
@@ -1292,10 +1317,12 @@ var getDatabaseStatsTool = {
|
|
|
1292
1317
|
stats_reset::text
|
|
1293
1318
|
FROM pg_stat_bgwriter
|
|
1294
1319
|
`;
|
|
1295
|
-
const
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1320
|
+
const dbStatsResult = await executeSqlWithFallback(client, getDbStatsSql, true);
|
|
1321
|
+
let bgWriterStatsResult = await executeSqlWithFallback(client, getBgWriterStatsSqlPg17, true);
|
|
1322
|
+
if (isSqlErrorResponse(bgWriterStatsResult)) {
|
|
1323
|
+
console.error("PostgreSQL 17+ query failed, trying PostgreSQL 16 query...");
|
|
1324
|
+
bgWriterStatsResult = await executeSqlWithFallback(client, getBgWriterStatsSqlPg16, true);
|
|
1325
|
+
}
|
|
1299
1326
|
const dbStats = handleSqlResponse(dbStatsResult, GetDbStatsOutputSchema.shape.database_stats);
|
|
1300
1327
|
const bgWriterStats = handleSqlResponse(bgWriterStatsResult, GetDbStatsOutputSchema.shape.bgwriter_stats);
|
|
1301
1328
|
return {
|
|
@@ -2315,6 +2342,7 @@ async function execute(input, context) {
|
|
|
2315
2342
|
}
|
|
2316
2343
|
context.log("execute_sql function installed successfully!", "info");
|
|
2317
2344
|
context.log("You may need to wait a few seconds for PostgREST to reload the schema.", "info");
|
|
2345
|
+
client.setRpcAvailable(true);
|
|
2318
2346
|
return {
|
|
2319
2347
|
success: true,
|
|
2320
2348
|
message: "execute_sql function installed successfully. You can now use tools that require SQL execution (list_tables, execute_sql, etc.)."
|
|
@@ -2663,32 +2691,67 @@ function wrapAllRagAgentTools(ragClient) {
|
|
|
2663
2691
|
import RdsAiPkg from "@alicloud/rdsai20250507/dist/client.js";
|
|
2664
2692
|
import * as $RdsAi from "@alicloud/rdsai20250507";
|
|
2665
2693
|
var RdsAiClient = RdsAiPkg.default || RdsAiPkg;
|
|
2694
|
+
var RDSAI_DEFAULT_ENDPOINT = "rdsai.aliyuncs.com";
|
|
2695
|
+
var RDSAI_CENTER_UNIT_REGIONS = /* @__PURE__ */ new Set([
|
|
2696
|
+
"cn-beijing",
|
|
2697
|
+
"cn-wulanchabu",
|
|
2698
|
+
"cn-hangzhou",
|
|
2699
|
+
"cn-shanghai",
|
|
2700
|
+
"cn-shenzhen",
|
|
2701
|
+
"cn-guangzhou"
|
|
2702
|
+
]);
|
|
2703
|
+
function resolveRdsAiEndpoint(regionId, explicitEndpoint) {
|
|
2704
|
+
if (explicitEndpoint) {
|
|
2705
|
+
return explicitEndpoint;
|
|
2706
|
+
}
|
|
2707
|
+
if (!regionId || RDSAI_CENTER_UNIT_REGIONS.has(regionId)) {
|
|
2708
|
+
return RDSAI_DEFAULT_ENDPOINT;
|
|
2709
|
+
}
|
|
2710
|
+
return `rdsai.${regionId}.aliyuncs.com`;
|
|
2711
|
+
}
|
|
2666
2712
|
var AliyunRdsAiClient = class {
|
|
2667
|
-
|
|
2668
|
-
// RdsAi Client instance
|
|
2713
|
+
clientCache;
|
|
2669
2714
|
config;
|
|
2670
2715
|
constructor(config) {
|
|
2671
2716
|
this.config = config;
|
|
2717
|
+
this.clientCache = /* @__PURE__ */ new Map();
|
|
2718
|
+
const defaultEndpoint = resolveRdsAiEndpoint(config.regionId, config.endpoint);
|
|
2719
|
+
this.clientCache.set(defaultEndpoint, this.createClient(defaultEndpoint, config.regionId));
|
|
2720
|
+
}
|
|
2721
|
+
createClient(endpoint, regionId) {
|
|
2672
2722
|
const openApiConfig = {
|
|
2673
|
-
accessKeyId: config.accessKeyId,
|
|
2674
|
-
accessKeySecret: config.accessKeySecret,
|
|
2675
|
-
endpoint
|
|
2723
|
+
accessKeyId: this.config.accessKeyId,
|
|
2724
|
+
accessKeySecret: this.config.accessKeySecret,
|
|
2725
|
+
endpoint,
|
|
2726
|
+
regionId
|
|
2676
2727
|
};
|
|
2677
|
-
|
|
2728
|
+
return new RdsAiClient(openApiConfig);
|
|
2729
|
+
}
|
|
2730
|
+
getClientForRegion(regionId) {
|
|
2731
|
+
const effectiveRegionId = regionId || this.config.regionId;
|
|
2732
|
+
const endpoint = resolveRdsAiEndpoint(effectiveRegionId, this.config.endpoint);
|
|
2733
|
+
const cached = this.clientCache.get(endpoint);
|
|
2734
|
+
if (cached) {
|
|
2735
|
+
return cached;
|
|
2736
|
+
}
|
|
2737
|
+
const client = this.createClient(endpoint, effectiveRegionId);
|
|
2738
|
+
this.clientCache.set(endpoint, client);
|
|
2739
|
+
return client;
|
|
2678
2740
|
}
|
|
2679
2741
|
/**
|
|
2680
2742
|
* List all Supabase instances
|
|
2681
2743
|
*/
|
|
2682
2744
|
async listSupabaseInstances(options) {
|
|
2745
|
+
const regionId = options?.regionId || this.config.regionId;
|
|
2683
2746
|
const request = new $RdsAi.DescribeAppInstancesRequest({
|
|
2684
2747
|
appType: "supabase",
|
|
2685
|
-
regionId
|
|
2748
|
+
regionId,
|
|
2686
2749
|
DBInstanceName: options?.dbInstanceName,
|
|
2687
2750
|
pageSize: options?.pageSize || 50,
|
|
2688
2751
|
pageNumber: options?.pageNumber || 1
|
|
2689
2752
|
});
|
|
2690
2753
|
try {
|
|
2691
|
-
const response = await this.
|
|
2754
|
+
const response = await this.getClientForRegion(regionId).describeAppInstances(request);
|
|
2692
2755
|
if (!response.body) {
|
|
2693
2756
|
throw new Error("Empty response from DescribeAppInstances API");
|
|
2694
2757
|
}
|
|
@@ -2714,19 +2777,21 @@ var AliyunRdsAiClient = class {
|
|
|
2714
2777
|
instances
|
|
2715
2778
|
};
|
|
2716
2779
|
} catch (error) {
|
|
2717
|
-
console.error("Error calling DescribeAppInstances:", error);
|
|
2780
|
+
console.error("Error calling DescribeAppInstances:", JSON.stringify(error, null, 2));
|
|
2781
|
+
console.error("Error code:", error?.code);
|
|
2782
|
+
console.error("Error data:", error?.data);
|
|
2718
2783
|
throw new Error(`Failed to list Supabase instances: ${error instanceof Error ? error.message : String(error)}`);
|
|
2719
2784
|
}
|
|
2720
2785
|
}
|
|
2721
2786
|
/**
|
|
2722
2787
|
* Get authentication information for a specific instance
|
|
2723
2788
|
*/
|
|
2724
|
-
async getInstanceAuthInfo(instanceName) {
|
|
2789
|
+
async getInstanceAuthInfo(instanceName, regionId) {
|
|
2725
2790
|
const request = new $RdsAi.DescribeInstanceAuthInfoRequest({
|
|
2726
2791
|
instanceName
|
|
2727
2792
|
});
|
|
2728
2793
|
try {
|
|
2729
|
-
const response = await this.
|
|
2794
|
+
const response = await this.getClientForRegion(regionId || this.config.regionId).describeInstanceAuthInfo(request);
|
|
2730
2795
|
if (!response.body) {
|
|
2731
2796
|
throw new Error("Empty response from DescribeInstanceAuthInfo API");
|
|
2732
2797
|
}
|
|
@@ -2760,7 +2825,7 @@ var AliyunRdsAiClient = class {
|
|
|
2760
2825
|
if (!instance) {
|
|
2761
2826
|
throw new Error(`Instance ${instanceName} not found. Available instances: ${instancesResponse.instances.map((i) => i.instanceName).join(", ")}`);
|
|
2762
2827
|
}
|
|
2763
|
-
const authInfo = await this.getInstanceAuthInfo(instanceName);
|
|
2828
|
+
const authInfo = await this.getInstanceAuthInfo(instanceName, instance.regionId || queryRegion);
|
|
2764
2829
|
const connectionString = useVpc ? instance.vpcConnectionString : instance.publicConnectionString;
|
|
2765
2830
|
const supabaseUrl = connectionString.startsWith("http") ? connectionString : `http://${connectionString}`;
|
|
2766
2831
|
return {
|
|
@@ -2854,7 +2919,8 @@ import { z as z27 } from "zod";
|
|
|
2854
2919
|
import { zodToJsonSchema as zodToJsonSchema3 } from "zod-to-json-schema";
|
|
2855
2920
|
var ConnectInstanceInputZodSchema = z27.object({
|
|
2856
2921
|
instance_name: z27.string().describe("The instance name (e.g., ra-supabase-8moov5lxba****)"),
|
|
2857
|
-
use_vpc: z27.boolean().optional().default(false).describe("Whether to use VPC connection instead of public connection")
|
|
2922
|
+
use_vpc: z27.boolean().optional().default(false).describe("Whether to use VPC connection instead of public connection"),
|
|
2923
|
+
region_id: z27.string().optional().describe("Region ID of the instance (e.g., cn-hangzhou, cn-chengdu). Required when connecting to an instance in a different region than the default startup region.")
|
|
2858
2924
|
});
|
|
2859
2925
|
var ConnectInstanceOutputZodSchema = z27.object({
|
|
2860
2926
|
success: z27.boolean(),
|
|
@@ -2869,7 +2935,7 @@ async function execute3(input, aliyunClient, createSupabaseClient, setCurrentIns
|
|
|
2869
2935
|
}
|
|
2870
2936
|
log(`Connecting to Supabase instance: ${input.instance_name}...`, "info");
|
|
2871
2937
|
try {
|
|
2872
|
-
const credentials = await aliyunClient.getSupabaseCredentials(input.instance_name, input.use_vpc);
|
|
2938
|
+
const credentials = await aliyunClient.getSupabaseCredentials(input.instance_name, input.use_vpc, input.region_id);
|
|
2873
2939
|
log(`Retrieved credentials for instance ${input.instance_name}`, "info");
|
|
2874
2940
|
log(`Supabase URL: ${credentials.supabaseUrl}`, "info");
|
|
2875
2941
|
const supabaseClient = await createSupabaseClient(
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aliyun-rds/supabase-mcp-server",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"description": "MCP (Model Context Protocol) server for self-hosted Supabase instances. Allows AI assistants to interact with your self-hosted Supabase database.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@alicloud/openapi-client": "^0.4.12",
|
|
36
36
|
"@alicloud/rdsai20250507": "^1.0.0",
|
|
37
|
+
"@aliyun-rds/supabase-mcp-server": "^1.0.7",
|
|
37
38
|
"@modelcontextprotocol/sdk": "latest",
|
|
38
39
|
"@supabase/supabase-js": "^2.49.4",
|
|
39
40
|
"commander": "^13.1.0",
|