|
| 1 | +// import { CallToolResult } from "@modelcontextprotocol/sdk/types.js"; |
| 2 | +// import { createUIResource } from "@mcp-ui/server"; |
| 3 | +// import { z } from "zod"; |
| 4 | +// import { readFileSync } from "fs"; |
| 5 | +// import { join, dirname } from "path"; |
| 6 | +// import { fileURLToPath } from "url"; |
| 7 | + |
| 8 | +// const __filename = fileURLToPath(import.meta.url); |
| 9 | +// const __dirname = dirname(__filename); |
| 10 | + |
| 11 | +// // Tool name to HTML file mappings |
| 12 | +// const TOOL_TO_HTML_MAPPINGS: Record<string, string> = { |
| 13 | +// "list-databases": "ListDatabases.html", |
| 14 | +// }; |
| 15 | + |
| 16 | +// /** |
| 17 | +// * Options for augmenting a tool result with UI |
| 18 | +// */ |
| 19 | +// export interface AugmentOptions { |
| 20 | +// toolName: string; |
| 21 | +// renderData: Record<string, unknown>; |
| 22 | +// } |
| 23 | + |
| 24 | +// /** |
| 25 | +// * Augment a tool result with UI using rawHtml content type |
| 26 | +// * This reads built HTML files from the UI build output and embeds them as rawHtml |
| 27 | +// * |
| 28 | +// * The render data is embedded in the UI resource using uiMetadata['initial-render-data']. |
| 29 | +// * The MCP client will automatically extract this data and pass it to the iframe via postMessage. |
| 30 | +// */ |
| 31 | +// export function augmentWithUI(toolResult: CallToolResult, options: AugmentOptions): CallToolResult { |
| 32 | +// const { toolName, renderData } = options; |
| 33 | + |
| 34 | +// console.log(`[augmentWithUI] Tool: ${toolName}, Result:`, JSON.stringify(toolResult, null, 2)); |
| 35 | + |
| 36 | +// // Check if we have a mapping for this tool |
| 37 | +// const htmlFileName = TOOL_TO_HTML_MAPPINGS[toolName]; |
| 38 | + |
| 39 | +// if (!htmlFileName) { |
| 40 | +// // No mapping registered for this tool name |
| 41 | +// return toolResult; |
| 42 | +// } |
| 43 | + |
| 44 | +// // // Validate renderData against the schema for this tool (if schema exists) |
| 45 | +// // const schema = TOOL_SCHEMAS[toolName]; |
| 46 | +// // if (schema) { |
| 47 | +// // try { |
| 48 | +// // schema.parse(renderData); |
| 49 | +// // console.log(`[augmentWithUI] Validation passed for tool: ${toolName}`); |
| 50 | +// // } catch (error) { |
| 51 | +// // const errorMessage = |
| 52 | +// // error instanceof z.ZodError |
| 53 | +// // ? `Schema validation failed for tool "${toolName}": ${error.issues |
| 54 | +// // .map((e) => e.message) |
| 55 | +// // .join(", ")}` |
| 56 | +// // : `Schema validation failed for tool "${toolName}"`; |
| 57 | +// // console.warn(`[augmentWithUI] ${errorMessage}`, error); |
| 58 | +// // // Return the tool result unmodified - validation failure prevents UI augmentation |
| 59 | +// // return toolResult; |
| 60 | +// // } |
| 61 | +// // } |
| 62 | + |
| 63 | +// // Read the built HTML file from the UI dist directory |
| 64 | +// // Path: from src/tools/ go up to ui/, then to dist/embeddable-uis/ |
| 65 | +// const uiDistPath = join(__dirname, "..", "..", "dist", "embeddable-uis", htmlFileName); |
| 66 | +// console.log(`[augmentWithUI] Looking for HTML file at: ${uiDistPath}`); |
| 67 | + |
| 68 | +// let htmlContent: string; |
| 69 | + |
| 70 | +// try { |
| 71 | +// htmlContent = readFileSync(uiDistPath, "utf-8"); |
| 72 | +// console.log(`[augmentWithUI] Successfully read HTML file: ${htmlFileName} (${htmlContent.length} bytes)`); |
| 73 | +// } catch (error) { |
| 74 | +// console.error(`[augmentWithUI] Failed to read HTML file ${htmlFileName} from ${uiDistPath}:`, error); |
| 75 | +// // Return the tool result unmodified if HTML file cannot be read |
| 76 | +// return toolResult; |
| 77 | +// } |
| 78 | + |
| 79 | +// // Create UI resource using @mcp-ui/server with rawHtml content |
| 80 | +// const uiResource = createUIResource({ |
| 81 | +// uri: `ui://${toolName}/${Date.now()}`, |
| 82 | +// content: { |
| 83 | +// type: "rawHtml", |
| 84 | +// htmlString: htmlContent, |
| 85 | +// }, |
| 86 | +// encoding: "text", |
| 87 | +// // ✅ Embed the render data in uiMetadata |
| 88 | +// // The MCP client will automatically extract this and pass it to the iframe via postMessage |
| 89 | +// uiMetadata: { |
| 90 | +// "initial-render-data": renderData, |
| 91 | +// }, |
| 92 | +// }); |
| 93 | + |
| 94 | +// console.log(`[augmentWithUI] Created UI resource:`, JSON.stringify(uiResource, null, 2)); |
| 95 | + |
| 96 | +// // Append the UI resource to the tool result content (keep existing content like text data) |
| 97 | +// const augmentedResult = { |
| 98 | +// ...toolResult, |
| 99 | +// content: [...(toolResult.content || []), uiResource], |
| 100 | +// }; |
| 101 | + |
| 102 | +// console.log(`[augmentWithUI] Returning augmented result with ${augmentedResult.content.length} content items`); |
| 103 | +// return augmentedResult; |
| 104 | +// } |
0 commit comments