MCP Server Examples: Complete Code Reference
TL;DR: 25+ MCP server code samples organized by category (database, filesystem, API, productivity). Python + FastMCP for speed, TypeScript for production. Complete code reference with copy-paste examples. Yes, paid MCP servers are a thing.
Look, I get it. Reading MCP documentation is boring. You want to see actual code. You want to copy something that works and tweak it for your use case. That's exactly what I would do too.
So here's the deal. I've put together 25+ MCP server examples organized by what they actually do. Database stuff, filesystem operations, API wrappers, productivity tools. Each one has working code you can steal and modify. Python and TypeScript because those are the languages people actually use for MCP servers.
And here's something nobody else talks about: paid MCP servers exist. You can build them. You can sell them. We'll get into that.
What you'll find in this MCP code reference:
- MCP server examples organized by category (so you can find what you need fast)
- Working code samples in both Python and TypeScript
- MCP implementation examples with real usage patterns
- How to sell your own paid MCP server (yeah, that's a thing now)
- Templates to get you started in minutes, not hours
Quick Start: Your First MCP Server#
Before we dive into the categories, let me show you the absolute minimum you need. This is the "hello world" of MCP servers.
I'm talking like 10 lines of code. That's it. If you can't get this running, something's wrong with your setup, not your code.
Python with FastMCP:
FastMCP is the way to go for Python. It handles all the boilerplate so you can focus on what your server actually does.
from fastmcp import FastMCP
mcp = FastMCP("hello-world")
@mcp.tool
def greet(name: str) -> str:
"""Say hello to someone."""
return f"Hello, {name}!"
if __name__ == "__main__":
mcp.run()
That's a working MCP server. Seven lines. The decorator pattern is clean and you can add more tools just by adding more functions.
TypeScript with the Official SDK:
TypeScript takes a bit more setup, but you get type safety in return. Worth it for production servers.
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
const server = new Server(
{ name: "hello-world", version: "1.0.0" },
{ capabilities: { tools: {} } }
);
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [{
name: "greet",
description: "Say hello to someone",
inputSchema: { type: "object", properties: { name: { type: "string" } } }
}]
}));
const transport = new StdioServerTransport();
await server.connect(transport);
A bit more verbose, sure. But you get autocomplete, type checking, and your IDE actually helps you. I use TypeScript for anything that's going to production.
The pattern is the same for both languages: define your server, declare your tools, run it. Everything else we cover builds on this foundation.
MCP Server List: Reference Implementations#
Before diving into code samples, here's a quick reference of MCP servers worth studying. These are the servers developers use as code reference points, based on Smithery.ai usage counts.
Let me break down why each of these MCP server examples matters:
| Rank | Server | Category | Why Developers Love It |
|---|---|---|---|
| 1 | GitHub MCP | Version Control | Lets AI manage repos, issues, and PRs. Huge time saver for code review workflows. |
| 2 | Filesystem | File System | The most basic and most useful. Read and write local files. Every developer needs this. |
| 3 | Memory | Data Store | Gives AI persistent memory across conversations. Game changer for context. |
| 4 | Supabase | Database | Full Postgres plus auth plus storage. Backend in a box. |
| 5 | Slack | Communication | Team messaging automation. Great for notifications and bot workflows. |
| 6 | Notion | Productivity | Page and database management. Knowledge base integration. |
The popularity isn't random. These MCP servers solve real problems that developers hit every day. If you're building something new, studying these examples is smart. See what patterns they use, how they structure their tools, what makes them usable.
MCP Server Examples by Category#
Alright, let's get into the actual code. I've organized these MCP examples by what problem they solve. Find your category, grab the code, modify it.
Database Servers#
Database MCP servers are probably the most useful category. Being able to have AI query your data directly is incredibly powerful. Here are working examples.
PostgreSQL MCP Server (Python):
This is the pattern I use for any Postgres integration. Simple, async, handles connections properly.
from fastmcp import FastMCP
import asyncpg
mcp = FastMCP("postgres-mcp")
DATABASE_URL = "postgresql://user:pass@localhost/mydb"
@mcp.tool
async def query(sql: str) -> list[dict]:
"""Execute a read-only SQL query on PostgreSQL."""
conn = await asyncpg.connect(DATABASE_URL)
try:
rows = await conn.fetch(sql)
return [dict(row) for row in rows]
finally:
await conn.close()
@mcp.tool
async def list_tables() -> list[str]:
"""List all tables in the database."""
sql = """
SELECT table_name FROM information_schema.tables
WHERE table_schema = 'public'
"""
result = await query(sql)
return [row['table_name'] for row in result]
@mcp.tool
async def describe_table(table_name: str) -> list[dict]:
"""Get column info for a specific table."""
sql = f"""
SELECT column_name, data_type, is_nullable
FROM information_schema.columns
WHERE table_name = '{table_name}'
"""
return await query(sql)
Pro tip: always include list_tables and describe_table tools. AI needs to understand your schema before it can write good queries.
SQLite MCP Server (TypeScript):
SQLite is perfect for local development and embedded databases. Here's a TypeScript implementation.
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import Database from "better-sqlite3";
const db = new Database("./data.sqlite");
const server = new Server(
{ name: "sqlite-mcp", version: "1.0.0" },
{ capabilities: { tools: {} } }
);
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
if (name === "query") {
const { sql } = args as { sql: string };
const result = db.prepare(sql).all();
return {
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
};
}
if (name === "execute") {
const { sql } = args as { sql: string };
const result = db.prepare(sql).run();
return {
content: [{ type: "text", text: `Affected rows: ${result.changes}` }]
};
}
});
Database MCP Server Comparison:
| Server | Database | Key Features | Best For |
|---|---|---|---|
| PostgreSQL MCP | PostgreSQL | Full SQL, async, connection pooling | Production apps |
| SQLite MCP | SQLite | Zero setup, embedded, fast | Local dev, prototypes |
| MongoDB MCP | MongoDB | Document queries, aggregation pipeline | Unstructured data |
| Supabase MCP | Supabase | Postgres + auth + realtime + storage | Full stack apps |
| MySQL MCP | MySQL | Enterprise features, replication | Legacy systems |
Each of these MCP server examples follows the same pattern: connect, expose query tools, handle cleanup. The database client changes, the structure stays the same.
Filesystem Servers#
Filesystem MCP servers let AI read and write files on your machine. Scary? A little. Useful? Incredibly.
Basic File Operations (Python):
from fastmcp import FastMCP
from pathlib import Path
import os
mcp = FastMCP("filesystem-mcp")
@mcp.tool
def read_file(path: str) -> str:
"""Read the contents of a file."""
file_path = Path(path).expanduser()
if not file_path.exists():
raise FileNotFoundError(f"File not found: {path}")
return file_path.read_text()
@mcp.tool
def write_file(path: str, content: str) -> str:
"""Write content to a file. Creates directories if needed."""
file_path = Path(path).expanduser()
file_path.parent.mkdir(parents=True, exist_ok=True)
file_path.write_text(content)
return f"Written {len(content)} bytes to {path}"
@mcp.tool
def list_directory(path: str = ".") -> list[dict]:
"""List files and directories at a path."""
dir_path = Path(path).expanduser()
items = []
for item in dir_path.iterdir():
items.append({
"name": item.name,
"type": "directory" if item.is_dir() else "file",
"size": item.stat().st_size if item.is_file() else None
})
return sorted(items, key=lambda x: (x["type"] == "file", x["name"]))
@mcp.tool
def search_files(pattern: str, directory: str = ".") -> list[str]:
"""Search for files matching a glob pattern."""
dir_path = Path(directory).expanduser()
return [str(p) for p in dir_path.rglob(pattern)]
I always add search_files to my filesystem MCP servers. AI asking you "where is that config file?" gets old fast.
File Watcher (TypeScript):
This MCP server example monitors directories for changes. Great for development workflows.
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { watch, FSWatcher } from "fs";
import { readdir, stat } from "fs/promises";
import { join } from "path";
const server = new Server(
{ name: "file-watcher-mcp", version: "1.0.0" },
{ capabilities: { tools: {} } }
);
let watchers: Map<string, FSWatcher> = new Map();
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
if (name === "watch_directory") {
const { path } = args as { path: string };
if (watchers.has(path)) {
return { content: [{ type: "text", text: `Already watching ${path}` }] };
}
const watcher = watch(path, { recursive: true }, (event, filename) => {
console.error(`[${event}] ${filename}`);
});
watchers.set(path, watcher);
return { content: [{ type: "text", text: `Now watching ${path}` }] };
}
if (name === "stop_watching") {
const { path } = args as { path: string };
const watcher = watchers.get(path);
if (watcher) {
watcher.close();
watchers.delete(path);
}
return { content: [{ type: "text", text: `Stopped watching ${path}` }] };
}
});
Filesystem MCP Examples:
| Server | Features | Use Case |
|---|---|---|
| @mcp/server-filesystem | Official, read/write/list/search | General file access |
| File Watcher MCP | Real-time change detection | Development, build systems |
| S3 MCP | AWS S3 bucket operations | Cloud storage |
| GCS MCP | Google Cloud Storage | Cloud storage |
| FTP MCP | FTP/SFTP operations | Legacy file transfers |
API Integration Servers#
These MCP server examples wrap external APIs so AI can interact with them. This is where things get really interesting.
REST API Wrapper (Python):
Generic pattern that works for any REST API. I use this as a starting point constantly.
from fastmcp import FastMCP
import httpx
from typing import Optional
mcp = FastMCP("rest-api-mcp")
BASE_URL = "https://api.example.com/v1"
API_KEY = os.environ.get("API_KEY")
@mcp.tool
async def api_get(endpoint: str, params: Optional[dict] = None) -> dict:
"""Make a GET request to the API."""
async with httpx.AsyncClient() as client:
response = await client.get(
f"{BASE_URL}{endpoint}",
params=params,
headers={"Authorization": f"Bearer {API_KEY}"}
)
response.raise_for_status()
return response.json()
@mcp.tool
async def api_post(endpoint: str, data: dict) -> dict:
"""Make a POST request to the API."""
async with httpx.AsyncClient() as client:
response = await client.post(
f"{BASE_URL}{endpoint}",
json=data,
headers={"Authorization": f"Bearer {API_KEY}"}
)
response.raise_for_status()
return response.json()
@mcp.tool
async def api_list_endpoints() -> list[str]:
"""List available API endpoints."""
return [
"/users - User management",
"/products - Product catalog",
"/orders - Order processing",
"/analytics - Usage statistics"
]
OAuth-Protected API (TypeScript):
When you need proper OAuth flow. More complex but necessary for Google, GitHub, etc.
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { OAuth2Client } from "google-auth-library";
const oauth2Client = new OAuth2Client({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
redirectUri: "http://localhost:3000/callback"
});
const server = new Server(
{ name: "oauth-api-mcp", version: "1.0.0" },
{ capabilities: { tools: {} } }
);
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
if (name === "get_auth_url") {
const url = oauth2Client.generateAuthUrl({
access_type: "offline",
scope: ["https://www.googleapis.com/auth/calendar.readonly"]
});
return { content: [{ type: "text", text: url }] };
}
if (name === "exchange_code") {
const { code } = args as { code: string };
const { tokens } = await oauth2Client.getToken(code);
oauth2Client.setCredentials(tokens);
return { content: [{ type: "text", text: "Authenticated successfully" }] };
}
if (name === "calendar_events") {
const response = await oauth2Client.request({
url: "https://www.googleapis.com/calendar/v3/calendars/primary/events"
});
return { content: [{ type: "text", text: JSON.stringify(response.data) }] };
}
});
API Integration Patterns:
| Pattern | Complexity | When to Use |
|---|---|---|
| Simple Bearer Token | Low | Most SaaS APIs |
| OAuth 2.0 | Medium | Google, GitHub, etc. |
| API Key + Secret | Low | AWS-style services |
| Webhook Receiver | Medium | Event-driven integrations |
| GraphQL Client | Medium | Modern APIs like GitHub's |
Developer Tools#
MCP servers for developer workflows. These examples automate the boring stuff.
Git Operations (Python):
from fastmcp import FastMCP
import subprocess
from typing import Optional
mcp = FastMCP("git-mcp")
def run_git(args: list[str], cwd: Optional[str] = None) -> str:
"""Run a git command and return output."""
result = subprocess.run(
["git"] + args,
capture_output=True,
text=True,
cwd=cwd
)
if result.returncode != 0:
raise Exception(f"Git error: {result.stderr}")
return result.stdout
@mcp.tool
def git_status(repo_path: str = ".") -> str:
"""Get current git status."""
return run_git(["status", "--porcelain"], repo_path)
@mcp.tool
def git_diff(file: Optional[str] = None, repo_path: str = ".") -> str:
"""Show git diff for a file or all changes."""
args = ["diff"]
if file:
args.append(file)
return run_git(args, repo_path)
@mcp.tool
def git_log(count: int = 10, repo_path: str = ".") -> str:
"""Show recent commit history."""
return run_git(
["log", f"-{count}", "--oneline", "--decorate"],
repo_path
)
@mcp.tool
def git_branch_list(repo_path: str = ".") -> str:
"""List all branches."""
return run_git(["branch", "-a"], repo_path)
@mcp.tool
def git_stash_changes(message: str, repo_path: str = ".") -> str:
"""Stash current changes with a message."""
return run_git(["stash", "push", "-m", message], repo_path)
Docker Management (TypeScript):
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { exec } from "child_process";
import { promisify } from "util";
const execAsync = promisify(exec);
const server = new Server(
{ name: "docker-mcp", version: "1.0.0" },
{ capabilities: { tools: {} } }
);
async function docker(args: string): Promise<string> {
const { stdout, stderr } = await execAsync(`docker ${args}`);
if (stderr && !stdout) throw new Error(stderr);
return stdout;
}
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
switch (name) {
case "list_containers":
const containers = await docker("ps --format '{{.Names}}\t{{.Status}}'");
return { content: [{ type: "text", text: containers }] };
case "container_logs":
const { container, lines = 50 } = args as { container: string; lines?: number };
const logs = await docker(`logs --tail ${lines} ${container}`);
return { content: [{ type: "text", text: logs }] };
case "restart_container":
const { name: containerName } = args as { name: string };
await docker(`restart ${containerName}`);
return { content: [{ type: "text", text: `Restarted ${containerName}` }] };
}
});
Developer Tool MCP Examples:
| Server | What It Does | Best For |
|---|---|---|
| GitHub MCP | Issues, PRs, repo management | Code review, project management |
| Git MCP | Local git operations | Day-to-day development |
| Docker MCP | Container management | DevOps, local dev |
| Kubernetes MCP | Cluster operations | Production infrastructure |
| CI/CD MCP | Pipeline triggers | Automation |
Productivity and Communication#
These MCP server examples integrate with the tools teams actually use every day.
Slack Integration (Python):
from fastmcp import FastMCP
from slack_sdk import WebClient
from slack_sdk.errors import SlackApiError
import os
mcp = FastMCP("slack-mcp")
client = WebClient(token=os.environ["SLACK_BOT_TOKEN"])
@mcp.tool
def send_message(channel: str, text: str) -> dict:
"""Send a message to a Slack channel."""
try:
response = client.chat_postMessage(channel=channel, text=text)
return {
"success": True,
"timestamp": response["ts"],
"channel": response["channel"]
}
except SlackApiError as e:
return {"success": False, "error": str(e)}
@mcp.tool
def list_channels() -> list[dict]:
"""List all accessible Slack channels."""
response = client.conversations_list(types="public_channel,private_channel")
return [
{"id": c["id"], "name": c["name"], "is_private": c["is_private"]}
for c in response["channels"]
]
@mcp.tool
def get_channel_history(channel: str, limit: int = 20) -> list[dict]:
"""Get recent messages from a channel."""
response = client.conversations_history(channel=channel, limit=limit)
return [
{"user": m.get("user"), "text": m.get("text"), "ts": m["ts"]}
for m in response["messages"]
]
@mcp.tool
def add_reaction(channel: str, timestamp: str, emoji: str) -> dict:
"""Add a reaction to a message."""
try:
client.reactions_add(channel=channel, timestamp=timestamp, name=emoji)
return {"success": True}
except SlackApiError as e:
return {"success": False, "error": str(e)}
Notion Integration (TypeScript):
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { Client } from "@notionhq/client";
const notion = new Client({ auth: process.env.NOTION_TOKEN });
const server = new Server(
{ name: "notion-mcp", version: "1.0.0" },
{ capabilities: { tools: {} } }
);
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
if (name === "search") {
const { query } = args as { query: string };
const response = await notion.search({
query,
filter: { property: "object", value: "page" }
});
return {
content: [{
type: "text",
text: JSON.stringify(response.results.map(page => ({
id: page.id,
title: page.properties?.title?.title?.[0]?.plain_text || "Untitled"
})))
}]
};
}
if (name === "get_page") {
const { page_id } = args as { page_id: string };
const page = await notion.pages.retrieve({ page_id });
const blocks = await notion.blocks.children.list({ block_id: page_id });
return {
content: [{
type: "text",
text: JSON.stringify({ page, blocks: blocks.results })
}]
};
}
if (name === "create_page") {
const { parent_id, title, content } = args as {
parent_id: string;
title: string;
content: string;
};
const page = await notion.pages.create({
parent: { page_id: parent_id },
properties: {
title: { title: [{ text: { content: title } }] }
},
children: [{
object: "block",
type: "paragraph",
paragraph: { rich_text: [{ text: { content } }] }
}]
});
return { content: [{ type: "text", text: `Created page: ${page.id}` }] };
}
});
Productivity MCP Examples:
| Server | Platform | Key Features |
|---|---|---|
| Slack MCP | Slack | Messages, channels, reactions, threads |
| Notion MCP | Notion | Pages, databases, blocks, search |
| Linear MCP | Linear | Issues, projects, cycles, roadmaps |
| Jira MCP | Jira | Tickets, sprints, boards, workflows |
| Calendar MCP | Google Calendar | Events, scheduling, availability |
| Email MCP | Gmail/IMAP | Read, send, search, organize |
AI and Memory Servers#
These MCP server examples give AI persistent memory. Without them, every conversation starts from zero.
Vector Memory with ChromaDB (Python):
This is how you give AI semantic search over its memories. Game changer for long-running projects.
from fastmcp import FastMCP
import chromadb
from chromadb.config import Settings
import uuid
mcp = FastMCP("memory-mcp")
client = chromadb.Client(Settings(
chroma_db_impl="duckdb+parquet",
persist_directory="./memory_store"
))
collection = client.get_or_create_collection(
name="memories",
metadata={"hnsw:space": "cosine"}
)
@mcp.tool
def remember(content: str, tags: list[str] = None) -> dict:
"""Store a memory for later retrieval."""
memory_id = str(uuid.uuid4())
metadata = {"tags": ",".join(tags)} if tags else {}
collection.add(
documents=[content],
ids=[memory_id],
metadatas=[metadata]
)
return {"id": memory_id, "status": "remembered"}
@mcp.tool
def recall(query: str, limit: int = 5) -> list[dict]:
"""Search memories by semantic similarity."""
results = collection.query(
query_texts=[query],
n_results=limit
)
memories = []
for i, doc in enumerate(results["documents"][0]):
memories.append({
"content": doc,
"id": results["ids"][0][i],
"distance": results["distances"][0][i] if results.get("distances") else None
})
return memories
@mcp.tool
def forget(memory_id: str) -> dict:
"""Delete a specific memory."""
collection.delete(ids=[memory_id])
return {"status": "forgotten", "id": memory_id}
@mcp.tool
def list_memories(limit: int = 20) -> list[dict]:
"""List recent memories."""
results = collection.peek(limit=limit)
return [
{"id": id, "content": doc[:100] + "..."}
for id, doc in zip(results["ids"], results["documents"])
]
Memory Server Comparison:
| Server | Type | Best For |
|---|---|---|
| Memory MCP | Key-value | Simple persistent context |
| ChromaDB MCP | Vector DB | Semantic search, embeddings |
| Qdrant MCP | Vector DB | Large-scale, production |
| Pinecone MCP | Vector DB | Managed, serverless |
| Vectara MCP | RAG | Retrieval-augmented generation |
| Redis MCP | Key-value | Fast, ephemeral memory |
MCP Server Examples by Language#
Same examples, organized by language. Pick your stack and go.
Python Examples#
Python dominates MCP server development. FastMCP makes it stupid simple.
Full-Featured Server Pattern:
Here's the pattern I use for production Python MCP servers. Multiple tools, resources, proper error handling.
from fastmcp import FastMCP
from typing import Optional
import logging
# Setup
mcp = FastMCP("production-server")
logger = logging.getLogger(__name__)
# Tools for actions
@mcp.tool
def create_item(name: str, data: dict) -> dict:
"""Create a new item with the given data."""
try:
# Your creation logic here
item_id = save_to_database(name, data)
return {"success": True, "id": item_id}
except Exception as e:
logger.error(f"Failed to create item: {e}")
return {"success": False, "error": str(e)}
@mcp.tool
def get_item(item_id: str) -> Optional[dict]:
"""Retrieve an item by ID."""
return fetch_from_database(item_id)
@mcp.tool
def update_item(item_id: str, updates: dict) -> dict:
"""Update an existing item."""
try:
update_in_database(item_id, updates)
return {"success": True}
except Exception as e:
return {"success": False, "error": str(e)}
@mcp.tool
def delete_item(item_id: str) -> dict:
"""Delete an item by ID."""
try:
delete_from_database(item_id)
return {"success": True}
except Exception as e:
return {"success": False, "error": str(e)}
# Resources for data access
@mcp.resource("items://{item_id}")
def item_resource(item_id: str) -> dict:
"""Resource for accessing item data directly."""
return fetch_from_database(item_id)
@mcp.resource("items://list")
def items_list_resource() -> list[dict]:
"""Resource for listing all items."""
return list_all_items()
# Prompts for common workflows
@mcp.prompt
def create_workflow() -> str:
"""Prompt for creating new items."""
return """
To create a new item, I need:
1. A name for the item
2. The data to store (as a dictionary)
Example: create_item(name="test", data={"key": "value"})
"""
Python Ecosystem Summary:
| Library | Purpose | When to Use |
|---|---|---|
| FastMCP | Rapid development | 90% of servers |
| mcp-server | Low-level control | Custom transports |
| asyncio | Async patterns | I/O heavy servers |
| Pydantic | Validation | Complex data models |
TypeScript Examples#
TypeScript is my choice for production MCP servers. The type safety is worth the extra ceremony.
Full-Featured Server Pattern:
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
// Schema definitions
const CreateItemSchema = z.object({
name: z.string().min(1),
data: z.record(z.unknown())
});
const UpdateItemSchema = z.object({
id: z.string().uuid(),
updates: z.record(z.unknown())
});
// Server setup
const server = new Server(
{ name: "production-server", version: "1.0.0" },
{ capabilities: { tools: {}, resources: {} } }
);
// Tool definitions
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: "create_item",
description: "Create a new item",
inputSchema: {
type: "object",
properties: {
name: { type: "string" },
data: { type: "object" }
},
required: ["name", "data"]
}
},
{
name: "get_item",
description: "Get an item by ID",
inputSchema: {
type: "object",
properties: {
id: { type: "string" }
},
required: ["id"]
}
},
{
name: "update_item",
description: "Update an existing item",
inputSchema: {
type: "object",
properties: {
id: { type: "string" },
updates: { type: "object" }
},
required: ["id", "updates"]
}
},
{
name: "delete_item",
description: "Delete an item",
inputSchema: {
type: "object",
properties: {
id: { type: "string" }
},
required: ["id"]
}
}
]
}));
// Tool handlers
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
switch (name) {
case "create_item": {
const { name, data } = CreateItemSchema.parse(args);
const id = await saveToDatabase(name, data);
return { content: [{ type: "text", text: JSON.stringify({ success: true, id }) }] };
}
case "get_item": {
const { id } = args as { id: string };
const item = await fetchFromDatabase(id);
return { content: [{ type: "text", text: JSON.stringify(item) }] };
}
case "update_item": {
const { id, updates } = UpdateItemSchema.parse(args);
await updateInDatabase(id, updates);
return { content: [{ type: "text", text: JSON.stringify({ success: true }) }] };
}
case "delete_item": {
const { id } = args as { id: string };
await deleteFromDatabase(id);
return { content: [{ type: "text", text: JSON.stringify({ success: true }) }] };
}
default:
throw new Error(`Unknown tool: ${name}`);
}
} catch (error) {
return {
content: [{
type: "text",
text: JSON.stringify({ success: false, error: String(error) })
}]
};
}
});
// Start server
const transport = new StdioServerTransport();
await server.connect(transport);
TypeScript Ecosystem:
| Package | Purpose | When to Use |
|---|---|---|
| @modelcontextprotocol/sdk | Official SDK | Always |
| zod | Runtime validation | Input validation |
| tsx | TypeScript execution | Development |
| tsup | Bundling | Production builds |
Other Languages#
MCP supports any language that can handle JSON-RPC over stdio. Here's the current state.
| Language | SDK/Library | Status | Maturity |
|---|---|---|---|
| Go | mcp-go | Community | Growing |
| Rust | mcp-rust | Community | Early |
| C# | MCP.NET | Official | Stable |
| Java | mcp-java | Community | Stable |
| Ruby | mcp-ruby | Community | Early |
| PHP | mcp-php | Community | Early |
The protocol is simple enough that writing your own implementation isn't crazy. JSON-RPC is well documented. But for production use, I'd stick with Python or TypeScript where the tooling is mature.
Are There Paid MCP Servers?#
Yes. And this is the part nobody talks about.
Here's the thing. Most MCP server examples you see online are open source. Cool for learning. But what about developers who want to build businesses around their MCP servers?
That's where MCPize comes in. It's a marketplace where developers sell MCP servers as products.
The ecosystem is mostly free right now. But that's changing fast.
Why developers charge for MCP servers:
- Premium API access isn't cheap. If your server wraps a paid API, you need to cover costs.
- Enterprise features require support. Companies pay for reliability and SLAs.
- Specialized tools save time. Time savings have real value.
- Continuous maintenance. Good servers need updates, bug fixes, security patches.
Pricing models that actually work:
| Model | Price Range | Best For |
|---|---|---|
| Subscription | $5-20/month | Ongoing access, regular updates |
| Usage-based | $0.01-0.10/call | API wrappers, high-volume tools |
| One-time | $10-50 | Simple tools, lifetime access |
| Freemium | Free + paid tier | Building audience, upselling power users |
The revenue opportunity:
MCPize offers 85% revenue share. You build the MCP server, set your price. MCPize handles hosting, billing, distribution, and payments.
I've seen developers make $500-2000/month from a single well-positioned MCP server. The ones that solve real pain points, not the toy examples.
What sells:
- Integrations with expensive enterprise APIs (cheaper than direct API access)
- Workflow automations that save hours per week
- Data processing that requires specialized knowledge
- Compliance and security focused tools
Templates and Starters#
Nobody should build from scratch anymore. These templates give you a head start.
| Template | Language | What's Included | Get Started |
|---|---|---|---|
| MCPize Python | Python | FastMCP, tests, CI/CD, linting | mcpize init --template python |
| MCPize TypeScript | TypeScript | Zod, ESLint, tests, builds | mcpize init --template typescript |
| Minimal Python | Python | Bare minimum, 10 lines | GitHub |
| Minimal TypeScript | TypeScript | Bare minimum, 20 lines | GitHub |
| FastMCP Advanced | Python | Multi-tool, resources, prompts | GitHub |
The MCPize templates are production-ready. Tests, linting, CI/CD config, everything. Run mcpize init and you're building features in minutes.
Example Servers on MCPize Marketplace#
These are real MCP servers you can install right now. Study them for inspiration.
Top Examples by Category:
| Server | Category | What Makes It Good |
|---|---|---|
| GitHub MCP | Dev Tools | Clean API, handles auth properly |
| Supabase MCP | Database | Full stack integration, real-time |
| Memory MCP | AI/Memory | Semantic search, persistence |
| Notion MCP | Productivity | Deep integration, block support |
| Slack MCP | Communication | Threading, reactions, search |
Each of these servers follows best practices:
- Clear tool descriptions (AI needs to understand what each tool does)
- Proper error handling (don't crash on bad input)
- Reasonable defaults (sensible behavior without configuration)
- Good documentation (users need to know how to set up)
FAQ#
What are MCP servers and clients?#
Simple breakdown. Servers expose capabilities: tools (actions), resources (data), and prompts (templates). Clients consume them. Claude Desktop, Cursor, VS Code with Copilot, these are clients. When you build an MCP server, you're building something these clients can use.
The protocol is just JSON-RPC over stdio. Servers wait for requests, process them, return results. That's it.
What is the most popular MCP server?#
GitHub MCP and Filesystem lead in usage. GitHub has around 2,890 uses tracked on Smithery. Filesystem is essential for any local development workflow.
But "popular" depends on your use case. For database work, PostgreSQL MCP and Supabase MCP dominate. For productivity, Notion and Slack are the top choices.
Can I sell my MCP server?#
Yes. Publish on MCPize, set your price, earn 85% of revenue. MCPize handles hosting, billing, and distribution.
The marketplace is still early. Good opportunity to establish yourself in a niche before it gets crowded.
What language should I use for MCP servers?#
Python with FastMCP for rapid development. The decorator syntax is clean and you can prototype fast. Great for data science integrations too.
TypeScript for production applications. Type safety catches bugs before users hit them. Better tooling for large codebases.
If you're just learning, start with Python. You can always rewrite in TypeScript later.
Do I need to build from scratch?#
No. Use templates: mcpize init --template python or mcpize init --template typescript.
Or fork an existing server from GitHub that's close to what you need. The MCP protocol is standardized, so the structure is always the same.
How do I test my MCP server?#
MCP Inspector is the official testing tool. It connects to your server over stdio and lets you call tools interactively.
npx @modelcontextprotocol/inspector your-server-command
For automated testing, mock the stdio transport and write unit tests for your tool handlers.
Next Steps#
You've seen the MCP server examples. Now build something.
Here's my recommended path:
- Pick a category that matches your idea
- Copy the relevant example as your starting point
- Modify for your use case (add tools, change logic)
- Test with MCP Inspector (make sure it actually works)
- Deploy and share (or sell on MCPize)
The hardest part is starting. These examples remove that barrier. Now it's just implementation.
Complete Build Guide Python Tutorial TypeScript TutorialRelated guides:
- What is MCP? for protocol fundamentals
- MCP Tutorial for hands-on beginner guide
- Monetize Your Server for pricing and revenue strategies
Building something interesting? Share it in the MCPize Discord or publish to the marketplace.



