1. Create the project
mkdir rack-status && cd rack-status
npm init -y
npm install @modelcontextprotocol/server zodSet "type": "module" in package.json. Tool & prompt schemas use Standard Schema, so Zod v4 is one option; Valibot or ArkType work the same way.
2. Write the server
import { McpServer } from "@modelcontextprotocol/server";
import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
import * as z from "zod/v4";
const server = new McpServer({ name: "rack-status", version: "1.0.0" });
server.registerTool(
"rack_status",
{
description: "Report a rack's power draw and inlet temperature",
inputSchema: z.object({ rack: z.string() }),
},
async ({ rack }) => ({
content: [{ type: "text", text: `${rack}: 14.5 kW, inlet 22 C` }],
})
);
server.registerTool(
"get_time",
{ description: "Current server time, ISO 8601", inputSchema: z.object({}) },
async () => ({ content: [{ type: "text", text: new Date().toISOString() }] })
);
const transport = new StdioServerTransport();
await server.connect(transport);Two tools, one file. registerTool takes the name, a description plus input schema, & the handler; the SDK answers tools/list & tools/call for you.
3. Run it
node server.jsOver stdio the server waits silently for a client. Wire it into a desktop app with the config in Connect a desktop client, or list & call the tools from a client built with @modelcontextprotocol/client.
4. Serve it over HTTP
For remote clients, swap the transport for Streamable HTTP. The SDK publishes thin middleware packages so the server sits inside the web framework you already run:
@modelcontextprotocol/node | Streamable HTTP over Node's IncomingMessage / ServerResponse |
|---|---|
@modelcontextprotocol/express | Express defaults plus Host header validation |
@modelcontextprotocol/fastify | Fastify defaults plus Host header validation |
@modelcontextprotocol/hono | Hono defaults, JSON body parsing hook, Host header validation |
On the fabric you do not pick the middleware: push the repository, name a pool, & the server answers at https://rack-status.<org>.nodemode.dev/mcp. The stdio build stays valid for local use.
Practices we hold servers to
- Validate every argument: type, required fields, length limits, permissions. The schema is the first gate, not the only one.
- No unrestricted shell, file deletion or system commands unless the tool runs in its own sandbox with a stated scope.
- One tool, one job.
search_customer,create_ticket,generate_report, never one tool that does everything.
Sources: the modelcontextprotocol/typescript-sdk README on GitHub (v2, 2026-07-28 spec), fetched 2026-09-03; the v1 shape is from a June 2026 walkthrough of the older @modelcontextprotocol/sdk API.