MCP Protocol in Practice: The Ultimate Guide to Building AI Agents in 2026#
In 2026, the Model Context Protocol (MCP) has become the de facto standard for AI Agent development. This guide takes you from protocol fundamentals to production deployment — covering server implementation, client integration, XiDao gateway routing, and real-world practices with Claude 4.7, GPT-5.5, and beyond.
Why MCP Matters in 2026#
When Anthropic released the initial MCP specification in late 2024, few anticipated how rapidly it would transform the AI ecosystem. In just over a year, MCP has evolved from an experimental protocol into the foundational infrastructure of the AI industry. By 2026, virtually every major AI model — Claude 4.7, GPT-5.5, Gemini 2.5 Ultra, DeepSeek-V4, Llama 4, and others — natively supports MCP.
What core problem does MCP solve? In a nutshell: it provides a standardized way for AI models to connect to external tools, data sources, and services. Before MCP, each AI platform had its own tool-calling mechanism, forcing developers to build separate integrations for every platform. MCP unifies this — build once, run everywhere.
┌─────────────────────────────────────────────────────┐
│ MCP Ecosystem Overview │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Claude │ │ GPT-5.5 │ │ Gemini │ ... │
│ │ 4.7 │ │ │ │ 2.5 │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │
│ └──────────┬───┴──────────────┘ │
│ │ │
│ ┌──────▼──────┐ │
│ │ MCP Client │ ← Unified client layer │
│ │ (JSON-RPC)│ │
│ └──────┬──────┘ │
│ │ │
│ ┌────────────┼────────────┐ │
│ │ │ │ │
│ ┌──▼───┐ ┌────▼───┐ ┌───▼────┐ │
│ │Tool │ │Resource│ │Prompt │ │
│ │Server│ │Server │ │Server │ │
│ └──┬───┘ └────┬───┘ └───┬────┘ │
│ │ │ │ │
│ ┌──▼───┐ ┌────▼───┐ ┌───▼────┐ │
│ │ DB │ │ File │ │ API │ │
│ └──────┘ └────────┘ └────────┘ │
└─────────────────────────────────────────────────────┘MCP Protocol Core Architecture#
Protocol Layers#
MCP uses a three-layer architecture:
- Transport Layer: Supports stdio, SSE (Server-Sent Events), and the Streamable HTTP transport added in 2025
- Message Layer: Based on JSON-RPC 2.0, handling requests, responses, and notifications
- Feature Layer: Four core capabilities — Tools, Resources, Prompts, and Sampling
┌───────────────────────────────────────┐
│ Feature Layer │
│ Tools │ Resources │ Prompts │ Sampling │
├───────────────────────────────────────┤
│ Message Layer (JSON-RPC 2.0) │
│ Request │ Response │ Notification │
├───────────────────────────────────────┤
│ Transport Layer │
│ stdio │ SSE │ Streamable HTTP │
└───────────────────────────────────────┘Four Core Capabilities#
| Capability | Direction | Description |
|---|---|---|
| Tools | Client → Server | AI models invoke external tools (function calling) |
| Resources | Client → Server | Read external data sources (files, databases, etc.) |
| Prompts | Client → Server | Retrieve predefined prompt templates |
| Sampling | Server → Client | Server requests AI model inference |
Hands-On: Building MCP Servers from Scratch#
Environment Setup#
Ensure your development environment meets these requirements:
# Node.js 20+ or Python 3.11+
node --version # v20.x+ recommended
python3 --version # 3.11+ recommended
# Install MCP SDK
# TypeScript
npm install @modelcontextprotocol/sdk
# Python
pip install mcpExample 1: TypeScript MCP Server (Database Query Tool)#
Let’s build a practical MCP Server that provides database querying capabilities:
// server.ts - Database Query MCP Server
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import Database from "better-sqlite3";
// Initialize database connection
const db = new Database("./data.db");
// Create MCP Server instance
const server = new McpServer({
name: "database-query-server",
version: "1.0.0",
capabilities: {
tools: {},
resources: {},
},
});
// ============ Tool Definitions ============
// Tool 1: Execute SQL Query
server.tool(
"query_database",
"Execute a SQL SELECT query and return results",
{
sql: z.string().describe("The SQL SELECT query to execute"),
params: z
.array(z.string())
.optional()
.describe("Parameterized query values"),
},
async ({ sql, params }) => {
// Safety check: only allow SELECT queries
if (!sql.trim().toUpperCase().startsWith("SELECT")) {
return {
content: [
{
type: "text",
text: "Error: Only SELECT queries are allowed",
},
],
isError: true,
};
}
try {
const stmt = db.prepare(sql);
const rows = params ? stmt.all(...params) : stmt.all();
return {
content: [
{
type: "text",
text: JSON.stringify(rows, null, 2),
},
],
};
} catch (error) {
return {
content: [
{
type: "text",
text: `Query execution failed: ${error.message}`,
},
],
isError: true,
};
}
}
);
// Tool 2: Get Table Schema
server.tool(
"list_tables",
"List all database tables and their schemas",
{},
async () => {
const tables = db
.prepare(
"SELECT name FROM sqlite_master WHERE type='table'"
)
.all();
const result = tables.map((t: any) => {
const columns = db
.prepare(`PRAGMA table_info(${t.name})`)
.all();
return {
table: t.name,
columns: columns.map((c: any) => ({
name: c.name,
type: c.type,
nullable: !c.notnull,
})),
};
});
return {
content: [
{
type: "text",
text: JSON.stringify(result, null, 2),
},
],
};
}
);
// ============ Resource Definitions ============
server.resource(
"database-schema",
"db://schema",
async (uri) => ({
contents: [
{
uri: uri.href,
text: JSON.stringify(
db
.prepare(
"SELECT * FROM sqlite_master WHERE type='table'"
)
.all(),
null,
2
),
},
],
})
);
// ============ Start Server ============
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Database MCP Server started");
}
main().catch(console.error);Example 2: Python MCP Server (API Aggregation Service)#
# server.py - API Aggregation MCP Server
import asyncio
import httpx
from mcp.server.fastmcp import FastMCP
# Create MCP Server
mcp = FastMCP(
name="api-aggregator",
version="1.0.0",
)
# HTTP client
http_client = httpx.AsyncClient(timeout=30.0)
@mcp.tool()
async def search_web(query: str, max_results: int = 5) -> str:
"""Search the web for up-to-date information"""
response = await http_client.get(
"https://api.search.example.com/search",
params={"q": query, "limit": max_results},
)
data = response.json()
results = [
f"### {r['title']}\n{r['snippet']}\nLink: {r['url']}"
for r in data["results"]
]
return "\n\n---\n\n".join(results)
@mcp.tool()
async def get_weather(city: str) -> str:
"""Get current weather information for a given city"""
response = await http_client.get(
f"https://api.weather.example.com/v1/current",
params={"city": city, "units": "metric"},
)
data = response.json()
return (
f"## Current Weather in {city}\n"
f"- Temperature: {data['temperature']}°C\n"
f"- Conditions: {data['description']}\n"
f"- Humidity: {data['humidity']}%\n"
f"- Wind Speed: {data['wind_speed']} km/h"
)
@mcp.tool()
async def translate_text(
text: str,
target_lang: str = "en"
) -> str:
"""Translate text to the specified language"""
response = await http_client.post(
"https://api.translate.example.com/v2/translate",
json={
"text": text,
"target": target_lang,
},
)
data = response.json()
return f"Translation ({target_lang}):\n{data['translated_text']}"
@mcp.resource("config://app")
def get_app_config() -> str:
"""Get application configuration"""
return """# API Aggregator Config
version: 1.0.0
services:
- web_search
- weather
- translation
"""
if __name__ == "__main__":
mcp.run(transport="stdio")Hands-On: Building an MCP Client#
TypeScript Client Implementation#
// client.ts - MCP Client
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
async function main() {
// Create MCP client
const transport = new StdioClientTransport({
command: "node",
args: ["./server.js"],
});
const client = new Client({
name: "my-agent-client",
version: "1.0.0",
});
await client.connect(transport);
// List available tools
const tools = await client.listTools();
console.log("Available tools:", tools);
// Call a tool
const result = await client.callTool({
name: "query_database",
arguments: {
sql: "SELECT * FROM users WHERE active = 1 LIMIT 10",
},
});
console.log("Query result:", result);
// Read resource
const resource = await client.readResource({
uri: "db://schema",
});
console.log("Database schema:", resource);
await client.close();
}
main().catch(console.error);Integrating with AI Models#
Combine the MCP Client with an AI model to build a complete Agent:
// agent.ts - Complete AI Agent Example
import Anthropic from "@anthropic-ai/sdk";
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
async function createAgent() {
// 1. Initialize MCP client
const transport = new StdioClientTransport({
command: "node",
args: ["./database-server.js"],
});
const mcpClient = new Client({
name: "xiadao-agent",
version: "1.0.0",
});
await mcpClient.connect(transport);
// 2. Get available tools, convert to Claude format
const toolsResponse = await mcpClient.listTools();
const claudeTools = toolsResponse.tools.map((tool) => ({
name: tool.name,
description: tool.description,
input_schema: tool.inputSchema,
}));
// 3. Initialize Claude client (via XiDao Gateway)
const anthropic = new Anthropic({
baseURL: "https://api.xidao.online/v1",
apiKey: process.env.XIDAO_API_KEY,
});
// 4. Agent conversation loop
const messages: Anthropic.MessageParam[] = [
{
role: "user",
content:
"Query the database for the number of active users registered in the last 7 days",
},
];
while (true) {
const response = await anthropic.messages.create({
model: "claude-4.7-sonnet",
max_tokens: 4096,
tools: claudeTools,
messages,
});
// Check for tool calls
const toolUseBlocks = response.content.filter(
(block) => block.type === "tool_use"
);
if (toolUseBlocks.length === 0) {
// No tool calls — return final result
const textBlock = response.content.find(
(block) => block.type === "text"
);
console.log("Agent reply:", textBlock?.text);
break;
}
// Process tool calls
messages.push({
role: "assistant",
content: response.content,
});
for (const toolCall of toolUseBlocks) {
console.log(`Calling tool: ${toolCall.name}`, toolCall.input);
const result = await mcpClient.callTool({
name: toolCall.name,
arguments: toolCall.input as Record<string, unknown>,
});
messages.push({
role: "user",
content: [
{
type: "tool_result",
tool_use_id: toolCall.id,
content: result.content as string,
},
],
});
}
}
await mcpClient.close();
}
createAgent().catch(console.error);XiDao API Gateway’s MCP Routing Support#
As a leading AI API gateway in 2026, XiDao provides comprehensive native support for the MCP protocol.
Unified MCP Gateway Architecture#
┌──────────────────────────────────────────────────┐
│ XiDao API Gateway │
│ │
│ ┌──────────────────────────────────────────────┐ │
│ │ MCP Protocol Router │ │
│ │ │ │
│ │ ┌─────────┐ ┌──────────┐ ┌──────────────┐ │ │
│ │ │ Routing │ │ Protocol │ │ Load │ │ │
│ │ │ Layer │ │ Transform│ │ Balancing │ │ │
│ │ └────┬────┘ └────┬─────┘ └──────┬───────┘ │ │
│ └───────┼───────────┼──────────────┼───────────┘ │
│ │ │ │ │
│ ┌─────┴───┐ ┌─────┴───┐ ┌───────┴────┐ │
│ │Claude │ │GPT-5.5 │ │Gemini 2.5 │ ... │
│ │4.7 │ │ │ │Ultra │ │
│ └─────────┘ └─────────┘ └────────────┘ │
│ │
│ ┌──────────────────────────────────────────────┐ │
│ │ MCP Server Registry │ │
│ │ • Auto-discover and register MCP Servers │ │
│ │ • Health checks & failover │ │
│ │ • Tool capability matching & routing │ │
│ └──────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────┘XiDao MCP Configuration Example#
# xidao-mcp-config.yaml
mcp_gateway:
enabled: true
# Model routing configuration
routing:
default_model: "claude-4.7-sonnet"
fallback_model: "gpt-5.5"
rules:
- match:
tool_type: "database"
route_to: "claude-4.7-opus"
- match:
tool_type: "code_generation"
route_to: "gpt-5.5"
- match:
tool_type: "multimodal"
route_to: "gemini-2.5-ultra"
# MCP Server management
servers:
- name: "db-server"
transport: "stdio"
command: "node"
args: ["./servers/db-server.js"]
health_check:
interval: 30s
timeout: 5s
- name: "api-aggregator"
transport: "sse"
url: "https://mcp-servers.xidao.online/api-aggregator"
auth:
type: "bearer"
token: "${MCP_API_TOKEN}"
# Rate limiting and security
security:
rate_limit: 1000 # max requests per minute
allowed_tools:
- "query_database"
- "search_web"
- "get_weather"
blocked_patterns:
- "DROP TABLE"
- "DELETE FROM"Calling MCP Through XiDao — Code Example#
# Using the XiDao SDK for MCP calls
import xidao
# Initialize XiDao client (handles MCP protocol automatically)
client = xidao.Client(
api_key="your-xidao-api-key",
gateway="https://api.xidao.online",
)
# Create an MCP-aware Agent
agent = client.create_agent(
model="claude-4.7-sonnet",
mcp_servers=[
{
"name": "database",
"transport": "stdio",
"command": "node",
"args": ["./db-server.js"],
},
{
"name": "web-search",
"transport": "sse",
"url": "https://mcp.xidao.online/web-search",
},
],
)
# Use the Agent — XiDao handles all MCP protocol details
result = agent.chat(
"Analyze the user growth trend over the past month "
"and search for industry reports from the same period"
)
print(result)Production Deployment Best Practices#
1. Containerizing MCP Servers#
# Dockerfile
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --production
COPY . .
RUN npm run build
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./
# Health check endpoint
HEALTHCHECK --interval=30s --timeout=5s \
CMD wget -qO- http://localhost:3000/health || exit 1
EXPOSE 3000
CMD ["node", "dist/server.js"]2. Docker Compose Orchestration#
# docker-compose.yml
version: "3.9"
services:
mcp-gateway:
image: xidao/mcp-gateway:latest
environment:
- XIDAO_API_KEY=${XIDAO_API_KEY}
- MCP_LOG_LEVEL=info
ports:
- "8080:8080"
depends_on:
mcp-db-server:
condition: service_healthy
mcp-api-server:
condition: service_healthy
deploy:
replicas: 3
resources:
limits:
memory: 512M
mcp-db-server:
build: ./servers/db
volumes:
- db-data:/app/data
healthcheck:
test: ["CMD", "node", "healthcheck.js"]
interval: 15s
timeout: 5s
retries: 3
mcp-api-server:
build: ./servers/api
environment:
- REDIS_URL=redis://redis:6379
depends_on:
- redis
redis:
image: redis:7-alpine
volumes:
- redis-data:/data
volumes:
db-data:
redis-data:3. Monitoring & Observability#
// monitoring.ts - MCP Server monitoring middleware
import { PrometheusExporter } from "@opentelemetry/exporter-prometheus";
import { MeterProvider } from "@opentelemetry/sdk-metrics";
// Prometheus metrics
const meterProvider = new MeterProvider({
readers: [
new PrometheusExporter({ port: 9090 }),
],
});
const meter = meterProvider.getMeter("mcp-server");
// Tool call counter
const toolCallCounter = meter.createCounter("mcp_tool_calls_total", {
description: "Total MCP tool invocations",
});
// Tool call latency histogram
const toolLatency = meter.createHistogram("mcp_tool_latency_ms", {
description: "MCP tool call latency in milliseconds",
});
// Wrap MCP Server tool handlers with instrumentation
function instrumentedHandler(name: string, handler: Function) {
return async (...args: any[]) => {
const startTime = Date.now();
try {
const result = await handler(...args);
toolCallCounter.add(1, {
tool: name,
status: "success",
});
return result;
} catch (error) {
toolCallCounter.add(1, {
tool: name,
status: "error",
});
throw error;
} finally {
toolLatency.record(Date.now() - startTime, {
tool: name,
});
}
};
}4. Security Hardening Checklist#
// security.ts - MCP security middleware
import { RateLimiter } from "limiter";
interface SecurityConfig {
maxToolCallsPerMinute: number;
maxInputLength: number;
blockedPatterns: RegExp[];
allowedOrigins: string[];
}
const securityConfig: SecurityConfig = {
maxToolCallsPerMinute: 60,
maxInputLength: 10000,
blockedPatterns: [
/DROP\s+TABLE/i,
/DELETE\s+FROM/i,
/TRUNCATE/i,
/--.*(?:password|secret|key)/i,
/\bexec\b.*\bcmd\b/i,
],
allowedOrigins: [
"https://xidao.online",
"https://api.xidao.online",
],
};
// Input validation middleware
function validateInput(input: unknown): boolean {
const str = JSON.stringify(input);
if (str.length > securityConfig.maxInputLength) {
throw new Error("Input exceeds maximum length");
}
for (const pattern of securityConfig.blockedPatterns) {
if (pattern.test(str)) {
throw new Error(`Input contains blocked pattern: ${pattern}`);
}
}
return true;
}
// Rate limiting
const limiter = new RateLimiter({
tokensPerInterval: securityConfig.maxToolCallsPerMinute,
interval: "minute",
});
export async function securityMiddleware(
request: any,
handler: Function
) {
// Rate limit check
if (!limiter.tryRemoveTokens(1)) {
throw new Error("Rate limit exceeded");
}
// Input validation
validateInput(request.params);
// Execute request
return handler(request);
}The 2026 MCP Ecosystem#
Major MCP Implementations#
| Framework/Platform | MCP Support | Notable Features |
|---|---|---|
| Claude 4.7 | Native | Sampling, multimodal tools |
| GPT-5.5 | Native | Function calling compatibility layer |
| Gemini 2.5 Ultra | Native | Large-context resource handling |
| DeepSeek-V4 | Native | Open-source optimized |
| LangChain 1.0 | Deep integration | Agent orchestration + MCP |
| LlamaIndex 1.0 | Deep integration | RAG + MCP resources |
| XiDao Gateway | Full support | Unified routing, load balancing, security |
Popular Community MCP Servers#
- @mcp/server-filesystem — File system operations
- @mcp/server-postgres — PostgreSQL database
- @mcp/server-github — GitHub API integration
- @mcp/server-slack — Slack messaging & channel management
- @mcp/server-aws — AWS cloud service operations
- @mcp/server-kubernetes — K8s cluster management
- @mcp/server-redis — Redis cache operations
- @mcp/server-terraform — Infrastructure as code management
Performance Optimization Tips#
1. Tool Description Optimization#
Good tool descriptions directly impact the AI model’s calling accuracy:
// ❌ Poor description
server.tool("query", "Query data", { sql: z.string() }, handler);
// ✅ Good description
server.tool(
"query_database",
"Execute a SQL SELECT query against a SQLite database. " +
"Returns an array of result rows as JSON. " +
"Supports parameterized queries to prevent SQL injection. " +
"Only supports read operations (SELECT), not writes.",
{
sql: z
.string()
.describe("Standard SQL SELECT statement, e.g.: SELECT * FROM users WHERE id = ?"),
params: z
.array(z.string())
.optional()
.describe("Values for parameterized placeholders (?) in the SQL"),
},
handler
);2. Response Format Optimization#
// Return structured, AI-friendly results
function formatForAI(data: any[]): string {
if (data.length === 0) {
return "Query returned empty results — no matching data found.";
}
// Provide summary
const summary = `Query returned ${data.length} records.\n`;
// Provide data preview
const preview = data.slice(0, 5).map((row, i) => {
return `Record ${i + 1}: ${JSON.stringify(row)}`;
});
// If data is large, suggest more precise queries
const hint =
data.length > 5
? `\n\nNote: Showing first 5 of ${data.length} records. Consider adding LIMIT or WHERE clauses for more precise results.`
: "";
return summary + preview.join("\n") + hint;
}3. Connection Pooling & Caching#
// Cache MCP Server connections
class McpConnectionPool {
private pool = new Map<string, Client>();
private maxSize: number;
constructor(maxSize = 10) {
this.maxSize = maxSize;
}
async getOrCreate(
key: string,
factory: () => Promise<Client>
): Promise<Client> {
if (this.pool.has(key)) {
return this.pool.get(key)!;
}
if (this.pool.size >= this.maxSize) {
// LRU eviction
const oldestKey = this.pool.keys().next().value;
const oldestClient = this.pool.get(oldestKey)!;
await oldestClient.close();
this.pool.delete(oldestKey);
}
const client = await factory();
this.pool.set(key, client);
return client;
}
}Conclusion#
In 2026, the Model Context Protocol has become the bedrock of AI Agent development. Whether you’re building a simple tool-augmented chatbot or a complex multi-agent system, MCP provides standardized, scalable infrastructure.
After reading this guide, you should have mastered:
- MCP Protocol Core Architecture — Transport, Message, and Feature layers
- Server Development — Both TypeScript and Python implementations
- Client Integration — Combining with AI models to build complete Agents
- Production Deployment — Containerization, monitoring, and security hardening
- Performance Optimization — Tool descriptions, response formatting, and connection management
Combined with the XiDao API Gateway’s MCP routing capabilities, you can effortlessly build cross-model, highly available AI Agent systems. XiDao provides a unified API interface, intelligent routing, load balancing, and security protection — letting you focus on business logic rather than infrastructure.
Start your MCP journey today:
This article was written by the XiDao AI API Gateway team. XiDao is dedicated to providing developers with the most convenient and powerful AI model access services, with full support for MCP protocol routing, load balancing, and security protection.