You keep hearing about MCP servers but every tutorial throws you into multi-agent swarms and complex architectures. Here's the simplest possible MCP server -- one file, one tool, fully runnable in 10 minutes.
The Code
Create a new project and install the SDK:
mkdir my-mcp-server && cd my-mcp-server
npm init -y
npm install @modelcontextprotocol/sdk zod
Create server.ts:
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
const server = new McpServer({
name: "weather-server",
version: "1.0.0",
});
server.registerTool(
"get-weather",
{
title: "Get Weather",
description: "Get current weather for a city",
inputSchema: z.object({
city: z.string().describe("City name"),
}),
},
async ({ city }) => {
const res = await fetch(
`https://wttr.in/${encodeURIComponent(city)}?format=j1`
);
const data = await res.json();
const current = data.current_condition[0];
return {
content: [
{
type: "text",
text: `${city}: ${current.temp_C}°C, ${current.weatherDesc[0].value}`,
},
],
};
}
);
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Weather MCP server running on stdio");
That's it. 30 lines. A fully functional MCP server.
What's Happening
Lines 1-3 import the three things every MCP server needs: McpServer to create the server instance, StdioServerTransport for the communication layer, and zod for input validation.
Lines 5-8 create your server with a name and version. These show up when AI clients discover your server.
Lines 10-31 register a single tool called get-weather. The inputSchema uses Zod to define and validate what the tool expects -- a city name as a string. The handler function fetches real weather data from wttr.in (a free API, no key needed) and returns it as a text content block.
Lines 33-35 wire up the stdio transport and start the server. Stdio means the AI client launches your server as a child process and communicates over stdin/stdout. This is how Claude Desktop, Cursor, and most local MCP clients work.
Connect It to Claude Desktop
Add this to your Claude Desktop config file (~/Library/Application Support/Claude/claude_desktop_config.json on macOS):
{
"mcpServers": {
"weather": {
"command": "npx",
"args": ["tsx", "/full/path/to/my-mcp-server/server.ts"]
}
}
}
Restart Claude Desktop. Ask it "What's the weather in Tokyo?" and it will call your get-weather tool.
Test It Without a Client
You can also test directly from the terminal using the MCP Inspector:
npx @modelcontextprotocol/inspector npx tsx server.ts
This opens a web UI where you can browse your server's tools and call them manually -- useful for debugging before connecting to an AI client.
What to Build Next
Now that you have a working server, swap the weather API for anything:
- Database queries: Register a tool that runs read-only SQL against your dev database
- Internal APIs: Wrap your company's REST endpoints as MCP tools
- File operations: Let AI assistants read/search your project files
Each new tool is just another server.registerTool() call with a schema and a handler. The MCP SDK handles discovery, validation, and communication automatically.
The full TypeScript SDK has examples for HTTP transports, authentication, streaming, and multi-tool servers at github.com/modelcontextprotocol/typescript-sdk.
This is part of the AI Agent Quick Tips series -- short, code-first tutorials for developers building with AI tools.
Top comments (0)