Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
854 changes: 854 additions & 0 deletions doc/MCP/FTS_USER_GUIDE.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions include/MCP_Thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ class MCP_Threads_Handler
char* mcp_mysql_password; ///< MySQL password for tool connections
char* mcp_mysql_schema; ///< Default schema/database
char* mcp_catalog_path; ///< Path to catalog SQLite database
char* mcp_fts_path; ///< Path to FTS SQLite database
} variables;

/**
Expand Down
192 changes: 192 additions & 0 deletions include/MySQL_FTS.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
#ifndef CLASS_MYSQL_FTS_H
#define CLASS_MYSQL_FTS_H

#include "sqlite3db.h"
#include <string>
#include <vector>
#include <memory>

// Forward declaration
class MySQL_Tool_Handler;

/**
* @brief MySQL Full Text Search (FTS) for Fast Data Discovery
*
* This class manages a dedicated SQLite database that provides:
* - Full-text search indexes for MySQL tables
* - Fast data discovery before querying the actual MySQL database
* - Cross-table search capabilities
* - BM25 ranking with FTS5
*
* The FTS system serves as a fast local cache for AI agents to quickly
* find relevant data before making targeted queries to MySQL backend.
*/
class MySQL_FTS {
private:
SQLite3DB* db;
std::string db_path;

/**
* @brief Initialize FTS schema
* @return 0 on success, -1 on error
*/
int init_schema();

/**
* @brief Create FTS metadata tables
* @return 0 on success, -1 on error
*/
int create_tables();

/**
* @brief Create per-index tables (data and FTS5 virtual table)
* @param schema Schema name
* @param table Table name
* @return 0 on success, -1 on error
*/
int create_index_tables(const std::string& schema, const std::string& table);

/**
* @brief Get sanitized data table name for a schema.table
* @param schema Schema name
* @param table Table name
* @return Sanitized table name
*/
std::string get_data_table_name(const std::string& schema, const std::string& table);

/**
* @brief Get FTS search table name for a schema.table
* @param schema Schema name
* @param table Table name
* @return Sanitized FTS table name
*/
std::string get_fts_table_name(const std::string& schema, const std::string& table);

/**
* @brief Sanitize a name for use as SQLite table name
* @param name Name to sanitize
* @return Sanitized name
*/
std::string sanitize_name(const std::string& name);

/**
* @brief Escape single quotes for SQL
* @param str String to escape
* @return Escaped string
*/
std::string escape_sql(const std::string& str);

public:
/**
* @brief Constructor
* @param path Path to the FTS database file
*/
MySQL_FTS(const std::string& path);

/**
* @brief Destructor
*/
~MySQL_FTS();

/**
* @brief Initialize the FTS database
* @return 0 on success, -1 on error
*/
int init();

/**
* @brief Close the FTS database
*/
void close();

/**
* @brief Check if an index exists for a schema.table
* @param schema Schema name
* @param table Table name
* @return true if exists, false otherwise
*/
bool index_exists(const std::string& schema, const std::string& table);

/**
* @brief Create and populate an FTS index for a MySQL table
*
* @param schema Schema name
* @param table Table name
* @param columns JSON array of column names to index
* @param primary_key Primary key column name
* @param where_clause Optional WHERE clause for filtering
* @param mysql_handler Pointer to MySQL_Tool_Handler for executing queries
* @return JSON result with success status and metadata
*/
std::string index_table(
const std::string& schema,
const std::string& table,
const std::string& columns,
const std::string& primary_key,
const std::string& where_clause,
MySQL_Tool_Handler* mysql_handler
);

/**
* @brief Search indexed data using FTS5
*
* @param query FTS5 search query
* @param schema Optional schema filter
* @param table Optional table filter
* @param limit Max results (default 100)
* @param offset Pagination offset (default 0)
* @return JSON result with matches and snippets
*/
std::string search(
const std::string& query,
const std::string& schema = "",
const std::string& table = "",
int limit = 100,
int offset = 0
);

/**
* @brief List all FTS indexes with metadata
* @return JSON array of indexes
*/
std::string list_indexes();

/**
* @brief Remove an FTS index
*
* @param schema Schema name
* @param table Table name
* @return JSON result
*/
std::string delete_index(const std::string& schema, const std::string& table);

/**
* @brief Refresh an index with fresh data (full rebuild)
*
* @param schema Schema name
* @param table Table name
* @param mysql_handler Pointer to MySQL_Tool_Handler for executing queries
* @return JSON result
*/
std::string reindex(
const std::string& schema,
const std::string& table,
MySQL_Tool_Handler* mysql_handler
);

/**
* @brief Rebuild ALL FTS indexes with fresh data
*
* @param mysql_handler Pointer to MySQL_Tool_Handler for executing queries
* @return JSON result with summary
*/
std::string rebuild_all(MySQL_Tool_Handler* mysql_handler);

/**
* @brief Get database handle for direct access
* @return SQLite3DB pointer
*/
SQLite3DB* get_db() { return db; }
};

#endif /* CLASS_MYSQL_FTS_H */
101 changes: 93 additions & 8 deletions include/MySQL_Tool_Handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define CLASS_MYSQL_TOOL_HANDLER_H

#include "MySQL_Catalog.h"
#include "MySQL_FTS.h"
#include "cpp.h"
#include <string>
#include <memory>
Expand Down Expand Up @@ -51,6 +52,10 @@ class MySQL_Tool_Handler {
// Catalog for LLM memory
MySQL_Catalog* catalog; ///< SQLite catalog for LLM discoveries

// FTS for fast data discovery
MySQL_FTS* fts; ///< SQLite FTS for full-text search
pthread_mutex_t fts_lock; ///< Mutex protecting FTS lifecycle/usage

// Query guardrails
int max_rows; ///< Maximum rows to return (default 200)
int timeout_ms; ///< Query timeout in milliseconds (default 2000)
Expand All @@ -74,13 +79,6 @@ class MySQL_Tool_Handler {
*/
void return_connection(MYSQL* mysql);

/**
* @brief Execute a query and return results as JSON
* @param query SQL query to execute
* @return JSON with results or error
*/
std::string execute_query(const std::string& query);

/**
* @brief Validate SQL is read-only
* @param query SQL to validate
Expand Down Expand Up @@ -111,16 +109,25 @@ class MySQL_Tool_Handler {
* @param password MySQL password
* @param schema Default schema/database
* @param catalog_path Path to catalog database
* @param fts_path Path to FTS database
*/
MySQL_Tool_Handler(
const std::string& hosts,
const std::string& ports,
const std::string& user,
const std::string& password,
const std::string& schema,
const std::string& catalog_path
const std::string& catalog_path,
const std::string& fts_path = ""
);

/**
* @brief Reset FTS database path at runtime
* @param path New SQLite FTS database path
* @return true on success, false on error
*/
bool reset_fts_path(const std::string& path);

/**
* @brief Destructor
*/
Expand All @@ -137,6 +144,13 @@ class MySQL_Tool_Handler {
*/
void close();

/**
* @brief Execute a query and return results as JSON
* @param query SQL query to execute
* @return JSON with results or error
*/
std::string execute_query(const std::string& query);

// ========== Inventory Tools ==========

/**
Expand Down Expand Up @@ -389,6 +403,77 @@ class MySQL_Tool_Handler {
* @return JSON result
*/
std::string catalog_delete(const std::string& kind, const std::string& key);

// ========== FTS Tools (Full Text Search) ==========

/**
* @brief Create and populate an FTS index for a MySQL table
* @param schema Schema name
* @param table Table name
* @param columns JSON array of column names to index
* @param primary_key Primary key column name
* @param where_clause Optional WHERE clause for filtering
* @return JSON result with success status and metadata
*/
std::string fts_index_table(
const std::string& schema,
const std::string& table,
const std::string& columns,
const std::string& primary_key,
const std::string& where_clause = ""
);

/**
* @brief Search indexed data using FTS5
* @param query FTS5 search query
* @param schema Optional schema filter
* @param table Optional table filter
* @param limit Max results (default 100)
* @param offset Pagination offset (default 0)
* @return JSON result with matches and snippets
*/
std::string fts_search(
const std::string& query,
const std::string& schema = "",
const std::string& table = "",
int limit = 100,
int offset = 0
);

/**
* @brief List all FTS indexes with metadata
* @return JSON array of indexes
*/
std::string fts_list_indexes();

/**
* @brief Remove an FTS index
* @param schema Schema name
* @param table Table name
* @return JSON result
*/
std::string fts_delete_index(const std::string& schema, const std::string& table);

/**
* @brief Refresh an index with fresh data (full rebuild)
* @param schema Schema name
* @param table Table name
* @return JSON result
*/
std::string fts_reindex(const std::string& schema, const std::string& table);

/**
* @brief Rebuild ALL FTS indexes with fresh data
* @return JSON result with summary
*/
std::string fts_rebuild_all();

/**
* @brief Reinitialize FTS handler with a new database path
* @param fts_path New path to FTS database
* @return 0 on success, -1 on error
*/
int reinit_fts(const std::string& fts_path);
};

#endif /* CLASS_MYSQL_TOOL_HANDLER_H */
Loading