feat: compile example servers to JavaScript for npm consumption (#259)
* feat: compile example servers to JavaScript for npm consumption
Add TypeScript compilation for server code so the example packages can be
imported and used by consumers without requiring TypeScript compilation.
Changes:
- Add tsconfig.server.json to each example for compiling server code
- Update package.json exports to point to compiled dist/server/server.js
- Add types field pointing to dist/server/server.d.ts
- Update build scripts to include server compilation step
- Fix .ts import extensions to .js in customer-segmentation-server
This enables importing the createServer function from published packages:
import { createServer } from '@modelcontextprotocol/server-basic-react';
* fix: add type assertion for Nominatim API response
* chore: regenerate schemas
* refactor: split server examples into library and binary entry points
- server.ts: exports createServer() only (library entry point)
- main.ts: entry point with main() that runs the server (binary)
- package.json: adds bin field for npx support, uses inline bun build
- tsconfig.server.json: emitDeclarationOnly, outputs to dist/
This allows:
1. Importing the server as a library: import { createServer } from '@modelcontextprotocol/server-basic-react'
2. Running with npx: npx @modelcontextprotocol/server-basic-react [--stdio]
Added migration script at scripts/migrate-server-examples.ts
* refactor: migrate remaining server examples to library/binary structure
Apply the same refactoring to all 13 remaining server examples:
- scenario-modeler-server, shadertoy-server, map-server
- cohort-heatmap-server, customer-segmentation-server, video-resource-server
- system-monitor-server, budget-allocator-server, sheet-music-server
- threejs-server, integration-server, transcript-server, wiki-explorer-server
Each now has:
- server.ts: exports createServer() (library)
- main.ts: runs the server (binary with shebang)
- bin field in package.json for npx support
* chore: remove unused server-utils.ts from video-resource-server/src
* update
* fix(build): make Windows-compatible by removing chmod and fixing bun externals
- Remove 'chmod +x dist/index.js' which doesn't exist on Windows
- Add '--external ./server.js' to prevent bun from treating the import as a second entry point
* fix(build): use .ts import for bun compatibility
- Change import from './server.js' to './server.ts' in main.ts files
- Remove --external flag since bun should inline everything
- Fixes Windows build where bun couldn't resolve .js to .ts properly
* fix(build): use --external for Windows bun compatibility
Bun on Windows incorrectly treats imported .ts files as entry points.
Use --external './server.js' to work around this, creating a runtime
dependency between index.js and server.js.
* style: fix prettier formatting in pdf-server/main.ts
* fix(build): remove quotes from --external for Windows cmd.exe compatibility
* fix(build): use glob pattern for --external to work on all platforms
The literal path --external ./server.js was not matching the import.
Using glob pattern --external "./server*" correctly externalizes the server module.
* fix(build): use */server.js pattern for --external
The "./server*" pattern was not matching on Windows.
Using "*/server.js" matches any path ending in /server.js which works cross-platform.
* fix(build): use *server.js pattern without slash for Windows compatibility
* update package-lock
* chore: regenerate package-lock.json for cross-platform compatibility
* fix(build): use ./server.js instead of glob pattern for Windows compatibility
* fix(build): use double quotes for banner to fix Windows cmd.exe compatibility
---------
Co-authored-by: Olivier Chafik <ochafik@anthropic.com>
This commit is contained in:
parent
75cbf8612c
commit
65a62a9fae
99 changed files with 2378 additions and 1740 deletions
94
examples/basic-server-preact/main.ts
Normal file
94
examples/basic-server-preact/main.ts
Normal file
|
|
@ -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);
|
||||
});
|
||||
|
|
@ -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"
|
||||
|
|
@ -27,7 +25,9 @@
|
|||
"@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",
|
||||
|
|
@ -35,11 +35,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"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
@ -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
examples/basic-server-preact/tsconfig.server.json
Normal file
17
examples/basic-server-preact/tsconfig.server.json
Normal file
|
|
@ -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
examples/basic-server-react/main.ts
Normal file
90
examples/basic-server-react/main.ts
Normal file
|
|
@ -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);
|
||||
});
|
||||
|
|
@ -9,16 +9,24 @@
|
|||
"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"
|
||||
|
|
@ -26,6 +34,8 @@
|
|||
"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"
|
||||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
||||
|
|
@ -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
examples/basic-server-react/tsconfig.server.json
Normal file
17
examples/basic-server-react/tsconfig.server.json
Normal file
|
|
@ -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"]
|
||||
}
|
||||
|
|
@ -1,12 +1,20 @@
|
|||
/**
|
||||
* Entry point for running the MCP server.
|
||||
* Run with: npx mcp-server-basic-solid
|
||||
* 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;
|
||||
|
|
@ -70,3 +78,17 @@ export async function startServer(
|
|||
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 (Solid)" });
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((e) => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
});
|
||||
|
|
@ -9,16 +9,14 @@
|
|||
"directory": "examples/basic-server-solid"
|
||||
},
|
||||
"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"
|
||||
|
|
@ -27,19 +25,29 @@
|
|||
"@modelcontextprotocol/ext-apps": "^0.4.0",
|
||||
"@modelcontextprotocol/sdk": "^1.24.0",
|
||||
"solid-js": "^1.9.0",
|
||||
"zod": "^4.1.13"
|
||||
"zod": "^4.1.13",
|
||||
"cors": "^2.8.5",
|
||||
"express": "^5.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@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",
|
||||
"vite-plugin-solid": "^2.0.0"
|
||||
},
|
||||
"types": "dist/server.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/server.d.ts",
|
||||
"default": "./dist/server.js"
|
||||
}
|
||||
},
|
||||
"bin": {
|
||||
"mcp-server-basic-solid": "dist/index.js"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 (Solid)",
|
||||
version: "1.0.0",
|
||||
|
|
@ -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 (Solid)" });
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((e) => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
});
|
||||
|
|
|
|||
17
examples/basic-server-solid/tsconfig.server.json
Normal file
17
examples/basic-server-solid/tsconfig.server.json
Normal file
|
|
@ -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"]
|
||||
}
|
||||
94
examples/basic-server-svelte/main.ts
Normal file
94
examples/basic-server-svelte/main.ts
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
/**
|
||||
* Entry point for running the MCP server.
|
||||
* Run with: npx mcp-server-basic-svelte
|
||||
* 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 (Svelte)" });
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((e) => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
});
|
||||
|
|
@ -9,16 +9,14 @@
|
|||
"directory": "examples/basic-server-svelte"
|
||||
},
|
||||
"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"
|
||||
|
|
@ -27,7 +25,9 @@
|
|||
"@modelcontextprotocol/ext-apps": "^0.4.0",
|
||||
"@modelcontextprotocol/sdk": "^1.24.0",
|
||||
"svelte": "^5.0.0",
|
||||
"zod": "^4.1.13"
|
||||
"zod": "^4.1.13",
|
||||
"cors": "^2.8.5",
|
||||
"express": "^5.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/vite-plugin-svelte": "^5.0.0",
|
||||
|
|
@ -35,11 +35,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-svelte": "dist/index.js"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 (Svelte)",
|
||||
version: "1.0.0",
|
||||
|
|
@ -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 (Svelte)" });
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((e) => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
});
|
||||
|
|
|
|||
17
examples/basic-server-svelte/tsconfig.server.json
Normal file
17
examples/basic-server-svelte/tsconfig.server.json
Normal file
|
|
@ -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"]
|
||||
}
|
||||
94
examples/basic-server-vanillajs/main.ts
Normal file
94
examples/basic-server-vanillajs/main.ts
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
/**
|
||||
* Entry point for running the MCP server.
|
||||
* Run with: npx mcp-server-basic-vanillajs
|
||||
* 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 ?? "3102", 10);
|
||||
await startServer(createServer, { port, name: "Basic MCP App Server (Vanilla JS)" });
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((e) => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
});
|
||||
|
|
@ -9,16 +9,14 @@
|
|||
"directory": "examples/basic-server-vanillajs"
|
||||
},
|
||||
"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"
|
||||
|
|
@ -26,18 +24,28 @@
|
|||
"dependencies": {
|
||||
"@modelcontextprotocol/ext-apps": "^0.4.0",
|
||||
"@modelcontextprotocol/sdk": "^1.24.0",
|
||||
"zod": "^4.1.13"
|
||||
"zod": "^4.1.13",
|
||||
"cors": "^2.8.5",
|
||||
"express": "^5.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@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-vanillajs": "dist/index.js"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,9 @@
|
|||
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 { z } from "zod";
|
||||
import { startServer } from "./server-utils.js";
|
||||
|
||||
const DIST_DIR = path.join(import.meta.dirname, "dist");
|
||||
|
||||
/**
|
||||
|
|
@ -62,17 +59,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 ?? "3102", 10);
|
||||
await startServer(createServer, { port, name: "Basic MCP App Server (Vanilla JS)" });
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((e) => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
});
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue