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.
package/dist/FastHonoMcp.js
CHANGED
|
@@ -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,
|
|
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,
|
|
61
|
-
const
|
|
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(
|
|
73
|
-
.map(([,
|
|
86
|
+
${Object.entries(mcpClients)
|
|
87
|
+
.map(([, mcpClient]) => `### ${mcpClient.name}
|
|
74
88
|
\`\`\`
|
|
75
|
-
${
|
|
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
|
|
107
|
-
const documentation = generateDemoDocumentation(serverName,
|
|
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,
|
|
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
|
-
|
|
148
|
+
mcpClients: Object.entries(mcpClients).map(([key, mcpClient]) => ({
|
|
134
149
|
id: key,
|
|
135
|
-
...
|
|
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
|
-
|
|
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
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
<
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
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(
|
|
184
|
-
<button class="copy-btn" onclick="copyToClipboard(\`${escapeForJs(
|
|
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
|
-
.
|
|
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
|
-
.
|
|
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
|
-
.
|
|
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-
|
|
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
|
-
.
|
|
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
|
-
${
|
|
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