@kadoa/mcp 0.3.7-rc.1 → 0.3.7-rc.3
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 +46 -9
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -49154,6 +49154,15 @@ async function refreshSupabaseJwt(ctx) {
|
|
|
49154
49154
|
ctx.supabaseJwt = data.access_token;
|
|
49155
49155
|
ctx.supabaseRefreshToken = data.refresh_token;
|
|
49156
49156
|
ctx.client.setBearerToken(data.access_token);
|
|
49157
|
+
try {
|
|
49158
|
+
await ctx.persist?.({
|
|
49159
|
+
supabaseJwt: ctx.supabaseJwt,
|
|
49160
|
+
supabaseRefreshToken: ctx.supabaseRefreshToken,
|
|
49161
|
+
teamId: ctx.teamId
|
|
49162
|
+
});
|
|
49163
|
+
} catch (e) {
|
|
49164
|
+
console.error("[JWT_REFRESH] WARN: persist failed, tokens updated in-memory only:", e);
|
|
49165
|
+
}
|
|
49157
49166
|
console.error(`[JWT_REFRESH] OK: token refreshed (team=${ctx.teamId ?? "unknown"}, newRefreshToken=${data.refresh_token.slice(0, 12)}...)`);
|
|
49158
49167
|
return data.access_token;
|
|
49159
49168
|
} catch (error48) {
|
|
@@ -49990,11 +49999,11 @@ function registerTools(server, ctx) {
|
|
|
49990
49999
|
return errorResult(`Team not found: "${identifier}". Available teams: ${teams.map((t) => t.name).join(", ")}`);
|
|
49991
50000
|
}
|
|
49992
50001
|
await ctx.client.setActiveTeam(match.id);
|
|
50002
|
+
ctx.teamId = match.id;
|
|
49993
50003
|
const newJwt = await refreshSupabaseJwt(ctx);
|
|
49994
50004
|
if (!newJwt) {
|
|
49995
50005
|
return errorResult("Failed to refresh session after team switch");
|
|
49996
50006
|
}
|
|
49997
|
-
ctx.teamId = match.id;
|
|
49998
50007
|
const config2 = loadConfig2();
|
|
49999
50008
|
config2.teamId = match.id;
|
|
50000
50009
|
config2.teamName = match.name;
|
|
@@ -54060,7 +54069,11 @@ async function refreshSupabaseToken(supabaseRefreshToken, context) {
|
|
|
54060
54069
|
function jwtClaims(jwt2) {
|
|
54061
54070
|
try {
|
|
54062
54071
|
const payload = JSON.parse(Buffer.from(jwt2.split(".")[1], "base64url").toString());
|
|
54063
|
-
return {
|
|
54072
|
+
return {
|
|
54073
|
+
email: payload.email,
|
|
54074
|
+
sub: payload.sub,
|
|
54075
|
+
activeTeamId: payload.app_metadata?.active_team_id
|
|
54076
|
+
};
|
|
54064
54077
|
} catch {
|
|
54065
54078
|
return {};
|
|
54066
54079
|
}
|
|
@@ -54367,20 +54380,22 @@ class KadoaOAuthProvider {
|
|
|
54367
54380
|
} else {
|
|
54368
54381
|
console.error(`[AUTH] REFRESH_WARN: using stale Supabase JWT as fallback (${context})`);
|
|
54369
54382
|
}
|
|
54383
|
+
const freshClaims = jwtClaims(supabaseJwt);
|
|
54384
|
+
const teamId = freshClaims.activeTeamId ?? entry.teamId;
|
|
54370
54385
|
const newAccessToken = randomToken();
|
|
54371
54386
|
const newRefreshToken = randomToken();
|
|
54372
54387
|
const expiresAt = Date.now() + ACCESS_TOKEN_TTL * 1000;
|
|
54373
54388
|
await this.store.set("access_tokens", newAccessToken, {
|
|
54374
54389
|
supabaseJwt,
|
|
54375
54390
|
supabaseRefreshToken,
|
|
54376
|
-
teamId
|
|
54391
|
+
teamId,
|
|
54377
54392
|
clientId: entry.clientId,
|
|
54378
54393
|
expiresAt
|
|
54379
54394
|
}, ACCESS_TOKEN_TTL);
|
|
54380
54395
|
await this.store.set("refresh_tokens", newRefreshToken, {
|
|
54381
54396
|
supabaseJwt,
|
|
54382
54397
|
supabaseRefreshToken,
|
|
54383
|
-
teamId
|
|
54398
|
+
teamId,
|
|
54384
54399
|
clientId: entry.clientId
|
|
54385
54400
|
}, 2592000);
|
|
54386
54401
|
return {
|
|
@@ -55075,17 +55090,18 @@ function resolveAuth(req) {
|
|
|
55075
55090
|
jwt: extra.supabaseJwt,
|
|
55076
55091
|
refreshToken: extra.supabaseRefreshToken ?? "",
|
|
55077
55092
|
teamId: extra.teamId ?? "",
|
|
55078
|
-
userId
|
|
55093
|
+
userId,
|
|
55094
|
+
mcpToken: req.auth.token
|
|
55079
55095
|
};
|
|
55080
55096
|
}
|
|
55081
55097
|
console.error(`[AUTH_RESOLVE] FAIL: no apiKey or supabaseJwt in extra (keys: ${Object.keys(extra).join(", ")})`);
|
|
55082
55098
|
return;
|
|
55083
55099
|
}
|
|
55084
|
-
async function startHttpServer() {
|
|
55100
|
+
async function startHttpServer(options) {
|
|
55085
55101
|
const port = parseInt(process.env.PORT || "3000", 10);
|
|
55086
55102
|
const app = createMcpExpressApp({ host: "0.0.0.0" });
|
|
55087
55103
|
app.set("trust proxy", 1);
|
|
55088
|
-
const store = new RedisTokenStore;
|
|
55104
|
+
const store = options?.store ?? new RedisTokenStore;
|
|
55089
55105
|
const provider = new KadoaOAuthProvider(store);
|
|
55090
55106
|
const serverUrl = process.env.MCP_SERVER_URL || `http://localhost:${port}`;
|
|
55091
55107
|
app.use(mcpAuthRouter({
|
|
@@ -55137,7 +55153,27 @@ async function startHttpServer() {
|
|
|
55137
55153
|
const server = auth.kind === "jwt" ? createServer({
|
|
55138
55154
|
jwt: auth.jwt,
|
|
55139
55155
|
refreshToken: auth.refreshToken,
|
|
55140
|
-
teamId: auth.teamId
|
|
55156
|
+
teamId: auth.teamId,
|
|
55157
|
+
persist: async (state) => {
|
|
55158
|
+
const entry = await store.get("access_tokens", auth.mcpToken);
|
|
55159
|
+
if (!entry) {
|
|
55160
|
+
console.error(`[PERSIST] WARN: access token gone from store (token=${auth.mcpToken.slice(0, 12)}...)`);
|
|
55161
|
+
return;
|
|
55162
|
+
}
|
|
55163
|
+
const remainingMs = entry.expiresAt - Date.now();
|
|
55164
|
+
if (remainingMs <= 0) {
|
|
55165
|
+
console.error(`[PERSIST] WARN: access token already expired, skipping persist`);
|
|
55166
|
+
return;
|
|
55167
|
+
}
|
|
55168
|
+
const ttlSeconds = Math.ceil(remainingMs / 1000);
|
|
55169
|
+
await store.set("access_tokens", auth.mcpToken, {
|
|
55170
|
+
...entry,
|
|
55171
|
+
supabaseJwt: state.supabaseJwt ?? entry.supabaseJwt,
|
|
55172
|
+
supabaseRefreshToken: state.supabaseRefreshToken ?? entry.supabaseRefreshToken,
|
|
55173
|
+
teamId: state.teamId ?? entry.teamId
|
|
55174
|
+
}, ttlSeconds);
|
|
55175
|
+
console.error(`[PERSIST] OK: updated access token in store (token=${auth.mcpToken.slice(0, 12)}..., team=${state.teamId ?? "unchanged"}, ttl=${ttlSeconds}s)`);
|
|
55176
|
+
}
|
|
55141
55177
|
}) : createServer({ apiKey: auth.apiKey });
|
|
55142
55178
|
await server.connect(transport);
|
|
55143
55179
|
await transport.handleRequest(req, res, req.body);
|
|
@@ -55197,7 +55233,8 @@ function createServer(auth) {
|
|
|
55197
55233
|
client: createKadoaClient({ jwt: auth.jwt }),
|
|
55198
55234
|
supabaseJwt: auth.jwt,
|
|
55199
55235
|
supabaseRefreshToken: auth.refreshToken,
|
|
55200
|
-
teamId: auth.teamId
|
|
55236
|
+
teamId: auth.teamId,
|
|
55237
|
+
persist: auth.persist
|
|
55201
55238
|
};
|
|
55202
55239
|
} else if (typeof auth === "object" && auth !== null && "apiKey" in auth) {
|
|
55203
55240
|
ctx = {
|