@ubuligan/create-mcp-server
v0.2.0
Published
Scaffold a production-ready MCP server (auth, rate limit, logging, deploy) in one command.
Maintainers
Readme
create-mcp-server
Scaffold a production-ready Model Context Protocol server in one command — not just a bare stub, but auth, rate limiting, structured logging, and deployment configs wired in from the start.
npm create @ubuligan/mcp-server my-server
# or
npx @ubuligan/create-mcp-server my-serverWhat you get
- Transports — Streamable HTTP (remote) and/or stdio (local clients like Claude Desktop). The entry point auto-selects at runtime.
- Auth (HTTP) — API key / Bearer, OAuth 2.1 resource server (JWKS +
.well-known/oauth-protected-resource), or a pluggable hook. - Rate limiting (HTTP) — fixed-window limiter keyed by auth identity, with
RateLimit-*headers. - Logging — structured
pinoto stderr (safe for stdio), with secret redaction. - Deployment — Docker (multi-stage), Cloudflare Workers, Fly/Railway/Vercel notes, Smithery manifest.
- DX — TypeScript,
tsxdev watch,tsupbuild,vitesttests, zod-validated env config.
Usage
Interactive:
npx @ubuligan/create-mcp-serverNon-interactive (CI / scripted):
npx @ubuligan/create-mcp-server api \
--transport http --auth oauth --deploy docker,cloudflare --yesOptions
| Flag | Description |
| --- | --- |
| -y, --yes | Accept defaults, skip prompts |
| -d, --description <s> | Project description |
| --transport <list> | stdio,http |
| --auth <mode> | apikey | oauth | none (HTTP only) |
| --deploy <list> | docker,cloudflare,vercel,smithery |
| --pm <name> | npm | pnpm | yarn | bun (default: auto-detect) |
| --no-install | Skip dependency install |
| --no-git | Skip git init |
Running the generated server
After scaffolding:
cd my-server
npm install
npm run buildstdio (local clients) — the server speaks MCP over stdin/stdout:
node dist/index.jsHTTP (remote) — Express server exposing /mcp and /health:
PORT=3000 node dist/index.js
curl http://localhost:3000/health # -> 200For HTTP with auth, set the relevant env (see the generated .env.example):
# apikey
MCP_API_KEY=secret PORT=3000 node dist/index.js
# call with: Authorization: Bearer secretConnecting a client
Claude Desktop
Add to claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/, Windows: %APPDATA%\Claude\), then restart Claude:
{
"mcpServers": {
"my-server": {
"command": "node",
"args": ["/absolute/path/my-server/dist/index.js"]
}
}
}Claude Code
# local (stdio)
claude mcp add my-server -- node /absolute/path/my-server/dist/index.js
# remote (HTTP)
claude mcp add --transport http my-server http://localhost:3000/mcpCursor / other clients
Any MCP-compatible client uses the same shape: command + args for stdio, or the /mcp URL for HTTP. The client lists your tools and calls them on demand.
Adding a tool
Tools live in src/tools/. Copy the echo pattern — export an input shape, a pure handler, and a register function:
// src/tools/weather.ts
import { z } from "zod";
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
export const weatherInput = {
city: z.string().describe("City name"),
};
export async function weather({ city }: { city: string }) {
const r = await fetch(`https://api.example.com/weather?q=${city}`);
const data = await r.json();
return { content: [{ type: "text" as const, text: `${city}: ${data.temp}°C` }] };
}
export function registerWeather(server: McpServer): void {
server.registerTool(
"weather",
{ title: "Weather", description: "Get weather for a city.", inputSchema: weatherInput },
weather,
);
}Register it in src/tools/index.ts:
import { registerWeather } from "./weather.js";
export function registerTools(server: McpServer): void {
registerEcho(server);
registerWeather(server); // <- add
}The handler is exported separately so you can unit-test it without a transport — see test/echo.test.ts. Rebuild (npm run build) and the client picks up the new tool.
Development (this generator)
npm install
npm run build # bundle CLI + copy templates into dist/
npm test # unit tests (scaffold into a temp dir)
RUN_E2E=1 npm test # also install + typecheck + build generated projectsHow it works
The generator composes template directories (src/templates/*) by selected
features, deep-merges each feature's package.partial.json, and substitutes
__TOKEN__ placeholders. See src/generator/ for the engine.
License
MIT
