Building Production Model Context Protocol (MCP) Servers in 2026
The Model Context Protocol (MCP) has evolved from an open-source standard created by Anthropic into the industry-wide integration foundation stewarded by the Linux Foundation's Agentic AI Foundation. Often described as the "USB-C port for AI", MCP provides a unified standard that allows developer IDEs (Cursor, VS Code, Claude Code) and autonomous terminal agents to seamlessly interact with local databases, cloud APIs, and developer tools.
1. MCP Transports: Stdio vs Streamable HTTP
MCP supports two core communication transports:
- Stdio Transport: The AI host process spawns your server executable as a child process and communicates via JSON-RPC 2.0 lines over standard input (stdin) and standard output (stdout). This is optimal for local CLI utilities, Git tools, and file-based scripts.
- Streamable HTTP Transport: Built for remote microservices and team-shared tools. Operates over standard HTTP(S) with streaming responses, allowing horizontal scaling behind reverse proxies without persistent WebSocket bottlenecks.
2. Building a Custom Stdio MCP Server in Node.js
Creating an MCP server using the official TypeScript/JavaScript SDK takes less than 50 lines of code:
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
const server = new Server(
{ name: "dev-analytics-server", version: "1.0.0" },
{ capabilities: { tools: {} } }
);
// 1. Declare Available Tools
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: "query_pageviews",
description: "Query active user pageviews by date range and country",
inputSchema: {
type: "object",
properties: {
daysAgo: { type: "number", description: "Number of past days to query" },
country: { type: "string", description: "Target ISO country code" }
},
required: ["daysAgo"]
}
}
]
}));
// 2. Handle Tool Invocations
server.setRequestHandler(CallToolRequestSchema, async (request) => {
if (request.params.name === "query_pageviews") {
const { daysAgo, country } = request.params.arguments;
const metrics = await fetchAnalyticsData(daysAgo, country);
return {
content: [{ type: "text", text: JSON.stringify(metrics, null, 2) }]
};
}
throw new Error(`Tool not found: ${request.params.name}`);
});
// 3. Connect via Standard I/O Transport
const transport = new StdioServerTransport();
await server.connect(transport);
3. Critical Production Security Guidelines
Because MCP servers execute system actions requested by LLM agents, you must implement strict security boundaries:
-
Never Log to stdout: All debugging information
must be routed to
stderr(e.g.console.error). Writing non-JSON data tostdoutcorrupts the JSON-RPC message framing and crashes the client connection. - Validate with Zod: Always strictly validate input parameters using schemas to prevent command injection (CWE-78) and path traversal (CWE-22).
-
Scope Credential Access: Pass API tokens and
database URLs via environment variables injected through
mcp_config.jsonrather than embedding secrets in source code.
Inspect and Validate JSON-RPC Payloads
Debugging MCP tool schemas and JSON-RPC payloads? Format, validate, and minify your tool definitions client-side using our free JSON Formatter & Validator.