@marsnme/mcp-gateway 0.1.8 → 0.2.0
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/package.json +3 -2
- package/server.mjs +311 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@marsnme/mcp-gateway",
|
|
3
|
-
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"mcpName": "io.github.Marsmanleo/marsnme",
|
|
5
5
|
"private": false,
|
|
6
6
|
"description": "Agent-agnostic, LLM-agnostic memory backend for MCP-compatible tools",
|
|
@@ -26,7 +26,8 @@
|
|
|
26
26
|
"session-memory",
|
|
27
27
|
"cross-session",
|
|
28
28
|
"llm",
|
|
29
|
-
"symbiosis"
|
|
29
|
+
"symbiosis",
|
|
30
|
+
"perplexity"
|
|
30
31
|
],
|
|
31
32
|
"bin": {
|
|
32
33
|
"marsnme": "server.mjs"
|
package/server.mjs
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import http from 'node:http';
|
|
3
3
|
import crypto from 'node:crypto';
|
|
4
4
|
import { execFileSync } from 'node:child_process';
|
|
5
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
5
6
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
6
7
|
import { dirname } from 'node:path';
|
|
7
8
|
|
|
@@ -171,6 +172,28 @@ if (!Number.isInteger(PORT) || PORT < 1 || PORT > 65535) {
|
|
|
171
172
|
throw new Error(`Invalid PORT: ${PORT_RAW || String(PORT)}. Must be an integer between 1 and 65535.`);
|
|
172
173
|
}
|
|
173
174
|
const SUPABASE_BASE_URL = process.env.SUPABASE_BASE_URL || 'http://127.0.0.1:8100';
|
|
175
|
+
const SUPABASE_AUTH_MODE_VALUES = new Set(['service', 'anon', 'hybrid']);
|
|
176
|
+
const SUPABASE_AUTH_MODE_RAW = String(process.env.MCP_SUPABASE_AUTH_MODE || 'service')
|
|
177
|
+
.trim()
|
|
178
|
+
.toLowerCase();
|
|
179
|
+
if (SUPABASE_AUTH_MODE_RAW && !SUPABASE_AUTH_MODE_VALUES.has(SUPABASE_AUTH_MODE_RAW)) {
|
|
180
|
+
console.warn(
|
|
181
|
+
`[config] invalid MCP_SUPABASE_AUTH_MODE=${SUPABASE_AUTH_MODE_RAW}; fallback to service`
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
const SUPABASE_AUTH_MODE = SUPABASE_AUTH_MODE_VALUES.has(SUPABASE_AUTH_MODE_RAW)
|
|
185
|
+
? SUPABASE_AUTH_MODE_RAW
|
|
186
|
+
: 'service';
|
|
187
|
+
const SUPABASE_ANON_KEY = String(process.env.SUPABASE_ANON_KEY || '').trim();
|
|
188
|
+
const ANON_ALLOWED_TOOL_NAMES = new Set([
|
|
189
|
+
'list_memories',
|
|
190
|
+
'search_memories',
|
|
191
|
+
'reload_source_registry',
|
|
192
|
+
'recall',
|
|
193
|
+
'health_check',
|
|
194
|
+
'explain_memory'
|
|
195
|
+
]);
|
|
196
|
+
const SUPABASE_REQUEST_CONTEXT = new AsyncLocalStorage();
|
|
174
197
|
const OAUTH_ENABLED = process.env.MCP_OAUTH_ENABLED !== 'false';
|
|
175
198
|
const REQUIRE_BEARER = process.env.MCP_REQUIRE_BEARER === 'true';
|
|
176
199
|
const BYPASS_BEARER_FOR_PRIVATE = process.env.MCP_BYPASS_BEARER_FOR_PRIVATE !== 'false';
|
|
@@ -711,11 +734,52 @@ function buildTools() {
|
|
|
711
734
|
required: ['id'],
|
|
712
735
|
additionalProperties: false
|
|
713
736
|
}
|
|
737
|
+
},
|
|
738
|
+
{
|
|
739
|
+
name: 'batch_promote',
|
|
740
|
+
description: `Auto-promote expiring short memories to long-term ${DB_PROFILE}.marsvault_chunks. Finds candidates via health check scoring, ingests content, marks promoted.`,
|
|
741
|
+
inputSchema: {
|
|
742
|
+
type: 'object',
|
|
743
|
+
properties: {
|
|
744
|
+
alert_window_hours: {
|
|
745
|
+
type: 'number',
|
|
746
|
+
minimum: 1,
|
|
747
|
+
maximum: 720,
|
|
748
|
+
default: 48,
|
|
749
|
+
description: 'Look-ahead window for expiring memories (hours)'
|
|
750
|
+
},
|
|
751
|
+
max_promote: {
|
|
752
|
+
type: 'number',
|
|
753
|
+
minimum: 1,
|
|
754
|
+
maximum: 50,
|
|
755
|
+
default: 10,
|
|
756
|
+
description: 'Maximum memories to promote in one batch'
|
|
757
|
+
},
|
|
758
|
+
dry_run: {
|
|
759
|
+
type: 'boolean',
|
|
760
|
+
default: false,
|
|
761
|
+
description: 'If true, list candidates without promoting'
|
|
762
|
+
},
|
|
763
|
+
memory_ids: {
|
|
764
|
+
type: 'array',
|
|
765
|
+
items: { type: 'string' },
|
|
766
|
+
maxItems: 50,
|
|
767
|
+
description: 'Optional explicit memory IDs to promote (skips auto-detection)'
|
|
768
|
+
},
|
|
769
|
+
origin: {
|
|
770
|
+
type: 'string',
|
|
771
|
+
description: 'Origin marker for promoted chunks',
|
|
772
|
+
default: 'batch-promote'
|
|
773
|
+
}
|
|
774
|
+
},
|
|
775
|
+
additionalProperties: false
|
|
776
|
+
}
|
|
714
777
|
}
|
|
715
778
|
];
|
|
716
779
|
}
|
|
717
780
|
|
|
718
781
|
const TOOLS = buildTools();
|
|
782
|
+
const TOOL_BY_NAME = new Map(TOOLS.map((tool) => [tool.name, tool]));
|
|
719
783
|
|
|
720
784
|
const OAUTH_CLIENTS = new Map();
|
|
721
785
|
const OAUTH_CODES = new Map();
|
|
@@ -876,7 +940,15 @@ function getServiceKey() {
|
|
|
876
940
|
);
|
|
877
941
|
}
|
|
878
942
|
|
|
879
|
-
const SERVICE_KEY = getServiceKey();
|
|
943
|
+
const SERVICE_KEY = SUPABASE_AUTH_MODE === 'anon' ? '' : getServiceKey();
|
|
944
|
+
if (
|
|
945
|
+
(SUPABASE_AUTH_MODE === 'anon' || SUPABASE_AUTH_MODE === 'hybrid') &&
|
|
946
|
+
!SUPABASE_ANON_KEY
|
|
947
|
+
) {
|
|
948
|
+
throw new Error(
|
|
949
|
+
'SUPABASE_ANON_KEY is required when MCP_SUPABASE_AUTH_MODE is anon or hybrid'
|
|
950
|
+
);
|
|
951
|
+
}
|
|
880
952
|
loadPersistedOauthClients();
|
|
881
953
|
|
|
882
954
|
if (STATIC_CLIENT_ID && STATIC_CLIENT_SECRET && OAUTH_ENABLED) {
|
|
@@ -935,10 +1007,67 @@ async function readRequestBody(req) {
|
|
|
935
1007
|
}
|
|
936
1008
|
}
|
|
937
1009
|
|
|
1010
|
+
function resolveSupabaseRequestAuthMode() {
|
|
1011
|
+
const storeMode = String(SUPABASE_REQUEST_CONTEXT.getStore()?.db_auth_mode || '')
|
|
1012
|
+
.trim()
|
|
1013
|
+
.toLowerCase();
|
|
1014
|
+
if (SUPABASE_AUTH_MODE_VALUES.has(storeMode)) {
|
|
1015
|
+
return storeMode;
|
|
1016
|
+
}
|
|
1017
|
+
if (SUPABASE_AUTH_MODE === 'anon') {
|
|
1018
|
+
return 'anon';
|
|
1019
|
+
}
|
|
1020
|
+
return 'service';
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
function isToolAllowedInAnonMode(toolName) {
|
|
1024
|
+
return ANON_ALLOWED_TOOL_NAMES.has(String(toolName || '').trim());
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
function assertToolCapabilityForAuthMode(toolName) {
|
|
1028
|
+
if (SUPABASE_AUTH_MODE !== 'anon') return;
|
|
1029
|
+
if (isToolAllowedInAnonMode(toolName)) return;
|
|
1030
|
+
throw new Error(
|
|
1031
|
+
`capability_not_available_in_anon_mode: ${toolName} is disabled; use MCP_SUPABASE_AUTH_MODE=service or hybrid`
|
|
1032
|
+
);
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
function resolveDbAuthModeForTool(toolName) {
|
|
1036
|
+
if (SUPABASE_AUTH_MODE === 'anon') return 'anon';
|
|
1037
|
+
if (SUPABASE_AUTH_MODE === 'service') return 'service';
|
|
1038
|
+
return isToolAllowedInAnonMode(toolName) ? 'anon' : 'service';
|
|
1039
|
+
}
|
|
1040
|
+
function listAvailableToolNamesForAuthMode(authMode) {
|
|
1041
|
+
if (authMode === 'anon') {
|
|
1042
|
+
return TOOLS
|
|
1043
|
+
.map((tool) => String(tool?.name || '').trim())
|
|
1044
|
+
.filter((name) => name && isToolAllowedInAnonMode(name));
|
|
1045
|
+
}
|
|
1046
|
+
return TOOLS.map((tool) => String(tool?.name || '').trim()).filter(Boolean);
|
|
1047
|
+
}
|
|
1048
|
+
function listAvailableToolsForAuthMode(authMode) {
|
|
1049
|
+
const names = listAvailableToolNamesForAuthMode(authMode);
|
|
1050
|
+
return names
|
|
1051
|
+
.map((name) => TOOL_BY_NAME.get(name))
|
|
1052
|
+
.filter((tool) => Boolean(tool));
|
|
1053
|
+
}
|
|
1054
|
+
function buildSupabaseCapabilityPayload() {
|
|
1055
|
+
return {
|
|
1056
|
+
mode: SUPABASE_AUTH_MODE,
|
|
1057
|
+
anon_allowed_tools: listAvailableToolNamesForAuthMode('anon'),
|
|
1058
|
+
effective_tools: listAvailableToolNamesForAuthMode(SUPABASE_AUTH_MODE)
|
|
1059
|
+
};
|
|
1060
|
+
}
|
|
1061
|
+
|
|
938
1062
|
async function supabaseRequest(path, options = {}) {
|
|
1063
|
+
const requestAuthMode = resolveSupabaseRequestAuthMode();
|
|
1064
|
+
const requestApiKey = requestAuthMode === 'anon' ? SUPABASE_ANON_KEY : SERVICE_KEY;
|
|
1065
|
+
if (!requestApiKey) {
|
|
1066
|
+
throw new Error(`Supabase API key missing for auth mode: ${requestAuthMode}`);
|
|
1067
|
+
}
|
|
939
1068
|
const headers = {
|
|
940
|
-
apikey:
|
|
941
|
-
Authorization: `Bearer ${
|
|
1069
|
+
apikey: requestApiKey,
|
|
1070
|
+
Authorization: `Bearer ${requestApiKey}`,
|
|
942
1071
|
'content-type': 'application/json'
|
|
943
1072
|
};
|
|
944
1073
|
if (options.profile) {
|
|
@@ -1455,7 +1584,10 @@ async function writeToolUsageTelemetry(payload = {}) {
|
|
|
1455
1584
|
new Date().toISOString();
|
|
1456
1585
|
const agentBody =
|
|
1457
1586
|
normalizeOptionalAgentBody(payload.agent_body) || DB_PROFILE;
|
|
1458
|
-
|
|
1587
|
+
if (SUPABASE_AUTH_MODE === 'anon') {
|
|
1588
|
+
return;
|
|
1589
|
+
}
|
|
1590
|
+
const writeTelemetry = async () => {
|
|
1459
1591
|
await supabaseRequest(
|
|
1460
1592
|
`/rest/v1/memory_tool_usage?select=${TOOL_USAGE_INSERT_SELECT_COLUMNS}`,
|
|
1461
1593
|
{
|
|
@@ -1473,6 +1605,13 @@ async function writeToolUsageTelemetry(payload = {}) {
|
|
|
1473
1605
|
]
|
|
1474
1606
|
}
|
|
1475
1607
|
);
|
|
1608
|
+
};
|
|
1609
|
+
try {
|
|
1610
|
+
if (SUPABASE_AUTH_MODE === 'hybrid') {
|
|
1611
|
+
await SUPABASE_REQUEST_CONTEXT.run({ db_auth_mode: 'service' }, writeTelemetry);
|
|
1612
|
+
} else {
|
|
1613
|
+
await writeTelemetry();
|
|
1614
|
+
}
|
|
1476
1615
|
} catch (error) {
|
|
1477
1616
|
console.warn(
|
|
1478
1617
|
`[telemetry] failed to persist memory_tool_usage: ${String(error?.message || error)}`
|
|
@@ -2717,6 +2856,156 @@ async function runHealthExpiryCheck(args = {}) {
|
|
|
2717
2856
|
return payload;
|
|
2718
2857
|
}
|
|
2719
2858
|
|
|
2859
|
+
async function runBatchPromote(args = {}) {
|
|
2860
|
+
const alertWindowHours = clampInteger(args.alert_window_hours, 1, 720, 48);
|
|
2861
|
+
const maxPromote = clampInteger(args.max_promote, 1, 50, 10);
|
|
2862
|
+
const dryRun = Boolean(args.dry_run);
|
|
2863
|
+
const origin = String(args.origin || 'batch-promote').trim() || 'batch-promote';
|
|
2864
|
+
const explicitIds = Array.isArray(args.memory_ids)
|
|
2865
|
+
? args.memory_ids
|
|
2866
|
+
.map((id) => normalizeOptionalUuid(id, 'memory_ids'))
|
|
2867
|
+
.filter(Boolean)
|
|
2868
|
+
: [];
|
|
2869
|
+
|
|
2870
|
+
const candidates = [];
|
|
2871
|
+
|
|
2872
|
+
if (explicitIds.length > 0) {
|
|
2873
|
+
for (const memoryId of explicitIds.slice(0, maxPromote)) {
|
|
2874
|
+
const memory = await fetchMemoryById(memoryId);
|
|
2875
|
+
if (!memory) {
|
|
2876
|
+
candidates.push({ id: memoryId, status: 'not_found', skipped: true });
|
|
2877
|
+
continue;
|
|
2878
|
+
}
|
|
2879
|
+
if (memory.promoted || memory.promoted_at) {
|
|
2880
|
+
candidates.push({
|
|
2881
|
+
id: memoryId,
|
|
2882
|
+
status: 'already_promoted',
|
|
2883
|
+
skipped: true,
|
|
2884
|
+
excerpt: String(memory.body || '').slice(0, 140)
|
|
2885
|
+
});
|
|
2886
|
+
continue;
|
|
2887
|
+
}
|
|
2888
|
+
candidates.push({
|
|
2889
|
+
id: memoryId,
|
|
2890
|
+
status: 'eligible',
|
|
2891
|
+
skipped: false,
|
|
2892
|
+
excerpt: String(memory.body || '').slice(0, 140),
|
|
2893
|
+
tags: normalizeTags(memory.tags),
|
|
2894
|
+
expires_at: memory.expires_at || null,
|
|
2895
|
+
memory
|
|
2896
|
+
});
|
|
2897
|
+
}
|
|
2898
|
+
} else {
|
|
2899
|
+
const healthResult = await runHealthExpiryCheck({
|
|
2900
|
+
alert_window_hours: alertWindowHours
|
|
2901
|
+
});
|
|
2902
|
+
const soonExpiring = healthResult?.expiry_alert?.soon_expiring || [];
|
|
2903
|
+
const recommended = soonExpiring
|
|
2904
|
+
.filter((item) => item.recommend_promote === 'Y')
|
|
2905
|
+
.slice(0, maxPromote);
|
|
2906
|
+
|
|
2907
|
+
for (const item of recommended) {
|
|
2908
|
+
const memory = await fetchMemoryById(item.id);
|
|
2909
|
+
if (!memory) {
|
|
2910
|
+
candidates.push({ id: item.id, status: 'not_found', skipped: true });
|
|
2911
|
+
continue;
|
|
2912
|
+
}
|
|
2913
|
+
candidates.push({
|
|
2914
|
+
id: item.id,
|
|
2915
|
+
status: 'eligible',
|
|
2916
|
+
skipped: false,
|
|
2917
|
+
excerpt: item.excerpt || String(memory.body || '').slice(0, 140),
|
|
2918
|
+
tags: item.tags || normalizeTags(memory.tags),
|
|
2919
|
+
expires_at: item.expires_at || memory.expires_at || null,
|
|
2920
|
+
recommendation_reason: item.recommendation_reason || null,
|
|
2921
|
+
memory
|
|
2922
|
+
});
|
|
2923
|
+
}
|
|
2924
|
+
}
|
|
2925
|
+
|
|
2926
|
+
const eligible = candidates.filter((c) => !c.skipped);
|
|
2927
|
+
|
|
2928
|
+
if (dryRun) {
|
|
2929
|
+
return {
|
|
2930
|
+
ok: true,
|
|
2931
|
+
dry_run: true,
|
|
2932
|
+
profile: DB_PROFILE,
|
|
2933
|
+
origin,
|
|
2934
|
+
alert_window_hours: alertWindowHours,
|
|
2935
|
+
max_promote: maxPromote,
|
|
2936
|
+
total_candidates: candidates.length,
|
|
2937
|
+
eligible_count: eligible.length,
|
|
2938
|
+
skipped_count: candidates.length - eligible.length,
|
|
2939
|
+
candidates: candidates.map(({ memory, ...rest }) => rest)
|
|
2940
|
+
};
|
|
2941
|
+
}
|
|
2942
|
+
|
|
2943
|
+
const promoted = [];
|
|
2944
|
+
const errors = [];
|
|
2945
|
+
|
|
2946
|
+
for (const candidate of eligible) {
|
|
2947
|
+
try {
|
|
2948
|
+
const memory = candidate.memory;
|
|
2949
|
+
const content = String(memory.body || '').trim();
|
|
2950
|
+
if (!content) {
|
|
2951
|
+
errors.push({ id: candidate.id, error: 'empty memory body' });
|
|
2952
|
+
continue;
|
|
2953
|
+
}
|
|
2954
|
+
|
|
2955
|
+
const ingestResult = await ingestMarsvaultChunks(
|
|
2956
|
+
{
|
|
2957
|
+
content,
|
|
2958
|
+
tags: normalizeTags(memory.tags),
|
|
2959
|
+
source_memory_id: memory.id,
|
|
2960
|
+
source_session_id: memory.session_id || null,
|
|
2961
|
+
source_tool: memory.source || null,
|
|
2962
|
+
origin
|
|
2963
|
+
},
|
|
2964
|
+
{
|
|
2965
|
+
defaultType: 'insight',
|
|
2966
|
+
defaultSourceFile: PROFILE.memoryIngestDefaultSourceFile,
|
|
2967
|
+
defaultSectionPrefix: 'batch-promote',
|
|
2968
|
+
defaultOrigin: origin,
|
|
2969
|
+
body: DB_PROFILE,
|
|
2970
|
+
fixedTags: [...PROFILE.memoryIngestFixedTags, 'batch-promote']
|
|
2971
|
+
}
|
|
2972
|
+
);
|
|
2973
|
+
|
|
2974
|
+
const promotedMemory = await markMemoryAsPromoted(memory.id);
|
|
2975
|
+
|
|
2976
|
+
promoted.push({
|
|
2977
|
+
id: memory.id,
|
|
2978
|
+
chunk_count: ingestResult.chunk_count || 0,
|
|
2979
|
+
promoted_at: promotedMemory?.promoted_at || null,
|
|
2980
|
+
excerpt: String(content).slice(0, 140)
|
|
2981
|
+
});
|
|
2982
|
+
} catch (error) {
|
|
2983
|
+
errors.push({
|
|
2984
|
+
id: candidate.id,
|
|
2985
|
+
error: normalizeOptionalText(error?.message || String(error), 280)
|
|
2986
|
+
});
|
|
2987
|
+
}
|
|
2988
|
+
}
|
|
2989
|
+
|
|
2990
|
+
return {
|
|
2991
|
+
ok: true,
|
|
2992
|
+
dry_run: false,
|
|
2993
|
+
profile: DB_PROFILE,
|
|
2994
|
+
origin,
|
|
2995
|
+
alert_window_hours: alertWindowHours,
|
|
2996
|
+
max_promote: maxPromote,
|
|
2997
|
+
total_candidates: candidates.length,
|
|
2998
|
+
promoted_count: promoted.length,
|
|
2999
|
+
error_count: errors.length,
|
|
3000
|
+
skipped_count: candidates.length - eligible.length,
|
|
3001
|
+
promoted,
|
|
3002
|
+
errors: errors.length > 0 ? errors : undefined,
|
|
3003
|
+
skipped: candidates
|
|
3004
|
+
.filter((c) => c.skipped)
|
|
3005
|
+
.map(({ memory, ...rest }) => rest)
|
|
3006
|
+
};
|
|
3007
|
+
}
|
|
3008
|
+
|
|
2720
3009
|
async function runHealthCheck(args = {}) {
|
|
2721
3010
|
const alertWindowHours = clampInteger(args.alert_window_hours, 1, 720, 48);
|
|
2722
3011
|
const gapDays = clampInteger(args.gap_days, 7, 365, 30);
|
|
@@ -3620,6 +3909,9 @@ async function callTool(name, args = {}) {
|
|
|
3620
3909
|
};
|
|
3621
3910
|
}
|
|
3622
3911
|
|
|
3912
|
+
if (toolName === 'batch_promote') {
|
|
3913
|
+
return await runBatchPromote(args);
|
|
3914
|
+
}
|
|
3623
3915
|
if (toolName === 'health_check') {
|
|
3624
3916
|
return await runHealthCheck(args);
|
|
3625
3917
|
}
|
|
@@ -4237,6 +4529,8 @@ const server = http.createServer(async (req, res) => {
|
|
|
4237
4529
|
embedding_provider: 'jina',
|
|
4238
4530
|
embedding_model: JINA_EMBEDDING_MODEL,
|
|
4239
4531
|
embedding_enabled: Boolean(JINA_API_KEY),
|
|
4532
|
+
supabase_auth_mode: SUPABASE_AUTH_MODE,
|
|
4533
|
+
supabase_capabilities: buildSupabaseCapabilityPayload(),
|
|
4240
4534
|
source_mode: SOURCE_MODE,
|
|
4241
4535
|
memory_sources: MEMORY_SOURCE_LIST.slice(),
|
|
4242
4536
|
extra_sources: EXTRA_SOURCE_LIST.slice(),
|
|
@@ -4318,14 +4612,24 @@ const server = http.createServer(async (req, res) => {
|
|
|
4318
4612
|
}
|
|
4319
4613
|
|
|
4320
4614
|
if (method === 'tools/list') {
|
|
4321
|
-
json(
|
|
4615
|
+
json(
|
|
4616
|
+
res,
|
|
4617
|
+
200,
|
|
4618
|
+
mcpResult(id, { tools: listAvailableToolsForAuthMode(SUPABASE_AUTH_MODE) })
|
|
4619
|
+
);
|
|
4322
4620
|
return;
|
|
4323
4621
|
}
|
|
4324
4622
|
|
|
4325
4623
|
if (method === 'tools/call') {
|
|
4326
|
-
const
|
|
4624
|
+
const requestedToolName = rpc?.params?.name;
|
|
4625
|
+
const toolName = resolveToolName(requestedToolName);
|
|
4626
|
+
assertToolCapabilityForAuthMode(toolName);
|
|
4627
|
+
const dbAuthMode = resolveDbAuthModeForTool(toolName);
|
|
4327
4628
|
const args = rpc?.params?.arguments ?? {};
|
|
4328
|
-
const result = await
|
|
4629
|
+
const result = await SUPABASE_REQUEST_CONTEXT.run(
|
|
4630
|
+
{ db_auth_mode: dbAuthMode },
|
|
4631
|
+
async () => await callTool(toolName, args)
|
|
4632
|
+
);
|
|
4329
4633
|
json(
|
|
4330
4634
|
res,
|
|
4331
4635
|
200,
|