From dee17f29ca0a5299b77958f6525b4e8d5f29bcd7 Mon Sep 17 00:00:00 2001 From: Anton Pidkuiko MacBook Date: Wed, 7 Jan 2026 12:36:59 +0000 Subject: [PATCH] fix(examples): add missing server-utils.ts to video-resource-server The server was importing from ../shared/server-utils.js which doesn't exist. Added the standard server-utils.ts file (matching other examples) and updated the import path to ./src/server-utils.js. --- examples/video-resource-server/server.ts | 10 +- .../video-resource-server/src/server-utils.ts | 110 ++++++++++++++++++ 2 files changed, 112 insertions(+), 8 deletions(-) create mode 100644 examples/video-resource-server/src/server-utils.ts diff --git a/examples/video-resource-server/server.ts b/examples/video-resource-server/server.ts index 0c3ae160..2ee36bf4 100644 --- a/examples/video-resource-server/server.ts +++ b/examples/video-resource-server/server.ts @@ -8,7 +8,6 @@ import { McpServer, ResourceTemplate, } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import type { CallToolResult, ReadResourceResult, @@ -22,7 +21,7 @@ import { RESOURCE_MIME_TYPE, RESOURCE_URI_META_KEY, } from "@modelcontextprotocol/ext-apps/server"; -import { startServer } from "../shared/server-utils.js"; +import { startServer } from "./src/server-utils.js"; const DIST_DIR = path.join(import.meta.dirname, "dist"); const RESOURCE_URI = "ui://video-player/mcp-app.html"; @@ -169,12 +168,7 @@ ${Object.entries(VIDEO_LIBRARY) } async function main() { - if (process.argv.includes("--stdio")) { - await createServer().connect(new StdioServerTransport()); - } else { - const port = parseInt(process.env.PORT ?? "3105", 10); - await startServer(createServer, { port, name: "Video Resource Server" }); - } + await startServer(createServer); } main().catch((e) => { diff --git a/examples/video-resource-server/src/server-utils.ts b/examples/video-resource-server/src/server-utils.ts new file mode 100644 index 00000000..40524237 --- /dev/null +++ b/examples/video-resource-server/src/server-utils.ts @@ -0,0 +1,110 @@ +/** + * Shared utilities for running MCP servers with various transports. + */ + +import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js"; +import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; +import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; +import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js"; +import cors from "cors"; +import type { Request, Response } from "express"; + +/** + * Starts an MCP server using the appropriate transport based on command-line arguments. + * + * If `--stdio` is passed, uses stdio transport. Otherwise, uses Streamable HTTP transport. + * + * @param createServer - Factory function that creates a new McpServer instance. + */ +export async function startServer( + createServer: () => McpServer, +): Promise { + try { + if (process.argv.includes("--stdio")) { + await startStdioServer(createServer); + } else { + await startStreamableHttpServer(createServer); + } + } catch (e) { + console.error(e); + process.exit(1); + } +} + +/** + * Starts an MCP server with stdio transport. + * + * @param createServer - Factory function that creates a new McpServer instance. + */ +export async function startStdioServer( + createServer: () => McpServer, +): Promise { + await createServer().connect(new StdioServerTransport()); +} + +/** + * Starts an MCP server with Streamable HTTP transport in stateless mode. + * + * Each request creates a fresh server and transport instance, which are + * closed when the response ends (no session tracking). + * + * The server listens on the port specified by the PORT environment variable, + * defaulting to 3001 if not set. + * + * @param createServer - Factory function that creates a new McpServer instance per request. + */ +export async function startStreamableHttpServer( + createServer: () => McpServer, +): Promise { + const port = parseInt(process.env.PORT ?? "3001", 10); + + // Express app - bind to all interfaces for development/testing + const expressApp = createMcpExpressApp({ host: "0.0.0.0" }); + expressApp.use(cors()); + + expressApp.all("/mcp", async (req: Request, res: Response) => { + // Create fresh server and transport for each request (stateless mode) + const server = createServer(); + const transport = new StreamableHTTPServerTransport({ + sessionIdGenerator: undefined, + }); + + // Clean up when response ends + res.on("close", () => { + transport.close().catch(() => {}); + server.close().catch(() => {}); + }); + + try { + await server.connect(transport); + await transport.handleRequest(req, res, req.body); + } catch (error) { + console.error("MCP error:", error); + if (!res.headersSent) { + res.status(500).json({ + jsonrpc: "2.0", + error: { code: -32603, message: "Internal server error" }, + id: null, + }); + } + } + }); + + const { promise, resolve, reject } = Promise.withResolvers(); + + const httpServer = expressApp.listen(port, (err?: Error) => { + if (err) return reject(err); + console.log(`Server listening on http://localhost:${port}/mcp`); + resolve(); + }); + + const shutdown = () => { + console.log("\nShutting down..."); + httpServer.close(() => process.exit(0)); + }; + + process.on("SIGINT", shutdown); + process.on("SIGTERM", shutdown); + + return promise; +}