MCP (Model Context Protocol) Complete Guide
이 글의 핵심
MCP (Model Context Protocol) is an open protocol that allows AI models to communicate with external resources — file systems, databases, web APIs — in a standardized way. Supported by Claude Desktop, Cursor, VS Code, and more.
What is MCP?
MCP (Model Context Protocol) is an open-source protocol Anthropic published in late 2024. It lets AI models communicate with external resources — file systems, databases, web APIs, dev tools — in a standardized way.
Client (Claude Desktop, Cursor, VS Code)
↕ MCP Protocol
Server (file system, DB, web API, Git, Slack...)
Why MCP?
Before MCP, every AI app had to write its own integration code for every external tool. MCP provides a USB-like standard interface: write an MCP server once and reuse it across all compatible clients.
| Before MCP | With MCP |
|---|---|
| Each app writes its own API integration | Write MCP server once → all clients use it |
| Model changes require code rewrites | Works regardless of model or client |
| Security/auth reimplemented repeatedly | Handled consistently on the server side |
MCP Architecture
┌─────────────────────────────────────────┐
│ MCP Client │
│ (Claude Desktop / Cursor / VS Code) │
└────────────────┬────────────────────────┘
│ JSON-RPC over stdio / SSE
┌────────────────▼────────────────────────┐
│ MCP Server │
│ ┌──────────┐ ┌──────────┐ ┌───────┐ │
│ │ Tools │ │Resources │ │Prompts│ │
│ └──────────┘ └──────────┘ └───────┘ │
└────────────────┬────────────────────────┘
│
┌───────────┼───────────┐
▼ ▼ ▼
File system Database Web API
3 Core Concepts
- Tools: Functions the AI can call (similar to Function Calling)
- Resources: Data the AI can read (files, DB records, etc.)
- Prompts: Reusable prompt templates
Quick Start: Python MCP Server
Installation
pip install mcp
# or using uv (recommended)
pip install uv
uv add mcp
Your First MCP Server
The list_tools function is implemented below. It handles the core logic described above:
# server.py
from mcp.server import Server
from mcp.server.models import InitializationOptions
from mcp.server.stdio import stdio_server
from mcp.types import Tool, TextContent
import mcp.types as types
# Create server instance
server = Server("my-first-server")
@server.list_tools()
async def list_tools() -> list[Tool]:
"""Return list of available tools"""
return [
Tool(
name="calculate",
description="Evaluates a mathematical expression",
inputSchema={
"type": "object",
"properties": {
"expression": {
"type": "string",
"description": "Expression to evaluate (e.g. 2 + 3 * 4)"
}
},
"required": ["expression"]
}
),
Tool(
name="get_current_time",
description="Returns the current time",
inputSchema={
"type": "object",
"properties": {}
}
)
]
@server.call_tool()
async def call_tool(name: str, arguments: dict) -> list[TextContent]:
"""Handle tool calls"""
if name == "calculate":
expression = arguments.get("expression", "")
try:
# Safe eval (use a proper sandbox in production)
result = eval(expression, {"__builtins__": {}}, {})
return [TextContent(type="text", text=f"{expression} = {result}")]
except Exception as e:
return [TextContent(type="text", text=f"Error: {str(e)}")]
elif name == "get_current_time":
from datetime import datetime
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
return [TextContent(type="text", text=f"Current time: {now}")]
raise ValueError(f"Unknown tool: {name}")
async def main():
# Run in stdio mode (for local Claude Desktop connections)
async with stdio_server() as (read_stream, write_stream):
await server.run(
read_stream,
write_stream,
InitializationOptions(
server_name="my-first-server",
server_version="1.0.0",
capabilities=server.get_capabilities(
notification_options=None,
experimental_capabilities={}
)
)
)
if __name__ == "__main__":
import asyncio
asyncio.run(main())
Real-World Example: File System MCP Server
The list_tools function is implemented below. It handles the core logic described above:
# file_server.py
from mcp.server import Server
from mcp.server.models import InitializationOptions
from mcp.server.stdio import stdio_server
from mcp.types import Tool, TextContent
from pathlib import Path
import os
server = Server("file-system-server")
ALLOWED_DIR = Path(os.environ.get("ALLOWED_DIR", "/tmp/mcp-files"))
ALLOWED_DIR.mkdir(exist_ok=True)
@server.list_tools()
async def list_tools() -> list[Tool]:
return [
Tool(
name="read_file",
description="Read file contents",
inputSchema={
"type": "object",
"properties": {
"path": {"type": "string", "description": "File path"}
},
"required": ["path"]
}
),
Tool(
name="write_file",
description="Write content to a file",
inputSchema={
"type": "object",
"properties": {
"path": {"type": "string", "description": "File path"},
"content": {"type": "string", "description": "Content to write"}
},
"required": ["path", "content"]
}
),
Tool(
name="list_files",
description="List files in a directory",
inputSchema={
"type": "object",
"properties": {
"directory": {"type": "string", "description": "Directory path (defaults to base dir)"}
}
}
)
]
def validate_path(path_str: str) -> Path:
"""Security: only allow paths within the permitted directory"""
path = (ALLOWED_DIR / path_str).resolve()
if not str(path).startswith(str(ALLOWED_DIR)):
raise ValueError("Access denied: path is outside the allowed directory")
return path
@server.call_tool()
async def call_tool(name: str, arguments: dict) -> list[TextContent]:
if name == "read_file":
path = validate_path(arguments["path"])
if not path.exists():
return [TextContent(type="text", text=f"Error: file not found: {path}")]
content = path.read_text(encoding="utf-8")
return [TextContent(type="text", text=content)]
elif name == "write_file":
path = validate_path(arguments["path"])
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(arguments["content"], encoding="utf-8")
return [TextContent(type="text", text=f"File saved: {path.name}")]
elif name == "list_files":
dir_path = validate_path(arguments.get("directory", "."))
if not dir_path.is_dir():
return [TextContent(type="text", text="Not a directory")]
files = []
for item in sorted(dir_path.iterdir()):
if item.is_dir():
files.append(f"📁 {item.name}/")
else:
size = item.stat().st_size
files.append(f"📄 {item.name} ({size:,} bytes)")
result = "\n".join(files) if files else "No files found"
return [TextContent(type="text", text=result)]
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,
InitializationOptions(server_name="file-system-server", server_version="1.0.0",
capabilities=server.get_capabilities(notification_options=None, experimental_capabilities={})))
if __name__ == "__main__":
import asyncio
asyncio.run(main())
Building an MCP Server with TypeScript
npm install @modelcontextprotocol/sdk
Import the required modules and set up the dependencies:
// server.ts
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import fetch from "node-fetch";
const server = new Server(
{ name: "weather-server", version: "1.0.0" },
{ capabilities: { tools: {} } }
);
// Define tools
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: "get_weather",
description: 'Get current weather for a city. MCP (Model Context Protocol) Complete Guide에 대한 완전한 가이드입니다. 실전 예제와 함께 핵심 개념부터 고급 활용까지 다룹니다.',
inputSchema: {
type: "object",
properties: {
city: {
type: "string",
description: "City name (in English)",
},
},
required: ["city"],
},
},
],
}));
// Handle tool calls
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
if (name === "get_weather") {
const city = args?.city as string;
const apiKey = process.env.OPENWEATHER_API_KEY;
const response = await fetch(
`https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${apiKey}&units=metric`
);
const data = (await response.json()) as any;
if (data.cod !== 200) {
return {
content: [{ type: "text", text: `Error: ${data.message}` }],
};
}
return {
content: [
{
type: "text",
text: `${city} weather: ${data.weather[0].description}, ${data.main.temp}°C (feels like ${data.main.feels_like}°C)`,
},
],
};
}
throw new Error(`Unknown tool: ${name}`);
});
// Start server
const transport = new StdioServerTransport();
await server.connect(transport);
Connecting to Claude Desktop
Configuration file:
// ~/Library/Application Support/Claude/claude_desktop_config.json (macOS)
// %APPDATA%\Claude\claude_desktop_config.json (Windows)
{
"mcpServers": {
"my-calculator": {
"command": "python",
"args": ["/path/to/server.py"],
"env": {}
},
"file-system": {
"command": "python",
"args": ["/path/to/file_server.py"],
"env": {
"ALLOWED_DIR": "/Users/username/Documents"
}
},
"weather": {
"command": "node",
"args": ["/path/to/weather-server/build/index.js"],
"env": {
"OPENWEATHER_API_KEY": "your-api-key-here"
}
}
}
}
Restart Claude Desktop and a 🔧 tool icon will appear at the bottom of the chat window.
Using Resources and Prompts
Resources (Reading Data)
The list_resources function is implemented below. It handles the core logic described above:
from mcp.types import Resource, TextResourceContents
@server.list_resources()
async def list_resources() -> list[Resource]:
return [
Resource(
uri="file:///config.json",
name="Config file",
description="Application configuration",
mimeType="application/json"
)
]
@server.read_resource()
async def read_resource(uri: str) -> str | bytes:
if uri == "file:///config.json":
return '{"version": "1.0", "debug": false}'
raise ValueError(f"Unknown resource: {uri}")
Prompts (Reusable Templates)
The list_prompts function is implemented below. It handles the core logic described above:
from mcp.types import Prompt, PromptArgument, GetPromptResult, PromptMessage
@server.list_prompts()
async def list_prompts() -> list[Prompt]:
return [
Prompt(
name="code_review",
description="Code review request prompt",
arguments=[
PromptArgument(name="language", description="Programming language", required=True),
PromptArgument(name="focus", description="Review focus area", required=False)
]
)
]
@server.get_prompt()
async def get_prompt(name: str, arguments: dict | None) -> GetPromptResult:
if name == "code_review":
language = arguments.get("language", "code") if arguments else "code"
focus = arguments.get("focus", "overall quality") if arguments else "overall quality"
return GetPromptResult(
description=f"{language} code review",
messages=[
PromptMessage(
role="user",
content=TextContent(
type="text",
text=f"""Please review the following {language} code with a focus on {focus}:
1. Code quality and readability
2. Potential bugs and errors
3. Performance optimization opportunities
4. Security vulnerabilities
5. Improvement suggestions (with code examples)"""
)
)
]
)
raise ValueError(f"Unknown prompt: {name}")
Popular MCP Servers
Official MCP servers from Anthropic and the community:
Run the following commands:
# Filesystem server (official)
npx -y @modelcontextprotocol/server-filesystem /path/to/directory
# SQLite server (official)
npx -y @modelcontextprotocol/server-sqlite /path/to/database.db
# GitHub server (official)
npx -y @modelcontextprotocol/server-github
# PostgreSQL server
npx -y @modelcontextprotocol/server-postgres postgresql://user:pass@localhost/db
# Slack server
npx -y @modelcontextprotocol/server-slack
# Brave Search server
npx -y @modelcontextprotocol/server-brave-search
Conclusion
MCP is rapidly becoming core infrastructure for the AI agent ecosystem. Learning it now gives you a significant edge in AI agent development.
Next steps:
Frequently Asked Questions (FAQ)
Q. When would I use this in practice?
A. MCP (Model Context Protocol) is Anthropic’s open standard for connecting AI to external tools. Learn how to build and co…
Q. What should I read before this?
A. Follow the previous article or related articles links at the bottom of each post to learn in sequence.
Q. Where can I study this more deeply?
A. Check cppreference and the relevant library’s official documentation. The reference links at the end of the article are also worth using.
Related Articles (Internal Links)
Other articles related to this topic.
- FastAPI Complete Guide | Python REST API· Async
- gRPC Complete Guide | Protocol Buffers· Service Definitions
- Claude API Complete Guide | Anthropic SDK Usage
Keywords Covered in This Article (Related Search Terms)
This article covers MCP, Claude, AI, Agent, Python, TypeScript, Tools, Anthropic.