evalstate HF Staff commited on
Commit
ce0e171
·
verified ·
1 Parent(s): f2fa63a

Add MCP Connect 2026 presentation with latest updates

Browse files
Files changed (29) hide show
  1. .gitattributes +6 -0
  2. 2026/mcp-connect/animations/chat-api-view.html +196 -0
  3. 2026/mcp-connect/animations/chat-demo.html +123 -0
  4. 2026/mcp-connect/animations/http-multinode-cookie.html +387 -0
  5. 2026/mcp-connect/animations/http-multinode-shared-storage.html +444 -0
  6. 2026/mcp-connect/animations/http-multinode-stateless.html +392 -0
  7. 2026/mcp-connect/animations/http-multinode.html +368 -0
  8. 2026/mcp-connect/animations/mcp-mrtr-flow.html +221 -0
  9. 2026/mcp-connect/animations/mcp-mrtr-request.html +233 -0
  10. 2026/mcp-connect/animations/mcp-stateful-request.html +318 -0
  11. 2026/mcp-connect/animations/shared/animation-config.js +32 -0
  12. 2026/mcp-connect/animations/shared/canvas-scale.js +44 -0
  13. 2026/mcp-connect/animations/shared/diagram-helpers.js +152 -0
  14. 2026/mcp-connect/animations/shared/http-diagram.css +505 -0
  15. 2026/mcp-connect/animations/shared/sequence-helpers.js +83 -0
  16. 2026/mcp-connect/animations/stdio-simple.html +722 -0
  17. 2026/mcp-connect/images/2026-02-03-mcp-server-stats.png +3 -0
  18. 2026/mcp-connect/images/2026-02-03-mcpremote1.png +3 -0
  19. 2026/mcp-connect/images/2026-02-03-mcpremote2.png +3 -0
  20. 2026/mcp-connect/images/2026-02-04-client-dataset.png +3 -0
  21. 2026/mcp-connect/images/2026-02-04-efficient.png +0 -0
  22. 2026/mcp-connect/images/github-mark.svg +1 -0
  23. 2026/mcp-connect/images/hf_logo.svg +8 -0
  24. 2026/mcp-connect/images/huggingface-mark-logo.svg +15 -0
  25. 2026/mcp-connect/images/intro-spaces.webm +3 -0
  26. 2026/mcp-connect/images/mcp-icon.svg +12 -0
  27. 2026/mcp-connect/images/xcom-logo-black.png +3 -0
  28. 2026/mcp-connect/presentation.html +0 -0
  29. index.html +16 -0
.gitattributes CHANGED
@@ -53,3 +53,9 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
53
  2025/secure-se-sep/images/local_context.png filter=lfs diff=lfs merge=lfs -text
54
  2025/secure-se-sep/images/model_parameters.png filter=lfs diff=lfs merge=lfs -text
55
  2025/secure-se-sep/images/xcom-logo-black.png filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
53
  2025/secure-se-sep/images/local_context.png filter=lfs diff=lfs merge=lfs -text
54
  2025/secure-se-sep/images/model_parameters.png filter=lfs diff=lfs merge=lfs -text
55
  2025/secure-se-sep/images/xcom-logo-black.png filter=lfs diff=lfs merge=lfs -text
56
+ 2026/mcp-connect/images/2026-02-03-mcp-server-stats.png filter=lfs diff=lfs merge=lfs -text
57
+ 2026/mcp-connect/images/2026-02-03-mcpremote1.png filter=lfs diff=lfs merge=lfs -text
58
+ 2026/mcp-connect/images/2026-02-03-mcpremote2.png filter=lfs diff=lfs merge=lfs -text
59
+ 2026/mcp-connect/images/2026-02-04-client-dataset.png filter=lfs diff=lfs merge=lfs -text
60
+ 2026/mcp-connect/images/intro-spaces.webm filter=lfs diff=lfs merge=lfs -text
61
+ 2026/mcp-connect/images/xcom-logo-black.png filter=lfs diff=lfs merge=lfs -text
2026/mcp-connect/animations/chat-api-view.html ADDED
@@ -0,0 +1,196 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <style>
6
+ * { margin: 0; padding: 0; box-sizing: border-box; }
7
+ html, body {
8
+ height: 100%;
9
+ overflow: hidden;
10
+ }
11
+
12
+ body {
13
+ background: transparent;
14
+ display: flex;
15
+ justify-content: center;
16
+ align-items: center;
17
+ width: 100vw;
18
+ height: 100vh;
19
+ font-family: 'SF Mono', 'Monaco', 'Consolas', monospace;
20
+ }
21
+
22
+ .api-window {
23
+ background: linear-gradient(135deg, #1e1e1e 0%, #252526 100%);
24
+ border-radius: 16px;
25
+ padding: 16px;
26
+ width: 480px;
27
+ height: 460px;
28
+ box-shadow: 0 10px 40px rgba(0,0,0,0.3);
29
+ overflow: hidden;
30
+ display: flex;
31
+ flex-direction: column;
32
+ }
33
+
34
+ .api-header {
35
+ color: #888;
36
+ font-size: 11px;
37
+ margin-bottom: 8px;
38
+ padding-bottom: 6px;
39
+ border-bottom: 1px solid #333;
40
+ }
41
+
42
+ .api-content {
43
+ font-size: 12px;
44
+ line-height: 1.5;
45
+ color: #d4d4d4;
46
+ flex: 1;
47
+ overflow: auto;
48
+ scrollbar-width: none;
49
+ }
50
+
51
+ .api-content::-webkit-scrollbar {
52
+ display: none;
53
+ }
54
+
55
+ .json-brace { color: #d4d4d4; }
56
+ .json-key { color: #9cdcfe; }
57
+ .json-string { color: #ce9178; }
58
+ .json-bracket { color: #d4d4d4; }
59
+ .json-punct { color: #d4d4d4; }
60
+
61
+ .message-block {
62
+ opacity: 0;
63
+ transform: translateX(-10px);
64
+ margin-left: 20px;
65
+ padding: 4px 0;
66
+ }
67
+
68
+ .message-block.show {
69
+ animation: slideInLeft 0.4s ease forwards;
70
+ }
71
+
72
+ .message-block.fade-out {
73
+ animation: fadeOut 0.8s ease forwards;
74
+ }
75
+
76
+ .role-user { border-left: 3px solid #0b93f6; padding-left: 10px; }
77
+ .role-assistant { border-left: 3px solid #34c759; padding-left: 10px; }
78
+
79
+ .static-content {
80
+ opacity: 0;
81
+ }
82
+ .static-content.show {
83
+ animation: fadeIn 0.3s ease forwards;
84
+ }
85
+ .static-content.fade-out {
86
+ animation: fadeOut 0.8s ease forwards;
87
+ }
88
+
89
+ @keyframes slideInLeft {
90
+ from { opacity: 0; transform: translateX(-10px); }
91
+ to { opacity: 1; transform: translateX(0); }
92
+ }
93
+
94
+ @keyframes fadeIn {
95
+ from { opacity: 0; }
96
+ to { opacity: 1; }
97
+ }
98
+
99
+ @keyframes fadeOut {
100
+ from { opacity: 1; }
101
+ to { opacity: 0; }
102
+ }
103
+
104
+ .content-truncated {
105
+ color: #666;
106
+ font-style: italic;
107
+ }
108
+ </style>
109
+ </head>
110
+ <body>
111
+ <div class="api-window canvas-root">
112
+ <div class="api-header">POST /v1/chat/completions</div>
113
+ <div class="api-content">
114
+ <div class="static-content" data-delay="0" id="openBrace">
115
+ <span class="json-brace">{</span><br>
116
+ &nbsp;&nbsp;<span class="json-key">"messages"</span><span class="json-punct">:</span> <span class="json-bracket">[</span>
117
+ </div>
118
+
119
+ <div class="message-block role-user" data-delay="0">
120
+ <span class="json-brace">{</span><br>
121
+ &nbsp;&nbsp;<span class="json-key">"role"</span><span class="json-punct">:</span> <span class="json-string">"user"</span><span class="json-punct">,</span><br>
122
+ &nbsp;&nbsp;<span class="json-key">"content"</span><span class="json-punct">:</span> <span class="json-string">"Can you help me find information about MCP servers?"</span><br>
123
+ <span class="json-brace">}</span>
124
+ </div>
125
+
126
+ <div class="message-block role-assistant" data-delay="2000">
127
+ <span class="json-brace">{</span><br>
128
+ &nbsp;&nbsp;<span class="json-key">"role"</span><span class="json-punct">:</span> <span class="json-string">"assistant"</span><span class="json-punct">,</span><br>
129
+ &nbsp;&nbsp;<span class="json-key">"content"</span><span class="json-punct">:</span> <span class="json-string">"Of course! I can search for MCP server documentation..."</span><br>
130
+ <span class="json-brace">}</span>
131
+ </div>
132
+
133
+ <div class="message-block role-user" data-delay="4000">
134
+ <span class="json-brace">{</span><br>
135
+ &nbsp;&nbsp;<span class="json-key">"role"</span><span class="json-punct">:</span> <span class="json-string">"user"</span><span class="json-punct">,</span><br>
136
+ &nbsp;&nbsp;<span class="json-key">"content"</span><span class="json-punct">:</span> <span class="json-string">"Great, what transport options are available?"</span><br>
137
+ <span class="json-brace">}</span>
138
+ </div>
139
+
140
+ <div class="message-block role-assistant" data-delay="6000">
141
+ <span class="json-brace">{</span><br>
142
+ &nbsp;&nbsp;<span class="json-key">"role"</span><span class="json-punct">:</span> <span class="json-string">"assistant"</span><span class="json-punct">,</span><br>
143
+ &nbsp;&nbsp;<span class="json-key">"content"</span><span class="json-punct">:</span> <span class="json-string">"MCP supports STDIO, Streamable HTTP, and..."</span><br>
144
+ <span class="json-brace">}</span>
145
+ </div>
146
+
147
+ <div class="message-block role-user" data-delay="8000">
148
+ <span class="json-brace">{</span><br>
149
+ &nbsp;&nbsp;<span class="json-key">"role"</span><span class="json-punct">:</span> <span class="json-string">"user"</span><span class="json-punct">,</span><br>
150
+ &nbsp;&nbsp;<span class="json-key">"content"</span><span class="json-punct">:</span> <span class="json-string">"Can servers make requests back to clients?"</span><br>
151
+ <span class="json-brace">}</span>
152
+ </div>
153
+
154
+ <div class="message-block role-assistant" data-delay="10000">
155
+ <span class="json-brace">{</span><br>
156
+ &nbsp;&nbsp;<span class="json-key">"role"</span><span class="json-punct">:</span> <span class="json-string">"assistant"</span><span class="json-punct">,</span><br>
157
+ &nbsp;&nbsp;<span class="json-key">"content"</span><span class="json-punct">:</span> <span class="json-string">"Yes! Servers can request Sampling and Elicitation..."</span><br>
158
+ <span class="json-brace">}</span>
159
+ </div>
160
+
161
+ <div class="static-content" data-delay="0" id="closeBrace">
162
+ &nbsp;&nbsp;<span class="json-bracket">]</span><br>
163
+ <span class="json-brace">}</span>
164
+ </div>
165
+ </div>
166
+ </div>
167
+
168
+ <script src="shared/sequence-helpers.js"></script>
169
+ <script src="shared/canvas-scale.js"></script>
170
+ <script>
171
+ const apiContent = document.querySelector('.api-content');
172
+ const timelineItems = Array.from(document.querySelectorAll('.message-block, .static-content'));
173
+ const delays = timelineItems.map((item) => parseInt(item.dataset.delay, 10) || 0);
174
+ const maxDelay = delays.length ? Math.max(...delays) : 0;
175
+ const cycleDuration = maxDelay + 4000 + 1000 + 2000;
176
+ apiContent.scrollTop = 0;
177
+
178
+ setInterval(() => {
179
+ apiContent.scrollTop = 0;
180
+ }, cycleDuration);
181
+
182
+ runSequenceAnimation({
183
+ selectors: ['.message-block', '.static-content'],
184
+ cyclePause: 2000,
185
+ fadeOutOffset: 4000,
186
+ initialDelay: 500,
187
+ onShow: (el) => {
188
+ if (el.classList.contains('message-block')) {
189
+ el.scrollIntoView({ block: 'nearest' });
190
+ }
191
+ },
192
+ });
193
+ scaleCanvas();
194
+ </script>
195
+ </body>
196
+ </html>
2026/mcp-connect/animations/chat-demo.html ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <style>
6
+ * { margin: 0; padding: 0; box-sizing: border-box; }
7
+ html, body {
8
+ height: 100%;
9
+ overflow: hidden;
10
+ }
11
+
12
+ body {
13
+ background: transparent;
14
+ display: flex;
15
+ justify-content: center;
16
+ align-items: center;
17
+ width: 100vw;
18
+ height: 100vh;
19
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
20
+ }
21
+
22
+ .chat-window {
23
+ background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
24
+ border-radius: 16px;
25
+ padding: 24px;
26
+ width: 480px;
27
+ height: 460px;
28
+ box-shadow: 0 10px 40px rgba(0,0,0,0.3);
29
+ overflow: hidden;
30
+ }
31
+
32
+ .chat-messages {
33
+ display: flex;
34
+ flex-direction: column;
35
+ gap: 14px;
36
+ }
37
+
38
+ .message {
39
+ display: flex;
40
+ opacity: 0;
41
+ transform: translateY(20px);
42
+ }
43
+
44
+ .message.show {
45
+ animation: slideIn 0.5s ease forwards;
46
+ }
47
+
48
+ .message.fade-out {
49
+ animation: fadeOut 0.8s ease forwards;
50
+ }
51
+
52
+ .user-message { justify-content: flex-end; }
53
+ .assistant-message { justify-content: flex-start; }
54
+
55
+ .message-bubble {
56
+ max-width: 85%;
57
+ padding: 12px 16px;
58
+ border-radius: 18px;
59
+ font-size: 14px;
60
+ line-height: 1.45;
61
+ box-shadow: 0 2px 8px rgba(0,0,0,0.15);
62
+ }
63
+
64
+ .user-message .message-bubble {
65
+ background: linear-gradient(135deg, #0b93f6 0%, #007AFF 100%);
66
+ color: white;
67
+ border-bottom-right-radius: 4px;
68
+ }
69
+
70
+ .assistant-message .message-bubble {
71
+ background: linear-gradient(135deg, #34c759 0%, #30d158 100%);
72
+ color: white;
73
+ border-bottom-left-radius: 4px;
74
+ }
75
+
76
+ @keyframes slideIn {
77
+ from { opacity: 0; transform: translateY(20px); }
78
+ to { opacity: 1; transform: translateY(0); }
79
+ }
80
+
81
+ @keyframes fadeOut {
82
+ from { opacity: 1; transform: translateY(0); }
83
+ to { opacity: 0; transform: translateY(-10px); }
84
+ }
85
+ </style>
86
+ </head>
87
+ <body>
88
+ <div class="chat-window canvas-root">
89
+ <div class="chat-messages" id="chatMessages">
90
+ <div class="message user-message" data-delay="0">
91
+ <div class="message-bubble">Can you help me find information about MCP servers?</div>
92
+ </div>
93
+ <div class="message assistant-message" data-delay="2000">
94
+ <div class="message-bubble">Of course! I can search for MCP server documentation. Let me use the search tool...</div>
95
+ </div>
96
+ <div class="message user-message" data-delay="4000">
97
+ <div class="message-bubble">Great, what transport options are available?</div>
98
+ </div>
99
+ <div class="message assistant-message" data-delay="6000">
100
+ <div class="message-bubble">MCP supports STDIO, Streamable HTTP, and the deprecated SSE transport. HTTP is recommended for remote servers.</div>
101
+ </div>
102
+ <div class="message user-message" data-delay="8000">
103
+ <div class="message-bubble">Can servers make requests back to clients?</div>
104
+ </div>
105
+ <div class="message assistant-message" data-delay="10000">
106
+ <div class="message-bubble">Yes! Servers can request Sampling and Elicitation from clients. This enables interactive workflows.</div>
107
+ </div>
108
+ </div>
109
+ </div>
110
+
111
+ <script src="shared/sequence-helpers.js"></script>
112
+ <script src="shared/canvas-scale.js"></script>
113
+ <script>
114
+ runSequenceAnimation({
115
+ selectors: ['.message'],
116
+ cyclePause: 2000,
117
+ fadeOutOffset: 4000,
118
+ initialDelay: 500,
119
+ });
120
+ scaleCanvas();
121
+ </script>
122
+ </body>
123
+ </html>
2026/mcp-connect/animations/http-multinode-cookie.html ADDED
@@ -0,0 +1,387 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <link rel="stylesheet" href="shared/http-diagram.css">
6
+ <style>
7
+ /* Make MCP-Cookie box much larger and prominent */
8
+ .message-session.mcp-cookie {
9
+ padding: 12px 16px;
10
+ border-radius: 12px;
11
+ min-width: 200px;
12
+ background: #f3e5f5;
13
+ border: 3px solid #ab47bc;
14
+ box-shadow: 0 6px 20px rgba(156, 39, 176, 0.35);
15
+ }
16
+
17
+ .message-session.mcp-cookie .cookie-label {
18
+ font-size: 10px;
19
+ font-weight: 600;
20
+ text-transform: uppercase;
21
+ letter-spacing: 0.5px;
22
+ color: #7b1fa2;
23
+ margin-bottom: 6px;
24
+ }
25
+
26
+ .message-session.mcp-cookie .cookie-value {
27
+ font-family: 'SF Mono', Monaco, monospace;
28
+ font-size: 14px;
29
+ font-weight: 700;
30
+ background: white;
31
+ padding: 6px 14px;
32
+ border-radius: 8px;
33
+ border: 2px solid #ce93d8;
34
+ color: #7b1fa2;
35
+ display: inline-block;
36
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
37
+ }
38
+
39
+ .message-session.mcp-cookie .cookie-value.empty {
40
+ color: #9e9e9e;
41
+ border-color: #e0e0e0;
42
+ font-style: italic;
43
+ }
44
+
45
+ /* Set-Cookie variation - green themed (server issuing) */
46
+ .message-session.mcp-cookie.set-cookie {
47
+ background: #e8f5e9;
48
+ border-color: #66bb6a;
49
+ box-shadow: 0 6px 20px rgba(76, 175, 80, 0.35);
50
+ }
51
+
52
+ .message-session.mcp-cookie.set-cookie .cookie-label {
53
+ color: #2e7d32;
54
+ }
55
+
56
+ .message-session.mcp-cookie.set-cookie .cookie-value {
57
+ border-color: #a5d6a7;
58
+ color: #2e7d32;
59
+ }
60
+
61
+ /* Request with cookie - blue themed */
62
+ .message.request .message-session.mcp-cookie:not(.set-cookie) {
63
+ background: #e3f2fd;
64
+ border-color: #42a5f5;
65
+ box-shadow: 0 6px 20px rgba(33, 150, 243, 0.35);
66
+ }
67
+
68
+ .message.request .message-session.mcp-cookie:not(.set-cookie) .cookie-label {
69
+ color: #1565c0;
70
+ }
71
+
72
+ .message.request .message-session.mcp-cookie:not(.set-cookie) .cookie-value {
73
+ border-color: #90caf9;
74
+ color: #1565c0;
75
+ }
76
+ </style>
77
+ </head>
78
+ <body>
79
+ <div class="canvas-root">
80
+ <div class="diagram">
81
+ <!-- Client -->
82
+ <div class="entity client">
83
+ <div class="entity-box" id="client-box">
84
+ <span>MCP Client</span>
85
+ <span class="entity-status" id="client-status"></span>
86
+ </div>
87
+ <div class="state-badge" id="client-state">
88
+ <div class="badge-title">Cookie Jar</div>
89
+ <div class="empty-state">empty</div>
90
+ <div class="session-id" id="client-session"></div>
91
+ <div class="caps-row" id="client-caps"></div>
92
+ </div>
93
+ </div>
94
+
95
+ <!-- Load Balancer -->
96
+ <div class="entity lb">
97
+ <div class="entity-box">LB</div>
98
+ </div>
99
+
100
+ <!-- Connection lines -->
101
+ <div class="connection conn-client-lb"></div>
102
+ <div class="connection conn-lb-servers"></div>
103
+
104
+ <!-- Server Cluster -->
105
+ <div class="server-cluster">
106
+ <div class="cluster-label">Streamable HTTP (Cookies)</div>
107
+ </div>
108
+
109
+ <!-- Server Nodes with session badges to the right -->
110
+ <div class="entity server server-1">
111
+ <div class="entity-box" id="server-1-box">
112
+ <span>Node 1</span>
113
+ <span class="entity-status" id="server-1-status"></span>
114
+ </div>
115
+ <div class="state-badge" id="server-1-state">
116
+ <div class="badge-title">Known Cookie</div>
117
+ <div class="empty-state">none</div>
118
+ <div class="session-id" id="server-1-session"></div>
119
+ <div class="caps-row" id="server-1-caps"></div>
120
+ </div>
121
+ </div>
122
+
123
+ <div class="entity server server-2">
124
+ <div class="entity-box" id="server-2-box">
125
+ <span>Node 2</span>
126
+ <span class="entity-status" id="server-2-status"></span>
127
+ </div>
128
+ <div class="state-badge" id="server-2-state">
129
+ <div class="badge-title">Known Cookie</div>
130
+ <div class="empty-state">none</div>
131
+ <div class="session-id" id="server-2-session"></div>
132
+ <div class="caps-row" id="server-2-caps"></div>
133
+ </div>
134
+ </div>
135
+
136
+ <div class="entity server server-3">
137
+ <div class="entity-box" id="server-3-box">
138
+ <span>Node 3</span>
139
+ <span class="entity-status" id="server-3-status"></span>
140
+ </div>
141
+ <div class="state-badge" id="server-3-state">
142
+ <div class="badge-title">Known Cookie</div>
143
+ <div class="empty-state">none</div>
144
+ <div class="session-id" id="server-3-session"></div>
145
+ <div class="caps-row" id="server-3-caps"></div>
146
+ </div>
147
+ </div>
148
+
149
+ <!-- Message -->
150
+ <div class="message" id="message">
151
+ <div class="message-header">
152
+ <span class="message-type" id="message-type">initialize</span>
153
+ <span class="message-arrow" id="message-arrow">→</span>
154
+ </div>
155
+ <div class="message-detail" id="message-detail">CallToolRequest</div>
156
+ <div class="message-session" id="message-session">MCP-Cookie: (none)</div>
157
+ </div>
158
+ </div>
159
+
160
+ <div class="narration" id="narration">
161
+ <span class="step-num" id="step-num">○</span>
162
+ <span id="narration-text">Client uses MCP cookies for session semantics...</span>
163
+ </div>
164
+
165
+ </div>
166
+
167
+ <script src="shared/animation-config.js"></script>
168
+ <script src="shared/diagram-helpers.js"></script>
169
+ <script src="shared/canvas-scale.js"></script>
170
+ <script>
171
+ const message = document.getElementById('message');
172
+ const messageType = document.getElementById('message-type');
173
+ const messageArrow = document.getElementById('message-arrow');
174
+ const messageDetail = document.getElementById('message-detail');
175
+ const messageSession = document.getElementById('message-session');
176
+ const narration = document.getElementById('narration');
177
+ const narrationText = document.getElementById('narration-text');
178
+ const stepNum = document.getElementById('step-num');
179
+
180
+ const clientBox = document.getElementById('client-box');
181
+ const clientState = document.getElementById('client-state');
182
+ const clientSession = document.getElementById('client-session');
183
+ const clientCaps = document.getElementById('client-caps');
184
+
185
+ const server1Box = document.getElementById('server-1-box');
186
+ const server2Box = document.getElementById('server-2-box');
187
+ const server3Box = document.getElementById('server-3-box');
188
+ const server1State = document.getElementById('server-1-state');
189
+ const server2State = document.getElementById('server-2-state');
190
+ const server3State = document.getElementById('server-3-state');
191
+ const server1Session = document.getElementById('server-1-session');
192
+ const server1Caps = document.getElementById('server-1-caps');
193
+ const server2Session = document.getElementById('server-2-session');
194
+ const server2Caps = document.getElementById('server-2-caps');
195
+ const server3Session = document.getElementById('server-3-session');
196
+ const server3Caps = document.getElementById('server-3-caps');
197
+
198
+
199
+ const messageElements = {
200
+ container: message,
201
+ header: message.querySelector('.message-header'),
202
+ type: messageType,
203
+ arrow: messageArrow,
204
+ detail: messageDetail,
205
+ session: messageSession,
206
+ };
207
+
208
+ // Positions (x centers)
209
+ const pos = {
210
+ client: 65,
211
+ lb: 240,
212
+ server1: 470,
213
+ server2: 470,
214
+ server3: 470
215
+ };
216
+ const yClient = 115;
217
+ const yServer1 = 38;
218
+ const yServer2 = 143;
219
+ const yServer3 = 248;
220
+
221
+
222
+ function setMessagePos(x, y) {
223
+ setMessagePosition(message, x, y);
224
+ }
225
+
226
+ function animateMessage(fromX, fromY, toX, toY, duration, callback) {
227
+ animateMessageBetween(message, fromX, fromY, toX, toY, duration, callback);
228
+ }
229
+
230
+ function animatePath(waypoints, totalDuration, callback) {
231
+ animatePathBetween(message, waypoints, totalDuration, callback);
232
+ }
233
+
234
+ function configMessage(type, arrow, method, detail, sessionText, sessionError, direction) {
235
+ configureMessage(messageElements, {
236
+ type,
237
+ arrow,
238
+ method,
239
+ detail,
240
+ sessionText,
241
+ sessionError,
242
+ direction,
243
+ });
244
+ }
245
+
246
+ function buildCookieMarkup(label, value, isEmpty) {
247
+ const valueClass = isEmpty ? 'cookie-value empty' : 'cookie-value';
248
+ return `<div class="cookie-label">${label}</div><div class="${valueClass}">${value}</div>`;
249
+ }
250
+
251
+ function resetAll() {
252
+ clientBox.className = 'entity-box';
253
+ server1Box.className = 'entity-box';
254
+ server2Box.className = 'entity-box';
255
+ server3Box.className = 'entity-box';
256
+ clientState.className = 'state-badge';
257
+ server1State.className = 'state-badge';
258
+ server2State.className = 'state-badge';
259
+ server3State.className = 'state-badge';
260
+ // Clear dynamic content
261
+ clientSession.textContent = '';
262
+ clientCaps.innerHTML = '';
263
+ server1Session.textContent = '';
264
+ server1Caps.innerHTML = '';
265
+ server2Session.textContent = '';
266
+ server2Caps.innerHTML = '';
267
+ server3Session.textContent = '';
268
+ server3Caps.innerHTML = '';
269
+ message.className = 'message';
270
+ }
271
+
272
+ const steps = [
273
+ // Step 0: Initial state
274
+ {
275
+ setup: () => {
276
+ resetAll();
277
+ stepNum.textContent = '○';
278
+ narrationText.textContent = 'Client and server exchange cookies at the MCP layer';
279
+ narration.className = 'narration';
280
+ },
281
+ animate: (done) => setTimeout(done, ANIMATION.INITIAL_PAUSE),
282
+ after: () => {}
283
+ },
284
+ // Step 1: tools/call → LB → Node 1 (no cookie yet)
285
+ {
286
+ setup: () => {
287
+ configMessage('request', '→', 'tools/call', 'CallToolRequest', buildCookieMarkup('MCP-Cookie', '(none)', true), false, 'right');
288
+ messageSession.classList.add('mcp-cookie');
289
+ setMessagePos(pos.client, yClient);
290
+ stepNum.textContent = '1';
291
+ narrationText.textContent = 'Client sends request without cookie (MCP JSON-RPC layer)';
292
+ narration.className = 'narration request-state';
293
+ clientBox.classList.add('alive', 'active');
294
+ },
295
+ animate: (done) => animatePath(
296
+ [{x: pos.client, y: yClient}, {x: pos.lb, y: yClient}, {x: pos.server1, y: yServer1}],
297
+ ANIMATION.MSG_DURATION,
298
+ done
299
+ ),
300
+ after: () => {
301
+ clientBox.classList.remove('active');
302
+ server1Box.classList.add('alive', 'active');
303
+ }
304
+ },
305
+ // Step 2: tools/call result ← Node 1 issues cookie
306
+ {
307
+ setup: () => {
308
+ configMessage('response', '←', 'tools/call', 'CallToolResult', buildCookieMarkup('Set-MCP-Cookie', 'cookie_4f2', false), false, 'left');
309
+ messageSession.classList.add('mcp-cookie', 'set-cookie');
310
+ setMessagePos(pos.server1, yServer1);
311
+ stepNum.textContent = '2';
312
+ narrationText.textContent = 'Server issues MCP cookie (can be copied to HTTP headers)';
313
+ narration.className = 'narration response-state';
314
+ server1Session.textContent = 'cookie_4f2';
315
+ server1State.classList.add('active');
316
+ },
317
+ animate: (done) => animatePath(
318
+ [{x: pos.server1, y: yServer1}, {x: pos.lb, y: yClient}, {x: pos.client, y: yClient}],
319
+ ANIMATION.MSG_DURATION,
320
+ done
321
+ ),
322
+ after: () => {
323
+ server1Box.classList.remove('active');
324
+ clientSession.textContent = 'cookie_4f2';
325
+ clientState.classList.add('active');
326
+ }
327
+ },
328
+ // Step 3: tools/call → LB → Node 2 (cookie included)
329
+ {
330
+ setup: () => {
331
+ configMessage('request', '→', 'tools/call', 'CallToolRequest', buildCookieMarkup('MCP-Cookie', 'cookie_4f2', false), false, 'right');
332
+ messageSession.classList.add('mcp-cookie');
333
+ setMessagePos(pos.client, yClient);
334
+ stepNum.textContent = '3';
335
+ narrationText.textContent = 'Client returns cookie on the next request';
336
+ narration.className = 'narration request-state';
337
+ clientBox.classList.add('active');
338
+ },
339
+ animate: (done) => animatePath(
340
+ [{x: pos.client, y: yClient}, {x: pos.lb, y: yClient}, {x: pos.server2, y: yServer2}],
341
+ ANIMATION.MSG_DURATION,
342
+ done
343
+ ),
344
+ after: () => {
345
+ clientBox.classList.remove('active');
346
+ server2Box.classList.add('alive', 'active');
347
+ }
348
+ },
349
+ // Step 4: tools/call result ← Node 2 recognizes cookie
350
+ {
351
+ setup: () => {
352
+ configMessage('response', '←', 'tools/call', 'CallToolResult', buildCookieMarkup('MCP-Cookie ✓', 'cookie_4f2', false), false, 'left');
353
+ messageSession.classList.add('mcp-cookie');
354
+ setMessagePos(pos.server2, yServer2);
355
+ stepNum.textContent = '4';
356
+ narrationText.textContent = 'Server uses cookie to maintain session semantics';
357
+ narration.className = 'narration response-state';
358
+ server2Session.textContent = 'cookie_4f2';
359
+ server2State.classList.add('active');
360
+ },
361
+ animate: (done) => animatePath(
362
+ [{x: pos.server2, y: yServer2}, {x: pos.lb, y: yClient}, {x: pos.client, y: yClient}],
363
+ ANIMATION.MSG_DURATION,
364
+ done
365
+ ),
366
+ after: () => {
367
+ server2Box.classList.remove('active');
368
+ }
369
+ },
370
+ // Step 5: Pause before restart
371
+ {
372
+ setup: () => {
373
+ message.className = 'message';
374
+ stepNum.textContent = '✓';
375
+ narrationText.textContent = 'MCP cookies preserve client/server context across requests';
376
+ narration.className = 'narration success-state';
377
+ },
378
+ animate: (done) => setTimeout(done, ANIMATION.ERROR_PAUSE),
379
+ after: () => {}
380
+ }
381
+ ];
382
+
383
+ runStepSequence(steps);
384
+ scaleCanvas();
385
+ </script>
386
+ </body>
387
+ </html>
2026/mcp-connect/animations/http-multinode-shared-storage.html ADDED
@@ -0,0 +1,444 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <link rel="stylesheet" href="shared/http-diagram.css">
6
+ <style>
7
+ /* Make RequestId box much larger and prominent */
8
+ .message-session.request-id {
9
+ padding: 12px 16px;
10
+ border-radius: 12px;
11
+ min-width: 180px;
12
+ background: #fff3e0;
13
+ border: 3px solid #ffa726;
14
+ box-shadow: 0 6px 20px rgba(255, 152, 0, 0.35);
15
+ }
16
+
17
+ .message-session.request-id .request-label {
18
+ font-size: 10px;
19
+ font-weight: 600;
20
+ text-transform: uppercase;
21
+ letter-spacing: 0.5px;
22
+ color: #e65100;
23
+ margin-bottom: 6px;
24
+ }
25
+
26
+ .message-session.request-id .request-value {
27
+ font-family: 'SF Mono', Monaco, monospace;
28
+ font-size: 14px;
29
+ font-weight: 700;
30
+ background: white;
31
+ padding: 6px 14px;
32
+ border-radius: 8px;
33
+ border: 2px solid #ffb74d;
34
+ color: #e65100;
35
+ display: inline-block;
36
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
37
+ }
38
+
39
+ /* Client response variation - blue themed */
40
+ .message.client-response .message-session.request-id {
41
+ background: #e3f2fd;
42
+ border-color: #42a5f5;
43
+ box-shadow: 0 6px 20px rgba(33, 150, 243, 0.35);
44
+ }
45
+
46
+ .message.client-response .message-session.request-id .request-label {
47
+ color: #1565c0;
48
+ }
49
+
50
+ .message.client-response .message-session.request-id .request-value {
51
+ border-color: #90caf9;
52
+ color: #1565c0;
53
+ }
54
+
55
+ /* Error variation - red themed */
56
+ .message.error-response .message-session.request-id {
57
+ background: #ffebee;
58
+ border-color: #ef5350;
59
+ box-shadow: 0 6px 20px rgba(244, 67, 54, 0.35);
60
+ }
61
+
62
+ .message.error-response .message-session.request-id .request-label {
63
+ color: #c62828;
64
+ }
65
+
66
+ .message.error-response .message-session.request-id .request-value {
67
+ border-color: #ef9a9a;
68
+ color: #c62828;
69
+ }
70
+ </style>
71
+ </head>
72
+ <body>
73
+ <div class="canvas-root">
74
+ <div class="diagram">
75
+ <!-- Client -->
76
+ <div class="entity client">
77
+ <div class="entity-box" id="client-box">
78
+ <span>MCP Client</span>
79
+ <span class="entity-status" id="client-status"></span>
80
+ </div>
81
+ <div class="state-badge" id="client-state">
82
+ <div class="badge-title">Connection State</div>
83
+ <div class="empty-state">Mcp-Session-Id: —</div>
84
+ <div class="session-id" id="client-session"></div>
85
+ <div class="caps-row" id="client-caps"></div>
86
+ </div>
87
+ </div>
88
+
89
+ <!-- Load Balancer -->
90
+ <div class="entity lb">
91
+ <div class="entity-box">LB</div>
92
+ </div>
93
+
94
+ <!-- Connection lines -->
95
+ <div class="connection conn-client-lb"></div>
96
+ <div class="connection conn-lb-servers"></div>
97
+
98
+ <!-- Server Cluster -->
99
+ <div class="server-cluster">
100
+ <div class="cluster-label">Streamable HTTP (Shared Init State)</div>
101
+ </div>
102
+
103
+ <!-- Server Nodes with session badges to the right -->
104
+ <div class="entity server server-1">
105
+ <div class="entity-box" id="server-1-box">
106
+ <span>Node 1</span>
107
+ <span class="entity-status" id="server-1-status"></span>
108
+ </div>
109
+ <div class="state-badge" id="server-1-state">
110
+ <div class="badge-title">Connection State</div>
111
+ <div class="empty-state">Mcp-Session-Id: —</div>
112
+ <div class="session-id" id="server-1-session"></div>
113
+ <div class="caps-row" id="server-1-caps"></div>
114
+ </div>
115
+ </div>
116
+
117
+ <div class="entity server server-2">
118
+ <div class="entity-box" id="server-2-box">
119
+ <span>Node 2</span>
120
+ <span class="entity-status" id="server-2-status"></span>
121
+ </div>
122
+ <div class="state-badge" id="server-2-state">
123
+ <div class="badge-title">Connection State</div>
124
+ <div class="empty-state">Mcp-Session-Id: —</div>
125
+ <div class="session-id" id="server-2-session"></div>
126
+ <div class="caps-row" id="server-2-caps"></div>
127
+ </div>
128
+ </div>
129
+
130
+ <div class="entity server server-3">
131
+ <div class="entity-box" id="server-3-box">
132
+ <span>Node 3</span>
133
+ <span class="entity-status" id="server-3-status"></span>
134
+ </div>
135
+ <div class="state-badge" id="server-3-state">
136
+ <div class="badge-title">Connection State</div>
137
+ <div class="empty-state">Mcp-Session-Id: —</div>
138
+ <div class="session-id" id="server-3-session"></div>
139
+ <div class="caps-row" id="server-3-caps"></div>
140
+ </div>
141
+ </div>
142
+
143
+ <!-- Message -->
144
+ <div class="message" id="message">
145
+ <div class="message-header">
146
+ <span class="message-type" id="message-type">initialize</span>
147
+ <span class="message-arrow" id="message-arrow">→</span>
148
+ </div>
149
+ <div class="message-detail" id="message-detail">InitializeRequest</div>
150
+ <div class="message-session" id="message-session">Mcp-Session-Id: sess_abc123</div>
151
+ </div>
152
+ </div>
153
+
154
+ <div class="narration" id="narration">
155
+ <span class="step-num" id="step-num">○</span>
156
+ <span id="narration-text">Shared storage syncs initialize state across servers...</span>
157
+ </div>
158
+
159
+ </div>
160
+
161
+ <script src="shared/animation-config.js"></script>
162
+ <script src="shared/diagram-helpers.js"></script>
163
+ <script src="shared/canvas-scale.js"></script>
164
+ <script>
165
+ const message = document.getElementById('message');
166
+ const messageType = document.getElementById('message-type');
167
+ const messageArrow = document.getElementById('message-arrow');
168
+ const messageDetail = document.getElementById('message-detail');
169
+ const messageSession = document.getElementById('message-session');
170
+ const narration = document.getElementById('narration');
171
+ const narrationText = document.getElementById('narration-text');
172
+ const stepNum = document.getElementById('step-num');
173
+
174
+ const clientBox = document.getElementById('client-box');
175
+ const clientState = document.getElementById('client-state');
176
+ const clientSession = document.getElementById('client-session');
177
+ const clientCaps = document.getElementById('client-caps');
178
+ const clientStatus = document.getElementById('client-status');
179
+
180
+ const server1Box = document.getElementById('server-1-box');
181
+ const server2Box = document.getElementById('server-2-box');
182
+ const server3Box = document.getElementById('server-3-box');
183
+ const server1State = document.getElementById('server-1-state');
184
+ const server2State = document.getElementById('server-2-state');
185
+ const server3State = document.getElementById('server-3-state');
186
+ const server1Status = document.getElementById('server-1-status');
187
+ const server2Status = document.getElementById('server-2-status');
188
+ const server3Status = document.getElementById('server-3-status');
189
+ const server1Session = document.getElementById('server-1-session');
190
+ const server1Caps = document.getElementById('server-1-caps');
191
+ const server2Session = document.getElementById('server-2-session');
192
+ const server2Caps = document.getElementById('server-2-caps');
193
+ const server3Session = document.getElementById('server-3-session');
194
+ const server3Caps = document.getElementById('server-3-caps');
195
+
196
+
197
+ const messageElements = {
198
+ container: message,
199
+ header: message.querySelector('.message-header'),
200
+ type: messageType,
201
+ arrow: messageArrow,
202
+ detail: messageDetail,
203
+ session: messageSession,
204
+ };
205
+
206
+ // Positions (x centers)
207
+ const pos = {
208
+ client: 65,
209
+ lb: 240,
210
+ server1: 470,
211
+ server2: 470,
212
+ server3: 470
213
+ };
214
+ const yClient = 115;
215
+ const yServer1 = 38;
216
+ const yServer2 = 143;
217
+ const yServer3 = 248;
218
+
219
+
220
+ function setMessagePos(x, y) {
221
+ setMessagePosition(message, x, y);
222
+ }
223
+
224
+ function animateMessage(fromX, fromY, toX, toY, duration, callback) {
225
+ animateMessageBetween(message, fromX, fromY, toX, toY, duration, callback);
226
+ }
227
+
228
+ function animatePath(waypoints, totalDuration, callback) {
229
+ animatePathBetween(message, waypoints, totalDuration, callback);
230
+ }
231
+
232
+ function configMessage(type, arrow, method, detail, sessionText, sessionError, direction) {
233
+ configureMessage(messageElements, {
234
+ type,
235
+ arrow,
236
+ method,
237
+ detail,
238
+ sessionText,
239
+ sessionError,
240
+ direction,
241
+ });
242
+ }
243
+
244
+ function buildRequestIdMarkup(requestId) {
245
+ return `<div class="request-label">Must route to original server</div><div class="request-value">${requestId}</div>`;
246
+ }
247
+
248
+ function setStatus(element, text, className) {
249
+ element.textContent = text;
250
+ element.className = 'entity-status' + (text ? ' visible' : '') + (className ? ' ' + className : '');
251
+ }
252
+
253
+ function resetAll() {
254
+ clientBox.className = 'entity-box';
255
+ server1Box.className = 'entity-box';
256
+ server2Box.className = 'entity-box';
257
+ server3Box.className = 'entity-box';
258
+ clientState.className = 'state-badge';
259
+ server1State.className = 'state-badge';
260
+ server2State.className = 'state-badge';
261
+ server3State.className = 'state-badge';
262
+ // Clear dynamic content
263
+ clientSession.textContent = '';
264
+ clientCaps.innerHTML = '';
265
+ server1Session.textContent = '';
266
+ server1Caps.innerHTML = '';
267
+ server2Session.textContent = '';
268
+ server2Caps.innerHTML = '';
269
+ server3Session.textContent = '';
270
+ server3Caps.innerHTML = '';
271
+ setStatus(clientStatus, '', '');
272
+ setStatus(server1Status, '', '');
273
+ setStatus(server2Status, '', '');
274
+ setStatus(server3Status, '', '');
275
+ message.className = 'message';
276
+ }
277
+
278
+ const steps = [
279
+ // Step 0: Initial state
280
+ {
281
+ setup: () => {
282
+ resetAll();
283
+ stepNum.textContent = '○';
284
+ narrationText.textContent = 'Shared storage syncs initialize state across servers';
285
+ narration.className = 'narration';
286
+ },
287
+ animate: (done) => setTimeout(done, ANIMATION.INITIAL_PAUSE),
288
+ after: () => {}
289
+ },
290
+ // Step 1: Initialize request → LB → Node 1
291
+ {
292
+ setup: () => {
293
+ configMessage('request', '→', 'initialize', 'InitializeRequest', null, false, 'right');
294
+ setMessagePos(pos.client, yClient);
295
+ stepNum.textContent = '1';
296
+ narrationText.textContent = 'Client initializes with capabilities';
297
+ narration.className = 'narration request-state';
298
+ clientBox.classList.add('alive', 'active');
299
+ },
300
+ animate: (done) => animatePath(
301
+ [{x: pos.client, y: yClient}, {x: pos.lb, y: yClient}, {x: pos.server1, y: yServer1}],
302
+ ANIMATION.MSG_DURATION,
303
+ done
304
+ ),
305
+ after: () => {
306
+ clientBox.classList.remove('active');
307
+ server1Box.classList.add('alive', 'active');
308
+ }
309
+ },
310
+ // Step 2: Initialize result ← shared to all nodes
311
+ {
312
+ setup: () => {
313
+ configMessage('response', '←', 'initialize', 'InitializeResult', 'Mcp-Session-Id: sess_shared', false, 'left');
314
+ setMessagePos(pos.server1, yServer1);
315
+ stepNum.textContent = '2';
316
+ narrationText.textContent = 'Shared store syncs session to all servers';
317
+ narration.className = 'narration response-state';
318
+ server1Session.textContent = 'sess_shared';
319
+ server1Caps.innerHTML = '<span class="cap">sampling ✓</span>';
320
+ server2Session.textContent = 'sess_shared';
321
+ server2Caps.innerHTML = '<span class="cap">sampling ✓</span>';
322
+ server3Session.textContent = 'sess_shared';
323
+ server3Caps.innerHTML = '<span class="cap">sampling ✓</span>';
324
+ server1State.classList.add('session');
325
+ server2State.classList.add('session');
326
+ server3State.classList.add('session');
327
+ },
328
+ animate: (done) => animatePath(
329
+ [{x: pos.server1, y: yServer1}, {x: pos.lb, y: yClient}, {x: pos.client, y: yClient}],
330
+ ANIMATION.MSG_DURATION,
331
+ done
332
+ ),
333
+ after: () => {
334
+ server1Box.classList.remove('active');
335
+ clientSession.textContent = 'sess_shared';
336
+ clientCaps.innerHTML = '<span class="cap">tools ✓</span><span class="cap">prompts ✓</span>';
337
+ clientState.classList.add('session');
338
+ }
339
+ },
340
+ // Step 3: notifications/initialized → LB → Node 1
341
+ {
342
+ setup: () => {
343
+ configMessage('notification', '→', 'initialized', 'notification', 'Mcp-Session-Id: sess_shared', false, 'right');
344
+ setMessagePos(pos.client, yClient);
345
+ stepNum.textContent = '3';
346
+ narrationText.textContent = 'Client sends initialized notification';
347
+ narration.className = 'narration notification-state';
348
+ clientBox.classList.add('active');
349
+ server2Box.classList.add('alive');
350
+ server3Box.classList.add('alive');
351
+ setStatus(server2Status, 'SYNCED', '');
352
+ setStatus(server3Status, 'SYNCED', '');
353
+ },
354
+ animate: (done) => animatePath(
355
+ [{x: pos.client, y: yClient}, {x: pos.lb, y: yClient}, {x: pos.server1, y: yServer1}],
356
+ ANIMATION.MSG_DURATION,
357
+ done
358
+ ),
359
+ after: () => {
360
+ clientBox.classList.remove('active');
361
+ clientState.classList.add('active');
362
+ server1State.classList.add('active');
363
+ server2State.classList.add('active');
364
+ server3State.classList.add('active');
365
+ setStatus(server2Status, '', '');
366
+ setStatus(server3Status, '', '');
367
+ }
368
+ },
369
+ // Step 4: Server sends elicitation request (waiting)
370
+ {
371
+ setup: () => {
372
+ configMessage('server-request', '←', 'elicitation/request', 'ElicitRequest', buildRequestIdMarkup('req_41'), false, 'left');
373
+ messageSession.classList.add('request-id');
374
+ setMessagePos(pos.server1, yServer1);
375
+ stepNum.textContent = '4';
376
+ narrationText.textContent = 'Node 1 asks client to confirm (WAITING)';
377
+ narration.className = 'narration waiting-state';
378
+ server1Box.classList.add('waiting');
379
+ setStatus(server1Status, 'WAITING', 'waiting');
380
+ },
381
+ animate: (done) => animatePath(
382
+ [{x: pos.server1, y: yServer1}, {x: pos.lb, y: yClient}, {x: pos.client, y: yClient}],
383
+ ANIMATION.MSG_DURATION,
384
+ done
385
+ ),
386
+ after: () => {
387
+ clientBox.classList.add('active');
388
+ }
389
+ },
390
+ // Step 5: Client responds but routed to Node 3
391
+ {
392
+ setup: () => {
393
+ configMessage('client-response', '→', 'elicitation/response', 'ElicitResult', buildRequestIdMarkup('req_41'), false, 'right');
394
+ messageSession.classList.add('request-id');
395
+ setMessagePos(pos.client, yClient);
396
+ stepNum.textContent = '5';
397
+ narrationText.textContent = 'Client response routed to the wrong server';
398
+ narration.className = 'narration request-state';
399
+ },
400
+ animate: (done) => animatePath(
401
+ [{x: pos.client, y: yClient}, {x: pos.lb, y: yClient}, {x: pos.server3, y: yServer3}],
402
+ ANIMATION.MSG_DURATION,
403
+ done
404
+ ),
405
+ after: () => {
406
+ clientBox.classList.remove('active');
407
+ server3Box.classList.add('active');
408
+ }
409
+ },
410
+ // Step 6: Error ← Node 3 doesn't know pending request
411
+ {
412
+ setup: () => {
413
+ configMessage('error-response', '←', 'ERROR', 'Unknown request', buildRequestIdMarkup('req_41'), true, 'left');
414
+ messageSession.classList.add('request-id');
415
+ setMessagePos(pos.server3, yServer3);
416
+ stepNum.textContent = '✗';
417
+ narrationText.textContent = 'Shared init state is not enough for server requests';
418
+ narration.className = 'narration error-state';
419
+ server3Box.classList.add('error');
420
+ },
421
+ animate: (done) => animatePath(
422
+ [{x: pos.server3, y: yServer3}, {x: pos.lb, y: yClient}, {x: pos.client, y: yClient}],
423
+ ANIMATION.MSG_DURATION,
424
+ done
425
+ ),
426
+ after: () => {
427
+ clientBox.classList.add('error');
428
+ }
429
+ },
430
+ // Step 7: Pause on error
431
+ {
432
+ setup: () => {
433
+ message.className = 'message';
434
+ },
435
+ animate: (done) => setTimeout(done, ANIMATION.ERROR_PAUSE),
436
+ after: () => {}
437
+ }
438
+ ];
439
+
440
+ runStepSequence(steps);
441
+ scaleCanvas();
442
+ </script>
443
+ </body>
444
+ </html>
2026/mcp-connect/animations/http-multinode-stateless.html ADDED
@@ -0,0 +1,392 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <link rel="stylesheet" href="shared/http-diagram.css">
6
+ <style>
7
+ /* Override message-session to be much larger for stateless demo */
8
+ .message-session.caps {
9
+ padding: 12px 16px;
10
+ border-radius: 12px;
11
+ min-width: 180px;
12
+ background: #e8f5e9;
13
+ border: 3px solid #66bb6a;
14
+ box-shadow: 0 6px 20px rgba(76, 175, 80, 0.35);
15
+ }
16
+
17
+ .message-session .session-label {
18
+ font-size: 11px;
19
+ font-weight: 600;
20
+ text-transform: uppercase;
21
+ letter-spacing: 0.5px;
22
+ color: #2e7d32;
23
+ margin-bottom: 8px;
24
+ }
25
+
26
+ .message-session .cap-row {
27
+ display: flex;
28
+ gap: 8px;
29
+ flex-wrap: wrap;
30
+ }
31
+
32
+ .message-session .cap-chip {
33
+ font-family: 'SF Mono', Monaco, monospace;
34
+ font-size: 12px;
35
+ font-weight: 600;
36
+ background: white;
37
+ padding: 6px 12px;
38
+ border-radius: 8px;
39
+ border: 2px solid #a5d6a7;
40
+ color: #2e7d32;
41
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
42
+ }
43
+
44
+ /* Make server response caps orange themed */
45
+ .message.response .message-session.caps {
46
+ background: #fff3e0;
47
+ border-color: #ffa726;
48
+ box-shadow: 0 6px 20px rgba(255, 152, 0, 0.35);
49
+ }
50
+
51
+ .message.response .message-session .session-label {
52
+ color: #e65100;
53
+ }
54
+
55
+ .message.response .message-session .cap-chip {
56
+ border-color: #ffb74d;
57
+ color: #e65100;
58
+ }
59
+ </style>
60
+ </head>
61
+ <body>
62
+ <div class="canvas-root">
63
+ <div class="diagram">
64
+ <!-- Client -->
65
+ <div class="entity client">
66
+ <div class="entity-box" id="client-box">
67
+ <span>MCP Client</span>
68
+ <span class="entity-status" id="client-status"></span>
69
+ </div>
70
+ <div class="state-badge" id="client-state">
71
+ <div class="badge-title">Connection State</div>
72
+ <div class="empty-state">stateless</div>
73
+ <div class="session-id" id="client-session"></div>
74
+ <div class="caps-row" id="client-caps"></div>
75
+ </div>
76
+ </div>
77
+
78
+ <!-- Load Balancer -->
79
+ <div class="entity lb">
80
+ <div class="entity-box">LB</div>
81
+ </div>
82
+
83
+ <!-- Connection lines -->
84
+ <div class="connection conn-client-lb"></div>
85
+ <div class="connection conn-lb-servers"></div>
86
+
87
+ <!-- Server Cluster -->
88
+ <div class="server-cluster">
89
+ <div class="cluster-label">Streamable HTTP (Stateless)</div>
90
+ </div>
91
+
92
+ <!-- Server Nodes with session badges to the right -->
93
+ <div class="entity server server-1">
94
+ <div class="entity-box" id="server-1-box">
95
+ <span>Node 1</span>
96
+ <span class="entity-status" id="server-1-status"></span>
97
+ </div>
98
+ <div class="state-badge" id="server-1-state">
99
+ <div class="badge-title">Connection State</div>
100
+ <div class="empty-state">stateless</div>
101
+ <div class="session-id" id="server-1-session"></div>
102
+ <div class="caps-row" id="server-1-caps"></div>
103
+ </div>
104
+ </div>
105
+
106
+ <div class="entity server server-2">
107
+ <div class="entity-box" id="server-2-box">
108
+ <span>Node 2</span>
109
+ <span class="entity-status" id="server-2-status"></span>
110
+ </div>
111
+ <div class="state-badge" id="server-2-state">
112
+ <div class="badge-title">Connection State</div>
113
+ <div class="empty-state">stateless</div>
114
+ <div class="session-id"></div>
115
+ <div class="caps-row"></div>
116
+ </div>
117
+ </div>
118
+
119
+ <div class="entity server server-3">
120
+ <div class="entity-box" id="server-3-box">
121
+ <span>Node 3</span>
122
+ <span class="entity-status" id="server-3-status"></span>
123
+ </div>
124
+ <div class="state-badge" id="server-3-state">
125
+ <div class="badge-title">Connection State</div>
126
+ <div class="empty-state">stateless</div>
127
+ <div class="session-id" id="server-3-session"></div>
128
+ <div class="caps-row" id="server-3-caps"></div>
129
+ </div>
130
+ </div>
131
+
132
+ <!-- Message -->
133
+ <div class="message" id="message">
134
+ <div class="message-header">
135
+ <span class="message-type" id="message-type">initialize</span>
136
+ <span class="message-arrow" id="message-arrow">→</span>
137
+ </div>
138
+ <div class="message-detail" id="message-detail">InitializeRequest</div>
139
+ <div class="message-session" id="message-session">Client capabilities: tools, prompts</div>
140
+ </div>
141
+ </div>
142
+
143
+ <div class="narration" id="narration">
144
+ <span class="step-num" id="step-num">○</span>
145
+ <span id="narration-text">Client sends stateless requests via HTTP...</span>
146
+ </div>
147
+
148
+ </div>
149
+
150
+ <script src="shared/animation-config.js"></script>
151
+ <script src="shared/diagram-helpers.js"></script>
152
+ <script src="shared/canvas-scale.js"></script>
153
+ <script>
154
+ const message = document.getElementById('message');
155
+ const messageType = document.getElementById('message-type');
156
+ const messageArrow = document.getElementById('message-arrow');
157
+ const messageDetail = document.getElementById('message-detail');
158
+ const messageSession = document.getElementById('message-session');
159
+ const narration = document.getElementById('narration');
160
+ const narrationText = document.getElementById('narration-text');
161
+ const stepNum = document.getElementById('step-num');
162
+
163
+ const clientBox = document.getElementById('client-box');
164
+ const clientState = document.getElementById('client-state');
165
+ const clientSession = document.getElementById('client-session');
166
+ const clientCaps = document.getElementById('client-caps');
167
+
168
+ const server1Box = document.getElementById('server-1-box');
169
+ const server2Box = document.getElementById('server-2-box');
170
+ const server3Box = document.getElementById('server-3-box');
171
+ const server1State = document.getElementById('server-1-state');
172
+ const server2State = document.getElementById('server-2-state');
173
+ const server3State = document.getElementById('server-3-state');
174
+ const server1Session = document.getElementById('server-1-session');
175
+ const server1Caps = document.getElementById('server-1-caps');
176
+ const server3Session = document.getElementById('server-3-session');
177
+ const server3Caps = document.getElementById('server-3-caps');
178
+
179
+
180
+ const messageElements = {
181
+ container: message,
182
+ header: message.querySelector('.message-header'),
183
+ type: messageType,
184
+ arrow: messageArrow,
185
+ detail: messageDetail,
186
+ session: messageSession,
187
+ };
188
+
189
+ // Positions (x centers)
190
+ const pos = {
191
+ client: 65,
192
+ lb: 240,
193
+ server1: 470,
194
+ server2: 470,
195
+ server3: 470
196
+ };
197
+ const yClient = 115;
198
+ const yServer1 = 38;
199
+ const yServer2 = 143;
200
+ const yServer3 = 248;
201
+
202
+ function buildCapsMarkup(label, caps) {
203
+ const chips = caps.map((cap) => `<span class="cap-chip">${cap} ✓</span>`).join('');
204
+ return `<div class="session-label">${label}</div><div class="cap-row">${chips}</div>`;
205
+ }
206
+
207
+
208
+ function setMessagePos(x, y) {
209
+ setMessagePosition(message, x, y);
210
+ }
211
+
212
+ function animateMessage(fromX, fromY, toX, toY, duration, callback) {
213
+ animateMessageBetween(message, fromX, fromY, toX, toY, duration, callback);
214
+ }
215
+
216
+ function animatePath(waypoints, totalDuration, callback) {
217
+ animatePathBetween(message, waypoints, totalDuration, callback);
218
+ }
219
+
220
+ function configMessage(type, arrow, method, detail, sessionText, sessionError, direction) {
221
+ configureMessage(messageElements, {
222
+ type,
223
+ arrow,
224
+ method,
225
+ detail,
226
+ sessionText,
227
+ sessionError,
228
+ direction,
229
+ });
230
+ }
231
+
232
+ function resetAll() {
233
+ clientBox.className = 'entity-box';
234
+ server1Box.className = 'entity-box';
235
+ server2Box.className = 'entity-box';
236
+ server3Box.className = 'entity-box';
237
+ clientState.className = 'state-badge';
238
+ server1State.className = 'state-badge';
239
+ server2State.className = 'state-badge';
240
+ server3State.className = 'state-badge';
241
+ // Clear dynamic content
242
+ clientSession.textContent = '';
243
+ clientCaps.innerHTML = '';
244
+ server1Session.textContent = '';
245
+ server1Caps.innerHTML = '';
246
+ server3Session.textContent = '';
247
+ server3Caps.innerHTML = '';
248
+ message.className = 'message';
249
+ }
250
+
251
+ const steps = [
252
+ // Step 0: Initial state
253
+ {
254
+ setup: () => {
255
+ resetAll();
256
+ stepNum.textContent = '○';
257
+ narrationText.textContent = 'Client sends stateless requests via load balancer...';
258
+ narration.className = 'narration';
259
+ },
260
+ animate: (done) => setTimeout(done, ANIMATION.INITIAL_PAUSE),
261
+ after: () => {}
262
+ },
263
+ // Step 1: tools/call → LB → Node 2 (client caps included)
264
+ {
265
+ setup: () => {
266
+ configMessage(
267
+ 'request',
268
+ '→',
269
+ 'tools/call',
270
+ 'CallToolRequest',
271
+ buildCapsMarkup('Client capabilities', ['tools', 'prompts']),
272
+ false,
273
+ 'right'
274
+ );
275
+ messageSession.classList.add('caps');
276
+ setMessagePos(pos.client, yClient);
277
+ stepNum.textContent = '1';
278
+ narrationText.textContent = 'Client sends tool call with capabilities on every request';
279
+ narration.className = 'narration request-state';
280
+ clientBox.classList.add('alive', 'active');
281
+ },
282
+ animate: (done) => animatePath(
283
+ [{x: pos.client, y: yClient}, {x: pos.lb, y: yClient}, {x: pos.server2, y: yServer2}],
284
+ ANIMATION.MSG_DURATION,
285
+ done
286
+ ),
287
+ after: () => {
288
+ clientBox.classList.remove('active');
289
+ server2Box.classList.add('alive', 'active');
290
+ }
291
+ },
292
+ // Step 2: tools/call result ← Node 2 (server caps included)
293
+ {
294
+ setup: () => {
295
+ configMessage(
296
+ 'response',
297
+ '←',
298
+ 'tools/call',
299
+ 'CallToolResult',
300
+ buildCapsMarkup('Server capabilities', ['sampling']),
301
+ false,
302
+ 'left'
303
+ );
304
+ messageSession.classList.add('caps');
305
+ setMessagePos(pos.server2, yServer2);
306
+ stepNum.textContent = '2';
307
+ narrationText.textContent = 'Node 2 responds with result and server capabilities';
308
+ narration.className = 'narration response-state';
309
+ },
310
+ animate: (done) => animatePath(
311
+ [{x: pos.server2, y: yServer2}, {x: pos.lb, y: yClient}, {x: pos.client, y: yClient}],
312
+ ANIMATION.MSG_DURATION,
313
+ done
314
+ ),
315
+ after: () => {
316
+ server2Box.classList.remove('active');
317
+ }
318
+ },
319
+ // Step 3: prompts/list → LB → Node 3
320
+ {
321
+ setup: () => {
322
+ configMessage(
323
+ 'request',
324
+ '→',
325
+ 'prompts/list',
326
+ 'ListPromptsRequest',
327
+ buildCapsMarkup('Client capabilities', ['tools', 'prompts']),
328
+ false,
329
+ 'right'
330
+ );
331
+ messageSession.classList.add('caps');
332
+ setMessagePos(pos.client, yClient);
333
+ stepNum.textContent = '3';
334
+ narrationText.textContent = 'Next request can hit any node in the cluster';
335
+ narration.className = 'narration request-state';
336
+ clientBox.classList.add('active');
337
+ },
338
+ animate: (done) => animatePath(
339
+ [{x: pos.client, y: yClient}, {x: pos.lb, y: yClient}, {x: pos.server3, y: yServer3}],
340
+ ANIMATION.MSG_DURATION,
341
+ done
342
+ ),
343
+ after: () => {
344
+ clientBox.classList.remove('active');
345
+ server3Box.classList.add('alive', 'active');
346
+ }
347
+ },
348
+ // Step 4: prompts/list result ← Node 3
349
+ {
350
+ setup: () => {
351
+ configMessage(
352
+ 'response',
353
+ '←',
354
+ 'prompts/list',
355
+ 'ListPromptsResult',
356
+ buildCapsMarkup('Server capabilities', ['sampling']),
357
+ false,
358
+ 'left'
359
+ );
360
+ messageSession.classList.add('caps');
361
+ setMessagePos(pos.server3, yServer3);
362
+ stepNum.textContent = '4';
363
+ narrationText.textContent = 'Node 3 replies with its capabilities and result';
364
+ narration.className = 'narration response-state';
365
+ },
366
+ animate: (done) => animatePath(
367
+ [{x: pos.server3, y: yServer3}, {x: pos.lb, y: yClient}, {x: pos.client, y: yClient}],
368
+ ANIMATION.MSG_DURATION,
369
+ done
370
+ ),
371
+ after: () => {
372
+ server3Box.classList.remove('active');
373
+ }
374
+ },
375
+ // Step 5: Pause before restart
376
+ {
377
+ setup: () => {
378
+ message.className = 'message';
379
+ stepNum.textContent = '✓';
380
+ narrationText.textContent = 'Stateless flow — capabilities travel with each message';
381
+ narration.className = 'narration success-state';
382
+ },
383
+ animate: (done) => setTimeout(done, ANIMATION.ERROR_PAUSE),
384
+ after: () => {}
385
+ }
386
+ ];
387
+
388
+ runStepSequence(steps);
389
+ scaleCanvas();
390
+ </script>
391
+ </body>
392
+ </html>
2026/mcp-connect/animations/http-multinode.html ADDED
@@ -0,0 +1,368 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <link rel="stylesheet" href="shared/http-diagram.css">
6
+
7
+ </head>
8
+ <body>
9
+ <div class="canvas-root">
10
+ <div class="diagram">
11
+ <!-- Client -->
12
+ <div class="entity client">
13
+ <div class="entity-box" id="client-box">
14
+ <span>MCP Client</span>
15
+ <span class="entity-status" id="client-status"></span>
16
+ </div>
17
+ <div class="state-badge" id="client-state">
18
+ <div class="badge-title">Connection State</div>
19
+ <div class="empty-state">Mcp-Session-Id: —</div>
20
+ <div class="session-id" id="client-session"></div>
21
+ <div class="caps-row" id="client-caps"></div>
22
+ </div>
23
+ </div>
24
+
25
+ <!-- Load Balancer -->
26
+ <div class="entity lb">
27
+ <div class="entity-box">LB</div>
28
+ </div>
29
+
30
+ <!-- Connection lines -->
31
+ <div class="connection conn-client-lb"></div>
32
+ <div class="connection conn-lb-servers"></div>
33
+
34
+ <!-- Server Cluster -->
35
+ <div class="server-cluster">
36
+ <div class="cluster-label">Streamable HTTP (MCP Servers)</div>
37
+ </div>
38
+
39
+ <!-- Server Nodes with session badges to the right -->
40
+ <div class="entity server server-1">
41
+ <div class="entity-box" id="server-1-box">
42
+ <span>Node 1</span>
43
+ <span class="entity-status" id="server-1-status"></span>
44
+ </div>
45
+ <div class="state-badge" id="server-1-state">
46
+ <div class="badge-title">Connection State</div>
47
+ <div class="empty-state">Mcp-Session-Id: —</div>
48
+ <div class="session-id" id="server-1-session"></div>
49
+ <div class="caps-row" id="server-1-caps"></div>
50
+ </div>
51
+ </div>
52
+
53
+ <div class="entity server server-2">
54
+ <div class="entity-box" id="server-2-box">
55
+ <span>Node 2</span>
56
+ <span class="entity-status" id="server-2-status"></span>
57
+ </div>
58
+ <div class="state-badge" id="server-2-state">
59
+ <div class="badge-title">Connection State</div>
60
+ <div class="empty-state">Mcp-Session-Id: —</div>
61
+ <div class="session-id"></div>
62
+ <div class="caps-row"></div>
63
+ </div>
64
+ </div>
65
+
66
+ <div class="entity server server-3">
67
+ <div class="entity-box" id="server-3-box">
68
+ <span>Node 3</span>
69
+ <span class="entity-status" id="server-3-status"></span>
70
+ </div>
71
+ <div class="state-badge" id="server-3-state">
72
+ <div class="badge-title">Connection State</div>
73
+ <div class="empty-state">Mcp-Session-Id: —</div>
74
+ <div class="session-id" id="server-3-session"></div>
75
+ <div class="caps-row" id="server-3-caps"></div>
76
+ </div>
77
+ </div>
78
+
79
+ <!-- Message -->
80
+ <div class="message" id="message">
81
+ <div class="message-header">
82
+ <span class="message-type" id="message-type">initialize</span>
83
+ <span class="message-arrow" id="message-arrow">→</span>
84
+ </div>
85
+ <div class="message-detail" id="message-detail">InitializeRequest</div>
86
+ <div class="message-session" id="message-session">Mcp-Session-Id: sess_abc123</div>
87
+ </div>
88
+ </div>
89
+
90
+ <div class="narration" id="narration">
91
+ <span class="step-num" id="step-num">○</span>
92
+ <span id="narration-text">Client connects via HTTP...</span>
93
+ </div>
94
+
95
+ </div>
96
+
97
+ <script src="shared/animation-config.js"></script>
98
+ <script src="shared/diagram-helpers.js"></script>
99
+ <script src="shared/canvas-scale.js"></script>
100
+ <script>
101
+ const message = document.getElementById('message');
102
+ const messageType = document.getElementById('message-type');
103
+ const messageArrow = document.getElementById('message-arrow');
104
+ const messageDetail = document.getElementById('message-detail');
105
+ const messageSession = document.getElementById('message-session');
106
+ const narration = document.getElementById('narration');
107
+ const narrationText = document.getElementById('narration-text');
108
+ const stepNum = document.getElementById('step-num');
109
+
110
+ const clientBox = document.getElementById('client-box');
111
+ const clientState = document.getElementById('client-state');
112
+ const clientSession = document.getElementById('client-session');
113
+ const clientCaps = document.getElementById('client-caps');
114
+
115
+ const server1Box = document.getElementById('server-1-box');
116
+ const server2Box = document.getElementById('server-2-box');
117
+ const server3Box = document.getElementById('server-3-box');
118
+ const server1State = document.getElementById('server-1-state');
119
+ const server2State = document.getElementById('server-2-state');
120
+ const server3State = document.getElementById('server-3-state');
121
+ const server1Session = document.getElementById('server-1-session');
122
+ const server1Caps = document.getElementById('server-1-caps');
123
+ const server3Session = document.getElementById('server-3-session');
124
+ const server3Caps = document.getElementById('server-3-caps');
125
+
126
+
127
+ const messageElements = {
128
+ container: message,
129
+ header: message.querySelector('.message-header'),
130
+ type: messageType,
131
+ arrow: messageArrow,
132
+ detail: messageDetail,
133
+ session: messageSession,
134
+ };
135
+
136
+ // Positions (x centers)
137
+ const pos = {
138
+ client: 65,
139
+ lb: 240,
140
+ server1: 470,
141
+ server2: 470,
142
+ server3: 470
143
+ };
144
+ const yClient = 115;
145
+ const yServer1 = 38;
146
+ const yServer2 = 143;
147
+ const yServer3 = 248;
148
+
149
+
150
+ function setMessagePos(x, y) {
151
+ setMessagePosition(message, x, y);
152
+ }
153
+
154
+ function animateMessage(fromX, fromY, toX, toY, duration, callback) {
155
+ animateMessageBetween(message, fromX, fromY, toX, toY, duration, callback);
156
+ }
157
+
158
+ function animatePath(waypoints, totalDuration, callback) {
159
+ animatePathBetween(message, waypoints, totalDuration, callback);
160
+ }
161
+
162
+ function configMessage(type, arrow, method, detail, sessionText, sessionError, direction) {
163
+ configureMessage(messageElements, {
164
+ type,
165
+ arrow,
166
+ method,
167
+ detail,
168
+ sessionText,
169
+ sessionError,
170
+ direction,
171
+ });
172
+ }
173
+
174
+ function resetAll() {
175
+ clientBox.className = 'entity-box';
176
+ server1Box.className = 'entity-box';
177
+ server2Box.className = 'entity-box';
178
+ server3Box.className = 'entity-box';
179
+ clientState.className = 'state-badge';
180
+ server1State.className = 'state-badge';
181
+ server2State.className = 'state-badge';
182
+ server3State.className = 'state-badge';
183
+ // Clear dynamic content
184
+ clientSession.textContent = '';
185
+ clientCaps.innerHTML = '';
186
+ server1Session.textContent = '';
187
+ server1Caps.innerHTML = '';
188
+ server3Session.textContent = '';
189
+ server3Caps.innerHTML = '';
190
+ message.className = 'message';
191
+ }
192
+
193
+ const steps = [
194
+ // Step 0: Initial state
195
+ {
196
+ setup: () => {
197
+ resetAll();
198
+ stepNum.textContent = '○';
199
+ narrationText.textContent = 'Client connects to server cluster via load balancer...';
200
+ narration.className = 'narration';
201
+ },
202
+ animate: (done) => setTimeout(done, ANIMATION.INITIAL_PAUSE),
203
+ after: () => {}
204
+ },
205
+ // Step 1: Initialize request → LB → Node 1
206
+ {
207
+ setup: () => {
208
+ configMessage('request', '→', 'initialize', 'InitializeRequest', null, false, 'right');
209
+ setMessagePos(pos.client, yClient);
210
+ stepNum.textContent = '1';
211
+ narrationText.textContent = 'Client sends InitializeRequest with capabilities';
212
+ narration.className = 'narration request-state';
213
+ clientBox.classList.add('alive', 'active');
214
+ },
215
+ animate: (done) => animatePath(
216
+ [{x: pos.client, y: yClient}, {x: pos.lb, y: yClient}, {x: pos.server1, y: yServer1}],
217
+ ANIMATION.MSG_DURATION,
218
+ done
219
+ ),
220
+ after: () => {
221
+ clientBox.classList.remove('active');
222
+ server1Box.classList.add('alive', 'active');
223
+ }
224
+ },
225
+ // Step 2: Initialize result ← with session ID
226
+ {
227
+ setup: () => {
228
+ configMessage('response', '←', 'initialize', 'InitializeResult', 'Mcp-Session-Id: sess_abc123', false, 'left');
229
+ setMessagePos(pos.server1, yServer1);
230
+ stepNum.textContent = '2';
231
+ narrationText.textContent = 'Node 1 creates session, stores client capabilities';
232
+ narration.className = 'narration response-state';
233
+ // Populate server 1 state
234
+ server1Session.textContent = 'sess_abc123';
235
+ server1Caps.innerHTML = '<span class="cap">sampling ✓</span>';
236
+ server1State.classList.add('session');
237
+ },
238
+ animate: (done) => animatePath(
239
+ [{x: pos.server1, y: yServer1}, {x: pos.lb, y: yClient}, {x: pos.client, y: yClient}],
240
+ ANIMATION.MSG_DURATION,
241
+ done
242
+ ),
243
+ after: () => {
244
+ server1Box.classList.remove('active');
245
+ clientSession.textContent = 'sess_abc123';
246
+ clientState.classList.add('session');
247
+ }
248
+ },
249
+ // Step 3: notifications/initialized → LB → Node 1
250
+ {
251
+ setup: () => {
252
+ configMessage('notification', '→', 'initialized', 'notification', 'Mcp-Session-Id: sess_abc123', false, 'right');
253
+ setMessagePos(pos.client, yClient);
254
+ stepNum.textContent = '3';
255
+ narrationText.textContent = 'Client sends initialized notification';
256
+ narration.className = 'narration notification-state';
257
+ clientBox.classList.add('active');
258
+ },
259
+ animate: (done) => animatePath(
260
+ [{x: pos.client, y: yClient}, {x: pos.lb, y: yClient}, {x: pos.server1, y: yServer1}],
261
+ ANIMATION.MSG_DURATION,
262
+ done
263
+ ),
264
+ after: () => {
265
+ clientBox.classList.remove('active');
266
+ // Populate client state
267
+ clientSession.textContent = 'sess_abc123';
268
+ clientCaps.innerHTML = '<span class="cap">tools ✓</span><span class="cap">prompts ✓</span>';
269
+ clientState.classList.add('active');
270
+ server1State.classList.add('active');
271
+ }
272
+ },
273
+ // Step 4: tools/call → LB → Node 1 (correct)
274
+ {
275
+ setup: () => {
276
+ configMessage('request', '→', 'tools/call', 'CallToolRequest', 'Mcp-Session-Id: sess_abc123', false, 'right');
277
+ setMessagePos(pos.client, yClient);
278
+ stepNum.textContent = '4';
279
+ narrationText.textContent = 'Client calls tool with session ID';
280
+ narration.className = 'narration request-state';
281
+ clientBox.classList.add('active');
282
+ },
283
+ animate: (done) => animatePath(
284
+ [{x: pos.client, y: yClient}, {x: pos.lb, y: yClient}, {x: pos.server1, y: yServer1}],
285
+ ANIMATION.MSG_DURATION,
286
+ done
287
+ ),
288
+ after: () => {
289
+ clientBox.classList.remove('active');
290
+ server1Box.classList.add('active');
291
+ }
292
+ },
293
+ // Step 5: tools/call result ←
294
+ {
295
+ setup: () => {
296
+ configMessage('response', '←', 'tools/call', 'CallToolResult', 'Mcp-Session-Id: sess_abc123', false, 'left');
297
+ setMessagePos(pos.server1, yServer1);
298
+ stepNum.textContent = '5';
299
+ narrationText.textContent = 'Node 1 has session + capabilities — success ✓';
300
+ narration.className = 'narration response-state';
301
+ },
302
+ animate: (done) => animatePath(
303
+ [{x: pos.server1, y: yServer1}, {x: pos.lb, y: yClient}, {x: pos.client, y: yClient}],
304
+ ANIMATION.MSG_DURATION,
305
+ done
306
+ ),
307
+ after: () => {
308
+ server1Box.classList.remove('active');
309
+ }
310
+ },
311
+ // Step 6: Another request → LB → Node 3 (WRONG!)
312
+ {
313
+ setup: () => {
314
+ configMessage('request', '→', 'tools/call', 'CallToolRequest', 'Mcp-Session-Id: sess_abc123', false, 'right');
315
+ setMessagePos(pos.client, yClient);
316
+ stepNum.textContent = '6';
317
+ narrationText.textContent = 'Next request... LB routes to Node 3!';
318
+ narration.className = 'narration request-state';
319
+ clientBox.classList.add('active');
320
+ },
321
+ animate: (done) => animatePath(
322
+ [{x: pos.client, y: yClient}, {x: pos.lb, y: yClient}, {x: pos.server3, y: yServer3}],
323
+ ANIMATION.MSG_DURATION,
324
+ done
325
+ ),
326
+ after: () => {
327
+ clientBox.classList.remove('active');
328
+ server3Box.classList.add('alive');
329
+ }
330
+ },
331
+ // Step 7: Error! Node 3 doesn't know this session
332
+ {
333
+ setup: () => {
334
+ configMessage('error-response', '←', '404 Not Found', 'Unknown session', 'Mcp-Session-Id: sess_abc123', true, 'left');
335
+ setMessagePos(pos.server3, yServer3);
336
+ stepNum.textContent = '✗';
337
+ narrationText.textContent = 'Node 3 has no session or capabilities — fails!';
338
+ narration.className = 'narration error-state';
339
+ server3Box.classList.add('error');
340
+ // Show error state with question marks
341
+ server3Session.textContent = 'sess_abc123 ?';
342
+ server3Caps.innerHTML = '<span class="cap">sampling ?</span>';
343
+ server3State.classList.add('error');
344
+ },
345
+ animate: (done) => animatePath(
346
+ [{x: pos.server3, y: yServer3}, {x: pos.lb, y: yClient}, {x: pos.client, y: yClient}],
347
+ ANIMATION.MSG_DURATION,
348
+ done
349
+ ),
350
+ after: () => {
351
+ clientBox.classList.add('error');
352
+ }
353
+ },
354
+ // Step 8: Pause on error
355
+ {
356
+ setup: () => {
357
+ message.className = 'message';
358
+ },
359
+ animate: (done) => setTimeout(done, ANIMATION.ERROR_PAUSE),
360
+ after: () => {}
361
+ }
362
+ ];
363
+
364
+ runStepSequence(steps);
365
+ scaleCanvas();
366
+ </script>
367
+ </body>
368
+ </html>
2026/mcp-connect/animations/mcp-mrtr-flow.html ADDED
@@ -0,0 +1,221 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <style>
6
+ * { margin: 0; padding: 0; box-sizing: border-box; }
7
+ body {
8
+ background: transparent;
9
+ display: flex;
10
+ justify-content: center;
11
+ align-items: center;
12
+ width: 100vw;
13
+ height: 100vh;
14
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
15
+ padding: 0;
16
+ overflow: hidden;
17
+ }
18
+
19
+ .flow-window {
20
+ background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
21
+ border-radius: 16px;
22
+ padding: 20px;
23
+ width: 480px;
24
+ height: 460px;
25
+ box-shadow: 0 10px 40px rgba(0,0,0,0.3);
26
+ overflow: hidden;
27
+ display: flex;
28
+ flex-direction: column;
29
+ }
30
+
31
+ .flow-header {
32
+ display: flex;
33
+ justify-content: space-between;
34
+ margin-bottom: 16px;
35
+ padding-bottom: 10px;
36
+ border-bottom: 1px solid #333;
37
+ }
38
+
39
+ .flow-header span {
40
+ font-size: 14px;
41
+ font-weight: 600;
42
+ text-transform: uppercase;
43
+ letter-spacing: 1px;
44
+ }
45
+
46
+ .client-label { color: #0b93f6; }
47
+ .server-label { color: #f5a623; }
48
+
49
+ .flow-messages {
50
+ display: flex;
51
+ flex-direction: column;
52
+ gap: 10px;
53
+ flex: 1;
54
+ overflow-y: auto;
55
+ padding-right: 6px;
56
+ scrollbar-width: none;
57
+ }
58
+
59
+ .flow-messages::-webkit-scrollbar {
60
+ width: 0;
61
+ height: 0;
62
+ }
63
+
64
+ .flow-msg {
65
+ display: flex;
66
+ align-items: center;
67
+ gap: 10px;
68
+ opacity: 0;
69
+ transform: translateY(10px);
70
+ }
71
+
72
+ .flow-msg.show {
73
+ animation: slideIn 0.4s ease forwards;
74
+ }
75
+
76
+ .flow-msg.fade-out {
77
+ animation: fadeOut 0.8s ease forwards;
78
+ }
79
+
80
+ .flow-msg.client-msg { flex-direction: row; }
81
+ .flow-msg.server-msg { flex-direction: row-reverse; }
82
+
83
+ .arrow {
84
+ font-size: 20px;
85
+ flex-shrink: 0;
86
+ width: 30px;
87
+ text-align: center;
88
+ }
89
+
90
+ .client-msg .arrow { color: #0b93f6; }
91
+ .server-msg .arrow { color: #f5a623; }
92
+
93
+ .msg-content {
94
+ flex: 1;
95
+ padding: 12px 16px;
96
+ border-radius: 10px;
97
+ font-size: 14px;
98
+ line-height: 1.5;
99
+ }
100
+
101
+ .client-msg .msg-content {
102
+ background: linear-gradient(135deg, #0b93f6 0%, #007AFF 100%);
103
+ color: white;
104
+ border-bottom-left-radius: 3px;
105
+ }
106
+
107
+ .server-msg .msg-content {
108
+ background: linear-gradient(135deg, #f5a623 0%, #f09819 100%);
109
+ color: white;
110
+ border-bottom-right-radius: 3px;
111
+ }
112
+
113
+ .msg-type {
114
+ font-weight: 600;
115
+ font-size: 12px;
116
+ opacity: 0.9;
117
+ margin-bottom: 4px;
118
+ }
119
+
120
+ .msg-detail {
121
+ font-size: 12px;
122
+ opacity: 0.85;
123
+ }
124
+
125
+ @keyframes slideIn {
126
+ from { opacity: 0; transform: translateY(10px); }
127
+ to { opacity: 1; transform: translateY(0); }
128
+ }
129
+
130
+ @keyframes fadeOut {
131
+ from { opacity: 1; }
132
+ to { opacity: 0; }
133
+ }
134
+ </style>
135
+ </head>
136
+ <body>
137
+ <div class="flow-window canvas-root">
138
+ <div class="flow-header">
139
+ <span class="client-label">Client</span>
140
+ <span class="server-label">Server</span>
141
+ </div>
142
+ <div class="flow-messages">
143
+ <div class="flow-msg client-msg" data-delay="0">
144
+ <div class="msg-content">
145
+ <div class="msg-type">CallToolRequest</div>
146
+ <div class="msg-detail">tool: "deploy_app", env: "production"</div>
147
+ </div>
148
+ <div class="arrow">→</div>
149
+ </div>
150
+
151
+ <div class="flow-msg server-msg" data-delay="2500">
152
+ <div class="msg-content">
153
+ <div class="msg-type">elicitation/create</div>
154
+ <div class="msg-detail">server waits for client reply</div>
155
+ </div>
156
+ <div class="arrow">←</div>
157
+ </div>
158
+
159
+ <div class="flow-msg client-msg" data-delay="5000">
160
+ <div class="msg-content">
161
+ <div class="msg-type">elicitation/response</div>
162
+ <div class="msg-detail">client must retain request id</div>
163
+ </div>
164
+ <div class="arrow">→</div>
165
+ </div>
166
+
167
+ <div class="flow-msg server-msg" data-delay="7500">
168
+ <div class="msg-content">
169
+ <div class="msg-type">sampling/createMessage</div>
170
+ <div class="msg-detail">server keeps call context</div>
171
+ </div>
172
+ <div class="arrow">←</div>
173
+ </div>
174
+
175
+ <div class="flow-msg client-msg" data-delay="10000">
176
+ <div class="msg-content">
177
+ <div class="msg-type">sampling/response</div>
178
+ <div class="msg-detail">client responds on new request</div>
179
+ </div>
180
+ <div class="arrow">→</div>
181
+ </div>
182
+
183
+ <div class="flow-msg server-msg" data-delay="12500">
184
+ <div class="msg-content">
185
+ <div class="msg-type">CallToolResult</div>
186
+ <div class="msg-detail">status: "success" ✓</div>
187
+ </div>
188
+ <div class="arrow">←</div>
189
+ </div>
190
+ </div>
191
+ </div>
192
+
193
+ <script src="shared/sequence-helpers.js"></script>
194
+ <script src="shared/canvas-scale.js"></script>
195
+ <script>
196
+ const flowMessages = document.querySelector('.flow-messages');
197
+ const flowItems = Array.from(document.querySelectorAll('.flow-msg'));
198
+ const delays = flowItems.map((item) => parseInt(item.dataset.delay, 10) || 0);
199
+ const maxDelay = delays.length ? Math.max(...delays) : 0;
200
+ const FADE_OUT_OFFSET = 2500;
201
+ const CYCLE_PAUSE = 3500;
202
+ const cycleDuration = maxDelay + FADE_OUT_OFFSET + 1000 + CYCLE_PAUSE;
203
+
204
+ flowMessages.scrollTop = 0;
205
+ setInterval(() => {
206
+ flowMessages.scrollTop = 0;
207
+ }, cycleDuration);
208
+
209
+ runSequenceAnimation({
210
+ selectors: ['.flow-msg'],
211
+ cyclePause: CYCLE_PAUSE,
212
+ fadeOutOffset: FADE_OUT_OFFSET,
213
+ initialDelay: 500,
214
+ onShow: (el) => {
215
+ el.scrollIntoView({ block: 'nearest' });
216
+ },
217
+ });
218
+ scaleCanvas();
219
+ </script>
220
+ </body>
221
+ </html>
2026/mcp-connect/animations/mcp-mrtr-request.html ADDED
@@ -0,0 +1,233 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <style>
6
+ * { margin: 0; padding: 0; box-sizing: border-box; }
7
+ body {
8
+ background: transparent;
9
+ display: flex;
10
+ justify-content: center;
11
+ align-items: center;
12
+ width: 100vw;
13
+ height: 100vh;
14
+ font-family: 'SF Mono', 'Monaco', 'Consolas', monospace;
15
+ padding: 0;
16
+ overflow: hidden;
17
+ }
18
+
19
+ .api-window {
20
+ background: linear-gradient(135deg, #1e1e1e 0%, #252526 100%);
21
+ border-radius: 16px;
22
+ padding: 12px;
23
+ width: 480px;
24
+ height: 460px;
25
+ box-shadow: 0 10px 40px rgba(0,0,0,0.3);
26
+ overflow: hidden;
27
+ display: flex;
28
+ flex-direction: column;
29
+ }
30
+
31
+ .api-header {
32
+ color: #888;
33
+ font-size: 11px;
34
+ margin-bottom: 4px;
35
+ padding-bottom: 3px;
36
+ border-bottom: 1px solid #333;
37
+ }
38
+
39
+ .request-label {
40
+ color: #569cd6;
41
+ font-size: 10px;
42
+ margin-bottom: 2px;
43
+ opacity: 0;
44
+ }
45
+ .request-label.show { animation: fadeIn 0.3s ease forwards; }
46
+ .request-label.fade-out { animation: fadeOut 0.8s ease forwards; }
47
+
48
+ .api-content {
49
+ font-size: 10px;
50
+ line-height: 1.3;
51
+ flex: 1;
52
+ overflow: auto;
53
+ padding-right: 6px;
54
+ scrollbar-width: none;
55
+ }
56
+
57
+ .api-content::-webkit-scrollbar {
58
+ display: none;
59
+ }
60
+
61
+ .json-brace { color: #d4d4d4; }
62
+ .json-key { color: #9cdcfe; }
63
+ .json-string { color: #ce9178; }
64
+ .json-bracket { color: #d4d4d4; }
65
+ .json-bool { color: #569cd6; }
66
+
67
+ .msg-block {
68
+ opacity: 0;
69
+ transform: translateX(-10px);
70
+ margin: 1px 0;
71
+ padding: 1px 0 1px 6px;
72
+ color: #d4d4d4;
73
+ }
74
+
75
+ .msg-block.show {
76
+ animation: slideInLeft 0.4s ease forwards;
77
+ }
78
+
79
+ .msg-block.fade-out {
80
+ animation: fadeOut 0.8s ease forwards;
81
+ }
82
+
83
+ .msg-block.client-req { border-left: 2px solid #0b93f6; }
84
+ .msg-block.server-req { border-left: 2px solid #f5a623; }
85
+ .msg-block.client-resp { border-left: 2px solid #34c759; }
86
+
87
+ .static-content {
88
+ opacity: 0;
89
+ }
90
+ .static-content.show { animation: fadeIn 0.3s ease forwards; }
91
+ .static-content.fade-out { animation: fadeOut 0.8s ease forwards; }
92
+
93
+ .request-group {
94
+ margin-bottom: 2px;
95
+ padding-bottom: 2px;
96
+ border-bottom: 1px dashed #333;
97
+ }
98
+
99
+ .request-group:last-child {
100
+ border-bottom: none;
101
+ }
102
+
103
+ @keyframes slideInLeft {
104
+ from { opacity: 0; transform: translateX(-10px); }
105
+ to { opacity: 1; transform: translateX(0); }
106
+ }
107
+
108
+ @keyframes fadeIn {
109
+ from { opacity: 0; }
110
+ to { opacity: 1; }
111
+ }
112
+
113
+ @keyframes fadeOut {
114
+ from { opacity: 1; }
115
+ to { opacity: 0; }
116
+ }
117
+
118
+ .dim { opacity: 0.5; }
119
+ </style>
120
+ </head>
121
+ <body>
122
+ <div class="api-window canvas-root">
123
+ <div class="api-header">POST /mcp (Client → Server)</div>
124
+ <div class="api-content">
125
+
126
+ <!-- Request 1: Initial CallToolRequest -->
127
+ <div class="request-group">
128
+ <div class="request-label" data-delay="0">Request #1 — tools/call</div>
129
+ <div class="msg-block client-req" data-delay="0">
130
+ <span class="json-brace">{</span><br>
131
+ &nbsp;&nbsp;<span class="json-key">"method"</span>: <span class="json-string">"tools/call"</span>,<br>
132
+ &nbsp;&nbsp;<span class="json-key">"params"</span>: <span class="json-brace">{</span> <span class="json-key">"name"</span>: <span class="json-string">"deploy_app"</span>, <span class="json-key">"env"</span>: <span class="json-string">"production"</span> <span class="json-brace">}</span><br>
133
+ <span class="json-brace">}</span>
134
+ </div>
135
+ </div>
136
+
137
+ <!-- Response 1: Incomplete result with dependent requests -->
138
+ <div class="request-group">
139
+ <div class="request-label" data-delay="2500">Response #1 — incomplete (dependent_requests)</div>
140
+ <div class="msg-block server-req" data-delay="2500">
141
+ <span class="json-brace">{</span><br>
142
+ &nbsp;&nbsp;<span class="json-key">"dependent_requests"</span>: <span class="json-brace">{</span><br>
143
+ &nbsp;&nbsp;&nbsp;&nbsp;<span class="json-key">"confirm"</span>: <span class="json-string">"elicitation/create"</span><br>
144
+ &nbsp;&nbsp;<span class="json-brace">}</span><br>
145
+ <span class="json-brace">}</span>
146
+ </div>
147
+ </div>
148
+
149
+ <!-- Request 2: Retry with dependent responses -->
150
+ <div class="request-group">
151
+ <div class="request-label" data-delay="5000">Request #2 — retry (elicitation response)</div>
152
+ <div class="msg-block client-req" data-delay="5000">
153
+ <span class="json-brace">{</span><br>
154
+ &nbsp;&nbsp;<span class="json-key">"method"</span>: <span class="json-string">"tools/call"</span>,<br>
155
+ &nbsp;&nbsp;<span class="json-key">"params"</span>: <span class="json-brace">{</span> <span class="json-key">"name"</span>: <span class="json-string">"deploy_app"</span> <span class="json-brace">}</span>,<br>
156
+ &nbsp;&nbsp;<span class="json-key">"dependent_responses"</span>: <span class="json-brace">{</span><br>
157
+ &nbsp;&nbsp;&nbsp;&nbsp;<span class="json-key">"confirm"</span>: <span class="json-brace">{</span> <span class="json-key">"result"</span>: <span class="json-brace">{</span> <span class="json-key">"action"</span>: <span class="json-string">"accept"</span> <span class="json-brace">}</span> <span class="json-brace">}</span><br>
158
+ &nbsp;&nbsp;<span class="json-brace">}</span><br>
159
+ <span class="json-brace">}</span>
160
+ </div>
161
+ </div>
162
+
163
+ <!-- Response 2: Incomplete result with next dependent request -->
164
+ <div class="request-group">
165
+ <div class="request-label" data-delay="7500">Response #2 — sampling request (dependent_requests)</div>
166
+ <div class="msg-block server-req" data-delay="7500">
167
+ <span class="json-brace">{</span><br>
168
+ &nbsp;&nbsp;<span class="json-key">"dependent_requests"</span>: <span class="json-brace">{</span><br>
169
+ &nbsp;&nbsp;&nbsp;&nbsp;<span class="json-key">"summary"</span>: <span class="json-string">"sampling/createMessage"</span><br>
170
+ &nbsp;&nbsp;<span class="json-brace">}</span><br>
171
+ <span class="json-brace">}</span>
172
+ </div>
173
+ </div>
174
+
175
+ <div class="request-group">
176
+ <div class="request-label" data-delay="10000">Request #3 — retry (sampling response added)</div>
177
+ <div class="msg-block client-req" data-delay="10000">
178
+ <span class="json-brace">{</span><br>
179
+ &nbsp;&nbsp;<span class="json-key">"method"</span>: <span class="json-string">"tools/call"</span>,<br>
180
+ &nbsp;&nbsp;<span class="json-key">"params"</span>: <span class="json-brace">{</span> <span class="json-key">"name"</span>: <span class="json-string">"deploy_app"</span> <span class="json-brace">}</span>,<br>
181
+ &nbsp;&nbsp;<span class="json-key">"dependent_responses"</span>: <span class="json-brace">{</span><br>
182
+ &nbsp;&nbsp;&nbsp;&nbsp;<span class="json-key">"confirm"</span>: <span class="json-brace">{</span> <span class="json-key">"result"</span>: <span class="json-brace">{</span> <span class="json-key">"action"</span>: <span class="json-string">"accept"</span> <span class="json-brace">}</span> <span class="json-brace">}</span>,<br>
183
+ &nbsp;&nbsp;&nbsp;&nbsp;<span class="json-key">"summary"</span>: <span class="json-brace">{</span> <span class="json-key">"result"</span>: <span class="json-brace">{</span> <span class="json-key">"content"</span>: <span class="json-string">"..."</span> <span class="json-brace">}</span> <span class="json-brace">}</span><br>
184
+ &nbsp;&nbsp;<span class="json-brace">}</span><br>
185
+ <span class="json-brace">}</span>
186
+ </div>
187
+ </div>
188
+
189
+ <!-- Response 3: Final result -->
190
+ <div class="request-group">
191
+ <div class="request-label" data-delay="12500">Response #3 — CallToolResult</div>
192
+ <div class="msg-block server-req" data-delay="12500">
193
+ <span class="json-brace">{</span><br>
194
+ &nbsp;&nbsp;<span class="json-key">"result"</span>: <span class="json-brace">{</span> <span class="json-key">"status"</span>: <span class="json-string">"success"</span> <span class="json-brace">}</span><br>
195
+ <span class="json-brace">}</span>
196
+ </div>
197
+ </div>
198
+
199
+ </div>
200
+ </div>
201
+
202
+ <script src="shared/sequence-helpers.js"></script>
203
+ <script src="shared/canvas-scale.js"></script>
204
+ <script>
205
+ const apiContent = document.querySelector('.api-content');
206
+ const timelineItems = Array.from(document.querySelectorAll('.msg-block, .request-label'));
207
+ const delays = timelineItems.map((item) => parseInt(item.dataset.delay, 10) || 0);
208
+ const maxDelay = delays.length ? Math.max(...delays) : 0;
209
+ const FADE_OUT_OFFSET = 2500;
210
+ const CYCLE_PAUSE = 3500;
211
+ const cycleDuration = maxDelay + FADE_OUT_OFFSET + 1000 + CYCLE_PAUSE;
212
+
213
+ apiContent.scrollTop = 0;
214
+ setInterval(() => {
215
+ apiContent.scrollTop = 0;
216
+ }, cycleDuration);
217
+
218
+ runSequenceAnimation({
219
+ selectors: ['.msg-block', '.request-label'],
220
+ cyclePause: CYCLE_PAUSE,
221
+ fadeOutOffset: FADE_OUT_OFFSET,
222
+ initialDelay: 500,
223
+ lastDelayOverride: 12500,
224
+ onShow: (el) => {
225
+ if (el.classList.contains('msg-block')) {
226
+ el.scrollIntoView({ block: 'nearest' });
227
+ }
228
+ },
229
+ });
230
+ scaleCanvas();
231
+ </script>
232
+ </body>
233
+ </html>
2026/mcp-connect/animations/mcp-stateful-request.html ADDED
@@ -0,0 +1,318 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <style>
6
+ * { margin: 0; padding: 0; box-sizing: border-box; }
7
+ body {
8
+ background: transparent;
9
+ display: flex;
10
+ justify-content: center;
11
+ align-items: center;
12
+ width: 100vw;
13
+ height: 100vh;
14
+ font-family: 'SF Mono', 'Monaco', 'Consolas', monospace;
15
+ padding: 0;
16
+ overflow: hidden;
17
+ }
18
+
19
+ .api-window {
20
+ background: linear-gradient(135deg, #1e1e1e 0%, #252526 100%);
21
+ border-radius: 16px;
22
+ padding: 20px;
23
+ width: 480px;
24
+ height: 460px;
25
+ box-shadow: 0 10px 40px rgba(0,0,0,0.3);
26
+ overflow: hidden;
27
+ position: relative;
28
+ }
29
+
30
+ .api-header {
31
+ color: #888;
32
+ font-size: 11px;
33
+ margin-bottom: 12px;
34
+ padding-bottom: 8px;
35
+ border-bottom: 1px solid #333;
36
+ }
37
+
38
+ .direction-label {
39
+ font-size: 10px;
40
+ margin-bottom: 10px;
41
+ padding: 4px 8px;
42
+ border-radius: 4px;
43
+ display: inline-block;
44
+ }
45
+ .to-server { background: #0b93f620; color: #0b93f6; }
46
+ .to-client { background: #f5a62320; color: #f5a623; }
47
+
48
+ .single-message {
49
+ position: absolute;
50
+ top: 80px;
51
+ left: 20px;
52
+ right: 20px;
53
+ opacity: 0;
54
+ transform: scale(0.95);
55
+ }
56
+
57
+ .single-message.show {
58
+ animation: popIn 0.3s ease forwards;
59
+ }
60
+
61
+ .single-message.fade-out {
62
+ animation: popOut 0.25s ease forwards;
63
+ }
64
+
65
+ .msg-box {
66
+ padding: 16px;
67
+ border-radius: 10px;
68
+ font-size: 11px;
69
+ line-height: 1.5;
70
+ color: #d4d4d4;
71
+ }
72
+
73
+ .client-msg .msg-box {
74
+ background: linear-gradient(135deg, #0b93f615 0%, #007AFF15 100%);
75
+ border: 1px solid #0b93f640;
76
+ }
77
+
78
+ .server-msg .msg-box {
79
+ background: linear-gradient(135deg, #f5a62315 0%, #f0981915 100%);
80
+ border: 1px solid #f5a62340;
81
+ }
82
+
83
+ .json-brace { color: #d4d4d4; }
84
+ .json-key { color: #9cdcfe; }
85
+ .json-string { color: #ce9178; }
86
+ .json-bool { color: #569cd6; }
87
+
88
+ .state-indicator {
89
+ position: absolute;
90
+ bottom: 20px;
91
+ left: 20px;
92
+ right: 20px;
93
+ padding: 12px;
94
+ background: #2d2d3a;
95
+ border-radius: 8px;
96
+ font-size: 10px;
97
+ color: #888;
98
+ opacity: 0;
99
+ }
100
+
101
+ .state-indicator.show {
102
+ animation: fadeIn 0.3s ease forwards;
103
+ }
104
+ .state-indicator.fade-out {
105
+ animation: fadeOut 0.5s ease forwards;
106
+ }
107
+
108
+ .state-indicator .label {
109
+ color: #f5a623;
110
+ font-weight: 600;
111
+ margin-bottom: 4px;
112
+ }
113
+
114
+ .state-dots {
115
+ display: flex;
116
+ gap: 6px;
117
+ margin-top: 8px;
118
+ }
119
+
120
+ .state-dot {
121
+ width: 8px;
122
+ height: 8px;
123
+ border-radius: 50%;
124
+ background: #444;
125
+ }
126
+ .state-dot.active { background: #f5a623; }
127
+
128
+ @keyframes popIn {
129
+ from { opacity: 0; transform: scale(0.95); }
130
+ to { opacity: 1; transform: scale(1); }
131
+ }
132
+
133
+ @keyframes popOut {
134
+ from { opacity: 1; transform: scale(1); }
135
+ to { opacity: 0; transform: scale(0.95); }
136
+ }
137
+
138
+ @keyframes fadeIn {
139
+ from { opacity: 0; }
140
+ to { opacity: 1; }
141
+ }
142
+
143
+ @keyframes fadeOut {
144
+ from { opacity: 1; }
145
+ to { opacity: 0; }
146
+ }
147
+ </style>
148
+ </head>
149
+ <body>
150
+ <div class="api-window canvas-root">
151
+ <div class="api-header">Current: Individual Messages (Stateful)</div>
152
+
153
+ <!-- Message 1: CallToolRequest -->
154
+ <div class="single-message client-msg" id="msg1">
155
+ <div class="direction-label to-server">→ Client to Server</div>
156
+ <div class="msg-box">
157
+ <span class="json-brace">{</span><br>
158
+ &nbsp;&nbsp;<span class="json-key">"method"</span>: <span class="json-string">"tools/call"</span>,<br>
159
+ &nbsp;&nbsp;<span class="json-key">"params"</span>: <span class="json-brace">{</span><br>
160
+ &nbsp;&nbsp;&nbsp;&nbsp;<span class="json-key">"name"</span>: <span class="json-string">"deploy_app"</span>,<br>
161
+ &nbsp;&nbsp;&nbsp;&nbsp;<span class="json-key">"env"</span>: <span class="json-string">"production"</span><br>
162
+ &nbsp;&nbsp;<span class="json-brace">}</span><br>
163
+ <span class="json-brace">}</span>
164
+ </div>
165
+ </div>
166
+
167
+ <!-- Message 2: ElicitationRequest -->
168
+ <div class="single-message server-msg" id="msg2">
169
+ <div class="direction-label to-client">← Server to Client</div>
170
+ <div class="msg-box">
171
+ <span class="json-brace">{</span><br>
172
+ &nbsp;&nbsp;<span class="json-key">"method"</span>: <span class="json-string">"elicitation/create"</span>,<br>
173
+ &nbsp;&nbsp;<span class="json-key">"params"</span>: <span class="json-brace">{</span><br>
174
+ &nbsp;&nbsp;&nbsp;&nbsp;<span class="json-key">"message"</span>: <span class="json-string">"Confirm deployment to production?"</span><br>
175
+ &nbsp;&nbsp;<span class="json-brace">}</span><br>
176
+ <span class="json-brace">}</span>
177
+ </div>
178
+ </div>
179
+
180
+ <!-- Message 3: ElicitationResponse -->
181
+ <div class="single-message client-msg" id="msg3">
182
+ <div class="direction-label to-server">→ Client to Server</div>
183
+ <div class="msg-box">
184
+ <span class="json-brace">{</span><br>
185
+ &nbsp;&nbsp;<span class="json-key">"result"</span>: <span class="json-brace">{</span><br>
186
+ &nbsp;&nbsp;&nbsp;&nbsp;<span class="json-key">"confirmed"</span>: <span class="json-bool">true</span><br>
187
+ &nbsp;&nbsp;<span class="json-brace">}</span><br>
188
+ <span class="json-brace">}</span>
189
+ </div>
190
+ </div>
191
+
192
+ <!-- Message 4: SamplingRequest -->
193
+ <div class="single-message server-msg" id="msg4">
194
+ <div class="direction-label to-client">← Server to Client</div>
195
+ <div class="msg-box">
196
+ <span class="json-brace">{</span><br>
197
+ &nbsp;&nbsp;<span class="json-key">"method"</span>: <span class="json-string">"sampling/createMessage"</span>,<br>
198
+ &nbsp;&nbsp;<span class="json-key">"params"</span>: <span class="json-brace">{</span><br>
199
+ &nbsp;&nbsp;&nbsp;&nbsp;<span class="json-key">"prompt"</span>: <span class="json-string">"Generate deployment summary"</span><br>
200
+ &nbsp;&nbsp;<span class="json-brace">}</span><br>
201
+ <span class="json-brace">}</span>
202
+ </div>
203
+ </div>
204
+
205
+ <!-- Message 5: SamplingResponse -->
206
+ <div class="single-message client-msg" id="msg5">
207
+ <div class="direction-label to-server">→ Client to Server</div>
208
+ <div class="msg-box">
209
+ <span class="json-brace">{</span><br>
210
+ &nbsp;&nbsp;<span class="json-key">"result"</span>: <span class="json-brace">{</span><br>
211
+ &nbsp;&nbsp;&nbsp;&nbsp;<span class="json-key">"content"</span>: <span class="json-string">"Deployed v2.1.0 to prod..."</span><br>
212
+ &nbsp;&nbsp;<span class="json-brace">}</span><br>
213
+ <span class="json-brace">}</span>
214
+ </div>
215
+ </div>
216
+
217
+ <!-- Message 6: CallToolResult -->
218
+ <div class="single-message server-msg" id="msg6">
219
+ <div class="direction-label to-client">← Server to Client</div>
220
+ <div class="msg-box">
221
+ <span class="json-brace">{</span><br>
222
+ &nbsp;&nbsp;<span class="json-key">"result"</span>: <span class="json-brace">{</span><br>
223
+ &nbsp;&nbsp;&nbsp;&nbsp;<span class="json-key">"status"</span>: <span class="json-string">"success"</span><br>
224
+ &nbsp;&nbsp;<span class="json-brace">}</span><br>
225
+ <span class="json-brace">}</span>
226
+ </div>
227
+ </div>
228
+
229
+ <!-- State indicator -->
230
+ <div class="state-indicator" id="stateBox">
231
+ <div class="label">⚠ Server must maintain state</div>
232
+ <div>Remembering: tool call, elicitation, sampling context...</div>
233
+ <div class="state-dots">
234
+ <div class="state-dot" id="dot1"></div>
235
+ <div class="state-dot" id="dot2"></div>
236
+ <div class="state-dot" id="dot3"></div>
237
+ <div class="state-dot" id="dot4"></div>
238
+ <div class="state-dot" id="dot5"></div>
239
+ <div class="state-dot" id="dot6"></div>
240
+ </div>
241
+ </div>
242
+ </div>
243
+
244
+ <script src="shared/canvas-scale.js"></script>
245
+ <script>
246
+ const messages = [
247
+ document.getElementById('msg1'),
248
+ document.getElementById('msg2'),
249
+ document.getElementById('msg3'),
250
+ document.getElementById('msg4'),
251
+ document.getElementById('msg5'),
252
+ document.getElementById('msg6')
253
+ ];
254
+ const dots = [
255
+ document.getElementById('dot1'),
256
+ document.getElementById('dot2'),
257
+ document.getElementById('dot3'),
258
+ document.getElementById('dot4'),
259
+ document.getElementById('dot5'),
260
+ document.getElementById('dot6')
261
+ ];
262
+ const stateBox = document.getElementById('stateBox');
263
+ const CYCLE_PAUSE = 3000;
264
+ const MSG_DURATION = 2500;
265
+
266
+ function runAnimation() {
267
+ // Reset
268
+ messages.forEach(m => m.classList.remove('show', 'fade-out'));
269
+ dots.forEach(d => d.classList.remove('active'));
270
+ stateBox.classList.remove('show', 'fade-out');
271
+
272
+ // Force reflow to ensure class removal is processed
273
+ void document.body.offsetHeight;
274
+
275
+ // Show state box
276
+ setTimeout(() => stateBox.classList.add('show'), 200);
277
+
278
+ // Show each message one at a time
279
+ messages.forEach((msg, i) => {
280
+ const showTime = i * MSG_DURATION;
281
+ const hideTime = showTime + MSG_DURATION - 300;
282
+
283
+ setTimeout(() => {
284
+ // Hide previous
285
+ if (i > 0) messages[i-1].classList.add('fade-out');
286
+ // Show current
287
+ msg.classList.add('show');
288
+ // Activate dot
289
+ dots[i].classList.add('active');
290
+ }, showTime);
291
+ });
292
+
293
+ // Fade out last message and state
294
+ const totalTime = messages.length * MSG_DURATION;
295
+ setTimeout(() => {
296
+ messages[messages.length - 1].classList.add('fade-out');
297
+ stateBox.classList.add('fade-out');
298
+ }, totalTime);
299
+
300
+ // Restart
301
+ setTimeout(runAnimation, totalTime + 1500 + CYCLE_PAUSE);
302
+ }
303
+
304
+ function startAnimation() {
305
+ setTimeout(runAnimation, 500);
306
+ }
307
+
308
+ if (document.readyState === 'complete') {
309
+ startAnimation();
310
+ } else {
311
+ window.addEventListener('load', startAnimation, { once: true });
312
+ }
313
+
314
+ window.addEventListener('pageshow', startAnimation);
315
+ scaleCanvas();
316
+ </script>
317
+ </body>
318
+ </html>
2026/mcp-connect/animations/shared/animation-config.js ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Shared animation timing constants
2
+ const ANIMATION = {
3
+ MSG_DURATION: 1200, // message travel time (ms)
4
+ STEP_PAUSE: 1500, // pause between steps (ms)
5
+ INITIAL_PAUSE: 3000, // pause at start before animation begins (ms)
6
+ ERROR_PAUSE: 4000, // pause on error state (ms)
7
+ };
8
+
9
+ // Shared color palette
10
+ const COLORS = {
11
+ client: '#1976d2',
12
+ clientLight: '#e3f2fd',
13
+ clientActive: '#bbdefb',
14
+
15
+ server: '#ef6c00',
16
+ serverLight: '#fff3e0',
17
+ serverActive: '#ffe0b2',
18
+
19
+ notification: '#7b1fa2',
20
+
21
+ success: '#4caf50',
22
+ successLight: '#e8f5e9',
23
+ successBorder: '#a5d6a7',
24
+
25
+ error: '#c62828',
26
+ errorLight: '#ffebee',
27
+ errorBorder: '#ef9a9a',
28
+
29
+ inactive: '#9e9e9e',
30
+ inactiveLight: '#f5f5f5',
31
+ inactiveBorder: '#e0e0e0',
32
+ };
2026/mcp-connect/animations/shared/canvas-scale.js ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ function scaleCanvas({ selector = '.canvas-root', minScale = 0.25, maxScale = 4 } = {}) {
2
+ const canvases = Array.from(document.querySelectorAll(selector));
3
+ if (canvases.length === 0) {
4
+ return;
5
+ }
6
+
7
+ function updateBaseSize(canvas) {
8
+ if (canvas.dataset.baseWidth && canvas.dataset.baseHeight) {
9
+ return;
10
+ }
11
+
12
+ const { width, height } = canvas.getBoundingClientRect();
13
+ if (width && height) {
14
+ canvas.dataset.baseWidth = width;
15
+ canvas.dataset.baseHeight = height;
16
+ }
17
+ }
18
+
19
+ function updateScale() {
20
+ canvases.forEach((canvas) => {
21
+ updateBaseSize(canvas);
22
+ const baseWidth = parseFloat(canvas.dataset.baseWidth || '0');
23
+ const baseHeight = parseFloat(canvas.dataset.baseHeight || '0');
24
+ if (!baseWidth || !baseHeight) {
25
+ return;
26
+ }
27
+
28
+ const scale = Math.min(window.innerWidth / baseWidth, window.innerHeight / baseHeight);
29
+ const clamped = Math.max(minScale, Math.min(scale, maxScale));
30
+ canvas.style.transform = `scale(${clamped})`;
31
+ canvas.style.transformOrigin = 'center';
32
+ });
33
+ }
34
+
35
+ const observer = new ResizeObserver(() => updateScale());
36
+ canvases.forEach((canvas) => {
37
+ observer.observe(canvas);
38
+ updateBaseSize(canvas);
39
+ });
40
+
41
+ window.addEventListener('resize', updateScale);
42
+ window.addEventListener('load', () => requestAnimationFrame(updateScale));
43
+ requestAnimationFrame(updateScale);
44
+ }
2026/mcp-connect/animations/shared/diagram-helpers.js ADDED
@@ -0,0 +1,152 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ function setMessagePosition(message, x, y) {
2
+ message.style.left = `${x}px`;
3
+ message.style.top = `${y}px`;
4
+ }
5
+
6
+ function animateMessageBetween(message, fromX, fromY, toX, toY, duration, callback) {
7
+ const startTime = performance.now();
8
+
9
+ function step(currentTime) {
10
+ const elapsed = currentTime - startTime;
11
+ const progress = Math.min(elapsed / duration, 1);
12
+ const eased = 1 - Math.pow(1 - progress, 3);
13
+ setMessagePosition(
14
+ message,
15
+ fromX + (toX - fromX) * eased,
16
+ fromY + (toY - fromY) * eased
17
+ );
18
+
19
+ if (progress < 1) {
20
+ requestAnimationFrame(step);
21
+ } else if (callback) {
22
+ callback();
23
+ }
24
+ }
25
+
26
+ requestAnimationFrame(step);
27
+ }
28
+
29
+ function animatePathBetween(message, waypoints, totalDuration, callback) {
30
+ if (waypoints.length < 2) {
31
+ if (callback) {
32
+ callback();
33
+ }
34
+ return;
35
+ }
36
+
37
+ let totalDist = 0;
38
+ for (let i = 0; i < waypoints.length - 1; i++) {
39
+ const dx = waypoints[i + 1].x - waypoints[i].x;
40
+ const dy = waypoints[i + 1].y - waypoints[i].y;
41
+ totalDist += Math.sqrt(dx * dx + dy * dy);
42
+ }
43
+
44
+ const durations = [];
45
+ for (let i = 0; i < waypoints.length - 1; i++) {
46
+ const dx = waypoints[i + 1].x - waypoints[i].x;
47
+ const dy = waypoints[i + 1].y - waypoints[i].y;
48
+ const legDist = Math.sqrt(dx * dx + dy * dy);
49
+ durations.push((legDist / totalDist) * totalDuration);
50
+ }
51
+
52
+ let i = 0;
53
+ function nextLeg() {
54
+ if (i < waypoints.length - 1) {
55
+ animateMessageBetween(
56
+ message,
57
+ waypoints[i].x, waypoints[i].y,
58
+ waypoints[i + 1].x, waypoints[i + 1].y,
59
+ durations[i],
60
+ () => {
61
+ i++;
62
+ nextLeg();
63
+ }
64
+ );
65
+ } else if (callback) {
66
+ callback();
67
+ }
68
+ }
69
+
70
+ nextLeg();
71
+ }
72
+
73
+ function configureMessage(elements, {
74
+ type,
75
+ arrow,
76
+ method,
77
+ detail,
78
+ sessionText,
79
+ sessionError = false,
80
+ direction = 'right',
81
+ } = {}) {
82
+ const container = elements.container;
83
+ const header = elements.header || container.querySelector('.message-header');
84
+
85
+ container.className = `message ${type} visible`;
86
+ elements.type.textContent = method;
87
+ elements.arrow.textContent = arrow;
88
+ elements.detail.textContent = detail;
89
+
90
+ if (elements.session) {
91
+ if (sessionText) {
92
+ elements.session.innerHTML = sessionText;
93
+ elements.session.style.display = 'block';
94
+ elements.session.className = 'message-session' + (sessionError ? ' error' : '');
95
+ } else {
96
+ elements.session.style.display = 'none';
97
+ }
98
+ }
99
+
100
+ if (header) {
101
+ header.style.flexDirection = direction === 'left' ? 'row-reverse' : 'row';
102
+ }
103
+ }
104
+
105
+ function runStepSequence(steps, { initialDelay = 100, stepPause, startOnLoad = true } = {}) {
106
+ if (!steps || steps.length === 0) {
107
+ return;
108
+ }
109
+
110
+ const pause = stepPause ?? (typeof ANIMATION !== 'undefined' ? ANIMATION.STEP_PAUSE : 1500);
111
+ let currentStep = 0;
112
+ let animationTimer = null;
113
+
114
+ function runStep() {
115
+ if (currentStep >= steps.length) {
116
+ currentStep = 0;
117
+ }
118
+
119
+ const step = steps[currentStep];
120
+ step.setup();
121
+
122
+ animationTimer = setTimeout(() => {
123
+ step.animate(() => {
124
+ if (step.after) {
125
+ step.after();
126
+ }
127
+ currentStep++;
128
+ animationTimer = setTimeout(runStep, pause);
129
+ });
130
+ }, initialDelay);
131
+ }
132
+
133
+ const start = () => {
134
+ if (animationTimer) {
135
+ clearTimeout(animationTimer);
136
+ }
137
+ currentStep = 0;
138
+ runStep();
139
+ };
140
+
141
+ if (startOnLoad) {
142
+ if (document.readyState === 'complete') {
143
+ start();
144
+ } else {
145
+ window.addEventListener('load', start, { once: true });
146
+ }
147
+
148
+ window.addEventListener('pageshow', start);
149
+ } else {
150
+ start();
151
+ }
152
+ }
2026/mcp-connect/animations/shared/http-diagram.css ADDED
@@ -0,0 +1,505 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ * { margin: 0; padding: 0; box-sizing: border-box; }
2
+ body {
3
+ background: #fafafa;
4
+ display: flex;
5
+ align-items: center;
6
+ justify-content: center;
7
+ width: 100vw;
8
+ height: 100vh;
9
+ overflow: hidden;
10
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
11
+ padding: 0;
12
+ }
13
+
14
+ .canvas-root {
15
+ display: inline-flex;
16
+ flex-direction: column;
17
+ align-items: center;
18
+ justify-content: center;
19
+ padding: 30px 20px;
20
+ }
21
+
22
+ .diagram {
23
+ position: relative;
24
+ width: 780px;
25
+ height: 320px;
26
+ }
27
+
28
+ /* Entity base styles */
29
+ .entity {
30
+ position: absolute;
31
+ display: flex;
32
+ flex-direction: column;
33
+ align-items: center;
34
+ gap: 8px;
35
+ }
36
+
37
+ /* Client - starts grey, becomes blue */
38
+ .client { left: 0; top: 100px; }
39
+ .client .entity-box {
40
+ width: 130px;
41
+ height: 80px;
42
+ border-radius: 16px;
43
+ background: #f5f5f5;
44
+ border: 3px solid #9e9e9e;
45
+ color: #9e9e9e;
46
+ display: flex;
47
+ flex-direction: column;
48
+ align-items: center;
49
+ justify-content: center;
50
+ font-weight: 600;
51
+ font-size: 14px;
52
+ transition: all 0.5s ease;
53
+ text-align: center;
54
+ line-height: 1.3;
55
+ gap: 2px;
56
+ }
57
+
58
+ .client .entity-box.alive {
59
+ background: #e3f2fd;
60
+ border-color: #1976d2;
61
+ color: #1976d2;
62
+ }
63
+
64
+ .client .entity-box.active {
65
+ background: #bbdefb;
66
+ border-color: #1976d2;
67
+ color: #1976d2;
68
+ box-shadow: 0 4px 20px rgba(25, 118, 210, 0.3);
69
+ }
70
+
71
+ /* Load Balancer */
72
+ .lb { left: 200px; top: 105px; }
73
+ .lb .entity-box {
74
+ width: 80px;
75
+ height: 70px;
76
+ background: linear-gradient(180deg, #fafafa 0%, #e0e0e0 100%);
77
+ border: 2px solid #9e9e9e;
78
+ border-radius: 8px;
79
+ display: flex;
80
+ align-items: center;
81
+ justify-content: center;
82
+ color: #616161;
83
+ font-weight: 600;
84
+ font-size: 13px;
85
+ box-shadow: 0 2px 8px rgba(0,0,0,0.08);
86
+ }
87
+
88
+ /* Server cluster bounding box */
89
+ .server-cluster {
90
+ position: absolute;
91
+ left: 400px;
92
+ top: 0;
93
+ width: 300px;
94
+ height: 320px;
95
+ border: 3px solid #ef6c00;
96
+ border-radius: 20px;
97
+ background: rgba(255, 243, 224, 0.3);
98
+ }
99
+
100
+ .cluster-label {
101
+ position: absolute;
102
+ top: -14px;
103
+ left: 24px;
104
+ background: #fafafa;
105
+ padding: 4px 16px;
106
+ font-size: 16px;
107
+ font-weight: 600;
108
+ color: #ef6c00;
109
+ white-space: nowrap;
110
+ }
111
+
112
+ /* Server nodes - horizontal layout with badge to right */
113
+ .server {
114
+ flex-direction: row;
115
+ align-items: center;
116
+ gap: 12px;
117
+ left: 420px;
118
+ }
119
+ .server-1 { top: 25px; }
120
+ .server-2 { top: 130px; }
121
+ .server-3 { top: 235px; }
122
+
123
+ .server .entity-box {
124
+ width: 100px;
125
+ height: 55px;
126
+ border-radius: 12px;
127
+ background: #f5f5f5;
128
+ border: 3px solid #bdbdbd;
129
+ color: #9e9e9e;
130
+ display: flex;
131
+ flex-direction: column;
132
+ align-items: center;
133
+ justify-content: center;
134
+ font-weight: 600;
135
+ font-size: 13px;
136
+ transition: all 0.5s ease;
137
+ text-align: center;
138
+ gap: 2px;
139
+ }
140
+
141
+ .server .entity-box.alive {
142
+ background: #fff3e0;
143
+ border-color: #ef6c00;
144
+ color: #ef6c00;
145
+ }
146
+
147
+ .server .entity-box.active {
148
+ background: #ffe0b2;
149
+ border-color: #ef6c00;
150
+ color: #ef6c00;
151
+ box-shadow: 0 4px 20px rgba(239, 108, 0, 0.3);
152
+ }
153
+
154
+ .server .entity-box.error {
155
+ background: #ffebee;
156
+ border-color: #c62828;
157
+ color: #c62828;
158
+ animation: shake 0.4s ease;
159
+ }
160
+
161
+ .server .entity-box.waiting {
162
+ animation: waitingPulse 1s ease-in-out infinite;
163
+ }
164
+
165
+ @keyframes waitingPulse {
166
+ 0%, 100% {
167
+ background: #fff3e0;
168
+ border-color: #ef6c00;
169
+ box-shadow: 0 4px 20px rgba(239, 108, 0, 0.2);
170
+ }
171
+ 50% {
172
+ background: #ffe0b2;
173
+ border-color: #e65100;
174
+ box-shadow: 0 4px 30px rgba(239, 108, 0, 0.5);
175
+ }
176
+ }
177
+
178
+ @keyframes shake {
179
+ 0%, 100% { transform: translateX(0); }
180
+ 25% { transform: translateX(-6px); }
181
+ 75% { transform: translateX(6px); }
182
+ }
183
+
184
+ .entity-status {
185
+ font-size: 9px;
186
+ font-weight: 600;
187
+ text-transform: uppercase;
188
+ letter-spacing: 0.3px;
189
+ opacity: 0;
190
+ transition: opacity 0.3s ease;
191
+ padding: 2px 6px;
192
+ border-radius: 3px;
193
+ }
194
+
195
+ .entity-status.visible {
196
+ opacity: 1;
197
+ }
198
+
199
+ .entity-status.waiting {
200
+ background: #e65100;
201
+ color: white;
202
+ animation: statusBlink 0.8s ease-in-out infinite;
203
+ }
204
+
205
+ @keyframes statusBlink {
206
+ 0%, 100% { opacity: 1; transform: scale(1); }
207
+ 50% { opacity: 0.7; transform: scale(1.05); }
208
+ }
209
+
210
+ /* State badge - shows session + capabilities */
211
+ .state-badge {
212
+ display: flex;
213
+ flex-direction: column;
214
+ align-items: flex-start;
215
+ gap: 4px;
216
+ padding: 8px 10px;
217
+ border-radius: 8px;
218
+ font-size: 10px;
219
+ font-weight: 600;
220
+ transition: all 0.4s ease;
221
+ /* Default: gray/inactive state */
222
+ background: #f5f5f5;
223
+ border: 1px solid #e0e0e0;
224
+ color: #9e9e9e;
225
+ min-width: 140px;
226
+ min-height: 64px;
227
+ }
228
+
229
+ .state-badge.active {
230
+ background: #e8f5e9;
231
+ border: 1px solid #a5d6a7;
232
+ color: #2e7d32;
233
+ }
234
+
235
+ .state-badge.error {
236
+ background: #ffebee;
237
+ border-color: #ef9a9a;
238
+ color: #c62828;
239
+ }
240
+
241
+ .state-badge .badge-title {
242
+ font-size: 8px;
243
+ text-transform: uppercase;
244
+ letter-spacing: 0.5px;
245
+ color: #888;
246
+ font-weight: 500;
247
+ }
248
+
249
+ .state-badge .session-id {
250
+ font-family: 'SF Mono', Monaco, monospace;
251
+ font-size: 10px;
252
+ display: none;
253
+ }
254
+
255
+ .state-badge.active .session-id,
256
+ .state-badge.error .session-id {
257
+ display: block;
258
+ }
259
+
260
+ .state-badge.session .session-id {
261
+ display: block;
262
+ }
263
+
264
+ .state-badge.session .empty-state {
265
+ display: none;
266
+ }
267
+
268
+ .state-badge .caps-row {
269
+ display: none;
270
+ gap: 4px;
271
+ flex-wrap: wrap;
272
+ }
273
+
274
+ .state-badge.active .caps-row,
275
+ .state-badge.error .caps-row {
276
+ display: flex;
277
+ }
278
+
279
+ .state-badge .cap {
280
+ font-family: 'SF Mono', Monaco, monospace;
281
+ font-size: 8px;
282
+ background: white;
283
+ padding: 1px 5px;
284
+ border-radius: 3px;
285
+ border: 1px solid #e0e0e0;
286
+ }
287
+
288
+ .state-badge.active .cap {
289
+ border-color: #c8e6c9;
290
+ }
291
+
292
+ .state-badge.error .cap {
293
+ border-color: #ef9a9a;
294
+ }
295
+
296
+ .state-badge .empty-state {
297
+ font-size: 9px;
298
+ color: #bdbdbd;
299
+ font-style: italic;
300
+ }
301
+
302
+ .state-badge.active .empty-state,
303
+ .state-badge.error .empty-state {
304
+ display: none;
305
+ }
306
+
307
+ /* Client state badge stays below */
308
+ .client .state-badge {
309
+ align-items: center;
310
+ }
311
+
312
+ .client .state-badge .caps-row {
313
+ justify-content: center;
314
+ }
315
+
316
+ /* Connection lines */
317
+ .connection {
318
+ position: absolute;
319
+ height: 2px;
320
+ background: #bdbdbd;
321
+ }
322
+
323
+ .conn-client-lb {
324
+ left: 140px;
325
+ width: 60px;
326
+ top: 140px;
327
+ }
328
+
329
+ .conn-lb-servers {
330
+ left: 290px;
331
+ width: 110px;
332
+ top: 140px;
333
+ }
334
+
335
+ /* The moving message */
336
+ .message {
337
+ position: absolute;
338
+ display: flex;
339
+ flex-direction: column;
340
+ align-items: center;
341
+ gap: 3px;
342
+ opacity: 0;
343
+ transition: opacity 0.2s ease;
344
+ pointer-events: none;
345
+ z-index: 100;
346
+ transform: translateX(-50%);
347
+ }
348
+
349
+ .message.visible {
350
+ opacity: 1;
351
+ }
352
+
353
+ .message-header {
354
+ display: flex;
355
+ align-items: center;
356
+ gap: 5px;
357
+ }
358
+
359
+ .message-arrow {
360
+ font-size: 24px;
361
+ font-weight: bold;
362
+ }
363
+
364
+ .message-type {
365
+ padding: 5px 10px;
366
+ border-radius: 6px;
367
+ font-size: 11px;
368
+ font-weight: 600;
369
+ white-space: nowrap;
370
+ box-shadow: 0 2px 10px rgba(0,0,0,0.15);
371
+ }
372
+
373
+ .message-detail {
374
+ padding: 3px 8px;
375
+ border-radius: 4px;
376
+ font-size: 9px;
377
+ font-family: 'SF Mono', Monaco, monospace;
378
+ background: rgba(255,255,255,0.95);
379
+ color: #666;
380
+ border: 1px solid #e0e0e0;
381
+ }
382
+
383
+ .message-session {
384
+ padding: 3px 8px;
385
+ border-radius: 4px;
386
+ font-size: 9px;
387
+ font-family: 'SF Mono', Monaco, monospace;
388
+ background: #e8f5e9;
389
+ color: #2e7d32;
390
+ border: 1px solid #a5d6a7;
391
+ }
392
+
393
+ .message-session.caps {
394
+ display: flex;
395
+ flex-direction: column;
396
+ gap: 3px;
397
+ align-items: flex-start;
398
+ }
399
+
400
+ .message-session .session-label {
401
+ font-size: 8px;
402
+ text-transform: uppercase;
403
+ letter-spacing: 0.4px;
404
+ color: #2e7d32;
405
+ }
406
+
407
+ .message-session .cap-row {
408
+ display: flex;
409
+ gap: 4px;
410
+ flex-wrap: wrap;
411
+ }
412
+
413
+ .message-session .cap-chip {
414
+ font-family: 'SF Mono', Monaco, monospace;
415
+ font-size: 8px;
416
+ background: white;
417
+ padding: 1px 5px;
418
+ border-radius: 3px;
419
+ border: 1px solid #c8e6c9;
420
+ color: #2e7d32;
421
+ }
422
+
423
+ .message-session.error {
424
+ background: #ffebee;
425
+ color: #c62828;
426
+ border-color: #ef9a9a;
427
+ }
428
+
429
+ .message.request .message-arrow { color: #1976d2; }
430
+ .message.request .message-type {
431
+ background: #1976d2;
432
+ color: white;
433
+ }
434
+
435
+ .message.response .message-arrow { color: #ef6c00; }
436
+ .message.response .message-type {
437
+ background: #ef6c00;
438
+ color: white;
439
+ }
440
+
441
+ .message.notification .message-arrow { color: #7b1fa2; }
442
+ .message.notification .message-type {
443
+ background: #7b1fa2;
444
+ color: white;
445
+ }
446
+
447
+ .message.server-request .message-arrow { color: #ef6c00; }
448
+ .message.server-request .message-type {
449
+ background: #ef6c00;
450
+ color: white;
451
+ }
452
+
453
+ .message.client-response .message-arrow { color: #1976d2; }
454
+ .message.client-response .message-type {
455
+ background: #1976d2;
456
+ color: white;
457
+ }
458
+
459
+ .message.error-response .message-arrow { color: #c62828; }
460
+ .message.error-response .message-type {
461
+ background: #c62828;
462
+ color: white;
463
+ }
464
+
465
+ /* Narration */
466
+ .narration {
467
+ margin-top: 25px;
468
+ padding: 14px 20px;
469
+ background: white;
470
+ border: 2px solid #e0e0e0;
471
+ border-radius: 12px;
472
+ font-size: 14px;
473
+ color: #333;
474
+ max-width: 700px;
475
+ text-align: center;
476
+ min-height: 52px;
477
+ display: flex;
478
+ align-items: center;
479
+ justify-content: center;
480
+ }
481
+
482
+ .narration .step-num {
483
+ display: inline-block;
484
+ width: 26px;
485
+ height: 26px;
486
+ background: #9e9e9e;
487
+ color: white;
488
+ border-radius: 50%;
489
+ font-size: 13px;
490
+ font-weight: 600;
491
+ line-height: 26px;
492
+ text-align: center;
493
+ margin-right: 12px;
494
+ flex-shrink: 0;
495
+ transition: background 0.3s ease;
496
+ }
497
+
498
+ .narration.request-state .step-num { background: #1976d2; }
499
+ .narration.response-state .step-num { background: #ef6c00; }
500
+ .narration.notification-state .step-num { background: #7b1fa2; }
501
+ .narration.waiting-state .step-num { background: #e65100; }
502
+ .narration.error-state .step-num { background: #c62828; }
503
+ .narration.error-state { border-color: #ef9a9a; background: #fff8f8; }
504
+ .narration.success-state .step-num { background: #4caf50; }
505
+
2026/mcp-connect/animations/shared/sequence-helpers.js ADDED
@@ -0,0 +1,83 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ function runSequenceAnimation({
2
+ selectors,
3
+ cyclePause = 2000,
4
+ fadeOutOffset = 4000,
5
+ initialDelay = 500,
6
+ lastDelayOverride,
7
+ onShow,
8
+ scrollContainerSelector,
9
+ } = {}) {
10
+ const groups = (selectors || []).flatMap((selector) =>
11
+ Array.from(document.querySelectorAll(selector))
12
+ );
13
+
14
+ if (groups.length === 0) {
15
+ return;
16
+ }
17
+
18
+ const delays = groups.map((el) => parseInt(el.dataset.delay, 10) || 0);
19
+ const maxDelay = Math.max(...delays, 0);
20
+ const finalDelay = Math.max(maxDelay, lastDelayOverride || 0);
21
+ const scrollContainer = scrollContainerSelector
22
+ ? document.querySelector(scrollContainerSelector)
23
+ : null;
24
+
25
+ let timers = [];
26
+
27
+ function clearTimers() {
28
+ timers.forEach((id) => clearTimeout(id));
29
+ timers = [];
30
+ }
31
+
32
+ function schedule(fn, delay) {
33
+ const id = setTimeout(fn, delay);
34
+ timers.push(id);
35
+ return id;
36
+ }
37
+
38
+ function runAnimation() {
39
+ clearTimers();
40
+ groups.forEach((el) => el.classList.remove('show', 'fade-out'));
41
+ if (scrollContainer) {
42
+ scrollContainer.scrollTop = 0;
43
+ }
44
+
45
+ // Force reflow to ensure class removal is processed before re-adding
46
+ void document.body.offsetHeight;
47
+
48
+ groups.forEach((el) => {
49
+ const delay = parseInt(el.dataset.delay, 10) || 0;
50
+ schedule(() => {
51
+ el.classList.add('show');
52
+ if (onShow) {
53
+ onShow(el);
54
+ }
55
+ if (scrollContainer) {
56
+ scrollContainer.scrollTop = scrollContainer.scrollHeight;
57
+ }
58
+ }, delay);
59
+ });
60
+
61
+ const fadeOutTime = finalDelay + fadeOutOffset;
62
+ schedule(() => {
63
+ groups.forEach((el) => el.classList.add('fade-out'));
64
+ }, fadeOutTime);
65
+
66
+ schedule(runAnimation, fadeOutTime + 1000 + cyclePause);
67
+ }
68
+
69
+ function start() {
70
+ clearTimers();
71
+ schedule(runAnimation, initialDelay);
72
+ }
73
+
74
+ if (document.readyState === 'complete') {
75
+ start();
76
+ } else {
77
+ window.addEventListener('load', start, { once: true });
78
+ }
79
+
80
+ window.addEventListener('pageshow', () => {
81
+ start();
82
+ });
83
+ }
2026/mcp-connect/animations/stdio-simple.html ADDED
@@ -0,0 +1,722 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <style>
6
+ * { margin: 0; padding: 0; box-sizing: border-box; }
7
+ body {
8
+ background: #fafafa;
9
+ display: flex;
10
+ align-items: center;
11
+ justify-content: center;
12
+ width: 100vw;
13
+ height: 100vh;
14
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
15
+ padding: 0;
16
+ overflow: hidden;
17
+ }
18
+
19
+ .canvas-root {
20
+ display: inline-flex;
21
+ flex-direction: column;
22
+ align-items: center;
23
+ justify-content: center;
24
+ padding: 24px 20px;
25
+ }
26
+
27
+ /* Process boundary container */
28
+ .process-boundary {
29
+ border: 2px dashed #9e9e9e;
30
+ border-radius: 20px;
31
+ padding: 30px 30px;
32
+ background: rgba(255, 255, 255, 0.5);
33
+ position: relative;
34
+ }
35
+
36
+ .process-label {
37
+ position: absolute;
38
+ top: -14px;
39
+ left: 50%;
40
+ transform: translateX(-50%);
41
+ background: #fafafa;
42
+ padding: 4px 20px;
43
+ font-size: 16px;
44
+ font-weight: 600;
45
+ color: #616161;
46
+ white-space: nowrap;
47
+ }
48
+
49
+ .diagram {
50
+ position: relative;
51
+ width: 500px;
52
+ height: 220px;
53
+ }
54
+
55
+ /* Entity base styles */
56
+ .entity {
57
+ position: absolute;
58
+ display: flex;
59
+ flex-direction: column;
60
+ align-items: center;
61
+ gap: 10px;
62
+ }
63
+
64
+ /* Client - starts grey, becomes blue */
65
+ .client { left: 0; top: 30px; }
66
+ .client .entity-box {
67
+ width: 130px;
68
+ min-height: 75px;
69
+ height: 80px;
70
+ border-radius: 16px;
71
+ background: #f5f5f5;
72
+ border: 3px solid #9e9e9e;
73
+ color: #9e9e9e;
74
+ display: flex;
75
+ flex-direction: column;
76
+ align-items: center;
77
+ justify-content: center;
78
+ font-weight: 600;
79
+ font-size: 14px;
80
+ transition: all 0.5s ease;
81
+ text-align: center;
82
+ line-height: 1.3;
83
+ gap: 4px;
84
+ }
85
+
86
+ .client .entity-box.alive {
87
+ background: #e3f2fd;
88
+ border-color: #1976d2;
89
+ color: #1976d2;
90
+ }
91
+
92
+ .client .entity-box.active {
93
+ background: #bbdefb;
94
+ border-color: #1976d2;
95
+ color: #1976d2;
96
+ box-shadow: 0 4px 20px rgba(25, 118, 210, 0.3);
97
+ }
98
+
99
+ /* Server - starts grey, becomes orange */
100
+ .server { right: 0; top: 30px; }
101
+ .server .entity-box {
102
+ width: 130px;
103
+ min-height: 75px;
104
+ height: 80px;
105
+ border-radius: 16px;
106
+ background: #f5f5f5;
107
+ border: 3px solid #9e9e9e;
108
+ color: #9e9e9e;
109
+ display: flex;
110
+ flex-direction: column;
111
+ align-items: center;
112
+ justify-content: center;
113
+ font-weight: 600;
114
+ font-size: 14px;
115
+ transition: all 0.5s ease;
116
+ text-align: center;
117
+ line-height: 1.3;
118
+ gap: 4px;
119
+ }
120
+
121
+ .server .entity-box.alive {
122
+ background: #fff3e0;
123
+ border-color: #ef6c00;
124
+ color: #ef6c00;
125
+ }
126
+
127
+ .server .entity-box.active {
128
+ background: #ffe0b2;
129
+ border-color: #ef6c00;
130
+ color: #ef6c00;
131
+ box-shadow: 0 4px 20px rgba(239, 108, 0, 0.3);
132
+ }
133
+
134
+ .server .entity-box.waiting {
135
+ animation: waitingPulse 1s ease-in-out infinite;
136
+ }
137
+
138
+ @keyframes waitingPulse {
139
+ 0%, 100% {
140
+ background: #fff3e0;
141
+ border-color: #ef6c00;
142
+ box-shadow: 0 4px 20px rgba(239, 108, 0, 0.2);
143
+ }
144
+ 50% {
145
+ background: #ffe0b2;
146
+ border-color: #e65100;
147
+ box-shadow: 0 4px 30px rgba(239, 108, 0, 0.5);
148
+ }
149
+ }
150
+
151
+ .entity-status {
152
+ font-size: 10px;
153
+ font-weight: 600;
154
+ text-transform: uppercase;
155
+ letter-spacing: 0.5px;
156
+ opacity: 0;
157
+ transition: opacity 0.3s ease;
158
+ padding: 2px 8px;
159
+ border-radius: 4px;
160
+ }
161
+
162
+ .entity-status.visible {
163
+ opacity: 1;
164
+ }
165
+
166
+ .entity-status.waiting {
167
+ background: #e65100;
168
+ color: white;
169
+ animation: statusBlink 0.8s ease-in-out infinite;
170
+ }
171
+
172
+ @keyframes statusBlink {
173
+ 0%, 100% { opacity: 1; transform: scale(1); }
174
+ 50% { opacity: 0.7; transform: scale(1.05); }
175
+ }
176
+
177
+ /* State indicator badge - shows capabilities learned */
178
+ .state-badge {
179
+ display: flex;
180
+ flex-direction: column;
181
+ align-items: center;
182
+ gap: 4px;
183
+ padding: 8px 12px;
184
+ border-radius: 10px;
185
+ font-size: 11px;
186
+ font-weight: 600;
187
+ transition: all 0.4s ease;
188
+ width: 130px;
189
+ min-height: 75px;
190
+ /* Default: gray/inactive state */
191
+ background: #f5f5f5;
192
+ border: 1px solid #e0e0e0;
193
+ color: #9e9e9e;
194
+ }
195
+
196
+ .state-badge.active {
197
+ background: #e8f5e9;
198
+ border: 1px solid #a5d6a7;
199
+ color: #2e7d32;
200
+ }
201
+
202
+ .state-badge .badge-title {
203
+ font-size: 9px;
204
+ text-transform: uppercase;
205
+ letter-spacing: 0.5px;
206
+ color: #999;
207
+ font-weight: 500;
208
+ }
209
+
210
+ .state-badge.active .badge-title {
211
+ color: #666;
212
+ }
213
+
214
+ .state-badge .caps-list {
215
+ display: flex;
216
+ flex-wrap: wrap;
217
+ gap: 4px;
218
+ justify-content: center;
219
+ }
220
+
221
+ .state-badge .cap {
222
+ display: flex;
223
+ align-items: center;
224
+ gap: 3px;
225
+ font-family: 'SF Mono', Monaco, monospace;
226
+ font-size: 9px;
227
+ background: white;
228
+ padding: 2px 6px;
229
+ border-radius: 4px;
230
+ border: 1px solid #e0e0e0;
231
+ opacity: 0;
232
+ transition: opacity 0.3s ease;
233
+ }
234
+
235
+ .state-badge.active .cap {
236
+ border-color: #c8e6c9;
237
+ opacity: 1;
238
+ }
239
+
240
+ .state-badge .cap .check {
241
+ color: #4caf50;
242
+ font-weight: bold;
243
+ }
244
+
245
+ .state-badge .empty-state {
246
+ font-size: 9px;
247
+ color: #bdbdbd;
248
+ font-style: italic;
249
+ }
250
+
251
+ .state-badge.active .empty-state {
252
+ display: none;
253
+ }
254
+
255
+ /* Connection line */
256
+ .connection {
257
+ position: absolute;
258
+ left: 145px;
259
+ right: 145px;
260
+ top: 70px;
261
+ height: 2px;
262
+ background: #bdbdbd;
263
+ }
264
+
265
+ .connection-label {
266
+ position: absolute;
267
+ left: 50%;
268
+ top: 50%;
269
+ transform: translate(-50%, -50%);
270
+ background: rgba(255, 255, 255, 0.9);
271
+ padding: 4px 12px;
272
+ font-size: 11px;
273
+ color: #757575;
274
+ font-weight: 500;
275
+ white-space: nowrap;
276
+ border-radius: 4px;
277
+ }
278
+
279
+ /* The moving message - centered around arrow */
280
+ .message {
281
+ position: absolute;
282
+ display: flex;
283
+ flex-direction: column;
284
+ align-items: center;
285
+ gap: 4px;
286
+ opacity: 0;
287
+ transition: opacity 0.2s ease;
288
+ pointer-events: none;
289
+ z-index: 100;
290
+ transform: translateX(-50%);
291
+ }
292
+
293
+ .message.visible {
294
+ opacity: 1;
295
+ }
296
+
297
+ .message-header {
298
+ display: flex;
299
+ align-items: center;
300
+ gap: 6px;
301
+ }
302
+
303
+ .message-arrow {
304
+ font-size: 28px;
305
+ font-weight: bold;
306
+ }
307
+
308
+ .message-type {
309
+ padding: 6px 12px;
310
+ border-radius: 8px;
311
+ font-size: 12px;
312
+ font-weight: 600;
313
+ white-space: nowrap;
314
+ box-shadow: 0 3px 12px rgba(0,0,0,0.15);
315
+ }
316
+
317
+ .message-detail {
318
+ padding: 3px 8px;
319
+ border-radius: 4px;
320
+ font-size: 10px;
321
+ font-family: 'SF Mono', Monaco, monospace;
322
+ background: rgba(255,255,255,0.95);
323
+ color: #666;
324
+ border: 1px solid #e0e0e0;
325
+ }
326
+
327
+ .message.request .message-arrow { color: #1976d2; }
328
+ .message.request .message-type {
329
+ background: #1976d2;
330
+ color: white;
331
+ }
332
+
333
+ .message.response .message-arrow { color: #ef6c00; }
334
+ .message.response .message-type {
335
+ background: #ef6c00;
336
+ color: white;
337
+ }
338
+
339
+ .message.notification .message-arrow { color: #7b1fa2; }
340
+ .message.notification .message-type {
341
+ background: #7b1fa2;
342
+ color: white;
343
+ }
344
+
345
+ .message.server-request .message-arrow { color: #ef6c00; }
346
+ .message.server-request .message-type {
347
+ background: #ef6c00;
348
+ color: white;
349
+ }
350
+
351
+ .message.client-response .message-arrow { color: #1976d2; }
352
+ .message.client-response .message-type {
353
+ background: #1976d2;
354
+ color: white;
355
+ }
356
+
357
+ /* Narration */
358
+ .narration {
359
+ margin-top: 30px;
360
+ padding: 16px 24px;
361
+ background: white;
362
+ border: 2px solid #e0e0e0;
363
+ border-radius: 12px;
364
+ font-size: 15px;
365
+ color: #333;
366
+ max-width: 650px;
367
+ text-align: center;
368
+ min-height: 56px;
369
+ display: flex;
370
+ align-items: center;
371
+ justify-content: center;
372
+ }
373
+
374
+ .narration .step-num {
375
+ display: inline-block;
376
+ width: 28px;
377
+ height: 28px;
378
+ background: #9e9e9e;
379
+ color: white;
380
+ border-radius: 50%;
381
+ font-size: 14px;
382
+ font-weight: 600;
383
+ line-height: 28px;
384
+ text-align: center;
385
+ margin-right: 14px;
386
+ flex-shrink: 0;
387
+ transition: background 0.3s ease;
388
+ }
389
+
390
+ .narration.request-state .step-num { background: #1976d2; }
391
+ .narration.response-state .step-num { background: #ef6c00; }
392
+ .narration.notification-state .step-num { background: #7b1fa2; }
393
+ .narration.success-state .step-num { background: #4caf50; }
394
+ .narration.waiting-state .step-num { background: #e65100; }
395
+ </style>
396
+ </head>
397
+ <body>
398
+ <div class="canvas-root">
399
+ <div class="process-boundary">
400
+ <div class="process-label">STDIO (Same Process)</div>
401
+
402
+ <div class="diagram">
403
+ <!-- Client -->
404
+ <div class="entity client">
405
+ <div class="entity-box" id="client-box">
406
+ <span>MCP Client</span>
407
+ <span class="entity-status" id="client-status"></span>
408
+ </div>
409
+ <div class="state-badge" id="client-state">
410
+ <div class="badge-title">Connection State</div>
411
+ <div class="empty-state">not connected</div>
412
+ <div class="caps-list">
413
+ <span class="cap"><span class="check">✓</span> tools</span>
414
+ <span class="cap"><span class="check">✓</span> prompts</span>
415
+ </div>
416
+ </div>
417
+ </div>
418
+
419
+ <!-- Connection line -->
420
+ <div class="connection">
421
+ <div class="connection-label">stdin / stdout</div>
422
+ </div>
423
+
424
+ <!-- Server -->
425
+ <div class="entity server">
426
+ <div class="entity-box" id="server-box">
427
+ <span>MCP Server</span>
428
+ <span class="entity-status" id="server-status"></span>
429
+ </div>
430
+ <div class="state-badge" id="server-state">
431
+ <div class="badge-title">Connection State</div>
432
+ <div class="empty-state">not connected</div>
433
+ <div class="caps-list">
434
+ <span class="cap"><span class="check">✓</span> sampling</span>
435
+ </div>
436
+ </div>
437
+ </div>
438
+
439
+ <!-- Message -->
440
+ <div class="message" id="message">
441
+ <div class="message-header">
442
+ <span class="message-type" id="message-type">initialize</span>
443
+ <span class="message-arrow" id="message-arrow">→</span>
444
+ </div>
445
+ <div class="message-detail" id="message-detail">request</div>
446
+ </div>
447
+ </div>
448
+ </div>
449
+
450
+ <div class="narration" id="narration">
451
+ <span class="step-num" id="step-num">○</span>
452
+ <span id="narration-text">Client spawns server as subprocess...</span>
453
+ </div>
454
+
455
+ </div>
456
+
457
+ <script src="shared/animation-config.js"></script>
458
+ <script src="shared/diagram-helpers.js"></script>
459
+ <script src="shared/canvas-scale.js"></script>
460
+ <script>
461
+ const message = document.getElementById('message');
462
+ const messageType = document.getElementById('message-type');
463
+ const messageArrow = document.getElementById('message-arrow');
464
+ const messageDetail = document.getElementById('message-detail');
465
+ const narration = document.getElementById('narration');
466
+ const narrationText = document.getElementById('narration-text');
467
+ const stepNum = document.getElementById('step-num');
468
+ const clientBox = document.getElementById('client-box');
469
+ const serverBox = document.getElementById('server-box');
470
+ const clientState = document.getElementById('client-state');
471
+ const serverState = document.getElementById('server-state');
472
+ const clientStatus = document.getElementById('client-status');
473
+ const serverStatus = document.getElementById('server-status');
474
+
475
+
476
+ const messageElements = {
477
+ container: message,
478
+ header: message.querySelector('.message-header'),
479
+ type: messageType,
480
+ arrow: messageArrow,
481
+ detail: messageDetail,
482
+ };
483
+
484
+ const clientCenter = 65;
485
+ const serverCenter = 435;
486
+ const msgY = 45;
487
+
488
+
489
+ function setMessagePos(x, y) {
490
+ setMessagePosition(message, x, y);
491
+ }
492
+
493
+ function animateMessage(fromX, fromY, toX, toY, duration, callback) {
494
+ animateMessageBetween(message, fromX, fromY, toX, toY, duration, callback);
495
+ }
496
+
497
+ function configMessage(type, arrow, method, detail, direction) {
498
+ configureMessage(messageElements, {
499
+ type,
500
+ arrow,
501
+ method,
502
+ detail,
503
+ direction,
504
+ });
505
+ }
506
+
507
+ function setStatus(element, text, className) {
508
+ element.textContent = text;
509
+ element.className = 'entity-status' + (text ? ' visible' : '') + (className ? ' ' + className : '');
510
+ }
511
+
512
+ const steps = [
513
+ // Step 0: Initial grey state
514
+ {
515
+ setup: () => {
516
+ message.className = 'message';
517
+ stepNum.textContent = '○';
518
+ narrationText.textContent = 'Client spawns server as subprocess...';
519
+ narration.className = 'narration';
520
+ clientBox.className = 'entity-box';
521
+ serverBox.className = 'entity-box';
522
+ clientState.classList.remove('active');
523
+ serverState.classList.remove('active');
524
+ setStatus(clientStatus, '', '');
525
+ setStatus(serverStatus, '', '');
526
+ },
527
+ animate: (done) => setTimeout(done, ANIMATION.INITIAL_PAUSE),
528
+ after: () => {}
529
+ },
530
+ // Step 1: Initialize request Client → Server
531
+ {
532
+ setup: () => {
533
+ configMessage('request', '→', 'initialize', 'InitializeRequest', 'right');
534
+ setMessagePos(clientCenter, msgY);
535
+ stepNum.textContent = '1';
536
+ narrationText.textContent = 'Client sends InitializeRequest with capabilities';
537
+ narration.className = 'narration request-state';
538
+ clientBox.classList.add('alive', 'active');
539
+ },
540
+ animate: (done) => animateMessage(clientCenter, msgY, serverCenter, msgY, ANIMATION.MSG_DURATION, done),
541
+ after: () => {
542
+ clientBox.classList.remove('active');
543
+ serverBox.classList.add('alive', 'active');
544
+ }
545
+ },
546
+ // Step 2: Initialize result Server → Client
547
+ {
548
+ setup: () => {
549
+ configMessage('response', '←', 'initialize', 'InitializeResult', 'left');
550
+ setMessagePos(serverCenter, msgY);
551
+ stepNum.textContent = '2';
552
+ narrationText.textContent = 'Server responds with InitializeResult';
553
+ narration.className = 'narration response-state';
554
+ },
555
+ animate: (done) => animateMessage(serverCenter, msgY, clientCenter, msgY, ANIMATION.MSG_DURATION, done),
556
+ after: () => {
557
+ serverBox.classList.remove('active');
558
+ clientBox.classList.add('active');
559
+ }
560
+ },
561
+ // Step 3: notifications/initialized Client → Server
562
+ {
563
+ setup: () => {
564
+ clientBox.classList.remove('active');
565
+ configMessage('notification', '→', 'initialized', 'notification', 'right');
566
+ setMessagePos(clientCenter, msgY);
567
+ stepNum.textContent = '3';
568
+ narrationText.textContent = 'Client sends initialized notification';
569
+ narration.className = 'narration notification-state';
570
+ clientBox.classList.add('active');
571
+ },
572
+ animate: (done) => animateMessage(clientCenter, msgY, serverCenter, msgY, ANIMATION.MSG_DURATION, done),
573
+ after: () => {
574
+ clientBox.classList.remove('active');
575
+ clientState.classList.add('active');
576
+ serverState.classList.add('active');
577
+ }
578
+ },
579
+ // Step 4: tools/list request
580
+ {
581
+ setup: () => {
582
+ configMessage('request', '→', 'tools/list', 'ListToolsRequest', 'right');
583
+ setMessagePos(clientCenter, msgY);
584
+ stepNum.textContent = '4';
585
+ narrationText.textContent = 'Client requests tool list';
586
+ narration.className = 'narration request-state';
587
+ clientBox.classList.add('active');
588
+ },
589
+ animate: (done) => animateMessage(clientCenter, msgY, serverCenter, msgY, ANIMATION.MSG_DURATION, done),
590
+ after: () => {
591
+ clientBox.classList.remove('active');
592
+ serverBox.classList.add('active');
593
+ }
594
+ },
595
+ // Step 5: tools/list response
596
+ {
597
+ setup: () => {
598
+ configMessage('response', '←', 'tools/list', 'ListToolsResult', 'left');
599
+ setMessagePos(serverCenter, msgY);
600
+ stepNum.textContent = '5';
601
+ narrationText.textContent = 'Server returns ListToolsResult';
602
+ narration.className = 'narration response-state';
603
+ },
604
+ animate: (done) => animateMessage(serverCenter, msgY, clientCenter, msgY, ANIMATION.MSG_DURATION, done),
605
+ after: () => {
606
+ serverBox.classList.remove('active');
607
+ }
608
+ },
609
+ // Step 6: prompts/list request
610
+ {
611
+ setup: () => {
612
+ configMessage('request', '→', 'prompts/list', 'ListPromptsRequest', 'right');
613
+ setMessagePos(clientCenter, msgY);
614
+ stepNum.textContent = '6';
615
+ narrationText.textContent = 'Client requests prompt list';
616
+ narration.className = 'narration request-state';
617
+ clientBox.classList.add('active');
618
+ },
619
+ animate: (done) => animateMessage(clientCenter, msgY, serverCenter, msgY, ANIMATION.MSG_DURATION, done),
620
+ after: () => {
621
+ clientBox.classList.remove('active');
622
+ serverBox.classList.add('active');
623
+ }
624
+ },
625
+ // Step 7: prompts/list response
626
+ {
627
+ setup: () => {
628
+ configMessage('response', '←', 'prompts/list', 'ListPromptsResult', 'left');
629
+ setMessagePos(serverCenter, msgY);
630
+ stepNum.textContent = '7';
631
+ narrationText.textContent = 'Server returns ListPromptsResult';
632
+ narration.className = 'narration response-state';
633
+ },
634
+ animate: (done) => animateMessage(serverCenter, msgY, clientCenter, msgY, ANIMATION.MSG_DURATION, done),
635
+ after: () => {
636
+ serverBox.classList.remove('active');
637
+ }
638
+ },
639
+ // Step 8: tools/call request
640
+ {
641
+ setup: () => {
642
+ configMessage('request', '→', 'tools/call', 'CallToolRequest', 'right');
643
+ setMessagePos(clientCenter, msgY);
644
+ stepNum.textContent = '8';
645
+ narrationText.textContent = 'Client calls a tool';
646
+ narration.className = 'narration request-state';
647
+ clientBox.classList.add('active');
648
+ },
649
+ animate: (done) => animateMessage(clientCenter, msgY, serverCenter, msgY, ANIMATION.MSG_DURATION, done),
650
+ after: () => {
651
+ clientBox.classList.remove('active');
652
+ serverBox.classList.add('active');
653
+ setStatus(serverStatus, 'processing', '');
654
+ }
655
+ },
656
+ // Step 9: Server sends sampling request BACK to client (server waits)
657
+ {
658
+ setup: () => {
659
+ configMessage('server-request', '←', 'sampling/createMessage', 'CreateMessageRequest', 'left');
660
+ setMessagePos(serverCenter, msgY);
661
+ stepNum.textContent = '9';
662
+ narrationText.textContent = 'Server needs LLM — sends sampling request to client';
663
+ narration.className = 'narration waiting-state';
664
+ serverBox.classList.remove('active');
665
+ serverBox.classList.add('waiting');
666
+ setStatus(serverStatus, 'WAITING', 'waiting');
667
+ },
668
+ animate: (done) => animateMessage(serverCenter, msgY, clientCenter, msgY, ANIMATION.MSG_DURATION, done),
669
+ after: () => {
670
+ clientBox.classList.add('active');
671
+ }
672
+ },
673
+ // Step 10: Client responds with sampling result
674
+ {
675
+ setup: () => {
676
+ configMessage('client-response', '→', 'sampling/createMessage', 'CreateMessageResult', 'right');
677
+ setMessagePos(clientCenter, msgY);
678
+ stepNum.textContent = '10';
679
+ narrationText.textContent = 'Client returns LLM response — server resumes';
680
+ narration.className = 'narration response-state';
681
+ },
682
+ animate: (done) => animateMessage(clientCenter, msgY, serverCenter, msgY, ANIMATION.MSG_DURATION, done),
683
+ after: () => {
684
+ clientBox.classList.remove('active');
685
+ serverBox.classList.remove('waiting');
686
+ serverBox.classList.add('active');
687
+ setStatus(serverStatus, 'processing', '');
688
+ }
689
+ },
690
+ // Step 11: tools/call response
691
+ {
692
+ setup: () => {
693
+ configMessage('response', '←', 'tools/call', 'CallToolResult', 'left');
694
+ setMessagePos(serverCenter, msgY);
695
+ stepNum.textContent = '11';
696
+ narrationText.textContent = 'Server completes tool call';
697
+ narration.className = 'narration response-state';
698
+ },
699
+ animate: (done) => animateMessage(serverCenter, msgY, clientCenter, msgY, ANIMATION.MSG_DURATION, done),
700
+ after: () => {
701
+ serverBox.classList.remove('active');
702
+ setStatus(serverStatus, '', '');
703
+ }
704
+ },
705
+ // Step 12: Pause before restart
706
+ {
707
+ setup: () => {
708
+ message.className = 'message';
709
+ stepNum.textContent = '✓';
710
+ narrationText.textContent = 'Connection complete — both sides know capabilities';
711
+ narration.className = 'narration success-state';
712
+ },
713
+ animate: (done) => setTimeout(done, ANIMATION.ERROR_PAUSE),
714
+ after: () => {}
715
+ }
716
+ ];
717
+
718
+ runStepSequence(steps);
719
+ scaleCanvas();
720
+ </script>
721
+ </body>
722
+ </html>
2026/mcp-connect/images/2026-02-03-mcp-server-stats.png ADDED

Git LFS Details

  • SHA256: c2b1a70674af22fb440cf8b6b36fbb6463f65ae8587908ca9feaa0ab10550517
  • Pointer size: 131 Bytes
  • Size of remote file: 229 kB
2026/mcp-connect/images/2026-02-03-mcpremote1.png ADDED

Git LFS Details

  • SHA256: ec92c2f68888e74aab259fe2983ec263fc1bb6f13502578569a137dfb39a0678
  • Pointer size: 131 Bytes
  • Size of remote file: 955 kB
2026/mcp-connect/images/2026-02-03-mcpremote2.png ADDED

Git LFS Details

  • SHA256: 54771193666fd7a3c5caf5a56395cda93094e4d7bab0180b1f7292c2278d2ab7
  • Pointer size: 131 Bytes
  • Size of remote file: 947 kB
2026/mcp-connect/images/2026-02-04-client-dataset.png ADDED

Git LFS Details

  • SHA256: 6f0f57aac37d6c46c1571f10e989fb21d6accd31fcc7fddc02d2cee3b22064bb
  • Pointer size: 131 Bytes
  • Size of remote file: 596 kB
2026/mcp-connect/images/2026-02-04-efficient.png ADDED
2026/mcp-connect/images/github-mark.svg ADDED
2026/mcp-connect/images/hf_logo.svg ADDED
2026/mcp-connect/images/huggingface-mark-logo.svg ADDED
2026/mcp-connect/images/intro-spaces.webm ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f0e4d819a50bd539e7dda538f1cd05ba1c33dfa565552986c96feadd8fce93c5
3
+ size 14977657
2026/mcp-connect/images/mcp-icon.svg ADDED
2026/mcp-connect/images/xcom-logo-black.png ADDED

Git LFS Details

  • SHA256: 391a3a86f40e253b584defa5f284c7402a2175a705ebb2b4b9460112fc92dc77
  • Pointer size: 131 Bytes
  • Size of remote file: 102 kB
2026/mcp-connect/presentation.html ADDED
The diff for this file is too large to render. See raw diff
 
index.html CHANGED
@@ -155,6 +155,22 @@
155
  <main>
156
  <h1>Conference Presentations</h1>
157
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
158
  <section>
159
  <h2>2025</h2>
160
  <ul class="conference-list">
 
155
  <main>
156
  <h1>Conference Presentations</h1>
157
 
158
+ <section>
159
+ <h2>2026</h2>
160
+ <ul class="conference-list">
161
+ <li class="conference">
162
+ <p class="conference-title">MCP Connect (February) <span class="tag">Feb 2026</span></p>
163
+ <div class="links">
164
+ <a href="https://lu.ma/mcpconnect" aria-label="Conference Site: MCP Connect">MCP Connect</a>
165
+ <a href="2026/mcp-connect/presentation.html">View presentation</a>
166
+ </div>
167
+ <div class="extras">
168
+ <p class="note">Talk covering MCP transport choices and trade-offs in Streamable HTTP, sessions and transport relationships, and analytics insights from the <a href="https://github.com/evalstate/hf-mcp-server">Hugging Face MCP Server</a> showing real-world client behavior at scale. Includes detailed experience report and data on session lengths, initialize:tool call ratios, and client patterns in production.</p>
169
+ </div>
170
+ </li>
171
+ </ul>
172
+ </section>
173
+
174
  <section>
175
  <h2>2025</h2>
176
  <ul class="conference-list">