burn-mcp-server 2.0.6 → 2.1.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/.cursor-plugin/plugin.json +19 -0
- package/.mcp.json +11 -0
- package/README.md +30 -1
- package/api/mcp.js +36075 -0
- package/dist/http.mjs +1131 -0
- package/dist/index.js +1021 -1009
- package/package.json +1 -1
- package/server.json +16 -2
- package/src/vercel-node-handler.ts +76 -0
- package/vercel.json +11 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "burn-mcp-server",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"mcpName": "io.github.Fisher521/burn-mcp-server",
|
|
5
5
|
"description": "Burn MCP — give your AI agent a reading workflow. 26 tools to search, triage, burn, vault, and analyze your saved articles. Works with Claude, Cursor, Windsurf.",
|
|
6
6
|
"main": "dist/index.js",
|
package/server.json
CHANGED
|
@@ -7,12 +7,12 @@
|
|
|
7
7
|
"source": "github"
|
|
8
8
|
},
|
|
9
9
|
"websiteUrl": "https://burn451.cloud",
|
|
10
|
-
"version": "2.0
|
|
10
|
+
"version": "2.1.0",
|
|
11
11
|
"packages": [
|
|
12
12
|
{
|
|
13
13
|
"registryType": "npm",
|
|
14
14
|
"identifier": "burn-mcp-server",
|
|
15
|
-
"version": "2.0
|
|
15
|
+
"version": "2.1.0",
|
|
16
16
|
"transport": {
|
|
17
17
|
"type": "stdio"
|
|
18
18
|
},
|
|
@@ -26,5 +26,19 @@
|
|
|
26
26
|
}
|
|
27
27
|
]
|
|
28
28
|
}
|
|
29
|
+
],
|
|
30
|
+
"remotes": [
|
|
31
|
+
{
|
|
32
|
+
"type": "streamable-http",
|
|
33
|
+
"url": "https://burn-mcp-server.vercel.app/api/mcp",
|
|
34
|
+
"headers": [
|
|
35
|
+
{
|
|
36
|
+
"name": "Authorization",
|
|
37
|
+
"description": "Bearer <BURN_MCP_TOKEN> — generate at https://burn451.cloud → Settings → MCP Server",
|
|
38
|
+
"isRequired": true,
|
|
39
|
+
"isSecret": true
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
}
|
|
29
43
|
]
|
|
30
44
|
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// Vercel Node runtime handler — uses StreamableHTTPServerTransport (non-Web variant).
|
|
2
|
+
// Pre-bundled by esbuild into api/mcp.js (Vercel detects .js as Node function).
|
|
3
|
+
|
|
4
|
+
import type { IncomingMessage, ServerResponse } from 'node:http'
|
|
5
|
+
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'
|
|
6
|
+
import { createClient } from '@supabase/supabase-js'
|
|
7
|
+
import { getOrExchangeSession } from './lib/auth.js'
|
|
8
|
+
import { createBurnServer } from './setup.js'
|
|
9
|
+
|
|
10
|
+
const SUPABASE_URL = process.env.BURN_SUPABASE_URL || 'https://juqtxylquemiuvvmgbej.supabase.co'
|
|
11
|
+
const SUPABASE_ANON_KEY = process.env.BURN_SUPABASE_ANON_KEY || 'sb_publishable_reVgmmCC6ndIo6jFRMM2LQ_wujj5FrO'
|
|
12
|
+
|
|
13
|
+
export default async function handler(req: IncomingMessage, res: ServerResponse): Promise<void> {
|
|
14
|
+
try {
|
|
15
|
+
// --- Auth ---
|
|
16
|
+
const authHeader = (req.headers.authorization || req.headers.Authorization || '') as string
|
|
17
|
+
const m = authHeader.match(/^Bearer\s+(.+)$/i)
|
|
18
|
+
const token = m?.[1]?.trim()
|
|
19
|
+
|
|
20
|
+
if (!token) {
|
|
21
|
+
res.statusCode = 401
|
|
22
|
+
res.setHeader('content-type', 'application/json')
|
|
23
|
+
res.end(JSON.stringify({
|
|
24
|
+
error: 'Missing Authorization header',
|
|
25
|
+
hint: 'Add `Authorization: Bearer <BURN_MCP_TOKEN>` — get yours at https://burn451.cloud → Settings → MCP Server.',
|
|
26
|
+
}))
|
|
27
|
+
return
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// --- Exchange token → Supabase session (in-memory cache per token) ---
|
|
31
|
+
let session
|
|
32
|
+
try {
|
|
33
|
+
session = await getOrExchangeSession(token)
|
|
34
|
+
} catch (e: any) {
|
|
35
|
+
res.statusCode = 401
|
|
36
|
+
res.setHeader('content-type', 'application/json')
|
|
37
|
+
res.end(JSON.stringify({ error: 'Invalid or expired Burn MCP token', detail: String(e?.message || e) }))
|
|
38
|
+
return
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// --- Per-request Supabase client with JWT in headers ---
|
|
42
|
+
const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY, {
|
|
43
|
+
auth: { persistSession: false, autoRefreshToken: false, detectSessionInUrl: false },
|
|
44
|
+
global: { headers: { Authorization: `Bearer ${session.access_token}` } },
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
const server = createBurnServer(supabase, { rateLimitPerMin: 60 })
|
|
48
|
+
|
|
49
|
+
// --- Stateless transport, JSON response mode ---
|
|
50
|
+
const transport = new StreamableHTTPServerTransport({
|
|
51
|
+
sessionIdGenerator: undefined,
|
|
52
|
+
enableJsonResponse: true,
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
await server.connect(transport)
|
|
56
|
+
|
|
57
|
+
// Read body — Vercel Node already parses JSON for us at req.body, but let's be safe
|
|
58
|
+
let parsedBody: unknown
|
|
59
|
+
if ((req as any).body !== undefined) {
|
|
60
|
+
parsedBody = (req as any).body
|
|
61
|
+
} else {
|
|
62
|
+
const chunks: Buffer[] = []
|
|
63
|
+
for await (const c of req) chunks.push(c as Buffer)
|
|
64
|
+
const raw = Buffer.concat(chunks).toString('utf8')
|
|
65
|
+
try { parsedBody = raw ? JSON.parse(raw) : undefined } catch { parsedBody = undefined }
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
await transport.handleRequest(req as any, res, parsedBody)
|
|
69
|
+
} catch (e: any) {
|
|
70
|
+
if (!res.headersSent) {
|
|
71
|
+
res.statusCode = 500
|
|
72
|
+
res.setHeader('content-type', 'application/json')
|
|
73
|
+
res.end(JSON.stringify({ error: 'Handler threw', message: String(e?.message || e), stack: String(e?.stack || '').slice(0, 2000) }))
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|