Model Context Protocol (MCP): The USB-C Moment for AI Tool Integration
on Mcp, Ai, Llm, Tool use, Claude, Integration, Protocol
Model Context Protocol (MCP): The USB-C Moment for AI Tool Integration
When Anthropic open-sourced the Model Context Protocol (MCP) in late 2024, it solved a problem that had been quietly strangling AI tool development: every AI system had its own proprietary way of connecting to external tools and data sources. By mid-2026, MCP has become the de facto standard — supported by Claude, OpenAI, Google Gemini, and hundreds of third-party tools. This is the guide to understanding and building with it.
Photo by Google DeepMind on Unsplash
The Problem MCP Solves
Before MCP, if you wanted to connect an AI assistant to your tools:
- Slack needed its own AI integration
- GitHub needed its own AI integration
- Your internal database needed custom code for each LLM
- Moving from Claude to GPT-4 meant rewriting all integrations
The result: M × N problem. M AI models × N tools = M×N custom integrations. Maintenance nightmare.
MCP’s solution: A standard protocol. Build one MCP server for your tool, and any MCP-compatible AI client can use it. Build one MCP client (AI host), and any MCP server works with it.
Before MCP: After MCP:
Claude → GitHub (custom) Claude ↘
Claude → Slack (custom) GPT-4 → MCP → GitHub Server
Claude → Jira (custom) Gemini ↗ → Slack Server
GPT-4 → GitHub (custom) → Jira Server
GPT-4 → Slack (custom)
(N×M integrations) (N + M integrations)
MCP Architecture
MCP is a client-server protocol running over:
- stdio: Process-based communication (most common for local tools)
- SSE (Server-Sent Events): HTTP-based for remote servers
- Streamable HTTP: The 2026 addition, replacing SSE for production deployments
AI Host (Claude, ChatGPT, etc.)
├── MCP Client
│ └── Protocol layer (JSON-RPC 2.0)
│ ├── stdio transport → [MCP Server: filesystem]
│ ├── stdio transport → [MCP Server: git]
│ └── HTTP transport → [MCP Server: Slack API]
└── Uses tool results to form responses
Three Primitives
1. Tools — Functions the model can call
{
"name": "read_file",
"description": "Read the contents of a file from the filesystem",
"inputSchema": {
"type": "object",
"properties": {
"path": {
"type": "string",
"description": "Absolute or relative path to the file"
}
},
"required": ["path"]
}
}
2. Resources — Data the model can read (like files, database records)
{
"uri": "file:///home/user/docs/report.pdf",
"name": "Q3 Report",
"mimeType": "application/pdf"
}
3. Prompts — Reusable prompt templates the model can invoke
{
"name": "code_review",
"description": "Review code for bugs and improvements",
"arguments": [
{"name": "code", "description": "The code to review", "required": true},
{"name": "language", "description": "Programming language", "required": false}
]
}
Building an MCP Server
TypeScript (Official SDK)
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import { execSync } from "child_process";
const server = new McpServer({
name: "git-tools",
version: "1.0.0",
});
// Register a tool
server.tool(
"git_log",
"Get recent git commits for a repository",
{
repo_path: z.string().describe("Path to the git repository"),
limit: z.number().default(10).describe("Number of commits to return"),
},
async ({ repo_path, limit }) => {
try {
const log = execSync(
`git -C "${repo_path}" log --oneline -${limit}`,
{ encoding: "utf-8" }
);
return {
content: [{ type: "text", text: log }],
};
} catch (error) {
return {
content: [{ type: "text", text: `Error: ${error.message}` }],
isError: true,
};
}
}
);
// Register a tool that creates files
server.tool(
"create_file",
"Create a new file with given content",
{
path: z.string().describe("File path to create"),
content: z.string().describe("File content"),
},
async ({ path, content }) => {
await fs.writeFile(path, content, "utf-8");
return {
content: [{ type: "text", text: `Created ${path}` }],
};
}
);
// Start server
const transport = new StdioServerTransport();
await server.connect(transport);
Python (Official SDK)
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp import types
import httpx
server = Server("weather-server")
@server.list_tools()
async def list_tools() -> list[types.Tool]:
return [
types.Tool(
name="get_weather",
description="Get current weather for a location",
inputSchema={
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "City name or coordinates"
}
},
"required": ["location"]
}
)
]
@server.call_tool()
async def call_tool(name: str, arguments: dict) -> list[types.TextContent]:
if name == "get_weather":
location = arguments["location"]
async with httpx.AsyncClient() as client:
response = await client.get(
"https://wttr.in/{location}?format=j1",
params={"location": location}
)
data = response.json()
current = data["current_condition"][0]
return [types.TextContent(
type="text",
text=f"Weather in {location}: {current['weatherDesc'][0]['value']}, "
f"{current['temp_C']}°C, feels like {current['FeelsLikeC']}°C"
)]
raise ValueError(f"Unknown tool: {name}")
async def main():
async with stdio_server() as (read_stream, write_stream):
await server.run(read_stream, write_stream, server.create_initialization_options())
import asyncio
asyncio.run(main())
Building an MCP Client
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
// Connect to an MCP server
const transport = new StdioClientTransport({
command: "node",
args: ["/path/to/my-server/index.js"],
});
const client = new Client({
name: "my-ai-client",
version: "1.0.0",
});
await client.connect(transport);
// List available tools
const tools = await client.listTools();
console.log("Available tools:", tools.tools.map(t => t.name));
// Call a tool
const result = await client.callTool({
name: "git_log",
arguments: {
repo_path: "/home/user/myproject",
limit: 5
}
});
console.log(result.content[0].text);
// Use with Claude (via Anthropic SDK)
import Anthropic from "@anthropic-ai/sdk";
const anthropic = new Anthropic();
// Convert MCP tools to Anthropic format
const anthropicTools = tools.tools.map(tool => ({
name: tool.name,
description: tool.description,
input_schema: tool.inputSchema
}));
const response = await anthropic.messages.create({
model: "claude-opus-4-5",
max_tokens: 4096,
tools: anthropicTools,
messages: [{ role: "user", content: "What were the last 5 commits in my project?" }]
});
// Handle tool use
if (response.stop_reason === "tool_use") {
for (const block of response.content) {
if (block.type === "tool_use") {
const toolResult = await client.callTool({
name: block.name,
arguments: block.input
});
// Feed back to Claude...
}
}
}
Remote MCP Servers (HTTP Transport)
For production deployments, use Streamable HTTP:
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import express from "express";
const app = express();
app.use(express.json());
const server = new McpServer({
name: "production-api-tools",
version: "1.0.0",
});
// Register tools...
server.tool("query_database", "Query the production database", {
sql: z.string().describe("SQL query (SELECT only)"),
}, async ({ sql }) => {
// Validate: only SELECT queries
if (!sql.trim().toUpperCase().startsWith("SELECT")) {
return { content: [{ type: "text", text: "Only SELECT queries allowed" }], isError: true };
}
const results = await db.query(sql);
return { content: [{ type: "text", text: JSON.stringify(results, null, 2) }] };
});
// Handle MCP over HTTP
app.post("/mcp", async (req, res) => {
const transport = new StreamableHTTPServerTransport({
sessionIdGenerator: undefined, // stateless mode
});
res.on("close", () => transport.close());
await server.connect(transport);
await transport.handleRequest(req, res, req.body);
});
app.listen(3000);
Connect from Claude Desktop:
// claude_desktop_config.json
{
"mcpServers": {
"my-api": {
"url": "https://my-mcp-server.example.com/mcp"
}
}
}
The MCP Ecosystem in 2026
The server ecosystem has exploded. Notable MCP servers:
Official (Anthropic/partners):
@modelcontextprotocol/server-filesystem— file system access@modelcontextprotocol/server-git— git operations@modelcontextprotocol/server-github— GitHub API@modelcontextprotocol/server-postgres— PostgreSQL@modelcontextprotocol/server-slack— Slack workspace@modelcontextprotocol/server-brave-search— web search
Community (widely used):
mcp-server-kubernetes— Kubernetes cluster managementmcp-server-aws— AWS SDK operationsmcp-server-stripe— Payment processingmcp-server-linear— Linear project managementmcp-server-figma— Figma design filesmcp-server-playwright— Browser automation
Registry: mcp.so lists 1,200+ servers as of July 2026.
Security Model
MCP doesn’t define authentication — that’s intentional. Use your platform’s auth:
// OAuth 2.0 example (MCP 2025-11-05 spec)
const transport = new StreamableHTTPServerTransport({
sessionIdGenerator: () => crypto.randomUUID(),
onsessioninitialized: async (sessionId, request) => {
const authHeader = request.headers.authorization;
if (!authHeader?.startsWith("Bearer ")) {
throw new Error("Unauthorized");
}
const token = authHeader.slice(7);
await validateToken(token); // Your auth logic
}
});
Key security principles:
- Principle of least privilege: Only expose the tools the AI needs
- Input validation: Validate all tool inputs — the model could pass arbitrary data
- Audit logging: Log all tool calls with inputs and outputs
- Rate limiting: Prevent runaway agent loops
- Sandbox destructive operations: Confirm before delete/write operations
MCP vs Function Calling
A common question: How is MCP different from OpenAI-style function calling?
| Aspect | Function Calling | MCP |
|---|---|---|
| Scope | Single LLM call | Persistent server process |
| State | Stateless | Can be stateful |
| Discovery | Defined in prompt | Dynamic list_tools |
| Reusability | Per-request | Across models and clients |
| Resources | Not standard | First-class primitive |
| Prompts | Not standard | First-class primitive |
| Ecosystem | Proprietary | Open standard |
Function calling is how the model invokes a tool within a single conversation. MCP is how the client discovers and connects to tool providers across conversations and models.
In practice: AI clients use function calling as the transport mechanism for MCP tool calls. They’re complementary, not competing.
Building a Production MCP Server: Checklist
- Input schema validation with Zod/Pydantic
- Error handling that returns
isError: truewith descriptive messages - Logging with request/response correlation IDs
- Rate limiting per session
- Health endpoint if HTTP-based
- Graceful shutdown handling
- Tool descriptions are accurate and include example inputs
- No sensitive data in tool descriptions (they go to the LLM)
- Idempotent tools where possible
- Confirmation for destructive operations
MCP has done for AI tool integration what REST did for web APIs — provided a standard interface that decouples producers from consumers. Building an MCP server today means your tool works with Claude, GPT-4o, Gemini, and any future model that adopts the standard. That’s a compelling reason to build to the standard, not to a specific model’s proprietary interface.
Photo by Possessed Photography on Unsplash
이 글이 도움이 되셨다면 공감 및 광고 클릭을 부탁드립니다 :)
