Files
sproutclaw-data/agent/extensions/pi-mcp-adapter/oauth-handler.ts
shumengya 50edff80f5 feat: 导出 SproutClaw .sproutclaw 配置
包含 extensions、skills、prompts、settings、auth、models、mcp 等配置。
排除 node_modules、npm 缓存、sessions 等运行时数据。
2026-06-26 15:48:56 +08:00

58 lines
1.7 KiB
TypeScript

// oauth-handler.ts - OAuth token management for MCP servers
import { existsSync, readFileSync } from "node:fs";
import type { OAuthTokens } from "@modelcontextprotocol/sdk/shared/auth.js";
import { getAuthEntryFilePath } from "./mcp-auth.ts";
// Token storage path for a server
function getTokensPath(serverName: string): string {
return getAuthEntryFilePath(serverName);
}
/**
* Get stored OAuth tokens for a server (if any).
* Returns undefined if no tokens or tokens are expired.
*
* Token file location: $MCP_OAUTH_DIR/sha256-<server-hash>/tokens.json when set,
* otherwise <Pi agent dir>/mcp-oauth/sha256-<server-hash>/tokens.json
*
* Expected format:
* {
* "access_token": "...",
* "token_type": "bearer",
* "refresh_token": "...", // optional
* "expires_in": 3600, // optional, seconds
* "expiresAt": 1234567890 // optional, absolute timestamp ms
* }
*/
export function getStoredTokens(serverName: string): OAuthTokens | undefined {
const tokensPath = getTokensPath(serverName);
if (!existsSync(tokensPath)) return undefined;
try {
const stored = JSON.parse(readFileSync(tokensPath, "utf-8"));
// Validate required field
if (!stored.access_token || typeof stored.access_token !== "string") {
return undefined;
}
// Check expiration if expiresAt is set
if (stored.expiresAt && typeof stored.expiresAt === "number") {
if (Date.now() > stored.expiresAt) {
// Token expired
return undefined;
}
}
return {
access_token: stored.access_token,
token_type: stored.token_type ?? "bearer",
refresh_token: stored.refresh_token,
expires_in: stored.expires_in,
};
} catch {
return undefined;
}
}