fix mcp server cloudfront cache bug

This commit is contained in:
ProgrammerIn-wonderland
2026-06-08 15:42:27 -04:00
parent def7290c48
commit 7bc6a52821
2 changed files with 30 additions and 5 deletions
+18 -3
View File
@@ -145,7 +145,10 @@ function formatPuterError(err) {
function jsonResponse(body) {
return new Response(JSON.stringify(body), {
status: 200,
headers: { 'content-type': 'application/json' },
// Per-user MCP results must never be cached by any CDN in front of the
// worker. (POST isn't cached by default, but be explicit — a misconfigured
// edge cache that ignores method/query could otherwise leak responses.)
headers: { 'content-type': 'application/json', 'Cache-Control': 'no-store' },
});
}
@@ -166,6 +169,7 @@ async function mcpPost(event) {
headers: {
'content-type': 'application/json',
'Access-Control-Allow-Origin': '*',
'Cache-Control': 'no-store',
'WWW-Authenticate': `Bearer resource_metadata="${origin}/.well-known/oauth-protected-resource"`,
},
},
@@ -193,9 +197,12 @@ async function mcpPost(event) {
return jsonResponse(response);
}
// Discovery / health.
// Discovery / health. This is the ONLY endpoint safe to cache: it's public,
// identical for every caller, and hammered by clients polling for the tool list.
// It's explicitly marked cacheable so a "respect-origin" CDN policy caches this
// and nothing else (every other response sends no-store).
function mcpInfo() {
return {
const body = {
name: 'puter-mcp',
description:
'MCP server for Puter filesystem, static website hosting, serverless worker, and app registration operations. POST JSON-RPC to ' +
@@ -203,6 +210,14 @@ function mcpInfo() {
transport: 'streamable-http',
tools: listTools().map((t) => t.name),
};
return new Response(JSON.stringify(body), {
status: 200,
headers: {
'content-type': 'application/json',
'Access-Control-Allow-Origin': '*',
'Cache-Control': 'public, max-age=300',
},
});
}
/** Attach the MCP routes to the (already-initialized) router. */
+12 -2
View File
@@ -87,17 +87,27 @@ async function sha256b64url(str) {
// ---- response helpers ------------------------------------------------------
// Every OAuth response is per-request (sealed flow/code blobs, one-time auth
// codes, tokens) and MUST NOT be cached. Without this, a caching layer in front
// of the worker (e.g. the puter.com zone) can replay one user's /authorize
// redirect — and thus their stale callback port / code — to everyone.
// RFC 6749 §5.1 also mandates no-store on the token endpoint.
const NO_STORE = {
'Cache-Control': 'no-store, no-cache, must-revalidate, max-age=0',
Pragma: 'no-cache',
};
function json(status, obj) {
return new Response(JSON.stringify(obj), {
status,
headers: { 'content-type': 'application/json', 'Access-Control-Allow-Origin': '*' },
headers: { 'content-type': 'application/json', 'Access-Control-Allow-Origin': '*', ...NO_STORE },
});
}
function redirect(location) {
return new Response(null, {
status: 302,
headers: { Location: location, 'Access-Control-Allow-Origin': '*' },
headers: { Location: location, 'Access-Control-Allow-Origin': '*', ...NO_STORE },
});
}