modality-mcp-kit 1.4.2 → 1.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -53,6 +53,7 @@ export class FastHonoMcp extends ModalityFastMCP {
53
53
  serverVersion: version,
54
54
  mcpPath,
55
55
  helloWorld,
56
+ middleware: this,
56
57
  }));
57
58
  return this;
58
59
  }
@@ -6,6 +6,15 @@
6
6
  *
7
7
  * Usage: /mcp-demo - returns MCP connection demo documentation and tool showcase
8
8
  */
9
+ import type { FastMCPCompatible } from "./util_mcp_tools_converter.js";
10
+ interface GroupedItem {
11
+ name: string;
12
+ description?: string;
13
+ }
14
+ interface ItemGroup {
15
+ groupName: string;
16
+ groupItems: GroupedItem[];
17
+ }
9
18
  interface MCPConnectionConfig {
10
19
  serverName: string;
11
20
  serverVersion?: string;
@@ -13,6 +22,8 @@ interface MCPConnectionConfig {
13
22
  mcpPath?: string;
14
23
  defaultFormat?: "json" | "markdown" | "html";
15
24
  helloWorld?: string;
25
+ middleware?: FastMCPCompatible;
26
+ customGroups?: ItemGroup[];
16
27
  }
17
28
  /**
18
29
  * Create MCP connection demo handler with server configuration
@@ -7,7 +7,7 @@
7
7
  * Usage: /mcp-demo - returns MCP connection demo documentation and tool showcase
8
8
  */
9
9
  const defaultOutputFormat = "html";
10
- const connectAIShowcase = (serverName, serverUrl, mcpPath = "/mcp") => ({
10
+ const connectAIShowcase = (serverName, mcpPath = "/mcp") => ({
11
11
  claudeCode: {
12
12
  name: "Claude Code",
13
13
  description: "Official Claude IDE tool for seamless development workflow",
@@ -55,10 +55,24 @@ const connectAIShowcase = (serverName, serverUrl, mcpPath = "/mcp") => ({
55
55
  },
56
56
  });
57
57
  // ============================================
58
+ // SERVER TOOLS EXTRACTION
59
+ // ============================================
60
+ const getServerTools = (middleware) => {
61
+ if (!middleware || !middleware.getTools) {
62
+ return [];
63
+ }
64
+ return middleware.getTools().map((tool) => ({
65
+ name: tool.name,
66
+ description: tool.description,
67
+ inputSchema: tool.inputSchema,
68
+ annotations: tool.annotations,
69
+ }));
70
+ };
71
+ // ============================================
58
72
  // DEMO CONTENT - MARKDOWN-BASED
59
73
  // ============================================
60
- const generateDemoDocumentation = (serverName, serverUrl, mcpPath = "/mcp", helloWorld) => {
61
- const tools = connectAIShowcase(serverName, "{serverUrl}", mcpPath);
74
+ const generateDemoDocumentation = (serverName, mcpPath = "/mcp", helloWorld) => {
75
+ const mcpClients = connectAIShowcase(serverName, mcpPath);
62
76
  return `# MCP Connection Guide
63
77
 
64
78
  ${helloWorld ? `## Hello Prompt\n\n${helloWorld}\n` : ""}## How to Connect
@@ -69,10 +83,10 @@ ${helloWorld ? `## Hello Prompt\n\n${helloWorld}\n` : ""}## How to Connect
69
83
 
70
84
  ## Connection Codes
71
85
 
72
- ${Object.entries(tools)
73
- .map(([, tool]) => `### ${tool.name}
86
+ ${Object.entries(mcpClients)
87
+ .map(([, mcpClient]) => `### ${mcpClient.name}
74
88
  \`\`\`
75
- ${tool.connectionCode}
89
+ ${mcpClient.connectionCode}
76
90
  \`\`\``)
77
91
  .join("\n\n")}
78
92
  `;
@@ -103,8 +117,8 @@ export const mcpConnectionDemoHandler = async (c, config) => {
103
117
  const mcpPath = config?.mcpPath || "/mcp";
104
118
  // Get server URL: from config only (client-side will detect actual protocol)
105
119
  let serverUrl = config?.serverUrl || "";
106
- const tools = connectAIShowcase(serverName, serverUrl, mcpPath);
107
- const documentation = generateDemoDocumentation(serverName, serverUrl, mcpPath, config?.helloWorld);
120
+ const mcpClients = connectAIShowcase(serverName, mcpPath);
121
+ const documentation = generateDemoDocumentation(serverName, mcpPath, config?.helloWorld);
108
122
  // Handle different format requests
109
123
  if (format === "markdown" || format === "md") {
110
124
  return new Response(documentation, {
@@ -117,7 +131,7 @@ export const mcpConnectionDemoHandler = async (c, config) => {
117
131
  });
118
132
  }
119
133
  if (format === "html") {
120
- const htmlContent = generateHtmlPage(serverUrl, config, tools, mcpPath);
134
+ const htmlContent = generateHtmlPage(serverUrl, config, mcpClients, mcpPath);
121
135
  return new Response(htmlContent, {
122
136
  status: 200,
123
137
  headers: {
@@ -128,11 +142,16 @@ export const mcpConnectionDemoHandler = async (c, config) => {
128
142
  });
129
143
  }
130
144
  // Default: JSON format with complete data
145
+ const serverTools = getServerTools(config?.middleware);
131
146
  const demoData = {
132
147
  documentation,
133
- tools: Object.entries(tools).map(([key, tool]) => ({
148
+ mcpClients: Object.entries(mcpClients).map(([key, mcpClient]) => ({
134
149
  id: key,
135
- ...tool,
150
+ ...mcpClient,
151
+ })),
152
+ serverTools: serverTools.map((tool) => ({
153
+ name: tool.name,
154
+ description: tool.description,
136
155
  })),
137
156
  server: {
138
157
  name: serverName,
@@ -141,7 +160,8 @@ export const mcpConnectionDemoHandler = async (c, config) => {
141
160
  mcpPath: mcpPath,
142
161
  },
143
162
  metadata: {
144
- toolCount: Object.keys(tools).length,
163
+ clientCount: Object.keys(mcpClients).length,
164
+ toolCount: serverTools.length,
145
165
  lastUpdated: new Date().toISOString(),
146
166
  format: "json",
147
167
  availableFormats: ["json", "markdown", "html"],
@@ -170,24 +190,55 @@ function escapeHtml(text) {
170
190
  function escapeForJs(text) {
171
191
  return text.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$/g, "\\$");
172
192
  }
173
- function generateHtmlPage(serverUrl, config, tools, mcpPath = "/mcp") {
174
- const toolsToDisplay = tools || connectAIShowcase(config?.serverName || "mcp-server", serverUrl, mcpPath);
175
- const toolsHtml = Object.entries(toolsToDisplay)
176
- .map(([, tool]) => `
177
- <div class="tool-card">
178
- <h3>${tool.name}</h3>
179
- <p class="tool-type">${tool.type}</p>
180
- <p class="tool-description">${tool.description}</p>
193
+ function markdownToHtml(markdown) {
194
+ if (!markdown)
195
+ return "";
196
+ let html = escapeHtml(markdown);
197
+ // Headers: # Title → <h3>Title</h3>
198
+ html = html.replace(/^### (.*?)$/gm, "<h3>$1</h3>");
199
+ html = html.replace(/^## (.*?)$/gm, "<h2>$1</h2>");
200
+ html = html.replace(/^# (.*?)$/gm, "<h1>$1</h1>");
201
+ // Bold: **text** → <strong>text</strong> (only properly paired)
202
+ html = html.replace(/\*\*([^\*]+)\*\*/g, "<strong>$1</strong>");
203
+ // Italic: *text* → <em>text</em> (require whitespace/boundaries around asterisks to avoid false matches)
204
+ html = html.replace(/(^|\s|\()\*([^\*\n]+)\*(?=\s|$|\.|\,|\)|:)/gm, "$1<em>$2</em>");
205
+ // Inline code: `code` → <code>code</code>
206
+ html = html.replace(/`([^`]+)`/g, "<code>$1</code>");
207
+ // Links: [text](url) → <a href="url">text</a>
208
+ html = html.replace(/\[([^\]]+)\]\(([^\)]+)\)/g, '<a href="$2" target="_blank">$1</a>');
209
+ // Line breaks
210
+ html = html.replace(/\n/g, "<br>");
211
+ return html;
212
+ }
213
+ function generateHtmlPage(serverUrl, config, mcpClientsArg, mcpPath = "/mcp") {
214
+ const mcpClientsToDisplay = mcpClientsArg || connectAIShowcase(config?.serverName || "mcp-server", mcpPath);
215
+ const serverTools = getServerTools(config?.middleware);
216
+ const mcpClientsHtml = Object.entries(mcpClientsToDisplay)
217
+ .map(([, mcpClient]) => `
218
+ <div class="mcp-client-card">
219
+ <h3>${mcpClient.name}</h3>
220
+ <p class="mcp-client-type">${mcpClient.type}</p>
221
+ <p class="mcp-client-description">${mcpClient.description}</p>
181
222
  <div class="connection-section">
182
223
  <label>Connection Code</label>
183
- <pre class="code-block"><code>${escapeHtml(tool.connectionCode)}</code></pre>
184
- <button class="copy-btn" onclick="copyToClipboard(\`${escapeForJs(tool.connectionCode)}\`)">
224
+ <pre class="code-block"><code>${escapeHtml(mcpClient.connectionCode)}</code></pre>
225
+ <button class="copy-btn" onclick="copyToClipboard(\`${escapeForJs(mcpClient.connectionCode)}\`)">
185
226
  Copy
186
227
  </button>
187
228
  </div>
188
229
  </div>
189
230
  `)
190
231
  .join("\n");
232
+ const serverToolsHtml = serverTools.length > 0
233
+ ? serverTools
234
+ .map((tool) => `
235
+ <div class="server-tool-card">
236
+ <h3>${tool.name}</h3>
237
+ ${tool.description ? `<div class="tool-description">${markdownToHtml(tool.description)}</div>` : ""}
238
+ </div>
239
+ `)
240
+ .join("\n")
241
+ : "";
191
242
  return `
192
243
  <!DOCTYPE html>
193
244
  <html lang="en">
@@ -277,7 +328,7 @@ function generateHtmlPage(serverUrl, config, tools, mcpPath = "/mcp") {
277
328
  gap: 2rem;
278
329
  }
279
330
 
280
- .tool-card {
331
+ .mcp-client-card {
281
332
  border: 1px solid #e0e0e0;
282
333
  border-radius: 8px;
283
334
  padding: 1.5rem;
@@ -285,19 +336,96 @@ function generateHtmlPage(serverUrl, config, tools, mcpPath = "/mcp") {
285
336
  background: white;
286
337
  }
287
338
 
288
- .tool-card:hover {
339
+ .mcp-client-card:hover {
289
340
  border-color: #667eea;
290
341
  box-shadow: 0 8px 24px rgba(102, 126, 234, 0.15);
291
342
  transform: translateY(-2px);
292
343
  }
293
344
 
294
- .tool-card h3 {
345
+ .mcp-client-card h3 {
295
346
  color: #333;
296
347
  margin-bottom: 0.5rem;
297
348
  font-size: 1.3rem;
298
349
  }
299
350
 
300
- .tool-type {
351
+ .server-tool-card {
352
+ border: 1px solid #e0e0e0;
353
+ border-radius: 8px;
354
+ padding: 1.5rem;
355
+ background: white;
356
+ border-left: 4px solid #764ba2;
357
+ }
358
+
359
+ .server-tool-card h3 {
360
+ color: #333;
361
+ margin-bottom: 0.5rem;
362
+ font-size: 1.1rem;
363
+ }
364
+
365
+ .tool-description {
366
+ color: #666;
367
+ font-size: 0.95rem;
368
+ line-height: 1.6;
369
+ }
370
+
371
+ .tool-description strong {
372
+ color: #333;
373
+ font-weight: 600;
374
+ }
375
+
376
+ .tool-description em {
377
+ font-style: italic;
378
+ color: #555;
379
+ }
380
+
381
+ .tool-description code {
382
+ background: #f5f5f5;
383
+ padding: 0.2rem 0.4rem;
384
+ border-radius: 3px;
385
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
386
+ font-size: 0.85rem;
387
+ color: #d63384;
388
+ border: 1px solid #e0e0e0;
389
+ }
390
+
391
+ .tool-description a {
392
+ color: #667eea;
393
+ text-decoration: none;
394
+ border-bottom: 1px solid #667eea;
395
+ }
396
+
397
+ .tool-description a:hover {
398
+ color: #764ba2;
399
+ border-bottom-color: #764ba2;
400
+ }
401
+
402
+ .tool-description h1,
403
+ .tool-description h2,
404
+ .tool-description h3 {
405
+ color: #333;
406
+ margin: 0.5rem 0 0.25rem 0;
407
+ font-weight: 600;
408
+ }
409
+
410
+ .tool-description h1 {
411
+ font-size: 1.1rem;
412
+ }
413
+
414
+ .tool-description h2 {
415
+ font-size: 1rem;
416
+ }
417
+
418
+ .tool-description h3 {
419
+ font-size: 0.95rem;
420
+ }
421
+
422
+ .tool-description br {
423
+ content: "";
424
+ display: block;
425
+ margin: 0.25rem 0;
426
+ }
427
+
428
+ .mcp-client-type {
301
429
  display: inline-block;
302
430
  background: #667eea;
303
431
  color: white;
@@ -309,7 +437,7 @@ function generateHtmlPage(serverUrl, config, tools, mcpPath = "/mcp") {
309
437
  margin-bottom: 1rem;
310
438
  }
311
439
 
312
- .tool-description {
440
+ .mcp-client-description {
313
441
  color: #666;
314
442
  margin-bottom: 1.5rem;
315
443
  line-height: 1.6;
@@ -440,9 +568,38 @@ function generateHtmlPage(serverUrl, config, tools, mcpPath = "/mcp") {
440
568
  <div class="tools-section">
441
569
  <h2>Connect your AI assistant</h2>
442
570
  <div class="tools-grid">
443
- ${toolsHtml}
571
+ ${mcpClientsHtml}
444
572
  </div>
445
573
  </div>
574
+
575
+ ${serverToolsHtml
576
+ ? `<div class="tools-section">
577
+ <h2>Server Tools</h2>
578
+ <div class="tools-grid">
579
+ ${serverToolsHtml}
580
+ </div>
581
+ </div>`
582
+ : ""}
583
+
584
+ ${config?.customGroups && config.customGroups.length > 0
585
+ ? config.customGroups
586
+ .map((group) => `
587
+ <div class="tools-section">
588
+ <h2>${group.groupName}</h2>
589
+ <div class="tools-grid">
590
+ ${group.groupItems
591
+ .map((item) => `
592
+ <div class="server-tool-card">
593
+ <h3>${item.name}</h3>
594
+ ${item.description ? `<div class="tool-description">${markdownToHtml(item.description)}</div>` : ""}
595
+ </div>
596
+ `)
597
+ .join("\n")}
598
+ </div>
599
+ </div>
600
+ `)
601
+ .join("\n")
602
+ : ""}
446
603
  </div>
447
604
 
448
605
  <footer>
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.4.2",
2
+ "version": "1.4.3",
3
3
  "name": "modality-mcp-kit",
4
4
  "repository": {
5
5
  "type": "git",