Templatetypescriptbeginnerโœ“ Production ReadyFree

TypeScript MCP Server Starter

Production-ready TypeScript MCP server with HTTP transport, API key auth, structured logging, health monitoring, and Docker support

๐Ÿ“– 12 minโš™๏ธ Setup: 15 minutilities
typescriptmcpexpresshttp-transportapi-key-authpinozodjestsupertestdocker

Files(18)

{
  "name": "typescript-mcp-starter",
  "version": "1.0.0",
  "description": "Production-ready TypeScript MCP server with HTTP transport and API key auth",
  "main": "dist/server.js",
  "scripts": {
    "build": "tsc",
    "start": "node dist/server.js",
    "dev": "ts-node-dev --respawn --transpile-only src/server.ts",
    "test": "jest",
    "test:watch": "jest --watch",
    "test:coverage": "jest --coverage",
    "lint": "eslint src --ext .ts",
    "typecheck": "tsc --noEmit"
  },
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.12.0",
    "express": "^4.19.2",
    "marked": "^12.0.0",
    "pino": "^9.2.0",
    "zod": "^3.23.8"
  },
  "devDependencies": {
    "@types/express": "^4.17.21",
    "@types/jest": "^29.5.12",
    "@types/node": "^20.14.0",
    "@types/supertest": "^6.0.2",
    "jest": "^29.7.0",
    "pino-pretty": "^11.2.1",
    "supertest": "^7.0.0",
    "ts-jest": "^29.1.4",
    "ts-node-dev": "^2.0.0",
    "typescript": "^5.4.5"
  },
  "engines": {
    "node": ">=20"
  }
}

TypeScript MCP Server Starter

A production-ready TypeScript MCP server template using HTTP transport with API key authentication, structured logging, health monitoring, and Docker support.

Overview

This template gives you a solid foundation for building Model Context Protocol (MCP) servers in TypeScript. It uses HTTP transport so your server can be deployed as a standard web service and called by any MCP-compatible client including Claude Desktop, Cursor, and Windsurf. Authentication is handled via API keys passed in request headers, making it straightforward to secure your server without complex OAuth flows.

The template is designed for developers who are new to MCP but comfortable with TypeScript and Node.js. Every piece of the stack โ€” logging, configuration, authentication, health checks, and testing โ€” is wired up and working out of the box. You clone the repo, set your environment variables, run docker compose up, and you have a running MCP server ready to extend with your own tools.

Inside you will find three realistic tool implementations: a text analysis tool that counts words, sentences, and estimates reading time; a URL metadata fetcher that retrieves page titles and descriptions; and a Markdown-to-plain-text converter. These serve as practical examples of how to validate inputs, handle errors gracefully, and return well-structured responses โ€” patterns you will apply directly to your own domain-specific tools.

What You'll Learn

  • How to structure a TypeScript MCP server project for maintainability and growth
  • Registering tools with the MCP SDK including input schemas and typed handlers
  • Implementing API key authentication as Express middleware
  • Loading and validating configuration from environment variables with Zod
  • Setting up Pino for structured JSON logging with request correlation IDs
  • Building a /health endpoint that returns dependency status as structured JSON
  • Writing unit and integration tests for MCP tools using Jest and Supertest
  • Containerising a Node.js service with a multi-stage Dockerfile and Docker Compose

Architecture

HTTP Client / MCP Host
        โ”‚
        โ–ผ
  Express Server
  โ”œโ”€โ”€ POST /mcp        โ† MCP tool calls (requires X-API-Key header)
  โ”œโ”€โ”€ GET  /mcp        โ† SSE stream for server-sent events
  โ”œโ”€โ”€ DELETE /mcp      โ† Session teardown
  โ””โ”€โ”€ GET  /health     โ† Dependency & liveness check (no auth)
        โ”‚
        โ–ผ
  McpServer (SDK)
  โ”œโ”€โ”€ analyzeText      โ† Word / sentence / reading-time stats
  โ”œโ”€โ”€ fetchUrlMetadata โ† Page title + description via HTTP
  โ””โ”€โ”€ markdownToText   โ† Strip Markdown โ†’ plain text

Requests arrive at Express. The requireApiKey middleware rejects any request to /mcp that is missing or has an incorrect X-API-Key header. Valid requests are forwarded to a StreamableHTTPServerTransport instance which handles the MCP wire protocol and dispatches to the registered tool handlers.

Project Structure

.
โ”œโ”€โ”€ src/
โ”‚   โ”œโ”€โ”€ __tests__/
โ”‚   โ”‚   โ”œโ”€โ”€ setup.ts          # Jest global env setup
โ”‚   โ”‚   โ”œโ”€โ”€ health.test.ts    # Health endpoint tests
โ”‚   โ”‚   โ””โ”€โ”€ server.test.ts    # Auth + MCP protocol tests
โ”‚   โ”œโ”€โ”€ tools/
โ”‚   โ”‚   โ”œโ”€โ”€ analyzeText.ts    # Text statistics tool
โ”‚   โ”‚   โ”œโ”€โ”€ fetchUrlMetadata.ts # URL metadata tool
โ”‚   โ”‚   โ””โ”€โ”€ markdownToText.ts # Markdown converter tool
โ”‚   โ”œโ”€โ”€ auth.ts               # API key middleware
โ”‚   โ”œโ”€โ”€ config.ts             # Zod-validated env config
โ”‚   โ”œโ”€โ”€ health.ts             # Health check handler
โ”‚   โ”œโ”€โ”€ logger.ts             # Pino logger setup
โ”‚   โ””โ”€โ”€ server.ts             # Express app + MCP wiring
โ”œโ”€โ”€ .env.example              # Environment variable documentation
โ”œโ”€โ”€ Dockerfile                # Multi-stage production image
โ”œโ”€โ”€ docker-compose.yml        # Local / CI compose file
โ”œโ”€โ”€ jest.config.ts            # Jest configuration
โ”œโ”€โ”€ package.json
โ””โ”€โ”€ tsconfig.json

Prerequisites

  • Node.js 20+ โ€” required by the engines field in package.json
  • npm 10+ โ€” ships with Node.js 20
  • Docker + Docker Compose โ€” for the containerised workflow (optional)
  • Basic familiarity with TypeScript and Express

Quick Start

Local development

# 1. Clone and install
git clone <your-repo-url>
cd typescript-mcp-starter
npm install

# 2. Configure environment
cp .env.example .env
# Edit .env and set MCP_API_KEY to a strong random value:
# openssl rand -hex 32

# 3. Start the dev server (hot-reload)
npm run dev

# 4. Verify health
curl http://localhost:3000/health

# 5. Call a tool
curl -X POST http://localhost:3000/mcp \
  -H 'Content-Type: application/json' \
  -H 'X-API-Key: <your-key>' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'

Docker

cp .env.example .env   # fill in MCP_API_KEY
docker compose up --build

Features

FeatureDetails
HTTP transportStreamableHTTPServerTransport โ€” works with any MCP-compatible host
API key authX-API-Key header validated by Express middleware
Zod configAll env vars validated at startup; process exits on misconfiguration
Pino loggingPretty in dev, JSON in production; configurable log level
Health endpointGET /health returns dependency status; no auth required
3 example toolsanalyzeText, fetchUrlMetadata, markdownToText
Full test suiteJest + Supertest; covers auth, health, and tool behaviour
DockerMulti-stage image; drops to node user; includes HEALTHCHECK

Works With

  • Claude Desktop โ€” add the server URL and API key to claude_desktop_config.json
  • Cursor โ€” configure under Settings โ†’ MCP Servers
  • Windsurf โ€” add to your MCP configuration file
  • Any MCP-compatible client that supports HTTP transport

Claude Desktop configuration example

{
  "mcpServers": {
    "my-server": {
      "url": "http://localhost:3000/mcp",
      "headers": {
        "X-API-Key": "your-api-key-here"
      }
    }
  }
}

Configuration

All configuration is read from environment variables. Copy .env.example to .env and adjust as needed.

VariableRequiredDefaultDescription
MCP_API_KEYโœ…โ€”API key clients must send in X-API-Key header. Min 16 chars.
PORT3000TCP port the server listens on
NODE_ENVdevelopmentdevelopment | production | test
LOG_LEVELinfotrace | debug | info | warn | error | fatal
REQUEST_TIMEOUT_MS30000Timeout for outbound HTTP requests (ms)
MAX_URL_REDIRECTS5Max redirects followed by fetchUrlMetadata

Generate a strong API key:

openssl rand -hex 32

Deployment

Railway / Render / Fly.io

  1. Push your repo to GitHub.
  2. Create a new service pointing at the repo.
  3. Set the environment variables listed above in the platform's dashboard.
  4. The platform will detect the Dockerfile and build automatically.

Manual VPS

# Build the production image
docker build -t mcp-server .

# Run with env vars from a .env file
docker run -d \
  --name mcp-server \
  -p 3000:3000 \
  --env-file .env \
  --restart unless-stopped \
  mcp-server

Production Checklist

  • MCP_API_KEY is set to a cryptographically random value of โ‰ฅ 32 characters
  • NODE_ENV=production is set (enables JSON logging)
  • LOG_LEVEL=info or higher (avoid debug/trace in prod)
  • Server is behind a TLS-terminating reverse proxy (nginx, Caddy, ALB, etc.)
  • Health endpoint is wired to your load balancer / container orchestrator
  • Docker image is built from the runner stage (not builder)
  • Container runs as the node user (non-root)
  • .env is in .gitignore and never committed
  • Dependency audit: npm audit --omit=dev

Testing

# Run all tests
npm test

# Watch mode
npm run test:watch

# Coverage report
npm run test:coverage

The test suite covers:

  • health.test.ts โ€” GET /health shape, timestamp validity, no-auth access, uptime format
  • server.test.ts โ€” authentication (missing key, wrong key, valid key), tools/list response shape, tool call happy-paths and error cases

Tests use a shared setup.ts that injects safe test values for all required environment variables before any module is imported.