AI assistants like Claude are powerful, but they have a fundamental limitation: they only know what they were trained on. They cannot check your calendar, query your database, read a file on your computer, or call an external API unless something explicitly gives them that access.
MCP servers solve this. MCP stands for Model Context Protocol, an open standard introduced by Anthropic in late 2024 that defines how AI models communicate with external tools and data sources. Instead of each developer building a custom integration for every AI tool and every external service, MCP provides one shared language. An AI that speaks MCP can connect to any MCP server, and a service that builds an MCP server can be reached by any MCP-compatible AI.
This guide explains what MCP is, how the pieces fit together, and walks through building a simple working MCP server in Node.js that you can connect to Claude Desktop.
What this covers:
What MCP is and why it exists
The three components: host, client, and server
The three things an MCP server can offer: tools, resources, and prompts
Building a simple MCP server in TypeScript
Connecting the server to Claude Desktop
Testing that it works
What MCP Is and Why It Exists
Before MCP, connecting an AI model to an external tool required custom integration code for every combination of model and tool. If you wanted Claude to read from a database, you built that integration. If you then wanted the same database access from a different AI model, you built it again. The result was a fragmented ecosystem where every team was solving the same problem from scratch.
MCP changes the equation. A service builds one MCP server. Any AI model that supports MCP can connect to it. The integration work happens once.
A useful analogy: before USB, every device needed its own proprietary cable and connector. USB created a standard that any device and any computer could use. MCP is USB for AI tools.
The Three Components
An MCP system has three distinct roles.
The host is the AI application the user interacts with. Claude Desktop is the most common example. The host provides the environment where the AI model runs.
The client is built into the host and manages the connection to MCP servers. Each client connects to one server. The host handles communication between clients and the model.
The server is what you build. It wraps a tool, a data source, or a service and exposes its capabilities in a way the AI can understand and use.
When you ask Claude "what files are in my project?" and Claude uses an MCP server to answer, the flow is: Claude (host) asks the client to query the MCP server, the server reads the filesystem, and the result comes back through the client to Claude, which uses it to form a response.
What an MCP Server Can Offer
MCP servers expose three types of capabilities.
Tools are functions the AI can call. They perform actions: create a file, send an email, query a database, call an API. Tools are the most commonly used capability and what this tutorial focuses on.
Resources are read-only data sources the AI can access for context: a document, a database table, a configuration file. Resources provide information without performing actions.
Prompts are pre-written instruction templates that help the AI perform specific tasks consistently. A prompt might define how to format a bug report or how to summarize a meeting.
For a beginner getting started, tools are the right focus. They are the most practical and the easiest to reason about.
Building Your First MCP Server
This tutorial builds a simple MCP server that exposes two tools: one that returns the current date and time, and one that converts a temperature from Celsius to Fahrenheit. These are intentionally simple — the goal is to understand the structure, not to build something impressive.
Prerequisites
Node.js 18 or higher
npm
Claude Desktop installed (free at claude.ai/download)
Basic familiarity with TypeScript
Step 1: Create the Project
mkdir my-first-mcp-server
cd my-first-mcp-server
npm init -y
npm install @modelcontextprotocol/sdk zod
npm install -D typescript @types/node tsx
Create a tsconfig.json:
{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "./dist",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true
},
"include": ["src/**/*"]
}
Step 2: Write the Server
Create src/index.ts:
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
// Create the MCP server with a name and version
const server = new McpServer({
name: "my-first-mcp-server",
version: "1.0.0",
});
// Tool 1: Return the current date and time
server.tool(
"get_current_time",
"Returns the current date and time in ISO format",
{}, // no input parameters needed
async () => {
const now = new Date().toISOString();
return {
content: [
{
type: "text",
text: `Current date and time: ${now}`,
},
],
};
}
);
// Tool 2: Convert Celsius to Fahrenheit
server.tool(
"celsius_to_fahrenheit",
"Converts a temperature from Celsius to Fahrenheit",
{
celsius: z.number().describe("Temperature in Celsius"),
},
async ({ celsius }) => {
const fahrenheit = (celsius * 9) / 5 + 32;
return {
content: [
{
type: "text",
text: `${celsius}°C = ${fahrenheit.toFixed(2)}°F`,
},
],
};
}
);
// Start the server using stdio transport
// stdio means the server communicates through standard input/output,
// which is how Claude Desktop launches and talks to local MCP servers
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("MCP server running"); // use stderr, never stdout
}
main().catch((err) => {
console.error("Server error:", err);
process.exit(1);
});
A few things worth noting about this code:
The server.tool() call takes four arguments: the tool name, a description the AI uses to understand when to use the tool, a Zod schema defining the input parameters, and the handler function that runs when the tool is called.
The description matters. Claude decides which tool to call based on the description. A clear, specific description produces better results than a vague one.
Logging uses console.error() rather than console.log(). This is important: the stdio transport sends messages to Claude over stdout. Anything written to stdout is interpreted as an MCP message. Using stdout for logging breaks the server. Always log to stderr with stdio-based servers.
Step 3: Add a Start Script
Update package.json to add a script:
{
"scripts": {
"start": "node --loader ts-node/esm src/index.ts",
"dev": "tsx src/index.ts"
}
}
Test that the server starts without errors:
npx tsx src/index.ts
You should see MCP server running in the terminal and no errors. Press Ctrl+C to stop it.
Connecting to Claude Desktop
Claude Desktop looks for MCP server configurations in a JSON file. The location depends on your operating system:
macOS:
~/Library/Application Support/Claude/claude_desktop_config.jsonWindows:
%APPDATA%\Claude\claude_desktop_config.json
Open (or create) that file and add your server:
{
"mcpServers": {
"my-first-mcp-server": {
"command": "npx",
"args": [
"tsx",
"/absolute/path/to/my-first-mcp-server/src/index.ts"
]
}
}
}
Replace /absolute/path/to/my-first-mcp-server with the actual full path to your project directory. On macOS and Linux, run pwd inside the project folder to get the full path. On Windows, run cd in Command Prompt.
Save the file and restart Claude Desktop completely (quit from the menu bar or system tray, then reopen).
Testing the Server
After restarting Claude Desktop, look for a small hammer icon near the chat input. This indicates that MCP tools are available. Clicking it shows a list of the tools your server has registered.
Try asking Claude:
"What time is it right now?"
"What is 25 degrees Celsius in Fahrenheit?"
"Convert 100°C to Fahrenheit"
Claude will call the appropriate tool from your server and use the result in its response. You should see it work in real time.
If the tools do not appear, check that the path in the config file is correct and that the server starts without errors when run manually. Claude Desktop logs connection errors that can help with debugging.
What to Build Next
The two tools in this tutorial are intentionally trivial. The same structure scales to genuinely useful things:
A tool that reads files from a specific directory on your computer
A tool that queries a local database and returns results
A tool that calls an external API (weather, stock prices, a project management tool)
A tool that creates or modifies files
The pattern is always the same: define the tool name and description, define the input schema with Zod, and write the handler that does the actual work and returns a text result.
For anything that involves authentication (API keys, OAuth), the handler function reads credentials from environment variables rather than hardcoding them. The MCP server configuration in claude_desktop_config.json supports an env field for passing environment variables:
{
"mcpServers": {
"my-weather-server": {
"command": "npx",
"args": ["tsx", "/path/to/weather-server/src/index.ts"],
"env": {
"WEATHER_API_KEY": "your-api-key-here"
}
}
}
}
Key Takeaways
MCP (Model Context Protocol) is an open standard that lets AI models connect to external tools and data sources through a consistent interface.
An MCP system has three roles: the host (the AI application), the client (built into the host, manages connections), and the server (what you build).
MCP servers expose three types of capabilities: tools (actions the AI can call), resources (read-only data), and prompts (instruction templates). Tools are the most common starting point.
Tool descriptions matter. Claude uses the description to decide which tool to call, so clear and specific descriptions produce better results.
stdio-based servers must never write to stdout. Use
console.error()for logging, notconsole.log().Claude Desktop reads server configuration from a JSON file. The path must be absolute, and Claude must be fully restarted after any config change.
Conclusion
MCP servers are how AI models like Claude gain the ability to do things beyond their training data. The protocol is well-designed, the SDK handles the communication layer, and building a basic server is significantly simpler than it sounds.
The server built in this tutorial is a starting point. The same structure, the same server.tool() pattern, applies whether the tool is returning the current time or querying a production database. Start simple, connect it to Claude Desktop, and build from there.
Built something with MCP or running into a specific issue with the setup? Share it in the comments.




