Skip to content

How to Build MCP Servers with mcp-builder

Purpose

I wanted to build an MCP server to connect my AI assistant to a custom data source. But I kept wondering: what’s the right way to structure it? Which framework should I use? How do I make it work across different AI tools?

This post shows how I approached MCP server development using the mcp-builder skill.

What is MCP?

MCP (Model Context Protocol) solves a real problem in AI development: integration fragmentation.

Before MCP, if I wanted my AI assistant to access my database, I needed:

  • One integration for Claude
  • Another for Cursor
  • Yet another for Copilot

Each AI tool had its own plugin system. Different APIs. Different patterns.

MCP creates a universal plugin layer:

mcp-architecture.txt
+------------------+ +------------------+ +------------------+
| MCP Host | | MCP Server | | External |
| (Claude Code) | --stdio | (Your Plugin) | ------> | System |
| | or | | | (API, DB) |
| MCP Client | HTTP | Tools | | |
+------------------+ +------------------+ +------------------+

Write once, use everywhere. Any MCP-compatible AI tool can use your server.

Core Capabilities

MCP servers provide three things:

CapabilityWhat It DoesExample
ToolsFunctions the AI can callquery_database, send_email
ResourcesData the AI can readFile contents, database records
PromptsPredefined templatesCommon workflows, query patterns

The mcp-builder Skill

I found out about mcp-builder from Anthropic’s skills repository. It’s an Agent Skill that guides you through the entire MCP server development cycle.

Installation

install-mcp-builder.sh
npx skills add anthropics/skills --skill mcp-builder

Once installed, my coding assistant gained expertise in MCP patterns. It knows:

  • How to structure tool definitions
  • Best practices for error messages
  • Transport options and when to use each
  • Testing with MCP Inspector

The Four-Phase Cycle

mcp-builder follows a structured approach:

Phase 1: Research and Planning

I started by defining what my server should do:

  • What external system am I connecting to?
  • What tools does the AI need?
  • What data should be exposed as resources?

Phase 2: Implementation

Two framework options:

FrameworkLanguageBest For
MCP SDKTypeScriptFull control, OAuth support
FastMCPTypeScript/PythonRapid development, less boilerplate

Phase 3: Review and Testing

Use MCP Inspector to validate your server works correctly.

Phase 4: Evaluation Creation

Create tests for tool correctness and document usage patterns.

Choosing a Framework

I tried both frameworks to understand the differences.

FastMCP Approach

FastMCP offers a simpler API with less code:

fastmcp-server.ts
import { FastMCP } from "fastmcp";
import { z } from "zod";
const server = new FastMCP({
name: "my-server",
version: "1.0.0"
});
server.addTool({
name: "add",
description: "Add two numbers",
parameters: z.object({
a: z.number(),
b: z.number()
}),
execute: async ({ a, b }) => String(a + b),
});
server.start({
transportType: "httpStream",
httpStream: { port: 3000 }
});

Clean and straightforward. I liked how the tool definition is self-contained.

MCP SDK Approach

The official SDK gives more control:

mcp-sdk-server.ts
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
const server = new McpServer({
name: "my-server",
version: "1.0.0"
});
server.tool("add", {
a: z.number(),
b: z.number()
}, async ({ a, b }) => ({
content: [{ type: "text", text: String(a + b) }],
}));

The SDK is better when you need OAuth or want to integrate with Express.js.

Transport Types: stdio vs HTTP

I had to decide between two transport options:

FeaturestdioHTTP
Use caseLocal clientsRemote access, cloud
Protocolstdin/stdoutHTTP/SSE
OAuthNoYes
DockerNoYes

When I Use stdio

  • Personal development on my laptop
  • Claude Desktop integration
  • Data that shouldn’t leave my machine

When I Use HTTP

  • Sharing with my team
  • Cloud deployment
  • Need authentication

Quick Start with create-mcp-server

Instead of starting from scratch, I used the create-mcp-server scaffolding tool:

create-server.sh
# Interactive mode
npx @agentailor/create-mcp-server
# Or specify options directly
npx @agentailor/create-mcp-server --name=my-server --stdio

This generated a complete project structure:

project-structure.txt
my-mcp-server/
+-- src/
| +-- server.ts # MCP server (tools, prompts, resources)
| +-- index.ts # Express app and transport setup
| +-- auth.ts # OAuth middleware (if enabled)
+-- Dockerfile # Production-ready Docker build
+-- package.json
+-- tsconfig.json
+-- .gitignore
+-- .env.example
+-- README.md

The generated project includes everything I needed:

  • TypeScript configuration
  • Docker support
  • Development scripts
  • MCP Inspector integration

Configuration

For Local Use

I added my server to ~/.claude.json:

claude-local-config.json
{
"mcpServers": {
"my-server": {
"command": "node",
"args": ["/path/to/my-server/dist/index.js"],
"env": {
"API_KEY": "${API_KEY}"
}
}
}
}

For Remote Deployment

For HTTP servers, I configured the URL:

claude-remote-config.json
{
"mcpServers": {
"my-remote-server": {
"url": "https://my-server.example.com/mcp",
"headers": {
"Authorization": "Bearer ${API_KEY}"
}
}
}
}

Best Practices I Learned

1. Write Clear Tool Descriptions

The AI reads your descriptions to decide which tool to use. Make them specific:

tool-descriptions.ts
// Good: Clear, specific, actionable
server.addTool({
name: "search_docs",
description: "Search documentation for a specific term. Returns matching sections with context.",
// ...
});
// Bad: Vague, unhelpful
server.addTool({
name: "search",
description: "Searches things",
// ...
});

2. Provide Actionable Error Messages

When something fails, tell the user what to do:

error-messages.ts
// Good: Tells user what to do
throw new Error("API key not found. Set the API_KEY environment variable or pass it in the config.");
// Bad: Cryptic error
throw new Error("Auth failed");

3. Validate All Inputs

Use Zod schemas to validate parameters:

input-validation.ts
server.addTool({
name: "query_database",
description: "Execute a SQL query on the database",
parameters: z.object({
query: z.string().min(1).max(1000),
limit: z.number().min(1).max(100).default(10),
}),
// ...
});

4. Never Hardcode Secrets

Always use environment variables:

env-config.json
{
"env": {
"API_KEY": "${API_KEY}"
}
}

Testing with MCP Inspector

The generated project includes an inspect script:

run-inspector.sh
npm run inspect

This opens MCP Inspector in my browser. I can:

  • See all tools, resources, and prompts
  • Test each tool interactively
  • View request/response logs
  • Debug errors

A Complete Example

Here’s a weather server I built:

weather-server.ts
import { FastMCP } from "fastmcp";
import { z } from "zod";
const server = new FastMCP({
name: "weather-server",
version: "1.0.0"
});
server.addTool({
name: "get_weather",
description: "Get current weather for a city",
parameters: z.object({
city: z.string().describe("City name"),
units: z.enum(["celsius", "fahrenheit"]).default("celsius"),
}),
execute: async ({ city, units }) => {
const response = await fetchWeatherData(city, units);
return JSON.stringify(response);
},
});
server.addResource({
uri: "weather://cities",
name: "Supported Cities",
mimeType: "application/json",
async load() {
return {
text: JSON.stringify(["San Francisco", "New York", "London"]),
};
},
});
server.start({
transportType: "httpStream",
httpStream: { port: 3000 }
});

Summary

In this post, I showed how to build MCP servers using mcp-builder. The key takeaways:

  1. MCP solves fragmentation: Write integrations once, use across any MCP-compatible AI tool
  2. mcp-builder guides development: Install with npx skills add anthropics/skills --skill mcp-builder
  3. Two framework options: FastMCP for simplicity, MCP SDK for full control
  4. Two transport types: stdio for local, HTTP for remote
  5. Use scaffolding: npx @agentailor/create-mcp-server generates production-ready projects

The combination of mcp-builder (knowledge) and create-mcp-server (scaffolding) gave me everything I needed to build MCP servers that work across Claude Code, Cursor, and any other MCP-compatible tool.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments