How to Build Your First Custom MCP Server: A Step-by-Step Guide
Learn how to build your first custom MCP (Model Context Protocol) server from scratch. This step-by-step tutorial covers project setup, registering tools and resources, configuring Claude Desktop and VS Code, error handling, and best practices for connecting AI agents to your internal systems.
By CoddyKit · 5 min read · 1043 wordsWhy MCP Servers Are the Missing Link in Your AI Workflow
By mid-2026, AI coding agents like Claude Code, GitHub Copilot, and Cursor have become standard developer tools. But most teams hit the same wall: these agents only know what they can access through built-in integrations. Your internal APIs, proprietary databases, and custom tooling remain invisible.
That is where the Model Context Protocol (MCP) changes everything. MCP is an open standard that lets AI agents connect to any external data source or tool through a simple, standardized interface. Building your own MCP server means your AI assistant can read your internal docs, query your databases, trigger your CI/CD pipelines, and more — all through natural language.
In this guide, you will build a fully functional MCP server from scratch in under 30 minutes.
What Is MCP, Exactly?
MCP follows a client-server architecture:
- MCP Host — The AI application (Claude Desktop, VS Code, etc.) that wants to use tools.
- MCP Client — The protocol layer inside the host that communicates with servers.
- MCP Server — A lightweight process that exposes tools, resources, and prompts to the host.
Think of an MCP server as a bridge between an AI agent and your systems. The server defines what tools are available and handles the execution when the agent calls them.
Prerequisites
- Node.js 18+ — Run
node --versionto check - npm — Comes bundled with Node.js
- An MCP-compatible host — Claude Desktop, VS Code with Copilot, or any MCP client
Step 1: Initialize the Project
Create a new directory and install the MCP SDK:
mkdir my-mcp-server && cd my-mcp-server
npm init -y
npm install @modelcontextprotocol/sdk zod
Open package.json and set the type to module so you can use ES imports:
{
"name": "my-mcp-server",
"version": "1.0.0",
"type": "module",
"main": "index.js"
}
Step 2: Scaffold the Server
Create index.js with the basic MCP server structure:
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
// Create the server instance
const server = new McpServer({
name: "my-custom-server",
version: "1.0.0",
});
// Register tools here (Step 3)
// Start the server
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("MCP server running on stdio");
This creates a server that communicates over stdio (standard input/output), which is the most common transport for local MCP servers.
Step 3: Add Your First Tool
Tools are functions the AI agent can call. Let us build a tool that queries a hypothetical internal API for deployment status:
server.registerTool(
"get-deploy-status",
{
title: "Get Deployment Status",
description: "Check the current deployment status for a given environment",
inputSchema: {
environment: z.enum(["staging", "production"]),
service: z.string().describe("Service name to check"),
},
},
async ({ environment, service }) => {
// Replace this with your actual API call
const response = await fetch(
`https://api.internal.example/deploy/${environment}/${service}`
);
const data = await response.json();
return {
content: [
{
type: "text",
text: `Service: ${data.service}\nStatus: ${data.status}\nLast deploy: ${data.lastDeploy}\nVersion: ${data.version}`,
},
],
};
}
);
Key points:
- Tool name — A unique identifier the agent uses to call the tool
- inputSchema — Zod schema that validates and types the input parameters
- Handler — Async function that executes when the tool is called
- Return value — Array of content blocks (text, images, etc.)
Step 4: Add a Resource
Resources let the AI agent read data without calling a tool. Think of them as readable endpoints:
server.registerResource(
"docs",
"docs://architecture",
{
title: "Architecture Documentation",
description: "Current system architecture overview",
},
async (uri) => {
const doc = await fetch("https://docs.internal.example/architecture.md");
const text = await doc.text();
return {
contents: [
{
uri: uri.href,
mimeType: "text/markdown",
text: text,
},
],
};
}
);
Now the AI agent can read your architecture docs and answer questions about your system without you pasting anything.
Step 5: Configure Your MCP Host
Tell your AI client about the server. For Claude Desktop, edit ~/Library/Application Support/Claude/claude_desktop_config.json on macOS:
{
"mcpServers": {
"my-custom-server": {
"command": "node",
"args": ["/absolute/path/to/my-mcp-server/index.js"]
}
}
}
Restart Claude Desktop. Your new tools will appear automatically.
For VS Code with MCP support, the configuration goes in your workspace .vscode/mcp.json:
{
"servers": {
"my-custom-server": {
"type": "stdio",
"command": "node",
"args": ["${workspaceFolder}/index.js"]
}
}
}
Step 6: Test It
Open your AI client and try a natural language prompt:
"What is the deployment status of our auth service in production?"
The agent should automatically call your get-deploy-status tool and return the result. Try asking about your architecture — the agent will read from your registered resource.
Step 7: Add Error Handling
Production MCP servers need resilience. Wrap your tool handlers:
async ({ environment, service }) => {
try {
const response = await fetch(
`https://api.internal.example/deploy/${environment}/${service}`,
{ signal: AbortSignal.timeout(5000) }
);
if (!response.ok) {
return {
content: [{
type: "text",
text: `Error: API returned ${response.status}`,
}],
isError: true,
};
}
const data = await response.json();
return {
content: [{
type: "text",
text: `Status: ${data.status} | Version: ${data.version}`,
}],
};
} catch (err) {
return {
content: [{
type: "text",
text: `Failed to fetch deploy status: ${err.message}`,
}],
isError: true,
};
}
}
What to Build Next
Once your first server is running, consider these extensions:
| Tool Idea | Use Case |
|---|---|
| CI/CD Trigger | Start a pipeline run from chat |
| Database Query | Run read-only SQL queries against staging |
| Log Fetcher | Pull recent logs for a service |
| Incident Lookup | Check PagerDuty or open incidents |
| Code Review | Fetch and summarize recent PRs |
Best Practices
- Keep servers focused — One server per domain (e.g., one for CI/CD, one for docs)
- Validate all inputs — Zod schemas are your first line of defense
- Use timeouts — Never let a tool hang the AI agent
- Return structured output — Consistent formatting helps the agent reason about results
- Mark errors clearly — Set
isError: trueso the agent knows something failed
Conclusion
MCP servers are the simplest way to give AI agents real access to your systems. With about 30 lines of code, you went from zero to a working tool that an AI can discover and call on its own. The protocol is open, the SDK is mature, and the ecosystem is growing fast in 2026.
Start small. Build one tool that saves you five minutes a day. Then build another. Before long, your AI assistant will know your infrastructure as well as you do.