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/plugins/genai
Rene Cannao 29402b4a42
docs(plugins/genai): close 3 small gaps from review
2 months ago
..
include docs(plugins/genai): close 3 small gaps from review 2 months ago
src docs(plugins/genai): close 3 small gaps from review 2 months ago
.gitignore feat(plugins/genai): Step 1 — empty plugin skeleton 2 months ago
Makefile genai: fix lifecycle reloads and drop dead MCP stats registration 2 months ago
README.md docs(plugins/genai): close 3 small gaps from review 2 months ago

README.md

ProxySQL GenAI Plugin — Reference

1. Overview

The genai plugin is a dynamically loaded plugin that adds GenAI, MCP (Model Context Protocol), RAG (Retrieval-Augmented Generation), and SQL anomaly-detection capabilities to ProxySQL. It hosts the MCP HTTP listener, the LLM bridge (OpenAI / Anthropic / generic / local llama.cpp), the FTS- and vector-backed schema discovery cache, and a pre-execution query hook that feeds the anomaly detector.

This is a v4.0+ plugin: it requires the chassis (PROXYSQL40=1 → implied by PROXYSQLGENAI=1) and is built only when the operator explicitly opts in via PROXYSQLGENAI=1. Without the flag, none of this code ships in proxysql — the binary stays a plain MySQL/PgSQL proxy.

What the plugin owns

Subsystem Class Header
MCP listener + lifecycle MCP_Threads_Handler MCP_Thread.h
MCP HTTP server ProxySQL_MCP_Server ProxySQL_MCP_Server.hpp
GenAI worker pool GenAI_Threads_Handler GenAI_Thread.h
AI features manager AI_Features_Manager AI_Features_Manager.h
Anomaly detection Anomaly_Detector Anomaly_Detector.h
Schema discovery Discovery_Schema Discovery_Schema.h
Vector storage AI_Vector_Storage AI_Vector_Storage.h
MySQL / PgSQL static harvesters Static_Harvester, PgSQL_Static_Harvester *Static_Harvester.h
LLM provider bridge LLM_Bridge, LLM_Clients LLM_Bridge.h
FTS index over MySQL catalogs MySQL_FTS, MySQL_Catalog MySQL_FTS.h / MySQL_Catalog.h
Tool handlers (per MCP endpoint) Admin_Tool_Handler, Cache_Tool_Handler, Config_Tool_Handler, MCP_Tool_Handler, MySQL_Tool_Handler, Observe_Tool_Handler, Query_Tool_Handler, RAG_Tool_Handler, Stats_Tool_Handler tool_handlers/*.h
Backend connection helper backend_client backend_client.h

For deeper architecture see doc/MCP/Architecture.md and doc/LLM_Bridge/ARCHITECTURE.md in the repo root; this document covers only the plugin lifecycle, configuration, and operational contract.

2. Building

PROXYSQLGENAI=1 make            # builds proxysql + the .so
PROXYSQLGENAI=1 make install    # installs both

PROXYSQLGENAI=1 cascades to PROXYSQL40=1PROXYSQL31=1PROXYSQLFFTO=1 + PROXYSQLTSDB=1. The plugin .so lands at /usr/lib/proxysql/ProxySQL_GenAI_Plugin.so.

The build also pulls sqlite-vec from deps/ and links vec.o into libproxysql.a so the plugin's AI_Vector_Storage can register the extension via proxy_sqlite3_vec_init. v3.0 builds (no PROXYSQLGENAI) skip both — see lib/proxy_sqlite3_symbols.cpp and src/Makefile for the #ifdef PROXYSQLGENAI / ifeq gates.

3. Loading

Add the plugin path to the plugins array in proxysql.cnf:

plugins = (
    "/usr/lib/proxysql/ProxySQL_GenAI_Plugin.so"
)

The plugins= line must be present before ProxySQL starts; plugins cannot be loaded after startup. Removing the line and restarting unloads the plugin cleanly.

4. Lifecycle

The chassis runs the plugin through five phases:

Phase Callback What the genai plugin does
A. load (chassis dlopen) reads the descriptor (abi_version=3)
B. register_schemas genai_register_schemas calls genai_register_admin_tables to publish the MCP table set + the three runtime_mcp_* projections via services->register_runtime_view
C. admin bootstrap (chassis) materialises the registered SQLite schemas
D. init genai_init Prometheus counters, query hook, constructs MCP_Threads_Handler / GenAI_Threads_Handler / AI_Features_Manager / Anomaly_Detector, registers admin SQL verbs
E. start genai_start reads mcp-* and genai-* from main.global_variables, installs profiles, starts the MCP listener if mcp-enabled=true, kicks off genai_refresh_runtime_components

Teardown (genai_stop) is the reverse, in dependency order: listener → tool handlers → AI features → GenAI workers → atomic clear of the embed-fn hook → anomaly detector. Counters stay registered against the shared Prometheus registry (prometheus-cpp has no unregister API).

5. Admin SQL surface

Registered with the chassis command registry; chassis admin dispatcher routes by canonical name + alias.

Command Effect
LOAD MCP VARIABLES TO RUNTIME push mcp-* from main.global_variables into MCP_Threads_Handler
LOAD MCP VARIABLES FROM DISK sync disk.global_variablesmain.global_variables (mcp-* slice), then implicit reload
LOAD MCP VARIABLES FROM CONFIG re-read mcp block from proxysql.cnf
SAVE MCP VARIABLES TO MEMORY / ... TO DISK reverse direction
LOAD MCP PROFILES TO RUNTIME atomic install of main.mcp_auth_profiles + main.mcp_target_profiles into the in-memory snapshot, rebuilds joined target_auth_map
SAVE MCP PROFILES TO MEMORY atomic dump of in-memory snapshot back to both editable tables in one transaction
LOAD MCP QUERY RULES TO RUNTIME install main.mcp_query_rules snapshot, attach to Discovery_Schema if listener up
SAVE MCP QUERY RULES TO MEMORY dump in-memory snapshot back to main.mcp_query_rules
LOAD GENAI VARIABLES TO RUNTIME / FROM CONFIG reload genai-* and reinit the GenAI/AI runtime stack
SAVE GENAI VARIABLES TO MEMORY dump runtime genai-* back to main.global_variables
LOAD/SAVE *PROFILES* / *QUERY RULES* TO/FROM DISK sync disk.*main.*

ABI 3 contract: runtime_mcp_* tables are chassis-projected views of module state. The plugin's project_*_to_runtime_view callbacks are the only writers; LOAD commands install snapshots into the module without touching runtime_<X>, and a SELECT against runtime_mcp_<X> triggers a fresh projection from the snapshot before returning rows.

6. Configuration

All mcp-* and genai-* keys live in main.global_variables. Canonical reference (with defaults and runtime semantics) is in doc/MCP/VARIABLES.md. The plugin re-reads on every LOAD ... TO RUNTIME command.

Tables owned by the plugin (registered in Phase B):

DB Table Purpose
admin mcp_query_rules editable query rules
admin mcp_auth_profiles editable backend auth profiles
admin mcp_target_profiles editable MCP target → hostgroup mapping
admin runtime_mcp_query_rules / runtime_mcp_auth_profiles / runtime_mcp_target_profiles chassis-projected views (no persistent rows; refreshed per SELECT from module snapshot)
config persistent copies of the three editable tables above for LOAD ... FROM DISK
stats (none currently — see "Known gaps" below)

7. Observability

Prometheus counters registered against the shared services->get_prometheus_registry():

Counter Increments when
proxysql_genai_detected_anomalies_total the anomaly detector flags a query (any risk)
proxysql_genai_blocked_queries_total the detector blocks a query (DENY returned to client)

Plugin log lines route through services->log_message (see genai_log() in plugin_main.cpp). Severity follows syslog levels; the chassis writes to proxysql.log.

8. Concurrency notes

  • genai_anomaly_embed_fn is std::atomic with acquire/release semantics; the embedding back-end pointer's lifetime is paired with the GloGATH global it dereferences (see the long comment in Anomaly_Detector.cpp).
  • MCP_Threads_Handler variable accessors (get_variable, set_variable, has_variable, get_variables_list) all serialize on the handler's pthread_rwlock.
  • genai_refresh_runtime_components is currently called from the admin SQL thread without quiescing readers — operators triggering LOAD GENAI VARIABLES TO RUNTIME while traffic is hot should expect brief reload-window blips. Tracked as a follow-up — see the detailed contract comment on the declaration in genai_plugin.h.
  • Profile triplet: install_profiles_from_admin and save_profiles_to_admin_table are atomic across both tables: one wrlock for both swaps + one BEGIN/COMMIT for both writes, FK-aware delete order. Per-table install/save methods exist but only rebuild one half of the joined target_auth_map; prefer the combined variants from new code.

9. Testing

Suite Path Coverage
Plugin lifecycle test/tap/tests/unit/genai_plugin_load_unit-t.cpp load → Phase B → init → start → LOAD MCP PROFILES → runtime view projection → SAVE round-trip → stop
Anomaly detector genai_plugin_anomaly_unit-t.cpp normalize_query, check_sql_injection (private-via-friend)
Backend client genai_plugin_backend_client_unit-t.cpp parse + dial guards
FTS string utils genai_fts_string_unit-t.cpp sanitize_name / escape_*
MCP variable accessors genai_mcp_thread_unit-t.cpp get_variable / set_variable round-trip + concurrency
Discovery schema genai_discovery_schema_unit-t.cpp catalog cache shape
LLM clients genai_llm_clients_unit-t.cpp HTTP client wiring
Chassis runtime-view dispatch plugin_runtime_views_unit-t.cpp end-to-end via real plugin .so

Integration tests live in the ai-g1 TAP group (run via test/infra/control/run-tests-isolated.bash TAP_GROUP=ai-g1); they spin up real MySQL 8.4 + PgSQL 16 backends and exercise the MCP endpoints + LLM surface end-to-end.

Known unit-test gaps

Admin_Tool_Handler, Cache_Tool_Handler, Config_Tool_Handler, Observe_Tool_Handler, and RAG_Tool_Handler have no dedicated unit test — coverage relies on ai-g1 integration tests. RAG is the most worth closing given vector-storage complexity.

10. Known gaps

  • stats_mcp_* tables: previously registered, dropped in the carve-out because there's no plugin-side writer in this branch. A plugin-side stats projection ABI is the natural follow-up (parallel to register_runtime_view).
  • genai_refresh_runtime_components race: see Concurrency notes above; needs a proper rwlock around GloGATH/GloAI consumers.
  • LLM_Bridge cache: lookup returns cache-miss, store is no-op (see // TODO markers). Callers handle the miss naturally.
  • Tool-handler unit tests: see Testing section.

11. History

The plugin is the result of an 8-step carve-out (Steps 18b on this branch) that moved ~28K LOC out of ProxySQL core. The original design and per-step plans live in docs/superpowers/specs/2026-04-16-genai-plugin-carveout-design.md and adjacent files; the consolidated PR is #5701.