Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
028d5f6
feat: compile example servers to JavaScript for npm consumption
jerome3o-anthropic Jan 13, 2026
91d5cb1
fix: add type assertion for Nominatim API response
jerome3o-anthropic Jan 13, 2026
2f7f7ee
chore: regenerate schemas
jerome3o-anthropic Jan 13, 2026
e114f51
refactor: split server examples into library and binary entry points
ochafik Jan 13, 2026
0008f2d
refactor: migrate remaining server examples to library/binary structure
ochafik Jan 13, 2026
b42fda5
chore: remove unused server-utils.ts from video-resource-server/src
ochafik Jan 13, 2026
e062feb
update
ochafik Jan 13, 2026
83226c8
Merge main into jerome/compile-examples-to-js
ochafik Jan 14, 2026
b7f614d
fix(build): make Windows-compatible by removing chmod and fixing bun …
ochafik Jan 14, 2026
aa343c6
fix(build): use .ts import for bun compatibility
ochafik Jan 14, 2026
d26eeb1
fix(build): use --external for Windows bun compatibility
ochafik Jan 14, 2026
14321bf
Merge main: add pdf-server with library/binary structure
ochafik Jan 14, 2026
0430ae7
style: fix prettier formatting in pdf-server/main.ts
ochafik Jan 14, 2026
a24dc6b
fix(build): remove quotes from --external for Windows cmd.exe compati…
ochafik Jan 14, 2026
5e72c2a
fix(build): use glob pattern for --external to work on all platforms
ochafik Jan 14, 2026
4bb29a5
fix(build): use */server.js pattern for --external
ochafik Jan 14, 2026
e8bd2e2
fix(build): use *server.js pattern without slash for Windows compatib…
ochafik Jan 14, 2026
421309f
update package-lock
ochafik Jan 14, 2026
4f26ca6
Merge main: resolve conflict in map-server/server.ts
ochafik Jan 14, 2026
a4d443e
chore: regenerate package-lock.json for cross-platform compatibility
ochafik Jan 14, 2026
3e5ebbc
fix(build): use ./server.js instead of glob pattern for Windows compa…
ochafik Jan 14, 2026
f90f9f5
fix(build): use double quotes for banner to fix Windows cmd.exe compa…
ochafik Jan 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 94 additions & 0 deletions examples/basic-server-preact/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/**
* Entry point for running the MCP server.
* Run with: npx mcp-server-basic-preact
* 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 ?? "3001", 10);
await startServer(createServer, { port, name: "Basic MCP App Server (Preact)" });
}
}

main().catch((e) => {
console.error(e);
process.exit(1);
});
24 changes: 16 additions & 8 deletions examples/basic-server-preact/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,14 @@
"directory": "examples/basic-server-preact"
},
"license": "MIT",
"main": "server.ts",
"main": "dist/server.js",
"files": [
"server.ts",
"server-utils.ts",
"dist"
],
"scripts": {
"build": "tsc --noEmit && cross-env INPUT=mcp-app.html vite build",
"build": "tsc --noEmit && cross-env INPUT=mcp-app.html vite build && tsc -p tsconfig.server.json && bun build server.ts --outdir dist --target node && bun build main.ts --outfile dist/index.js --target node --external \"./server.js\" --banner \"#!/usr/bin/env node\"",
"watch": "cross-env INPUT=mcp-app.html vite build --watch",
"serve": "bun --watch server.ts",
"serve": "bun --watch main.ts",
"start": "cross-env NODE_ENV=development npm run build && npm run serve",
"dev": "cross-env NODE_ENV=development concurrently 'npm run watch' 'npm run serve'",
"prepublishOnly": "npm run build"
Expand All @@ -27,19 +25,29 @@
"@modelcontextprotocol/ext-apps": "^0.4.0",
"@modelcontextprotocol/sdk": "^1.24.0",
"preact": "^10.0.0",
"zod": "^4.1.13"
"zod": "^4.1.13",
"cors": "^2.8.5",
"express": "^5.1.0"
},
"devDependencies": {
"@preact/preset-vite": "^2.0.0",
"@types/cors": "^2.8.19",
"@types/express": "^5.0.0",
"@types/node": "^22.0.0",
"concurrently": "^9.2.1",
"cors": "^2.8.5",
"cross-env": "^10.1.0",
"express": "^5.1.0",
"typescript": "^5.9.3",
"vite": "^6.0.0",
"vite-plugin-singlefile": "^2.3.0"
},
"types": "dist/server.d.ts",
"exports": {
".": {
"types": "./dist/server.d.ts",
"default": "./dist/server.js"
}
},
"bin": {
"mcp-server-basic-preact": "dist/index.js"
}
}
19 changes: 1 addition & 18 deletions examples/basic-server-preact/server.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import type { CallToolResult, ReadResourceResult } from "@modelcontextprotocol/sdk/types.js";
import fs from "node:fs/promises";
import path from "node:path";
import { registerAppTool, registerAppResource, RESOURCE_MIME_TYPE } from "@modelcontextprotocol/ext-apps/server";
import { startServer } from "./server-utils.js";

const DIST_DIR = path.join(import.meta.dirname, "dist");

/**
* Creates a new MCP server instance with tools and resources registered.
*/
function createServer(): McpServer {
export function createServer(): McpServer {
const server = new McpServer({
name: "Basic MCP App Server (Preact)",
version: "1.0.0",
Expand Down Expand Up @@ -55,17 +52,3 @@ function createServer(): McpServer {

return server;
}

async function main() {
if (process.argv.includes("--stdio")) {
await createServer().connect(new StdioServerTransport());
} else {
const port = parseInt(process.env.PORT ?? "3001", 10);
await startServer(createServer, { port, name: "Basic MCP App Server (Preact)" });
}
}

main().catch((e) => {
console.error(e);
process.exit(1);
});
17 changes: 17 additions & 0 deletions examples/basic-server-preact/tsconfig.server.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"compilerOptions": {
"target": "ES2022",
"lib": ["ES2022"],
"module": "NodeNext",
"moduleResolution": "NodeNext",
"declaration": true,
"emitDeclarationOnly": true,
"outDir": "./dist",
"rootDir": ".",
"strict": true,
"skipLibCheck": true,
"esModuleInterop": true,
"resolveJsonModule": true
},
"include": ["server.ts"]
}
90 changes: 90 additions & 0 deletions examples/basic-server-react/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/**
* Entry point for running the MCP server.
* Run with: npx @modelcontextprotocol/server-basic-react
* Or: node dist/index.js [--stdio]
*/

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";
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 ?? "3001", 10);
await startServer(createServer, { port, name: "Basic MCP App Server (React)" });
}
}

main().catch((e) => {
console.error(e);
process.exit(1);
});
22 changes: 15 additions & 7 deletions examples/basic-server-react/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,33 @@
"directory": "examples/basic-server-react"
},
"license": "MIT",
"main": "server.ts",
"main": "dist/server.js",
"types": "dist/server.d.ts",
"bin": {
"mcp-server-basic-react": "dist/index.js"
},
"files": [
"server.ts",
"server-utils.ts",
"dist"
],
"exports": {
".": {
"types": "./dist/server.d.ts",
"default": "./dist/server.js"
}
},
"scripts": {
"build": "tsc --noEmit && cross-env INPUT=mcp-app.html vite build",
"build": "tsc --noEmit && cross-env INPUT=mcp-app.html vite build && tsc -p tsconfig.server.json && bun build server.ts --outdir dist --target node && bun build main.ts --outfile dist/index.js --target node --external \"./server.js\" --banner \"#!/usr/bin/env node\"",
"watch": "cross-env INPUT=mcp-app.html vite build --watch",
"serve": "bun --watch server.ts",
"serve": "bun --watch main.ts",
"start": "cross-env NODE_ENV=development npm run build && npm run serve",
"dev": "cross-env NODE_ENV=development concurrently 'npm run watch' 'npm run serve'",
"prepublishOnly": "npm run build"
},
"dependencies": {
"@modelcontextprotocol/ext-apps": "^0.4.0",
"@modelcontextprotocol/sdk": "^1.24.0",
"cors": "^2.8.5",
"express": "^5.1.0",
"react": "^19.2.0",
"react-dom": "^19.2.0",
"zod": "^4.1.13"
Expand All @@ -38,9 +48,7 @@
"@types/react-dom": "^19.2.2",
"@vitejs/plugin-react": "^4.3.4",
"concurrently": "^9.2.1",
"cors": "^2.8.5",
"cross-env": "^10.1.0",
"express": "^5.1.0",
"typescript": "^5.9.3",
"vite": "^6.0.0",
"vite-plugin-singlefile": "^2.3.0"
Expand Down
16 changes: 0 additions & 16 deletions examples/basic-server-react/server.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { registerAppResource, registerAppTool, RESOURCE_MIME_TYPE } from "@modelcontextprotocol/ext-apps/server";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import type { CallToolResult, ReadResourceResult } from "@modelcontextprotocol/sdk/types.js";
import fs from "node:fs/promises";
import path from "node:path";
import { startServer } from "./server-utils.js";

const DIST_DIR = path.join(import.meta.dirname, "dist");

Expand Down Expand Up @@ -52,17 +50,3 @@ export function createServer(): McpServer {

return server;
}

async function main() {
if (process.argv.includes("--stdio")) {
await createServer().connect(new StdioServerTransport());
} else {
const port = parseInt(process.env.PORT ?? "3001", 10);
await startServer(createServer, { port, name: "Basic MCP App Server (React)" });
}
}

main().catch((e) => {
console.error(e);
process.exit(1);
});
17 changes: 17 additions & 0 deletions examples/basic-server-react/tsconfig.server.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"compilerOptions": {
"target": "ES2022",
"lib": ["ES2022"],
"module": "NodeNext",
"moduleResolution": "NodeNext",
"declaration": true,
"emitDeclarationOnly": true,
"outDir": "./dist",
"rootDir": ".",
"strict": true,
"skipLibCheck": true,
"esModuleInterop": true,
"resolveJsonModule": true
},
"include": ["server.ts"]
}
Loading
Loading