You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
proxysql/doc/MCP/Architecture.md

22 KiB

MCP Architecture

This document describes the architecture of the MCP (Model Context Protocol) module in ProxySQL, including endpoint design, tool handler implementation, and future architectural direction.

Overview

The MCP module implements JSON-RPC 2.0 over HTTPS for LLM (Large Language Model) integration with ProxySQL. It provides multiple endpoints, each designed to serve specific purposes while sharing a single HTTPS server.

Key Concepts

  • MCP Endpoint: A distinct HTTPS endpoint (e.g., /mcp/config, /mcp/query) that implements MCP protocol
  • Tool Handler: A C++ class that implements specific tools available to LLMs
  • Tool Discovery: Dynamic discovery via tools/list method (MCP protocol standard)
  • Endpoint Authentication: Per-endpoint Bearer token authentication
  • Connection Pooling: MySQL connection pooling for efficient database access

Current Architecture

Component Diagram

┌─────────────────────────────────────────────────────────────────────────────┐
│                              ProxySQL Process                               │
│                                                                             │
│  ┌──────────────────────────────────────────────────────────────────────┐  │
│  │                     MCP_Threads_Handler                               │  │
│  │  - Configuration variables (mcp-*)                                    │  │
│  │  - Status variables                                                   │  │
│  │  - mcp_server (ProxySQL_MCP_Server)                                   │  │
│  │  - mysql_tool_handler (MySQL_Tool_Handler)                            │  │
│  └──────────────────────────────────────────────────────────────────────┘  │
│                                    │                                        │
│                                    ▼                                        │
│  ┌──────────────────────────────────────────────────────────────────────┐  │
│  │                     ProxySQL_MCP_Server                               │  │
│  │                      (Single HTTPS Server)                            │  │
│  │                                                                       │  │
│  │  Port: mcp-port (default 6071)                                        │  │
│  │  SSL: Uses ProxySQL's certificates                                    │  │
│  └──────────────────────────────────────────────────────────────────────┘  │
│                                    │                                        │
│              ┌─────────────────────┼─────────────────────┐                 │
│              ▼                     ▼                     ▼                 │
│  ┌───────────────────┐ ┌───────────────────┐ ┌───────────────────┐         │
│  │   /mcp/config     │ │   /mcp/observe    │ │   /mcp/query      │         │
│  │ MCP_JSONRPC_      │ │ MCP_JSONRPC_      │ │ MCP_JSONRPC_      │         │
│  │ Resource          │ │ Resource          │ │ Resource          │         │
│  └─────────┬─────────┘ └─────────┬─────────┘ └─────────┬─────────┘         │
│            │                     │                     │                     │
│            └─────────────────────┼─────────────────────┘                     │
│                                  ▼                                         │
│           ┌────────────────────────────────────────────┐                    │
│           │      MySQL_Tool_Handler (Shared)           │                    │
│           │                                            │                    │
│           │  Tools:                                    │                    │
│           │  - list_schemas                            │                    │
│           │  - list_tables                             │                    │
│           │  - describe_table                          │                    │
│           │  - get_constraints                         │                    │
│           │  - table_profile                           │                    │
│           │  - column_profile                          │                    │
│           │  - sample_rows                             │                    │
│           │  - run_sql_readonly                        │                    │
│           │  - catalog_* (6 tools)                     │                    │
│           └────────────────────────────────────────────┘                    │
│                                  │                                         │
│                                  ▼                                         │
│           ┌────────────────────────────────────────────┐                    │
│           │         MySQL Backend                      │                    │
│           │    (Connection Pool)                       │                    │
│           └────────────────────────────────────────────┘                    │
└─────────────────────────────────────────────────────────────────────────────┘

Current Limitations

  1. All endpoints share the same tool handler - No differentiation between endpoints
  2. Same tools available everywhere - No specialized tools per endpoint
  3. Single connection pool - All queries use the same MySQL connections
  4. No per-endpoint authentication in code - Variables exist but not implemented

File Structure

include/
├── MCP_Thread.h          # MCP_Threads_Handler class definition
├── MCP_Endpoint.h        # MCP_JSONRPC_Resource class definition
├── MySQL_Tool_Handler.h  # MySQL_Tool_Handler class definition
├── MySQL_Catalog.h       # SQLite catalog for LLM memory
└── ProxySQL_MCP_Server.hpp # ProxySQL_MCP_Server class definition

lib/
├── MCP_Thread.cpp        # MCP_Threads_Handler implementation
├── MCP_Endpoint.cpp      # MCP_JSONRPC_Resource implementation
├── MySQL_Tool_Handler.cpp # MySQL_Tool_Handler implementation
├── MySQL_Catalog.cpp     # SQLite catalog implementation
└── ProxySQL_MCP_Server.cpp # HTTPS server implementation

Request Flow (Current)

1. LLM Client → POST /mcp/{endpoint} → HTTPS Server (port 6071)
2. HTTPS Server → MCP_JSONRPC_Resource::render_POST()
3. MCP_JSONRPC_Resource → handle_jsonrpc_request()
4. Route based on JSON-RPC method:
   - initialize/ping → Handled directly
   - tools/list → handle_tools_list()
   - tools/describe → handle_tools_describe()
   - tools/call → handle_tools_call() → MySQL_Tool_Handler
5. MySQL_Tool_Handler → MySQL Backend (via connection pool)
6. Return JSON-RPC response

Future Architecture: Multiple Tool Handlers

Goal

Each MCP endpoint will have its own dedicated tool handler with specific tools designed for that endpoint's purpose. This allows for:

  • Specialized tools - Different tools for different purposes
  • Isolated resources - Separate connection pools per endpoint
  • Independent authentication - Per-endpoint credentials
  • Clear separation of concerns - Each endpoint has a well-defined purpose

Target Architecture

┌─────────────────────────────────────────────────────────────────────────────┐
│                              ProxySQL Process                               │
│                                                                             │
│  ┌──────────────────────────────────────────────────────────────────────┐  │
│  │                     MCP_Threads_Handler                               │  │
│  │  - Configuration variables                                            │  │
│  │  - Status variables                                                   │  │
│  │  - mcp_server                                                         │  │
│  │  - config_tool_handler  (NEW)                                         │  │
│  │  - query_tool_handler   (NEW)                                         │  │
│  │  - admin_tool_handler   (NEW)                                         │  │
│  │  - cache_tool_handler   (NEW)                                         │  │
│  │  - observe_tool_handler (NEW)                                         │  │
│  └──────────────────────────────────────────────────────────────────────┘  │
│                                    │                                        │
│                                    ▼                                        │
│  ┌──────────────────────────────────────────────────────────────────────┐  │
│  │                     ProxySQL_MCP_Server                               │  │
│  │                      (Single HTTPS Server)                            │  │
│  └──────────────────────────────────────────────────────────────────────┘  │
│                                    │                                        │
│    ┌──────────────┬──────────────┼──────────────┬──────────────┬─────────┐  │
│    ▼              ▼              ▼              ▼              ▼         ▼  │
│ ┌────┐        ┌────┐         ┌────┐         ┌────┐         ┌────┐    ┌───┐│
│ │conf│        │obs │         │qry │         │adm │         │cach│    │cat││
│ │TH  │        │TH  │         │TH  │         │TH  │         │TH  │    │log│││
│ └─┬──┘        └─┬──┘         └─┬──┘         └─┬──┘         └─┬──┘    └─┬─┘│
│   │             │               │               │               │        │  │
│   │             │               │               │               │        │  │
│ Tools:         Tools:         Tools:         Tools:         Tools:      │  │
│ - get_config   - list_        - list_        - admin_       - get_      │  │
│ - set_config    stats          schemas       - set_          cache      │  │
│ - reload       - show_        - list_        - reload       - set_      │  │
│                 metrics        tables                       - invalidate │  │
│                               - query                                  │  │
│                                                                         │  │
└─────────────────────────────────────────────────────────────────────────────┘

Where:

  • TH = Tool Handler

Endpoint Specifications

/mcp/config - Configuration Endpoint

Purpose: Runtime configuration and management of ProxySQL

Tools:

  • get_config - Get current configuration values
  • set_config - Modify configuration values
  • reload_config - Reload configuration from disk/memory
  • list_variables - List all available variables
  • get_status - Get server status information

Use Cases:

  • LLM assistants that need to configure ProxySQL
  • Automated configuration management
  • Dynamic tuning based on workload

Authentication: mcp-config_endpoint_auth (Bearer token)


/mcp/observe - Observability Endpoint

Purpose: Real-time metrics, statistics, and monitoring data

Tools:

  • list_stats - List available statistics
  • get_stats - Get specific statistics
  • show_connections - Show active connections
  • show_queries - Show query statistics
  • get_health - Get health check information
  • show_metrics - Show performance metrics

Use Cases:

  • LLM assistants for monitoring and observability
  • Automated alerting and health checks
  • Performance analysis

Authentication: mcp-observe_endpoint_auth (Bearer token)


/mcp/query - Query Endpoint

Purpose: Safe database exploration and query execution

Tools:

  • list_schemas - List databases
  • list_tables - List tables in schema
  • describe_table - Get table structure
  • get_constraints - Get foreign keys and constraints
  • sample_rows - Get sample data
  • run_sql_readonly - Execute read-only SQL
  • explain_sql - Explain query execution plan

Use Cases:

  • LLM assistants for database exploration
  • Data analysis and discovery
  • Query optimization assistance

Authentication: mcp-query_endpoint_auth (Bearer token)


/mcp/admin - Administration Endpoint

Purpose: Administrative operations

Tools:

  • admin_list_users - List MySQL users
  • admin_create_user - Create MySQL user
  • admin_grant_permissions - Grant permissions
  • admin_show_processes - Show running processes
  • admin_kill_query - Kill a running query
  • admin_flush_cache - Flush various caches
  • admin_reload - Reload users/servers

Use Cases:

  • LLM assistants for administration tasks
  • Automated user management
  • Emergency operations

Authentication: mcp-admin_endpoint_auth (Bearer token, most restrictive)


/mcp/cache - Cache Endpoint

Purpose: Query cache management

Tools:

  • get_cache_stats - Get cache statistics
  • invalidate_cache - Invalidate cache entries
  • set_cache_ttl - Set cache TTL
  • clear_cache - Clear all cache
  • warm_cache - Warm up cache with queries
  • get_cache_entries - List cached queries

Use Cases:

  • LLM assistants for cache optimization
  • Automated cache management
  • Performance tuning

Authentication: mcp-cache_endpoint_auth (Bearer token)


Tool Discovery Flow

MCP clients should discover available tools dynamically:

1. Client → POST /mcp/config → {"method": "tools/list", ...}
2. Server → {"result": {"tools": [
      {"name": "get_config", "description": "..."},
      {"name": "set_config", "description": "..."},
      ...
   ]}}

3. Client → POST /mcp/query → {"method": "tools/list", ...}
4. Server → {"result": {"tools": [
      {"name": "list_schemas", "description": "..."},
      {"name": "list_tables", "description": "..."},
      ...
   ]}}

Example Discovery:

# Discover tools on /mcp/query endpoint
curl -k -X POST https://127.0.0.1:6071/mcp/query \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -d '{"jsonrpc": "2.0", "method": "tools/list", "id": 1}'

Tool Handler Base Class

All tool handlers will inherit from a common base class:

class MCP_Tool_Handler {
public:
    virtual ~MCP_Tool_Handler() = default;

    // Tool discovery
    virtual json get_tool_list() = 0;
    virtual json get_tool_description(const std::string& tool_name) = 0;
    virtual json execute_tool(const std::string& tool_name, const json& arguments) = 0;

    // Lifecycle
    virtual int init() = 0;
    virtual void close() = 0;
};

Per-Endpoint Authentication

Each endpoint validates its own Bearer token. The implementation is complete and supports:

  • Bearer token from Authorization header
  • Query parameter fallback (?token=xxx) for simple testing
  • No authentication when token is not configured (backward compatible)
bool MCP_JSONRPC_Resource::authenticate_request(const http_request& req) {
    // Get the expected auth token for this endpoint
    char* expected_token = nullptr;

    if (endpoint_name == "config") {
        expected_token = handler->variables.mcp_config_endpoint_auth;
    } else if (endpoint_name == "observe") {
        expected_token = handler->variables.mcp_observe_endpoint_auth;
    } else if (endpoint_name == "query") {
        expected_token = handler->variables.mcp_query_endpoint_auth;
    } else if (endpoint_name == "admin") {
        expected_token = handler->variables.mcp_admin_endpoint_auth;
    } else if (endpoint_name == "cache") {
        expected_token = handler->variables.mcp_cache_endpoint_auth;
    }

    // If no auth token is configured, allow the request
    if (!expected_token || strlen(expected_token) == 0) {
        return true; // No authentication required
    }

    // Try to get Bearer token from Authorization header
    std::string auth_header = req.get_header("Authorization");

    if (auth_header.empty()) {
        // Fallback: try getting from query parameter
        const std::map<std::string, std::string, http::arg_comparator>& args = req.get_args();
        auto it = args.find("token");
        if (it != args.end()) {
            auth_header = "Bearer " + it->second;
        }
    }

    if (auth_header.empty()) {
        return false; // No authentication provided
    }

    // Check if it's a Bearer token
    const std::string bearer_prefix = "Bearer ";
    if (auth_header.length() <= bearer_prefix.length() ||
        auth_header.compare(0, bearer_prefix.length(), bearer_prefix) != 0) {
        return false; // Invalid format
    }

    // Extract and validate token
    std::string provided_token = auth_header.substr(bearer_prefix.length());
    // Trim whitespace
    size_t start = provided_token.find_first_not_of(" \t\n\r");
    size_t end = provided_token.find_last_not_of(" \t\n\r");
    if (start != std::string::npos && end != std::string::npos) {
        provided_token = provided_token.substr(start, end - start + 1);
    }

    return (provided_token == expected_token);
}

Status: Implemented (lib/MCP_Endpoint.cpp)

Connection Pooling Strategy

Each tool handler manages its own connection pool:

class Config_Tool_Handler : public MCP_Tool_Handler {
private:
    std::vector<MYSQL*> config_connection_pool;  // For ProxySQL admin
    pthread_mutex_t pool_lock;
};

Implementation Roadmap

Phase 1: Base Infrastructure

  1. Create MCP_Tool_Handler base class
  2. Create stub implementations for all 5 tool handlers
  3. Update MCP_Threads_Handler to manage all handlers
  4. Update ProxySQL_MCP_Server to pass handlers to endpoints

Phase 2: Tool Implementation

  1. Implement Config_Tool_Handler tools
  2. Implement Query_Tool_Handler tools (move from MySQL_Tool_Handler)
  3. Implement Admin_Tool_Handler tools
  4. Implement Cache_Tool_Handler tools
  5. Implement Observe_Tool_Handler tools

Phase 3: Authentication & Testing

  1. Implement per-endpoint authentication
  2. ⚠️ Update test scripts to use dynamic tool discovery
  3. ⚠️ Add integration tests for each endpoint
  4. ⚠️ Documentation updates

Migration Strategy

Backward Compatibility

The migration to multiple tool handlers will maintain backward compatibility:

  1. The existing mysql_tool_handler will be renamed to query_tool_handler
  2. Existing tools will continue to work on /mcp/query
  3. New endpoints will be added incrementally
  4. Deprecation warnings for accessing tools on wrong endpoints

Gradual Migration

Step 1: Add new base class and stub handlers (no behavior change)
Step 2: Implement /mcp/config endpoint (new functionality)
Step 3: Move MySQL tools to /mcp/query (existing tools migrate)
Step 4: Implement /mcp/admin (new functionality)
Step 5: Implement /mcp/cache (new functionality)
Step 6: Implement /mcp/observe (new functionality)
Step 7: Enable per-endpoint auth

Version

  • MCP Thread Version: 0.1.0
  • Architecture Version: 1.0 (design document)
  • Last Updated: 2025-01-12