presentations-test / 2026 /mcp-connect /animations /http-multinode-cookie.html
evalstate's picture
evalstate HF Staff
Scratch test presentation publishing pipeline
5949d89 verified
Raw
History Blame Contribute Delete
13.7 kB
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="shared/http-diagram.css">
<style>
/* Make MCP-Cookie box much larger and prominent */
.message-session.mcp-cookie {
padding: 12px 16px;
border-radius: 12px;
min-width: 200px;
background: #f3e5f5;
border: 3px solid #ab47bc;
box-shadow: 0 6px 20px rgba(156, 39, 176, 0.35);
}
.message-session.mcp-cookie .cookie-label {
font-size: 10px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
color: #7b1fa2;
margin-bottom: 6px;
}
.message-session.mcp-cookie .cookie-value {
font-family: 'SF Mono', Monaco, monospace;
font-size: 14px;
font-weight: 700;
background: white;
padding: 6px 14px;
border-radius: 8px;
border: 2px solid #ce93d8;
color: #7b1fa2;
display: inline-block;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.message-session.mcp-cookie .cookie-value.empty {
color: #9e9e9e;
border-color: #e0e0e0;
font-style: italic;
}
/* Set-Cookie variation - green themed (server issuing) */
.message-session.mcp-cookie.set-cookie {
background: #e8f5e9;
border-color: #66bb6a;
box-shadow: 0 6px 20px rgba(76, 175, 80, 0.35);
}
.message-session.mcp-cookie.set-cookie .cookie-label {
color: #2e7d32;
}
.message-session.mcp-cookie.set-cookie .cookie-value {
border-color: #a5d6a7;
color: #2e7d32;
}
/* Request with cookie - blue themed */
.message.request .message-session.mcp-cookie:not(.set-cookie) {
background: #e3f2fd;
border-color: #42a5f5;
box-shadow: 0 6px 20px rgba(33, 150, 243, 0.35);
}
.message.request .message-session.mcp-cookie:not(.set-cookie) .cookie-label {
color: #1565c0;
}
.message.request .message-session.mcp-cookie:not(.set-cookie) .cookie-value {
border-color: #90caf9;
color: #1565c0;
}
</style>
</head>
<body>
<div class="canvas-root">
<div class="diagram">
<!-- Client -->
<div class="entity client">
<div class="entity-box" id="client-box">
<span>MCP Client</span>
<span class="entity-status" id="client-status"></span>
</div>
<div class="state-badge" id="client-state">
<div class="badge-title">Cookie Jar</div>
<div class="empty-state">empty</div>
<div class="session-id" id="client-session"></div>
<div class="caps-row" id="client-caps"></div>
</div>
</div>
<!-- Load Balancer -->
<div class="entity lb">
<div class="entity-box">LB</div>
</div>
<!-- Connection lines -->
<div class="connection conn-client-lb"></div>
<div class="connection conn-lb-servers"></div>
<!-- Server Cluster -->
<div class="server-cluster">
<div class="cluster-label">Streamable HTTP (Cookies)</div>
</div>
<!-- Server Nodes with session badges to the right -->
<div class="entity server server-1">
<div class="entity-box" id="server-1-box">
<span>Node 1</span>
<span class="entity-status" id="server-1-status"></span>
</div>
<div class="state-badge" id="server-1-state">
<div class="badge-title">Known Cookie</div>
<div class="empty-state">none</div>
<div class="session-id" id="server-1-session"></div>
<div class="caps-row" id="server-1-caps"></div>
</div>
</div>
<div class="entity server server-2">
<div class="entity-box" id="server-2-box">
<span>Node 2</span>
<span class="entity-status" id="server-2-status"></span>
</div>
<div class="state-badge" id="server-2-state">
<div class="badge-title">Known Cookie</div>
<div class="empty-state">none</div>
<div class="session-id" id="server-2-session"></div>
<div class="caps-row" id="server-2-caps"></div>
</div>
</div>
<div class="entity server server-3">
<div class="entity-box" id="server-3-box">
<span>Node 3</span>
<span class="entity-status" id="server-3-status"></span>
</div>
<div class="state-badge" id="server-3-state">
<div class="badge-title">Known Cookie</div>
<div class="empty-state">none</div>
<div class="session-id" id="server-3-session"></div>
<div class="caps-row" id="server-3-caps"></div>
</div>
</div>
<!-- Message -->
<div class="message" id="message">
<div class="message-header">
<span class="message-type" id="message-type">initialize</span>
<span class="message-arrow" id="message-arrow">β†’</span>
</div>
<div class="message-detail" id="message-detail">CallToolRequest</div>
<div class="message-session" id="message-session">MCP-Cookie: (none)</div>
</div>
</div>
<div class="narration" id="narration">
<span class="step-num" id="step-num">β—‹</span>
<span id="narration-text">Client uses MCP cookies for session semantics...</span>
</div>
</div>
<script src="shared/animation-config.js"></script>
<script src="shared/diagram-helpers.js"></script>
<script src="shared/canvas-scale.js"></script>
<script>
const message = document.getElementById('message');
const messageType = document.getElementById('message-type');
const messageArrow = document.getElementById('message-arrow');
const messageDetail = document.getElementById('message-detail');
const messageSession = document.getElementById('message-session');
const narration = document.getElementById('narration');
const narrationText = document.getElementById('narration-text');
const stepNum = document.getElementById('step-num');
const clientBox = document.getElementById('client-box');
const clientState = document.getElementById('client-state');
const clientSession = document.getElementById('client-session');
const clientCaps = document.getElementById('client-caps');
const server1Box = document.getElementById('server-1-box');
const server2Box = document.getElementById('server-2-box');
const server3Box = document.getElementById('server-3-box');
const server1State = document.getElementById('server-1-state');
const server2State = document.getElementById('server-2-state');
const server3State = document.getElementById('server-3-state');
const server1Session = document.getElementById('server-1-session');
const server1Caps = document.getElementById('server-1-caps');
const server2Session = document.getElementById('server-2-session');
const server2Caps = document.getElementById('server-2-caps');
const server3Session = document.getElementById('server-3-session');
const server3Caps = document.getElementById('server-3-caps');
const messageElements = {
container: message,
header: message.querySelector('.message-header'),
type: messageType,
arrow: messageArrow,
detail: messageDetail,
session: messageSession,
};
// Positions (x centers)
const pos = {
client: 65,
lb: 240,
server1: 470,
server2: 470,
server3: 470
};
const yClient = 115;
const yServer1 = 38;
const yServer2 = 143;
const yServer3 = 248;
function setMessagePos(x, y) {
setMessagePosition(message, x, y);
}
function animateMessage(fromX, fromY, toX, toY, duration, callback) {
animateMessageBetween(message, fromX, fromY, toX, toY, duration, callback);
}
function animatePath(waypoints, totalDuration, callback) {
animatePathBetween(message, waypoints, totalDuration, callback);
}
function configMessage(type, arrow, method, detail, sessionText, sessionError, direction) {
configureMessage(messageElements, {
type,
arrow,
method,
detail,
sessionText,
sessionError,
direction,
});
}
function buildCookieMarkup(label, value, isEmpty) {
const valueClass = isEmpty ? 'cookie-value empty' : 'cookie-value';
return `<div class="cookie-label">${label}</div><div class="${valueClass}">${value}</div>`;
}
function resetAll() {
clientBox.className = 'entity-box';
server1Box.className = 'entity-box';
server2Box.className = 'entity-box';
server3Box.className = 'entity-box';
clientState.className = 'state-badge';
server1State.className = 'state-badge';
server2State.className = 'state-badge';
server3State.className = 'state-badge';
// Clear dynamic content
clientSession.textContent = '';
clientCaps.innerHTML = '';
server1Session.textContent = '';
server1Caps.innerHTML = '';
server2Session.textContent = '';
server2Caps.innerHTML = '';
server3Session.textContent = '';
server3Caps.innerHTML = '';
message.className = 'message';
}
const steps = [
// Step 0: Initial state
{
setup: () => {
resetAll();
stepNum.textContent = 'β—‹';
narrationText.textContent = 'Client and server exchange cookies at the MCP layer';
narration.className = 'narration';
},
animate: (done) => setTimeout(done, ANIMATION.INITIAL_PAUSE),
after: () => {}
},
// Step 1: tools/call β†’ LB β†’ Node 1 (no cookie yet)
{
setup: () => {
configMessage('request', 'β†’', 'tools/call', 'CallToolRequest', buildCookieMarkup('MCP-Cookie', '(none)', true), false, 'right');
messageSession.classList.add('mcp-cookie');
setMessagePos(pos.client, yClient);
stepNum.textContent = '1';
narrationText.textContent = 'Client sends request without cookie (MCP JSON-RPC layer)';
narration.className = 'narration request-state';
clientBox.classList.add('alive', 'active');
},
animate: (done) => animatePath(
[{x: pos.client, y: yClient}, {x: pos.lb, y: yClient}, {x: pos.server1, y: yServer1}],
ANIMATION.MSG_DURATION,
done
),
after: () => {
clientBox.classList.remove('active');
server1Box.classList.add('alive', 'active');
}
},
// Step 2: tools/call result ← Node 1 issues cookie
{
setup: () => {
configMessage('response', '←', 'tools/call', 'CallToolResult', buildCookieMarkup('Set-MCP-Cookie', 'cookie_4f2', false), false, 'left');
messageSession.classList.add('mcp-cookie', 'set-cookie');
setMessagePos(pos.server1, yServer1);
stepNum.textContent = '2';
narrationText.textContent = 'Server issues MCP cookie (can be copied to HTTP headers)';
narration.className = 'narration response-state';
server1Session.textContent = 'cookie_4f2';
server1State.classList.add('active');
},
animate: (done) => animatePath(
[{x: pos.server1, y: yServer1}, {x: pos.lb, y: yClient}, {x: pos.client, y: yClient}],
ANIMATION.MSG_DURATION,
done
),
after: () => {
server1Box.classList.remove('active');
clientSession.textContent = 'cookie_4f2';
clientState.classList.add('active');
}
},
// Step 3: tools/call β†’ LB β†’ Node 2 (cookie included)
{
setup: () => {
configMessage('request', 'β†’', 'tools/call', 'CallToolRequest', buildCookieMarkup('MCP-Cookie', 'cookie_4f2', false), false, 'right');
messageSession.classList.add('mcp-cookie');
setMessagePos(pos.client, yClient);
stepNum.textContent = '3';
narrationText.textContent = 'Client returns cookie on the next request';
narration.className = 'narration request-state';
clientBox.classList.add('active');
},
animate: (done) => animatePath(
[{x: pos.client, y: yClient}, {x: pos.lb, y: yClient}, {x: pos.server2, y: yServer2}],
ANIMATION.MSG_DURATION,
done
),
after: () => {
clientBox.classList.remove('active');
server2Box.classList.add('alive', 'active');
}
},
// Step 4: tools/call result ← Node 2 recognizes cookie
{
setup: () => {
configMessage('response', '←', 'tools/call', 'CallToolResult', buildCookieMarkup('MCP-Cookie βœ“', 'cookie_4f2', false), false, 'left');
messageSession.classList.add('mcp-cookie');
setMessagePos(pos.server2, yServer2);
stepNum.textContent = '4';
narrationText.textContent = 'Server uses cookie to maintain session semantics';
narration.className = 'narration response-state';
server2Session.textContent = 'cookie_4f2';
server2State.classList.add('active');
},
animate: (done) => animatePath(
[{x: pos.server2, y: yServer2}, {x: pos.lb, y: yClient}, {x: pos.client, y: yClient}],
ANIMATION.MSG_DURATION,
done
),
after: () => {
server2Box.classList.remove('active');
}
},
// Step 5: Pause before restart
{
setup: () => {
message.className = 'message';
stepNum.textContent = 'βœ“';
narrationText.textContent = 'MCP cookies preserve client/server context across requests';
narration.className = 'narration success-state';
},
animate: (done) => setTimeout(done, ANIMATION.ERROR_PAUSE),
after: () => {}
}
];
runStepSequence(steps);
scaleCanvas();
</script>
</body>
</html>