#ai /
MCP Protocol Introduction: Connecting AI to Your Development Toolchain
An in-depth analysis of the Model Context Protocol (MCP) design philosophy, architecture, and implementation, helping developers understand how to let AI interact with external tools.
Goal
This article aims to help developers understand MCP (Model Context Protocol) core concepts, architecture design, and implementation methods, and master how to let AI assistants connect to external tools and data sources.
Background
AI assistants (like Claude, GPT) are powerful but cannot directly access external systems. MCP is an open protocol from Anthropic designed to solve this problem -- enabling AI to securely connect to various tools and data sources.
Why Do We Need MCP?
- Tool Integration: AI needs to access file systems, databases, APIs, etc.
- Data Access: AI needs to obtain context information
- Security Control: Needs standardized permission management
- Interoperability: Different AI tools need unified interfaces
MCP's Goal
MCP aims to create a universal protocol enabling AI to:
- Discover available tools
- Understand tool capabilities
- Securely invoke tools
- Obtain execution results
1. MCP Architecture
Core Components
+-----------------------------------------------------------+
| MCP Architecture |
+-----------------------------------------------------------+
| |
| +----------------+ +----------------+ |
| | MCP Host | | MCP Server | |
| | (AI App) |<---->| (Tool Provider) |
| +----------------+ +----------------+ |
| | | |
| | | |
| v v |
| +----------------+ +----------------+ |
| | MCP Client | | Tools/Resources| |
| | (Protocol) | | (Functionality)| |
| +----------------+ +----------------+ |
| |
+-----------------------------------------------------------+
Communication Flow
sequenceDiagram
participant Host as MCP Host
participant Client as MCP Client
participant Server as MCP Server
Host->>Client: Initialize connection
Client->>Server: Send initialize request
Server-->>Client: Return capability info
Client-->>Host: Report available tools
Host->>Client: Request tool execution
Client->>Server: Invoke tool
Server-->>Client: Return result
Client-->>Host: Return execution result
2. MCP Protocol Details
Message Format
MCP uses JSON-RPC 2.0 as the message format:
// Request message
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "read_file",
"arguments": {
"path": "/path/to/file.txt"
}
}
}
// Response message
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "File content..."
}
]
}
}
Capability Negotiation
// Initialize request
{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {
"tools": {},
"resources": {}
},
"clientInfo": {
"name": "my-ai-app",
"version": "1.0.0"
}
}
}
// Initialize response
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2024-11-05",
"capabilities": {
"tools": {
"listChanged": true
},
"resources": {
"subscribe": true
}
},
"serverInfo": {
"name": "my-mcp-server",
"version": "1.0.0"
}
}
}
3. MCP Server Implementation
Node.js Implementation
// server.ts
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
const server = new Server(
{
name: 'my-mcp-server',
version: '1.0.0',
},
{
capabilities: {
tools: {},
resources: {},
},
}
);
// Define tools
server.setRequestHandler('tools/list', async () => {
return {
tools: [
{
name: 'read_file',
description: 'Read file content',
inputSchema: {
type: 'object',
properties: {
path: {
type: 'string',
description: 'File path',
},
},
required: ['path'],
},
},
{
name: 'write_file',
description: 'Write file content',
inputSchema: {
type: 'object',
properties: {
path: {
type: 'string',
description: 'File path',
},
content: {
type: 'string',
description: 'File content',
},
},
required: ['path', 'content'],
},
},
],
};
});
// Handle tool calls
server.setRequestHandler('tools/call', async (request) => {
const { name, arguments: args } = request.params;
switch (name) {
case 'read_file':
const content = await readFile(args.path);
return {
content: [
{
type: 'text',
text: content,
},
],
};
case 'write_file':
await writeFile(args.path, args.content);
return {
content: [
{
type: 'text',
text: 'File written successfully',
},
],
};
default:
throw new Error(`Unknown tool: ${name}`);
}
});
// Start server
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error('MCP Server running on stdio');
}
main().catch(console.error);
Python Implementation
# server.py
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp.types import Tool, TextContent
import asyncio
import json
server = Server("my-mcp-server")
@server.list_tools()
async def list_tools():
return [
Tool(
name="read_file",
description="Read file content",
inputSchema={
"type": "object",
"properties": {
"path": {
"type": "string",
"description": "File path"
}
},
"required": ["path"]
}
),
Tool(
name="write_file",
description="Write file content",
inputSchema={
"type": "object",
"properties": {
"path": {
"type": "string",
"description": "File path"
},
"content": {
"type": "string",
"description": "File content"
}
},
"required": ["path", "content"]
}
)
]
@server.call_tool()
async def call_tool(name: str, arguments: dict):
if name == "read_file":
with open(arguments["path"], "r") as f:
content = f.read()
return [TextContent(type="text", text=content)]
elif name == "write_file":
with open(arguments["path"], "w") as f:
f.write(arguments["content"])
return [TextContent(type="text", text="File written successfully")]
else:
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()
)
if __name__ == "__main__":
asyncio.run(main())
4. MCP Client Implementation
Connecting to MCP Server
// client.ts
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
async function main() {
// Create transport layer
const transport = new StdioClientTransport({
command: 'node',
args: ['server.js'],
});
// Create client
const client = new Client(
{
name: 'my-mcp-client',
version: '1.0.0',
},
{
capabilities: {},
}
);
// Connect to server
await client.connect(transport);
// List available tools
const tools = await client.request(
{ method: 'tools/list' },
{}
);
console.log('Available tools:', tools);
// Invoke tool
const result = await client.request(
{
method: 'tools/call',
params: {
name: 'read_file',
arguments: {
path: '/path/to/file.txt',
},
},
},
{}
);
console.log('Result:', result);
}
main().catch(console.error);
5. Practical Application Examples
1. File System Access
// MCP Server for file system
const fileSystemServer = {
tools: [
{
name: 'list_directory',
description: 'List directory contents',
inputSchema: {
type: 'object',
properties: {
path: { type: 'string' },
},
},
},
{
name: 'read_file',
description: 'Read file',
inputSchema: {
type: 'object',
properties: {
path: { type: 'string' },
},
},
},
],
};
2. Database Query
// MCP Server for database
const databaseServer = {
tools: [
{
name: 'query',
description: 'Execute SQL query',
inputSchema: {
type: 'object',
properties: {
sql: { type: 'string' },
},
},
},
{
name: 'list_tables',
description: 'List all tables',
inputSchema: {
type: 'object',
properties: {},
},
},
],
};
3. API Call
// MCP Server for API
const apiServer = {
tools: [
{
name: 'get_request',
description: 'Send GET request',
inputSchema: {
type: 'object',
properties: {
url: { type: 'string' },
headers: { type: 'object' },
},
},
},
{
name: 'post_request',
description: 'Send POST request',
inputSchema: {
type: 'object',
properties: {
url: { type: 'string' },
body: { type: 'object' },
},
},
},
],
};
6. Security Considerations
Permission Control
// Permission check middleware
async function checkPermission(toolName: string, args: any) {
// Check if tool is allowed
const allowedTools = ['read_file', 'list_directory'];
if (!allowedTools.includes(toolName)) {
throw new Error('Tool not allowed');
}
// Check path permissions
if (toolName === 'read_file') {
const allowedPaths = ['/allowed/path'];
if (!allowedPaths.some(p => args.path.startsWith(p))) {
throw new Error('Path not allowed');
}
}
return true;
}
Audit Logging
// Audit logging
function logToolCall(toolName: string, args: any, result: any) {
console.log(JSON.stringify({
timestamp: new Date().toISOString(),
tool: toolName,
args,
result,
user: getCurrentUser(),
}));
}
7. MCP Ecosystem
Existing MCP Servers
## Official MCP Servers
### File System
- @modelcontextprotocol/server-filesystem
### Database
- @modelcontextprotocol/server-postgres
- @modelcontextprotocol/server-sqlite
### API
- @modelcontextprotocol/server-github
- @modelcontextprotocol/server-slack
### Development Tools
- @modelcontextprotocol/server-git
- @modelcontextprotocol/server-puppeteer
Tool Integration
## Applications Supporting MCP
### Claude Desktop
- Native MCP support
- Can configure custom servers
### Claude Code
- Supports MCP servers
- Can access file systems, Git, etc.
### Other AI Applications
- Integrate MCP through SDK
- Can create custom servers
8. Best Practices
1. Tool Design
// Good tool design
{
name: "search_files",
description: "Search for files containing specific content in a directory",
inputSchema: {
type: "object",
properties: {
directory: {
type: "string",
description: "Search directory"
},
pattern: {
type: "string",
description: "Search pattern (regex)"
},
fileTypes: {
type: "array",
items: { type: "string" },
description: "File type filter"
}
},
required: ["directory", "pattern"]
}
}
2. Error Handling
// Error handling
try {
const result = await executeTool(toolName, args);
return { success: true, data: result };
} catch (error) {
return {
success: false,
error: {
message: error.message,
code: error.code,
},
};
}
3. Performance Optimization
// Performance optimization
// 1. Cache tool list
let cachedTools = null;
async function getTools() {
if (!cachedTools) {
cachedTools = await fetchTools();
}
return cachedTools;
}
// 2. Batch operations
async function executeBatch(toolCalls) {
return Promise.all(toolCalls.map(executeTool));
}
Summary
MCP is an important open protocol that provides a standardized way for AI to interact with the outside world.
| Feature | Advantage | Use Case | |---------|-----------|----------| | Standardization | Unified interface | Multi-tool integration | | Security | Permission control | Enterprise applications | | Extensibility | Pluggable architecture | Various tools | | Interoperability | Cross-platform support | Multiple AI applications |
Recommendations:
- Understand MCP: This is an important standard in the AI toolchain
- Try Implementation: Start with simple servers
- Watch Ecosystem: MCP ecosystem is rapidly developing
- Security First: Pay attention to permission control in implementation
- Continuous Learning: MCP is still evolving
MCP extends AI's capabilities to the external world, providing a foundation for building smarter applications. This introductory guide will help you understand MCP's value and implementation methods.