Build a Production-Ready MCP Server with TypeScript: A Complete Guide
The Model Context Protocol (MCP) has emerged as a game-changer in the AI ecosystem, enabling developers to build servers that expose data and functionality to Large Language Models in a standardized way. In this comprehensive guide, we'll walk through building a production-ready MCP server with TypeScript, implementing secure HTTP transport for public exposure, and deploying it to Smithery and mcp.so.
What is MCP and Why Does It Matter in 2026?
The Model Context Protocol is rapidly becoming the de facto standard for AI-tool integration. With the explosion of AI agents and copilots in 2026, the need for standardized, secure ways to connect LLMs to external tools and data sources has never been greater.
MCP servers allow you to:
- Expose data through Resources (like GET endpoints)
- Provide functionality through Tools (like POST endpoints)
- Define interaction patterns through Prompts (reusable templates)
Unlike traditional REST APIs, MCP is specifically designed for AI interactions, providing built-in support for structured tool calling, context management, and capability negotiation between clients and servers.
Setting Up Your TypeScript MCP Server
Prerequisites
- Node.js 18+
- TypeScript 5.0+
- npm or yarn
Installation
npm init -y
npm install @modelcontextprotocol/sdk zod express cors
npm install -D typescript @types/node @types/express @types/cors tsx
Project Structure
mcp-data-api/
├── src/
│ ├── index.ts # Main entry point
│ ├── server.ts # MCP server implementation
│ ├── resources/ # Resource handlers
│ ├── tools/ # Tool implementations
│ └── transports/ # Transport configurations
├── tsconfig.json
├── package.json
└── Dockerfile
Implementing StreamableHTTPServerTransport
The StreamableHTTPServerTransport is essential for exposing your MCP server publicly. Unlike stdio (which requires local process communication), HTTP transport allows remote AI clients to connect.
Why Streamable HTTP?
- Remote Access: Clients can connect from anywhere
- Scalability: Works with load balancers and container orchestration
- Standard Integration: Uses familiar HTTP/HTTPS protocols
DNS Rebinding Protection
When exposing MCP servers publicly, DNS rebinding attacks are a significant threat. Here's how to protect your server:
Origin Validation Middleware
app.use((req, res, next) => {
const allowedOrigins = [
"https://your-production-domain.com",
"https://smithery.ai",
"https://mcp.so"
];
const origin = req.headers.origin;
if (origin && !allowedOrigins.includes(origin)) {
return res.status(403).json({ error: "Origin not allowed" });
}
next();
});
Secret Token Validation
const API_SECRET = process.env.MCP_API_SECRET;
app.use("/mcp", (req, res, next) => {
const secret = req.headers["x-mcp-secret"];
if (!secret || secret !== API_SECRET) {
return res.status(401).json({ error: "Invalid or missing secret" });
}
next();
});
Deployment to Smithery
Smithery provides an excellent platform for hosting MCP servers with built-in discovery, OAuth support, and client configuration management.
# Install Smithery CLI
npm install -g @smithery/cli
# Authenticate
smithery login
# Publish your server
smithery mcp publish "https://api.your-domain.com/mcp" -n @your-org/mcp-data-api
Best Practices for Production
- Health Checks: Implement
/healthendpoint for container orchestration - Rate Limiting: Use express-rate-limit to prevent abuse
- Logging: Implement structured logging with request IDs
- Metrics: Add Prometheus metrics for monitoring
- Graceful Shutdown: Handle SIGTERM properly
- CORS Configuration: Be explicit about allowed origins
Conclusion
Building a production-ready MCP server with TypeScript is straightforward with the official SDK. The key considerations for public exposure are:
- Implement proper DNS rebinding protection
- Use HTTPS in production
- Add secret token validation
- Configure allowed origins carefully
- Deploy to platforms like Smithery for easy discovery
Star, fork, and contribute to the project!