import { McpServer, type CallToolResult, type ReadResourceResult, } from "@modelcontextprotocol/server"; import fs from "node:fs/promises"; import path from "node:path"; import { registerAppTool, registerAppResource, RESOURCE_MIME_TYPE, } from "@modelcontextprotocol/ext-apps/server"; import { z } from "zod"; // Works both from source (server.ts) and compiled (dist/server.js) const DIST_DIR = import.meta.filename.endsWith(".ts") ? path.join(import.meta.dirname, "dist") : import.meta.dirname; const resourceUri = "ui://transcript/mcp-app.html"; /** * Creates a new MCP server instance with tools and resources registered. */ export function createServer(): McpServer { const server = new McpServer({ name: "Transcript Server", version: "1.0.0", }); // Register the transcribe tool - opens a UI for live speech transcription registerAppTool( server, "transcribe", { title: "Transcribe Speech", description: "Opens a live speech transcription interface using the Web Speech API.", inputSchema: z.object({}), _meta: { ui: { resourceUri } }, }, async (): Promise => { return { content: [ { type: "text", text: JSON.stringify({ status: "ready", message: "Transcription UI opened. Speak into your microphone.", }), }, ], }; }, ); // Register the UI resource registerAppResource( server, resourceUri, resourceUri, { mimeType: RESOURCE_MIME_TYPE, description: "Transcript UI" }, async (): Promise => { const html = await fs.readFile( path.join(DIST_DIR, "mcp-app.html"), "utf-8", ); return { contents: [ { uri: resourceUri, mimeType: RESOURCE_MIME_TYPE, text: html, _meta: { ui: { // Request microphone for Web Speech API, clipboard for copy button permissions: { microphone: {}, clipboardWrite: {} }, }, }, }, ], }; }, ); return server; }