Building Your First MCP Server
Setting Up the Project
Let's build a real MCP server from scratch using TypeScript. Start by initializing your project:
mkdir my-mcp-server && cd my-mcp-server
npm init -y
npm install @modelcontextprotocol/sdk zod
npm install -D typescript @types/node
npx tsc --init
Set "module": "node16" and "moduleResolution": "node16" in your tsconfig.json. MCP servers use ES modules, so add "type": "module" to your package.json.
Defining Your First Tool
Create src/index.ts. The SDK provides a McpServer class that handles all protocol details:
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: "my-first-server",
version: "1.0.0",
});
server.tool(
"get-weather",
"Get current weather for a city",
{ city: z.string().describe("City name") },
async ({ city }) => {
// In production, call a real weather API
return {
content: [
{ type: "text", text: `Weather in ${city}: 22°C, partly cloudy` },
],
};
}
);
The server.tool() method takes four arguments: a name, a description (used by the AI model to decide when to call it), a Zod schema for input validation, and an async handler function.
Adding Resources
Resources give the model read access to data. Let's add a configuration resource:
server.resource(
"config",
"app://config/current",
{ description: "Current application configuration" },
async () => ({
contents: [
{
uri: "app://config/current",
text: JSON.stringify({ env: "production", debug: false }),
mimeType: "application/json",
},
],
})
);
Connecting the Transport
The final step is wiring the transport and starting the server:
const transport = new StdioServerTransport();
await server.connect(transport);
Build with npx tsc and your server is ready.
Testing with MCP Inspector
Before connecting to a real host, test with the MCP Inspector — a browser-based tool for debugging MCP servers:
npx @modelcontextprotocol/inspector node dist/index.js
The Inspector shows all registered tools, resources, and prompts. You can invoke them interactively and see the full request/response cycle.
Connecting to Claude Desktop
Add your server to Claude Desktop's configuration file (claude_desktop_config.json):
{
"mcpServers": {
"my-first-server": {
"command": "node",
"args": ["/absolute/path/to/dist/index.js"]
}
}
}
Restart Claude Desktop and your tools appear automatically. Claude will call them when relevant to the conversation.
Connecting to Claude Code
For Claude Code, add the server to your project's .mcp.json:
{
"mcpServers": {
"my-first-server": {
"command": "node",
"args": ["./dist/index.js"]
}
}
}
Claude Code picks it up immediately — your tools are available in the coding workflow.
Production Examples
Simple weather servers are fine for learning, but MCP servers scale to serious production use. MCP-Vanguard exposes 89 security tools — from vulnerability scanning to threat intelligence — all through a single MCP server. InfraOps-MCP provides 92 infrastructure management tools for Docker, system monitoring, networking, and more.
These projects demonstrate the pattern: take your team's existing tooling and expertise, wrap it in well-typed MCP tools with clear descriptions, and suddenly your entire AI-powered workflow has access to it.
In the next lesson, we'll explore how to design the agents that use these tools effectively.