ext-apps/examples/debug-server/main.ts
Olivier Chafik 8a877b36b4
feat(debug-server): add interactive debug server example (#321)
* feat(examples): add debug-server example

A comprehensive debug/development server for testing MCP Apps SDK features:
- Vanilla TypeScript UI with collapsible panels
- Message visualization (sent, received, errors)
- Server tool calling interface
- Multiple tool endpoints for testing

* refactor(debug-server): convert to React

- Replace vanilla TypeScript with React components
- Add comprehensive Host Styles panel showing all CSS variables grouped by category
- Use React hooks (useApp, useHostStyles, useAutoResize)
- Cleaner state management with useReducer for event log
- Collapsible sections for better organization
- CSS modules for scoped styling

* fix(debug-server): correct server name in main.ts

* Revert "refactor(debug-server): convert to React"

This reverts commit 5d22d2daa9a98ba412892447202ef10fbdb62f5b.

* fix(debug-server): update default values for multipleBlocks and includeMeta

* fix(debug-server): correct serve script and server name

- serve script now runs main.ts instead of server.ts
- Updated server name to 'Debug Server'
- Fixed npx command in comment

* fix: increase maxHeight to 6000px and add tools capability to debug app

- basic-host: Increase maxHeight from 600 to 6000px
- debug-server: Add tools capability to enable oncalltool/onlisttools handlers

* fix(debug-server): use consistent callback names for event tracking

Event types now match callback names (ontoolinput, ontoolresult, etc.)
so the Callback Status panel shows correct counts and payloads.

* feat(debug-server): add Update (Image) button for model context

* feat(debug-server): add expandable event log entries

- Click on any event log row to expand/collapse
- Arrow indicator rotates when expanded
- Full JSON payload shown indented in pre block
- Max height with scroll for large payloads

* style(debug-server): format long line in fullPayload function

* test(debug-server): add to E2E tests and screenshot specs

* chore: regenerate package-lock.json for cross-platform compatibility

* update dep
2026-01-23 12:39:40 +00:00

94 lines
2.6 KiB
TypeScript

/**
* Entry point for running the MCP server.
* Run with: npx mcp-server-debug
* Or: node dist/index.js [--stdio]
*/
/**
* Shared utilities for running MCP servers with Streamable HTTP transport.
*/
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js";
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import cors from "cors";
import type { Request, Response } from "express";
import { createServer } from "./server.js";
export interface ServerOptions {
port: number;
name?: string;
}
/**
* Starts an MCP server with Streamable HTTP transport in stateless mode.
*
* @param createServer - Factory function that creates a new McpServer instance per request.
* @param options - Server configuration options.
*/
export async function startServer(
createServer: () => McpServer,
options: ServerOptions,
): Promise<void> {
const { port, name = "MCP Server" } = options;
const app = createMcpExpressApp({ host: "0.0.0.0" });
app.use(cors());
app.all("/mcp", async (req: Request, res: Response) => {
const server = createServer();
const transport = new StreamableHTTPServerTransport({
sessionIdGenerator: undefined,
});
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 httpServer = app.listen(port, (err) => {
if (err) {
console.error("Failed to start server:", err);
process.exit(1);
}
console.log(`${name} listening on http://localhost:${port}/mcp`);
});
const shutdown = () => {
console.log("\nShutting down...");
httpServer.close(() => process.exit(0));
};
process.on("SIGINT", shutdown);
process.on("SIGTERM", shutdown);
}
async function main() {
if (process.argv.includes("--stdio")) {
await createServer().connect(new StdioServerTransport());
} else {
const port = parseInt(process.env.PORT ?? "3110", 10);
await startServer(createServer, { port, name: "Debug Server" });
}
}
main().catch((e) => {
console.error(e);
process.exit(1);
});