Skip to content

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 Prompts

Tool 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 successfully

Resource 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 data

Core 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

Internal documentation for iNET Portal