burn-mcp-server 2.0.5 → 2.0.7
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/LICENSE +21 -0
- package/README.md +68 -4
- package/api/health.mjs +7 -0
- package/api/mcp.js +36075 -0
- package/dist/http.mjs +1131 -0
- package/dist/index.js +965 -923
- package/glama.json +3 -0
- package/package.json +12 -6
- package/public/index.html +47 -0
- package/server.json +21 -6
- package/src/http-dev.ts +56 -0
- package/src/http.ts +62 -0
- package/src/index.ts +28 -1344
- package/src/lib/auth-stdio.ts +26 -0
- package/src/lib/auth.ts +71 -0
- package/src/setup.ts +1529 -0
- package/src/vercel-handler.ts +20 -0
- package/src/vercel-node-handler.ts +76 -0
- package/tsconfig.json +10 -6
- package/vercel.json +9 -0
- package/.mcpregistry_github_token +0 -1
- package/.mcpregistry_registry_token +0 -1
- package/smithery.yaml +0 -17
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// stdio-only: local session cache on disk (~/.burn/mcp-session.json)
|
|
2
|
+
// NEVER import this from http.ts — it pulls in node:fs/os/path which crashes Edge runtime.
|
|
3
|
+
|
|
4
|
+
import { homedir } from 'node:os'
|
|
5
|
+
import { readFileSync, writeFileSync, mkdirSync } from 'node:fs'
|
|
6
|
+
import { join } from 'node:path'
|
|
7
|
+
import type { Session } from './auth.js'
|
|
8
|
+
|
|
9
|
+
const CACHE_DIR = join(homedir(), '.burn')
|
|
10
|
+
const CACHE_FILE = join(CACHE_DIR, 'mcp-session.json')
|
|
11
|
+
|
|
12
|
+
export function loadCachedSession(): Session | null {
|
|
13
|
+
try {
|
|
14
|
+
const raw = readFileSync(CACHE_FILE, 'utf-8')
|
|
15
|
+
const data = JSON.parse(raw)
|
|
16
|
+
if (data.access_token && data.refresh_token) return data
|
|
17
|
+
} catch { /* no cache or invalid */ }
|
|
18
|
+
return null
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function saveCachedSession(session: Session): void {
|
|
22
|
+
try {
|
|
23
|
+
mkdirSync(CACHE_DIR, { recursive: true })
|
|
24
|
+
writeFileSync(CACHE_FILE, JSON.stringify(session), { mode: 0o600 })
|
|
25
|
+
} catch { /* non-fatal */ }
|
|
26
|
+
}
|
package/src/lib/auth.ts
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
// Burn MCP auth — Edge/runtime-safe (no node: imports here)
|
|
2
|
+
//
|
|
3
|
+
// stdio-only session cache (fs-based) is in ./auth-stdio.ts — only imported by src/index.ts.
|
|
4
|
+
// HTTP mode uses in-memory TTL cache declared here (safe in Edge).
|
|
5
|
+
|
|
6
|
+
import { SupabaseClient } from '@supabase/supabase-js'
|
|
7
|
+
|
|
8
|
+
const DEFAULT_EXCHANGE_URL = 'https://api.burn451.cloud/api/mcp-exchange'
|
|
9
|
+
|
|
10
|
+
export interface Session {
|
|
11
|
+
access_token: string
|
|
12
|
+
refresh_token: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** Exchange a long-lived MCP token for a Supabase session (fresh from API). */
|
|
16
|
+
export async function exchangeToken(
|
|
17
|
+
mcpToken: string,
|
|
18
|
+
exchangeUrl: string = process.env.BURN_MCP_EXCHANGE_URL || DEFAULT_EXCHANGE_URL,
|
|
19
|
+
): Promise<Session> {
|
|
20
|
+
const resp = await fetch(exchangeUrl, {
|
|
21
|
+
method: 'POST',
|
|
22
|
+
headers: { 'Content-Type': 'application/json' },
|
|
23
|
+
body: JSON.stringify({ token: mcpToken }),
|
|
24
|
+
})
|
|
25
|
+
if (!resp.ok) {
|
|
26
|
+
let detail = ''
|
|
27
|
+
try { detail = JSON.stringify(await resp.json()) } catch {}
|
|
28
|
+
throw new Error(`Token exchange failed (${resp.status}): ${detail}`)
|
|
29
|
+
}
|
|
30
|
+
const data = await resp.json() as any
|
|
31
|
+
if (!data.access_token || !data.refresh_token) {
|
|
32
|
+
throw new Error('Token exchange succeeded but returned no session tokens')
|
|
33
|
+
}
|
|
34
|
+
return { access_token: data.access_token, refresh_token: data.refresh_token }
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Apply a session to a supabase client, with optional auto-cache on token refresh (stdio mode only). */
|
|
38
|
+
export async function applySession(
|
|
39
|
+
supabase: SupabaseClient,
|
|
40
|
+
session: Session,
|
|
41
|
+
onRefresh?: (s: Session) => void,
|
|
42
|
+
): Promise<void> {
|
|
43
|
+
const { error } = await supabase.auth.setSession(session)
|
|
44
|
+
if (error) throw new Error(`Failed to set session: ${error.message}`)
|
|
45
|
+
if (onRefresh) {
|
|
46
|
+
supabase.auth.onAuthStateChange((_event, s) => {
|
|
47
|
+
if (s?.access_token && s?.refresh_token) {
|
|
48
|
+
onRefresh({ access_token: s.access_token, refresh_token: s.refresh_token })
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
// HTTP mode: per-token in-memory session cache (TTL-based, safe in Edge)
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
|
|
58
|
+
interface CacheEntry { session: Session; expiresAt: number }
|
|
59
|
+
const httpSessionCache = new Map<string, CacheEntry>()
|
|
60
|
+
const HTTP_CACHE_TTL_MS = 5 * 60_000 // 5 min
|
|
61
|
+
|
|
62
|
+
/** Get or refresh a session for an HTTP request. */
|
|
63
|
+
export async function getOrExchangeSession(mcpToken: string): Promise<Session> {
|
|
64
|
+
const now = Date.now()
|
|
65
|
+
const cached = httpSessionCache.get(mcpToken)
|
|
66
|
+
if (cached && cached.expiresAt > now) return cached.session
|
|
67
|
+
|
|
68
|
+
const session = await exchangeToken(mcpToken)
|
|
69
|
+
httpSessionCache.set(mcpToken, { session, expiresAt: now + HTTP_CACHE_TTL_MS })
|
|
70
|
+
return session
|
|
71
|
+
}
|