Kiến trúc MCP
Overview
MCP architecture dựa trên client-server model với JSON-RPC 2.0 protocol. Architecture được thiết kế để:
- Simple và lightweight
- Secure và extensible
- Cross-platform compatible
- Easy to implement
High-level Architecture
┌─────────────────────────────────────────────────────────────┐
│ AI Application │
│ (MCP Client) │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ Claude │ │ Cursor │ │ Custom AI App │ │
│ │ Desktop │ │ IDE │ │ │ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
└─────────────────────┬───────────────────────────────────────┘
│ MCP Protocol (JSON-RPC 2.0)
│
┌─────────────────────▼───────────────────────────────────────┐
│ MCP Servers │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ Database │ │ File │ │ API │ │
│ │ Server │ │ Server │ │ Server │ │
│ │ │ │ │ │ │ │
│ │ • Tools │ │ • Tools │ │ • Tools │ │
│ │ • Resources │ │ • Resources │ │ • Resources │ │
│ │ • Prompts │ │ • Prompts │ │ • Prompts │ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
└─────────────────────┬───────────────────────────────────────┘
│
┌─────────────────────▼───────────────────────────────────────┐
│ External Systems │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ MongoDB │ │ File System │ │ REST APIs │ │
│ │ PostgreSQL │ │ Network │ │ GraphQL │ │
│ │ MySQL │ │ Cloud │ │ Webhooks │ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
└─────────────────────────────────────────────────────────────┘Core Components
1. Transport Layer
Cách client và server communicate:
stdio Transport (Default)
javascript
// Client launches server process
const server = spawn('mongodb-mcp-server', ['--connection-string', 'mongodb://...']);
// Communication via stdin/stdout
server.stdin.write(JSON.stringify({
jsonrpc: "2.0",
id: 1,
method: "tools/list"
}));
server.stdout.on('data', (data) => {
const response = JSON.parse(data.toString());
console.log(response);
});Pros:
- Simple setup
- No network configuration
- Secure (local process)
- Default for most clients
Cons:
- Single client per server
- Process management overhead
- Limited to local execution
HTTP Transport
javascript
// Server runs as HTTP service
const express = require('express');
const app = express();
app.post('/mcp', (req, res) => {
const request = req.body;
const response = await handleMCPRequest(request);
res.json(response);
});
app.listen(3000);Pros:
- Multiple clients
- Remote access
- Load balancing
- Monitoring integration
Cons:
- Network configuration
- Security considerations
- Authentication required
- More complex setup
Custom Transport
javascript
// WebSocket, gRPC, or custom protocol
class WebSocketTransport {
constructor(ws) {
this.ws = ws;
}
async send(message) {
this.ws.send(JSON.stringify(message));
}
async receive() {
return new Promise((resolve) => {
this.ws.on('message', (data) => {
resolve(JSON.parse(data));
});
});
}
}2. Protocol Layer
JSON-RPC 2.0 based protocol:
Request Format
json
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "query_database",
"arguments": {
"query": "SELECT * FROM users"
}
}
}Response Format
json
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"content": [
{
"type": "text",
"text": "Found 25 users"
}
]
}
}Error Format
json
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32601,
"message": "Method not found",
"data": {
"details": "Tool 'query_database' not found"
}
}
}3. Server Capabilities
Server advertise capabilities during initialization:
json
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2024-11-05",
"capabilities": {
"tools": {},
"resources": {},
"prompts": {},
"logging": {},
"experimental": {}
},
"serverInfo": {
"name": "mongodb-mcp-server",
"version": "1.0.0"
}
}
}Message Flow
Initialization Flow
mermaid
sequenceDiagram
participant C as Client
participant S as Server
C->>S: Initialize
S->>C: Server Capabilities
C->>S: Tools/List
S->>C: Available Tools
C->>S: Resources/List
S->>C: Available Resources
C->>S: Prompts/List
S->>C: Available PromptsTool Execution Flow
mermaid
sequenceDiagram
participant AI as AI Agent
participant C as Client
participant S as Server
participant DB as Database
AI->>C: "Query users from database"
C->>S: tools/call (query_database)
S->>DB: Execute SQL query
DB->>S: Query results
S->>C: Tool result
C->>AI: Results from database
AI->>C: "Create report file"
C->>S: tools/call (write_file)
S->>C: File created
C->>AI: File created successfullyResource Access Flow
mermaid
sequenceDiagram
participant AI as AI Agent
participant C as Client
participant S as Server
participant FS as File System
AI->>C: "Read configuration file"
C->>S: resources/read (file://config.json)
S->>FS: Read file
FS->>S: File content
S->>C: Resource content
C->>AI: Configuration dataCore MCP Operations
1. Tools Operations
List Tools
javascript
// Request
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list"
}
// Response
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"tools": [
{
"name": "query_database",
"description": "Execute SQL query",
"inputSchema": {
"type": "object",
"properties": {
"query": {"type": "string"}
}
}
}
]
}
}Call Tool
javascript
// Request
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "query_database",
"arguments": {
"query": "SELECT * FROM users WHERE active = true"
}
}
}
// Response
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"content": [
{
"type": "text",
"text": "Query executed successfully. Found 42 active users."
},
{
"type": "json",
"json": {
"users": [...],
"count": 42
}
}
]
}
}2. Resources Operations
List Resources
javascript
// Request
{
"jsonrpc": "2.0",
"id": 3,
"method": "resources/list"
}
// Response
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"resources": [
{
"uri": "file:///config/database.json",
"name": "Database Configuration",
"description": "Database connection settings",
"mimeType": "application/json"
}
]
}
}Read Resource
javascript
// Request
{
"jsonrpc": "2.0",
"id": 4,
"method": "resources/read",
"params": {
"uri": "file:///config/database.json"
}
}
// Response
{
"jsonrpc": "2.0",
"id": 4,
"result": {
"contents": [
{
"uri": "file:///config/database.json",
"mimeType": "application/json",
"text": "{\"host\": \"localhost\", \"port\": 5432}"
}
]
}
}3. Prompts Operations
List Prompts
javascript
// Request
{
"jsonrpc": "2.0",
"id": 5,
"method": "prompts/list"
}
// Response
{
"jsonrpc": "2.0",
"id": 5,
"result": {
"prompts": [
{
"name": "analyze_data",
"description": "Analyze database data",
"arguments": [
{
"name": "table",
"description": "Table to analyze",
"required": true
}
]
}
]
}
}Get Prompt
javascript
// Request
{
"jsonrpc": "2.0",
"id": 6,
"method": "prompts/get",
"params": {
"name": "analyze_data",
"arguments": {
"table": "users"
}
}
}
// Response
{
"jsonrpc": "2.0",
"id": 6,
"result": {
"description": "Analyze users table",
"messages": [
{
"role": "user",
"content": {
"type": "text",
"text": "Please analyze the users table and provide insights about user behavior patterns."
}
}
]
}
}Server Implementation Patterns
1. Basic Server Structure
javascript
class MCPServer {
constructor() {
this.tools = new Map();
this.resources = new Map();
this.prompts = new Map();
}
async initialize(request) {
return {
protocolVersion: "2024-11-05",
capabilities: {
tools: {},
resources: {},
prompts: {}
},
serverInfo: {
name: "my-mcp-server",
version: "1.0.0"
}
};
}
async listTools() {
return {
tools: Array.from(this.tools.values())
};
}
async callTool(name, arguments) {
const tool = this.tools.get(name);
if (!tool) {
throw new Error(`Tool ${name} not found`);
}
return await tool.handler(arguments);
}
}2. Tool Implementation
javascript
class DatabaseTool {
constructor(connection) {
this.connection = connection;
}
get definition() {
return {
name: "query_database",
description: "Execute SQL query",
inputSchema: {
type: "object",
properties: {
query: { type: "string" },
database: { type: "string" }
},
required: ["query"]
}
};
}
async handler(args) {
try {
const result = await this.connection.query(args.query);
return {
content: [
{
type: "text",
text: `Query executed successfully. ${result.rows.length} rows returned.`
},
{
type: "json",
json: result.rows
}
]
};
} catch (error) {
return {
content: [
{
type: "text",
text: `Error executing query: ${error.message}`
}
],
isError: true
};
}
}
}3. Resource Implementation
javascript
class FileResource {
constructor(basePath) {
this.basePath = basePath;
}
async list() {
const files = await this.scanDirectory(this.basePath);
return {
resources: files.map(file => ({
uri: `file://${file.path}`,
name: file.name,
description: `File: ${file.name}`,
mimeType: this.getMimeType(file.name)
}))
};
}
async read(uri) {
const filePath = uri.replace('file://', '');
const content = await fs.readFile(filePath, 'utf-8');
return {
contents: [
{
uri,
mimeType: this.getMimeType(filePath),
text: content
}
]
};
}
}Security Architecture
1. Authentication
javascript
// JWT-based authentication
class AuthMiddleware {
constructor(secretKey) {
this.secretKey = secretKey;
}
async authenticate(token) {
try {
const decoded = jwt.verify(token, this.secretKey);
return decoded;
} catch (error) {
throw new Error('Invalid authentication token');
}
}
async authorize(user, resource, action) {
// Check user permissions
const permissions = await this.getUserPermissions(user);
return permissions.includes(`${resource}:${action}`);
}
}2. Permission Model
javascript
const permissions = {
// Resource-level permissions
"file://config/*": ["read"],
"file://logs/*": ["read", "write"],
"database://users": ["read", "write"],
"database://admin": ["read"],
// Tool-level permissions
"tools/query": ["execute"],
"tools/write_file": ["execute"],
"tools/delete": ["admin"],
// Prompt-level permissions
"prompts/*": ["use"]
};3. Audit Trail
javascript
class AuditLogger {
async log(event) {
await this.db.insert('audit_logs', {
timestamp: new Date(),
user: event.user,
action: event.action,
resource: event.resource,
result: event.result,
ip: event.ip
});
}
}Performance Considerations
1. Connection Pooling
javascript
class DatabasePool {
constructor(config) {
this.pool = new Pool(config);
}
async execute(query) {
const client = await this.pool.connect();
try {
return await client.query(query);
} finally {
client.release();
}
}
}2. Caching
javascript
class ResourceCache {
constructor(ttl = 300000) { // 5 minutes
this.cache = new Map();
this.ttl = ttl;
}
async get(key) {
const cached = this.cache.get(key);
if (cached && Date.now() - cached.timestamp < this.ttl) {
return cached.value;
}
return null;
}
async set(key, value) {
this.cache.set(key, {
value,
timestamp: Date.now()
});
}
}3. Rate Limiting
javascript
class RateLimiter {
constructor(maxRequests = 100, windowMs = 60000) {
this.maxRequests = maxRequests;
this.windowMs = windowMs;
this.requests = new Map();
}
async isAllowed(clientId) {
const now = Date.now();
const windowStart = now - this.windowMs;
const clientRequests = this.requests.get(clientId) || [];
const recentRequests = clientRequests.filter(time => time > windowStart);
if (recentRequests.length >= this.maxRequests) {
return false;
}
recentRequests.push(now);
this.requests.set(clientId, recentRequests);
return true;
}
}Error Handling
1. Standardized Errors
javascript
class MCPError extends Error {
constructor(code, message, data = null) {
super(message);
this.code = code;
this.data = data;
}
}
// Standard error codes
const ErrorCodes = {
INVALID_REQUEST: -32600,
METHOD_NOT_FOUND: -32601,
INVALID_PARAMS: -32602,
INTERNAL_ERROR: -32603,
PARSE_ERROR: -32700
};2. Error Recovery
javascript
class ErrorHandler {
async handle(error, context) {
// Log error
await this.logger.error(error, context);
// Determine error type
if (error instanceof ValidationError) {
return {
code: ErrorCodes.INVALID_PARAMS,
message: "Invalid parameters",
data: { validationErrors: error.errors }
};
}
if (error instanceof DatabaseError) {
return {
code: ErrorCodes.INTERNAL_ERROR,
message: "Database operation failed",
data: { query: error.query }
};
}
// Default error
return {
code: ErrorCodes.INTERNAL_ERROR,
message: "Internal server error"
};
}
}Summary
MCP Architecture:
- ✅ Simple: JSON-RPC 2.0 based
- ✅ Flexible: Multiple transport options
- ✅ Secure: Built-in authentication/authorization
- ✅ Extensible: Easy to add new capabilities
- ✅ Performant: Connection pooling, caching, rate limiting
Key Components:
- Transport Layer: stdio, HTTP, custom
- Protocol Layer: JSON-RPC 2.0 messages
- Server Capabilities: Tools, Resources, Prompts
- Security: Authentication, authorization, audit
- Performance: Pooling, caching, rate limiting
Design Principles:
- Standardization across platforms
- Security by default
- Extensibility for custom needs
- Performance at scale
Tiếp theo: 3. MCP Server là gì? → Hiểu sâu về MCP servers