MindsDB 25.5.3.0__py3-none-any.whl → 25.5.4.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of MindsDB might be problematic. Click here for more details.

Files changed (310) hide show
  1. mindsdb/__about__.py +1 -1
  2. mindsdb/__main__.py +127 -79
  3. mindsdb/api/a2a/__init__.py +0 -0
  4. mindsdb/api/a2a/__main__.py +114 -0
  5. mindsdb/api/a2a/a2a_client.py +439 -0
  6. mindsdb/api/a2a/agent.py +308 -0
  7. mindsdb/api/a2a/common/__init__.py +0 -0
  8. mindsdb/api/a2a/common/client/__init__.py +4 -0
  9. mindsdb/api/a2a/common/client/card_resolver.py +21 -0
  10. mindsdb/api/a2a/common/client/client.py +86 -0
  11. mindsdb/api/a2a/common/server/__init__.py +4 -0
  12. mindsdb/api/a2a/common/server/server.py +164 -0
  13. mindsdb/api/a2a/common/server/task_manager.py +287 -0
  14. mindsdb/api/a2a/common/server/utils.py +28 -0
  15. mindsdb/api/a2a/common/types.py +365 -0
  16. mindsdb/api/a2a/constants.py +9 -0
  17. mindsdb/api/a2a/run_a2a.py +129 -0
  18. mindsdb/api/a2a/task_manager.py +594 -0
  19. mindsdb/api/executor/command_executor.py +47 -27
  20. mindsdb/api/executor/datahub/classes/response.py +5 -2
  21. mindsdb/api/executor/datahub/datanodes/integration_datanode.py +39 -72
  22. mindsdb/api/executor/planner/query_planner.py +10 -1
  23. mindsdb/api/executor/sql_query/result_set.py +185 -52
  24. mindsdb/api/executor/sql_query/sql_query.py +1 -1
  25. mindsdb/api/executor/sql_query/steps/apply_predictor_step.py +9 -12
  26. mindsdb/api/executor/sql_query/steps/fetch_dataframe.py +8 -10
  27. mindsdb/api/executor/sql_query/steps/fetch_dataframe_partition.py +5 -44
  28. mindsdb/api/executor/sql_query/steps/insert_step.py +24 -15
  29. mindsdb/api/executor/sql_query/steps/join_step.py +1 -1
  30. mindsdb/api/executor/sql_query/steps/project_step.py +1 -1
  31. mindsdb/api/executor/sql_query/steps/sql_steps.py +1 -1
  32. mindsdb/api/executor/sql_query/steps/subselect_step.py +4 -8
  33. mindsdb/api/executor/sql_query/steps/union_step.py +1 -3
  34. mindsdb/api/http/initialize.py +99 -83
  35. mindsdb/api/http/namespaces/analysis.py +3 -3
  36. mindsdb/api/http/namespaces/file.py +8 -2
  37. mindsdb/api/http/namespaces/sql.py +13 -27
  38. mindsdb/api/mcp/start.py +42 -5
  39. mindsdb/api/mysql/mysql_proxy/data_types/mysql_packet.py +0 -1
  40. mindsdb/api/mysql/mysql_proxy/data_types/mysql_packets/binary_resultset_row_package.py +52 -19
  41. mindsdb/api/mysql/mysql_proxy/executor/mysql_executor.py +8 -10
  42. mindsdb/api/mysql/mysql_proxy/libs/constants/mysql.py +54 -38
  43. mindsdb/api/mysql/mysql_proxy/mysql_proxy.py +82 -115
  44. mindsdb/api/mysql/mysql_proxy/utilities/dump.py +351 -0
  45. mindsdb/api/postgres/postgres_proxy/executor/executor.py +1 -1
  46. mindsdb/api/postgres/postgres_proxy/postgres_proxy.py +5 -6
  47. mindsdb/integrations/handlers/altibase_handler/altibase_handler.py +26 -27
  48. mindsdb/integrations/handlers/altibase_handler/connection_args.py +13 -13
  49. mindsdb/integrations/handlers/altibase_handler/tests/test_altibase_handler.py +8 -8
  50. mindsdb/integrations/handlers/altibase_handler/tests/test_altibase_handler_dsn.py +13 -13
  51. mindsdb/integrations/handlers/anthropic_handler/__init__.py +2 -2
  52. mindsdb/integrations/handlers/anthropic_handler/anthropic_handler.py +1 -3
  53. mindsdb/integrations/handlers/aurora_handler/aurora_handler.py +1 -0
  54. mindsdb/integrations/handlers/autosklearn_handler/autosklearn_handler.py +1 -1
  55. mindsdb/integrations/handlers/autosklearn_handler/config.py +0 -1
  56. mindsdb/integrations/handlers/bigquery_handler/bigquery_handler.py +1 -1
  57. mindsdb/integrations/handlers/bigquery_handler/tests/test_bigquery_handler.py +1 -1
  58. mindsdb/integrations/handlers/binance_handler/binance_handler.py +1 -0
  59. mindsdb/integrations/handlers/binance_handler/binance_tables.py +3 -4
  60. mindsdb/integrations/handlers/byom_handler/__init__.py +0 -1
  61. mindsdb/integrations/handlers/ckan_handler/ckan_handler.py +3 -0
  62. mindsdb/integrations/handlers/clickhouse_handler/__init__.py +1 -1
  63. mindsdb/integrations/handlers/cloud_spanner_handler/tests/test_cloud_spanner_handler.py +0 -2
  64. mindsdb/integrations/handlers/cloud_sql_handler/cloud_sql_handler.py +0 -1
  65. mindsdb/integrations/handlers/cohere_handler/__init__.py +1 -1
  66. mindsdb/integrations/handlers/cohere_handler/cohere_handler.py +11 -13
  67. mindsdb/integrations/handlers/confluence_handler/confluence_tables.py +6 -0
  68. mindsdb/integrations/handlers/databend_handler/connection_args.py +1 -1
  69. mindsdb/integrations/handlers/databend_handler/databend_handler.py +4 -4
  70. mindsdb/integrations/handlers/databend_handler/tests/__init__.py +0 -1
  71. mindsdb/integrations/handlers/databend_handler/tests/test_databend_handler.py +1 -1
  72. mindsdb/integrations/handlers/derby_handler/connection_args.py +1 -1
  73. mindsdb/integrations/handlers/derby_handler/derby_handler.py +14 -22
  74. mindsdb/integrations/handlers/derby_handler/tests/test_derby_handler.py +6 -6
  75. mindsdb/integrations/handlers/discord_handler/discord_handler.py +5 -5
  76. mindsdb/integrations/handlers/discord_handler/discord_tables.py +3 -3
  77. mindsdb/integrations/handlers/discord_handler/tests/test_discord.py +5 -3
  78. mindsdb/integrations/handlers/dockerhub_handler/dockerhub.py +3 -3
  79. mindsdb/integrations/handlers/dockerhub_handler/dockerhub_handler.py +2 -2
  80. mindsdb/integrations/handlers/dockerhub_handler/dockerhub_tables.py +57 -54
  81. mindsdb/integrations/handlers/dremio_handler/__init__.py +2 -2
  82. mindsdb/integrations/handlers/druid_handler/__init__.py +1 -1
  83. mindsdb/integrations/handlers/druid_handler/druid_handler.py +2 -2
  84. mindsdb/integrations/handlers/edgelessdb_handler/tests/test_edgelessdb_handler.py +9 -9
  85. mindsdb/integrations/handlers/email_handler/email_client.py +1 -1
  86. mindsdb/integrations/handlers/email_handler/email_ingestor.py +1 -1
  87. mindsdb/integrations/handlers/email_handler/email_tables.py +0 -1
  88. mindsdb/integrations/handlers/email_handler/settings.py +0 -1
  89. mindsdb/integrations/handlers/eventstoredb_handler/eventstoredb_handler.py +2 -1
  90. mindsdb/integrations/handlers/firebird_handler/firebird_handler.py +1 -1
  91. mindsdb/integrations/handlers/flaml_handler/flaml_handler.py +9 -9
  92. mindsdb/integrations/handlers/frappe_handler/frappe_client.py +5 -5
  93. mindsdb/integrations/handlers/frappe_handler/frappe_handler.py +6 -5
  94. mindsdb/integrations/handlers/frappe_handler/frappe_tables.py +2 -2
  95. mindsdb/integrations/handlers/github_handler/connection_args.py +2 -2
  96. mindsdb/integrations/handlers/github_handler/github_handler.py +1 -8
  97. mindsdb/integrations/handlers/github_handler/github_tables.py +13 -24
  98. mindsdb/integrations/handlers/gitlab_handler/gitlab_handler.py +2 -1
  99. mindsdb/integrations/handlers/gitlab_handler/gitlab_tables.py +1 -4
  100. mindsdb/integrations/handlers/gmail_handler/gmail_handler.py +6 -13
  101. mindsdb/integrations/handlers/google_books_handler/google_books_handler.py +2 -1
  102. mindsdb/integrations/handlers/google_books_handler/google_books_tables.py +0 -3
  103. mindsdb/integrations/handlers/google_calendar_handler/google_calendar_handler.py +4 -4
  104. mindsdb/integrations/handlers/google_calendar_handler/google_calendar_tables.py +2 -6
  105. mindsdb/integrations/handlers/google_content_shopping_handler/google_content_shopping_handler.py +3 -2
  106. mindsdb/integrations/handlers/google_content_shopping_handler/google_content_shopping_tables.py +0 -3
  107. mindsdb/integrations/handlers/google_fit_handler/google_fit_handler.py +10 -12
  108. mindsdb/integrations/handlers/google_fit_handler/google_fit_tables.py +11 -13
  109. mindsdb/integrations/handlers/google_search_handler/google_search_handler.py +2 -1
  110. mindsdb/integrations/handlers/google_search_handler/google_search_tables.py +0 -3
  111. mindsdb/integrations/handlers/groq_handler/__init__.py +3 -3
  112. mindsdb/integrations/handlers/hackernews_handler/hn_handler.py +5 -7
  113. mindsdb/integrations/handlers/hackernews_handler/hn_table.py +6 -7
  114. mindsdb/integrations/handlers/hive_handler/tests/test_hive_handler.py +1 -1
  115. mindsdb/integrations/handlers/hsqldb_handler/connection_args.py +6 -6
  116. mindsdb/integrations/handlers/hsqldb_handler/hsqldb_handler.py +4 -3
  117. mindsdb/integrations/handlers/huggingface_api_handler/exceptions.py +1 -1
  118. mindsdb/integrations/handlers/huggingface_api_handler/huggingface_api_handler.py +1 -8
  119. mindsdb/integrations/handlers/huggingface_handler/huggingface_handler.py +6 -6
  120. mindsdb/integrations/handlers/huggingface_handler/requirements.txt +1 -1
  121. mindsdb/integrations/handlers/huggingface_handler/requirements_cpu.txt +1 -1
  122. mindsdb/integrations/handlers/ignite_handler/ignite_handler.py +2 -1
  123. mindsdb/integrations/handlers/impala_handler/impala_handler.py +9 -12
  124. mindsdb/integrations/handlers/impala_handler/tests/test_impala_handler.py +11 -11
  125. mindsdb/integrations/handlers/influxdb_handler/influxdb_handler.py +10 -13
  126. mindsdb/integrations/handlers/influxdb_handler/influxdb_tables.py +20 -20
  127. mindsdb/integrations/handlers/informix_handler/__about__.py +8 -8
  128. mindsdb/integrations/handlers/informix_handler/__init__.py +12 -5
  129. mindsdb/integrations/handlers/informix_handler/informix_handler.py +99 -133
  130. mindsdb/integrations/handlers/informix_handler/tests/test_informix_handler.py +13 -11
  131. mindsdb/integrations/handlers/ingres_handler/__about__.py +0 -1
  132. mindsdb/integrations/handlers/ingres_handler/ingres_handler.py +1 -0
  133. mindsdb/integrations/handlers/jira_handler/jira_handler.py +4 -4
  134. mindsdb/integrations/handlers/jira_handler/jira_tables.py +9 -9
  135. mindsdb/integrations/handlers/kinetica_handler/__init__.py +0 -1
  136. mindsdb/integrations/handlers/langchain_handler/langchain_handler.py +4 -4
  137. mindsdb/integrations/handlers/langchain_handler/tools.py +9 -10
  138. mindsdb/integrations/handlers/leonardoai_handler/__init__.py +1 -1
  139. mindsdb/integrations/handlers/lightwood_handler/functions.py +2 -2
  140. mindsdb/integrations/handlers/lightwood_handler/lightwood_handler.py +0 -1
  141. mindsdb/integrations/handlers/lightwood_handler/tests/test_lightwood_handler.py +11 -11
  142. mindsdb/integrations/handlers/llama_index_handler/llama_index_handler.py +4 -4
  143. mindsdb/integrations/handlers/llama_index_handler/settings.py +10 -9
  144. mindsdb/integrations/handlers/materialize_handler/tests/test_materialize_handler.py +8 -10
  145. mindsdb/integrations/handlers/matrixone_handler/matrixone_handler.py +4 -4
  146. mindsdb/integrations/handlers/matrixone_handler/tests/test_matrixone_handler.py +8 -9
  147. mindsdb/integrations/handlers/maxdb_handler/connection_args.py +25 -25
  148. mindsdb/integrations/handlers/maxdb_handler/maxdb_handler.py +1 -0
  149. mindsdb/integrations/handlers/mediawiki_handler/mediawiki_handler.py +3 -2
  150. mindsdb/integrations/handlers/mediawiki_handler/mediawiki_tables.py +1 -1
  151. mindsdb/integrations/handlers/mendeley_handler/__about__.py +1 -1
  152. mindsdb/integrations/handlers/mendeley_handler/__init__.py +2 -2
  153. mindsdb/integrations/handlers/mendeley_handler/mendeley_handler.py +48 -56
  154. mindsdb/integrations/handlers/mendeley_handler/mendeley_tables.py +24 -29
  155. mindsdb/integrations/handlers/mendeley_handler/tests/test_mendeley_handler.py +19 -17
  156. mindsdb/integrations/handlers/merlion_handler/merlion_handler.py +5 -4
  157. mindsdb/integrations/handlers/minds_endpoint_handler/__init__.py +3 -3
  158. mindsdb/integrations/handlers/mlflow_handler/mlflow_handler.py +58 -36
  159. mindsdb/integrations/handlers/monetdb_handler/__about__.py +8 -8
  160. mindsdb/integrations/handlers/monetdb_handler/__init__.py +15 -5
  161. mindsdb/integrations/handlers/monetdb_handler/connection_args.py +17 -18
  162. mindsdb/integrations/handlers/monetdb_handler/monetdb_handler.py +40 -57
  163. mindsdb/integrations/handlers/monetdb_handler/tests/test_monetdb_handler.py +7 -8
  164. mindsdb/integrations/handlers/monetdb_handler/utils/monet_get_id.py +13 -14
  165. mindsdb/integrations/handlers/monkeylearn_handler/__about__.py +1 -1
  166. mindsdb/integrations/handlers/monkeylearn_handler/__init__.py +1 -1
  167. mindsdb/integrations/handlers/monkeylearn_handler/monkeylearn_handler.py +2 -5
  168. mindsdb/integrations/handlers/ms_one_drive_handler/ms_graph_api_one_drive_client.py +1 -0
  169. mindsdb/integrations/handlers/ms_one_drive_handler/ms_one_drive_handler.py +1 -1
  170. mindsdb/integrations/handlers/ms_teams_handler/ms_graph_api_teams_client.py +23 -23
  171. mindsdb/integrations/handlers/ms_teams_handler/ms_teams_handler.py +3 -3
  172. mindsdb/integrations/handlers/ms_teams_handler/ms_teams_tables.py +10 -5
  173. mindsdb/integrations/handlers/mssql_handler/mssql_handler.py +73 -8
  174. mindsdb/integrations/handlers/mysql_handler/__about__.py +8 -8
  175. mindsdb/integrations/handlers/mysql_handler/__init__.py +15 -5
  176. mindsdb/integrations/handlers/mysql_handler/connection_args.py +43 -47
  177. mindsdb/integrations/handlers/mysql_handler/mysql_handler.py +101 -34
  178. mindsdb/integrations/handlers/mysql_handler/settings.py +15 -13
  179. mindsdb/integrations/handlers/neuralforecast_handler/neuralforecast_handler.py +1 -1
  180. mindsdb/integrations/handlers/newsapi_handler/newsapi_handler.py +1 -1
  181. mindsdb/integrations/handlers/newsapi_handler/tests/test_newsapi_handler.py +4 -4
  182. mindsdb/integrations/handlers/nuo_jdbc_handler/connection_args.py +2 -2
  183. mindsdb/integrations/handlers/nuo_jdbc_handler/nuo_jdbc_handler.py +28 -36
  184. mindsdb/integrations/handlers/nuo_jdbc_handler/tests/test_nuo_handler.py +5 -5
  185. mindsdb/integrations/handlers/oceanbase_handler/oceanbase_handler.py +0 -1
  186. mindsdb/integrations/handlers/oceanbase_handler/tests/test_oceanbase_handler.py +8 -10
  187. mindsdb/integrations/handlers/ollama_handler/ollama_handler.py +3 -3
  188. mindsdb/integrations/handlers/opengauss_handler/tests/test_opengauss_handler.py +1 -2
  189. mindsdb/integrations/handlers/openstreetmap_handler/__init__.py +7 -7
  190. mindsdb/integrations/handlers/oracle_handler/connection_args.py +6 -0
  191. mindsdb/integrations/handlers/oracle_handler/oracle_handler.py +77 -11
  192. mindsdb/integrations/handlers/orioledb_handler/tests/test_orioledb_handler.py +8 -10
  193. mindsdb/integrations/handlers/palm_handler/__about__.py +1 -1
  194. mindsdb/integrations/handlers/palm_handler/__init__.py +1 -1
  195. mindsdb/integrations/handlers/palm_handler/palm_handler.py +1 -3
  196. mindsdb/integrations/handlers/paypal_handler/paypal_handler.py +2 -2
  197. mindsdb/integrations/handlers/paypal_handler/paypal_tables.py +15 -14
  198. mindsdb/integrations/handlers/pgvector_handler/pgvector_handler.py +53 -10
  199. mindsdb/integrations/handlers/phoenix_handler/__init__.py +1 -1
  200. mindsdb/integrations/handlers/phoenix_handler/phoenix_handler.py +1 -0
  201. mindsdb/integrations/handlers/pinot_handler/__init__.py +1 -1
  202. mindsdb/integrations/handlers/pinot_handler/pinot_handler.py +3 -2
  203. mindsdb/integrations/handlers/plaid_handler/plaid_handler.py +13 -13
  204. mindsdb/integrations/handlers/plaid_handler/plaid_tables.py +10 -12
  205. mindsdb/integrations/handlers/plaid_handler/utils.py +4 -6
  206. mindsdb/integrations/handlers/planetscale_handler/planetscale_handler.py +1 -4
  207. mindsdb/integrations/handlers/portkey_handler/__init__.py +2 -2
  208. mindsdb/integrations/handlers/postgres_handler/postgres_handler.py +105 -24
  209. mindsdb/integrations/handlers/postgres_handler/tests/test_postgres_handler.py +11 -6
  210. mindsdb/integrations/handlers/questdb_handler/questdb_handler.py +1 -2
  211. mindsdb/integrations/handlers/questdb_handler/tests/test_questdb_handler.py +2 -3
  212. mindsdb/integrations/handlers/quickbooks_handler/quickbooks_handler.py +6 -8
  213. mindsdb/integrations/handlers/quickbooks_handler/quickbooks_table.py +10 -10
  214. mindsdb/integrations/handlers/rag_handler/ingest.py +2 -2
  215. mindsdb/integrations/handlers/rag_handler/rag_handler.py +1 -1
  216. mindsdb/integrations/handlers/rag_handler/settings.py +1 -1
  217. mindsdb/integrations/handlers/reddit_handler/reddit_handler.py +2 -7
  218. mindsdb/integrations/handlers/reddit_handler/reddit_tables.py +2 -3
  219. mindsdb/integrations/handlers/replicate_handler/replicate_handler.py +6 -6
  220. mindsdb/integrations/handlers/rocket_chat_handler/rocket_chat_handler.py +1 -2
  221. mindsdb/integrations/handlers/rocket_chat_handler/rocket_chat_tables.py +0 -3
  222. mindsdb/integrations/handlers/rockset_handler/connection_args.py +14 -14
  223. mindsdb/integrations/handlers/rockset_handler/tests/test_rockset_handler.py +1 -0
  224. mindsdb/integrations/handlers/scylla_handler/scylla_handler.py +6 -5
  225. mindsdb/integrations/handlers/sendinblue_handler/sendinblue_handler.py +2 -1
  226. mindsdb/integrations/handlers/sendinblue_handler/sendinblue_tables.py +16 -16
  227. mindsdb/integrations/handlers/sentence_transformers_handler/__init__.py +1 -1
  228. mindsdb/integrations/handlers/sheets_handler/connection_args.py +1 -1
  229. mindsdb/integrations/handlers/shopify_handler/shopify_handler.py +7 -6
  230. mindsdb/integrations/handlers/shopify_handler/shopify_tables.py +38 -41
  231. mindsdb/integrations/handlers/singlestore_handler/__about__.py +1 -1
  232. mindsdb/integrations/handlers/singlestore_handler/__init__.py +0 -1
  233. mindsdb/integrations/handlers/singlestore_handler/singlestore_handler.py +1 -0
  234. mindsdb/integrations/handlers/singlestore_handler/tests/test_singlestore_handler.py +3 -3
  235. mindsdb/integrations/handlers/slack_handler/__init__.py +3 -3
  236. mindsdb/integrations/handlers/snowflake_handler/snowflake_handler.py +100 -6
  237. mindsdb/integrations/handlers/solr_handler/connection_args.py +7 -7
  238. mindsdb/integrations/handlers/solr_handler/solr_handler.py +2 -1
  239. mindsdb/integrations/handlers/solr_handler/tests/test_solr_handler.py +2 -1
  240. mindsdb/integrations/handlers/sqlany_handler/sqlany_handler.py +3 -2
  241. mindsdb/integrations/handlers/sqlite_handler/sqlite_handler.py +1 -0
  242. mindsdb/integrations/handlers/sqreamdb_handler/connection_args.py +1 -1
  243. mindsdb/integrations/handlers/sqreamdb_handler/sqreamdb_handler.py +15 -20
  244. mindsdb/integrations/handlers/sqreamdb_handler/tests/test_sqreamdb_handler.py +4 -4
  245. mindsdb/integrations/handlers/stabilityai_handler/__init__.py +1 -1
  246. mindsdb/integrations/handlers/starrocks_handler/starrocks_handler.py +0 -1
  247. mindsdb/integrations/handlers/starrocks_handler/tests/test_starrocks_handler.py +8 -10
  248. mindsdb/integrations/handlers/statsforecast_handler/statsforecast_handler.py +2 -2
  249. mindsdb/integrations/handlers/strava_handler/strava_handler.py +4 -8
  250. mindsdb/integrations/handlers/strava_handler/strava_tables.py +22 -30
  251. mindsdb/integrations/handlers/stripe_handler/stripe_handler.py +3 -2
  252. mindsdb/integrations/handlers/stripe_handler/stripe_tables.py +11 -27
  253. mindsdb/integrations/handlers/supabase_handler/tests/test_supabase_handler.py +1 -1
  254. mindsdb/integrations/handlers/surrealdb_handler/surrealdb_handler.py +4 -4
  255. mindsdb/integrations/handlers/tdengine_handler/tdengine_handler.py +25 -27
  256. mindsdb/integrations/handlers/tdengine_handler/tests/test_tdengine_handler.py +8 -8
  257. mindsdb/integrations/handlers/tidb_handler/tests/test_tidb_handler.py +1 -2
  258. mindsdb/integrations/handlers/timegpt_handler/timegpt_handler.py +5 -5
  259. mindsdb/integrations/handlers/tpot_handler/tpot_handler.py +21 -26
  260. mindsdb/integrations/handlers/trino_handler/trino_handler.py +14 -14
  261. mindsdb/integrations/handlers/twitter_handler/twitter_handler.py +2 -4
  262. mindsdb/integrations/handlers/unify_handler/tests/test_unify_handler.py +7 -8
  263. mindsdb/integrations/handlers/unify_handler/unify_handler.py +9 -9
  264. mindsdb/integrations/handlers/vertex_handler/vertex_client.py +1 -1
  265. mindsdb/integrations/handlers/vertica_handler/tests/test_vertica_handler.py +11 -11
  266. mindsdb/integrations/handlers/vertica_handler/vertica_handler.py +11 -14
  267. mindsdb/integrations/handlers/vitess_handler/tests/test_vitess_handler.py +9 -11
  268. mindsdb/integrations/handlers/vitess_handler/vitess_handler.py +0 -1
  269. mindsdb/integrations/handlers/web_handler/web_handler.py +1 -0
  270. mindsdb/integrations/handlers/whatsapp_handler/__init__.py +3 -3
  271. mindsdb/integrations/handlers/writer_handler/evaluate.py +1 -1
  272. mindsdb/integrations/handlers/writer_handler/settings.py +0 -1
  273. mindsdb/integrations/handlers/writer_handler/writer_handler.py +1 -0
  274. mindsdb/integrations/handlers/youtube_handler/youtube_handler.py +5 -5
  275. mindsdb/integrations/handlers/youtube_handler/youtube_tables.py +26 -27
  276. mindsdb/integrations/handlers/yugabyte_handler/tests/test_yugabyte_handler.py +3 -3
  277. mindsdb/integrations/handlers/yugabyte_handler/yugabyte_handler.py +0 -6
  278. mindsdb/integrations/libs/response.py +67 -52
  279. mindsdb/integrations/libs/vectordatabase_handler.py +6 -0
  280. mindsdb/integrations/utilities/handler_utils.py +15 -3
  281. mindsdb/integrations/utilities/handlers/api_utilities/__init__.py +0 -1
  282. mindsdb/integrations/utilities/handlers/auth_utilities/__init__.py +0 -2
  283. mindsdb/integrations/utilities/utils.py +3 -3
  284. mindsdb/interfaces/agents/agents_controller.py +164 -1
  285. mindsdb/interfaces/agents/constants.py +15 -0
  286. mindsdb/interfaces/agents/langchain_agent.py +16 -4
  287. mindsdb/interfaces/agents/mindsdb_database_agent.py +101 -2
  288. mindsdb/interfaces/knowledge_base/controller.py +25 -0
  289. mindsdb/interfaces/knowledge_base/preprocessing/document_preprocessor.py +13 -10
  290. mindsdb/interfaces/knowledge_base/preprocessing/json_chunker.py +434 -0
  291. mindsdb/interfaces/knowledge_base/preprocessing/models.py +54 -0
  292. mindsdb/interfaces/query_context/context_controller.py +66 -10
  293. mindsdb/interfaces/skills/custom/text2sql/mindsdb_kb_tools.py +190 -0
  294. mindsdb/interfaces/skills/custom/text2sql/mindsdb_sql_toolkit.py +92 -0
  295. mindsdb/interfaces/skills/skill_tool.py +202 -57
  296. mindsdb/interfaces/skills/sql_agent.py +205 -17
  297. mindsdb/interfaces/storage/fs.py +1 -0
  298. mindsdb/interfaces/variables/__init__.py +0 -0
  299. mindsdb/interfaces/variables/variables_controller.py +97 -0
  300. mindsdb/migrations/env.py +5 -7
  301. mindsdb/migrations/migrate.py +47 -7
  302. mindsdb/migrations/versions/2025-05-21_9f150e4f9a05_checkpoint_1.py +360 -0
  303. mindsdb/utilities/config.py +331 -219
  304. mindsdb/utilities/starters.py +13 -0
  305. {mindsdb-25.5.3.0.dist-info → mindsdb-25.5.4.0.dist-info}/METADATA +641 -695
  306. {mindsdb-25.5.3.0.dist-info → mindsdb-25.5.4.0.dist-info}/RECORD +309 -288
  307. {mindsdb-25.5.3.0.dist-info → mindsdb-25.5.4.0.dist-info}/WHEEL +1 -1
  308. mindsdb/integrations/handlers/monkeylearn_handler/requirements.txt +0 -1
  309. {mindsdb-25.5.3.0.dist-info → mindsdb-25.5.4.0.dist-info}/licenses/LICENSE +0 -0
  310. {mindsdb-25.5.3.0.dist-info → mindsdb-25.5.4.0.dist-info}/top_level.txt +0 -0
@@ -48,6 +48,4 @@ class UnionStepCall(BaseStepCall):
48
48
  })
49
49
  resp_df.replace({np.nan: None}, inplace=True)
50
50
 
51
- data = ResultSet().from_df_cols(resp_df, col_names=names)
52
-
53
- return data
51
+ return ResultSet.from_df_cols(df=resp_df, columns_dict=names)
@@ -4,9 +4,11 @@ import mimetypes
4
4
  import threading
5
5
  import traceback
6
6
  import webbrowser
7
+
7
8
  from pathlib import Path
8
9
  from http import HTTPStatus
9
10
 
11
+
10
12
  import requests
11
13
  from flask import Flask, url_for, make_response, request, send_from_directory
12
14
  from flask.json import dumps
@@ -68,7 +70,9 @@ try:
68
70
  from opentelemetry.instrumentation.flask import FlaskInstrumentor
69
71
  from opentelemetry.instrumentation.requests import RequestsInstrumentor
70
72
  except ImportError:
71
- logger.debug("OpenTelemetry is not avaiable. Please run `pip install -r requirements/requirements-opentelemetry.txt` to use it.")
73
+ logger.debug(
74
+ "OpenTelemetry is not avaiable. Please run `pip install -r requirements/requirements-opentelemetry.txt` to use it."
75
+ )
72
76
  FlaskInstrumentor = _NoOpFlaskInstrumentor
73
77
  RequestsInstrumentor = _NoOpRequestsInstrumentor
74
78
 
@@ -78,6 +82,7 @@ class Swagger_Api(Api):
78
82
  This is a modification of the base Flask Restplus Api class due to the issue described here
79
83
  https://github.com/noirbizarre/flask-restplus/issues/223
80
84
  """
85
+
81
86
  @property
82
87
  def specs_url(self):
83
88
  return url_for(self.endpoint("specs"), _external=False)
@@ -92,7 +97,10 @@ def custom_output_json(data, code, headers=None):
92
97
  def get_last_compatible_gui_version() -> Version:
93
98
  logger.debug("Getting last compatible frontend..")
94
99
  try:
95
- res = requests.get('https://mindsdb-web-builds.s3.amazonaws.com/compatible-config.json', timeout=5)
100
+ res = requests.get(
101
+ "https://mindsdb-web-builds.s3.amazonaws.com/compatible-config.json",
102
+ timeout=5,
103
+ )
96
104
  except (ConnectionError, requests.exceptions.ConnectionError) as e:
97
105
  logger.error(f"Is no connection. {e}")
98
106
  return False
@@ -118,13 +126,16 @@ def get_last_compatible_gui_version() -> Version:
118
126
  gui_versions = {}
119
127
  max_mindsdb_lv = None
120
128
  max_gui_lv = None
121
- for el in versions['mindsdb']:
122
- if el['mindsdb_version'] is None:
123
- gui_lv = parse_version(el['gui_version'])
129
+ for el in versions["mindsdb"]:
130
+ if el["mindsdb_version"] is None:
131
+ gui_lv = parse_version(el["gui_version"])
124
132
  else:
125
- mindsdb_lv = parse_version(el['mindsdb_version'])
126
- gui_lv = parse_version(el['gui_version'])
127
- if mindsdb_lv.base_version not in gui_versions or gui_lv > gui_versions[mindsdb_lv.base_version]:
133
+ mindsdb_lv = parse_version(el["mindsdb_version"])
134
+ gui_lv = parse_version(el["gui_version"])
135
+ if (
136
+ mindsdb_lv.base_version not in gui_versions
137
+ or gui_lv > gui_versions[mindsdb_lv.base_version]
138
+ ):
128
139
  gui_versions[mindsdb_lv.base_version] = gui_lv
129
140
  if max_mindsdb_lv is None or max_mindsdb_lv < mindsdb_lv:
130
141
  max_mindsdb_lv = mindsdb_lv
@@ -139,7 +150,11 @@ def get_last_compatible_gui_version() -> Version:
139
150
  elif current_mindsdb_lv > all_mindsdb_lv[-1]:
140
151
  gui_version_lv = max_gui_lv
141
152
  else:
142
- lower_versions = {key: value for key, value in gui_versions.items() if parse_version(key) < current_mindsdb_lv}
153
+ lower_versions = {
154
+ key: value
155
+ for key, value in gui_versions.items()
156
+ if parse_version(key) < current_mindsdb_lv
157
+ }
143
158
  if len(lower_versions) == 0:
144
159
  gui_version_lv = gui_versions[all_mindsdb_lv[0].base_version]
145
160
  else:
@@ -156,12 +171,12 @@ def get_last_compatible_gui_version() -> Version:
156
171
  def get_current_gui_version() -> Version:
157
172
  logger.debug("Getting current frontend version..")
158
173
  config = Config()
159
- static_path = Path(config['paths']['static'])
160
- version_txt_path = static_path.joinpath('version.txt')
174
+ static_path = Path(config["paths"]["static"])
175
+ version_txt_path = static_path.joinpath("version.txt")
161
176
 
162
177
  current_gui_version = None
163
178
  if version_txt_path.is_file():
164
- with open(version_txt_path, 'rt') as f:
179
+ with open(version_txt_path, "rt") as f:
165
180
  current_gui_version = f.readline()
166
181
 
167
182
  current_gui_lv = (
@@ -177,7 +192,7 @@ def initialize_static():
177
192
  config = Config()
178
193
  last_gui_version_lv = get_last_compatible_gui_version()
179
194
  current_gui_version_lv = get_current_gui_version()
180
- required_gui_version = config['gui'].get('version')
195
+ required_gui_version = config["gui"].get("version")
181
196
 
182
197
  if required_gui_version is not None:
183
198
  required_gui_version_lv = parse_version(required_gui_version)
@@ -193,7 +208,10 @@ def initialize_static():
193
208
  return False
194
209
 
195
210
  # ignore versions like '23.9.2.2'
196
- if current_gui_version_lv is not None and len(current_gui_version_lv.release) < 3:
211
+ if (
212
+ current_gui_version_lv is not None
213
+ and len(current_gui_version_lv.release) < 3
214
+ ):
197
215
  if current_gui_version_lv == last_gui_version_lv:
198
216
  return True
199
217
  logger.debug("Updating gui..")
@@ -204,37 +222,40 @@ def initialize_static():
204
222
 
205
223
 
206
224
  def initialize_app(config, no_studio):
207
- static_root = config['paths']['static']
225
+ static_root = config["paths"]["static"]
208
226
  logger.debug(f"Static route: {static_root}")
209
- gui_exists = Path(static_root).joinpath('index.html').is_file()
227
+ gui_exists = Path(static_root).joinpath("index.html").is_file()
210
228
  logger.debug(f"Does GUI already exist.. {'YES' if gui_exists else 'NO'}")
211
229
  init_static_thread = None
212
- if (
213
- no_studio is False
214
- and (
215
- config['gui']['autoupdate'] is True
216
- or gui_exists is False
217
- )
230
+ if no_studio is False and (
231
+ config["gui"]["autoupdate"] is True or gui_exists is False
218
232
  ):
219
- init_static_thread = threading.Thread(target=initialize_static, name='initialize_static')
233
+ init_static_thread = threading.Thread(
234
+ target=initialize_static, name="initialize_static"
235
+ )
220
236
  init_static_thread.start()
221
237
 
238
+ # Wait for static initialization.
239
+ if not no_studio and init_static_thread is not None:
240
+ init_static_thread.join()
241
+
222
242
  app, api = initialize_flask(config, init_static_thread, no_studio)
223
243
  Compress(app)
244
+
224
245
  initialize_interfaces(app)
225
246
 
226
247
  if os.path.isabs(static_root) is False:
227
248
  static_root = os.path.join(os.getcwd(), static_root)
228
249
  static_root = Path(static_root)
229
250
 
230
- @app.route('/', defaults={'path': ''}, methods=['GET'])
231
- @app.route('/<path:path>', methods=['GET'])
251
+ @app.route("/", defaults={"path": ""}, methods=["GET"])
252
+ @app.route("/<path:path>", methods=["GET"])
232
253
  def root_index(path):
233
- if path.startswith('api/'):
254
+ if path.startswith("api/"):
234
255
  return http_error(
235
256
  HTTPStatus.NOT_FOUND,
236
- 'Not found',
237
- 'The endpoint you are trying to access does not exist on the server.'
257
+ "Not found",
258
+ "The endpoint you are trying to access does not exist on the server.",
238
259
  )
239
260
 
240
261
  # Normalize the path.
@@ -244,14 +265,14 @@ def initialize_app(config, no_studio):
244
265
  if not full_path.startswith(str(static_root)):
245
266
  return http_error(
246
267
  HTTPStatus.FORBIDDEN,
247
- 'Forbidden',
248
- 'You are not allowed to access the requested resource.'
268
+ "Forbidden",
269
+ "You are not allowed to access the requested resource.",
249
270
  )
250
271
 
251
272
  if os.path.isfile(full_path):
252
273
  return send_from_directory(static_root, path)
253
274
  else:
254
- return send_from_directory(static_root, 'index.html')
275
+ return send_from_directory(static_root, "index.html")
255
276
 
256
277
  protected_namespaces = [
257
278
  tab_ns,
@@ -270,7 +291,7 @@ def initialize_app(config, no_studio):
270
291
  skills_ns,
271
292
  agents_ns,
272
293
  jobs_ns,
273
- knowledge_bases_ns
294
+ knowledge_bases_ns,
274
295
  ]
275
296
 
276
297
  for ns in protected_namespaces:
@@ -285,20 +306,20 @@ def initialize_app(config, no_studio):
285
306
  # pass through HTTP errors
286
307
  # NOTE flask_restx require 'message', also it modyfies 'application/problem+json' to 'application/json'
287
308
  if isinstance(e, HTTPException):
288
- return ({
289
- 'title': e.name,
290
- 'detail': e.description,
291
- 'message': e.description
292
- }, e.code, {
293
- 'Content-Type': 'application/problem+json'
294
- })
295
- return ({
296
- 'title': getattr(type(e), "__name__") or "Unknown error",
297
- 'detail': str(e),
298
- 'message': str(e)
299
- }, 500, {
300
- 'Content-Type': 'application/problem+json'
301
- })
309
+ return (
310
+ {"title": e.name, "detail": e.description, "message": e.description},
311
+ e.code,
312
+ {"Content-Type": "application/problem+json"},
313
+ )
314
+ return (
315
+ {
316
+ "title": getattr(type(e), "__name__") or "Unknown error",
317
+ "detail": str(e),
318
+ "message": str(e),
319
+ },
320
+ 500,
321
+ {"Content-Type": "application/problem+json"},
322
+ )
302
323
 
303
324
  @app.teardown_appcontext
304
325
  def remove_session(*args, **kwargs):
@@ -312,31 +333,34 @@ def initialize_app(config, no_studio):
312
333
 
313
334
  # region routes where auth is required
314
335
  if (
315
- config['auth']['http_auth_enabled'] is True
316
- and any(request.path.startswith(f'/api{ns.path}') for ns in protected_namespaces)
336
+ config["auth"]["http_auth_enabled"] is True
337
+ and any(
338
+ request.path.startswith(f"/api{ns.path}") for ns in protected_namespaces
339
+ )
317
340
  and check_auth() is False
318
341
  ):
319
342
  return http_error(
320
- HTTPStatus.UNAUTHORIZED, 'Unauthorized',
321
- 'Authorization is required to complete the request'
343
+ HTTPStatus.UNAUTHORIZED,
344
+ "Unauthorized",
345
+ "Authorization is required to complete the request",
322
346
  )
323
347
  # endregion
324
348
 
325
- company_id = request.headers.get('company-id')
326
- user_class = request.headers.get('user-class')
349
+ company_id = request.headers.get("company-id")
350
+ user_class = request.headers.get("user-class")
327
351
 
328
352
  try:
329
- email_confirmed = int(request.headers.get('email-confirmed', 1))
353
+ email_confirmed = int(request.headers.get("email-confirmed", 1))
330
354
  except Exception:
331
355
  email_confirmed = 1
332
356
 
333
357
  try:
334
- user_id = int(request.headers.get('user-id', 0))
358
+ user_id = int(request.headers.get("user-id", 0))
335
359
  except Exception:
336
360
  user_id = 0
337
361
 
338
362
  try:
339
- session_id = request.cookies.get('session')
363
+ session_id = request.cookies.get("session")
340
364
  except Exception:
341
365
  session_id = "unknown"
342
366
 
@@ -366,10 +390,6 @@ def initialize_app(config, no_studio):
366
390
  ctx.user_class = user_class
367
391
  ctx.email_confirmed = email_confirmed
368
392
 
369
- # Wait for static initialization.
370
- if not no_studio and init_static_thread is not None:
371
- init_static_thread.join()
372
-
373
393
  logger.debug("Done initializing app.")
374
394
  return app
375
395
 
@@ -377,13 +397,13 @@ def initialize_app(config, no_studio):
377
397
  def initialize_flask(config, init_static_thread, no_studio):
378
398
  logger.debug("Initializing flask..")
379
399
  # region required for windows https://github.com/mindsdb/mindsdb/issues/2526
380
- mimetypes.add_type('text/css', '.css')
381
- mimetypes.add_type('text/javascript', '.js')
400
+ mimetypes.add_type("text/css", ".css")
401
+ mimetypes.add_type("text/javascript", ".js")
382
402
  # endregion
383
403
 
384
404
  kwargs = {}
385
405
  if no_studio is not True:
386
- static_path = os.path.join(config['paths']['static'], 'static/')
406
+ static_path = os.path.join(config["paths"]["static"], "static/")
387
407
  if os.path.isabs(static_path) is False:
388
408
  static_path = os.path.join(os.getcwd(), static_path)
389
409
  kwargs["static_url_path"] = "/static"
@@ -397,35 +417,31 @@ def initialize_flask(config, init_static_thread, no_studio):
397
417
  FlaskInstrumentor().instrument_app(app)
398
418
  RequestsInstrumentor().instrument()
399
419
 
400
- app.config['SECRET_KEY'] = os.environ.get('FLASK_SECRET_KEY', secrets.token_hex(32))
401
- app.config['SESSION_COOKIE_NAME'] = 'session'
402
- app.config['PERMANENT_SESSION_LIFETIME'] = config['auth']['http_permanent_session_lifetime']
403
- app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 60
404
- app.config['SWAGGER_HOST'] = 'http://localhost:8000/mindsdb'
420
+ app.config["SECRET_KEY"] = os.environ.get("FLASK_SECRET_KEY", secrets.token_hex(32))
421
+ app.config["SESSION_COOKIE_NAME"] = "session"
422
+ app.config["PERMANENT_SESSION_LIFETIME"] = config["auth"][
423
+ "http_permanent_session_lifetime"
424
+ ]
425
+ app.config["SEND_FILE_MAX_AGE_DEFAULT"] = 60
426
+ app.config["SWAGGER_HOST"] = "http://localhost:8000/mindsdb"
405
427
  app.json = CustomJSONProvider()
406
428
 
407
- authorizations = {
408
- 'apikey': {
409
- 'type': 'session',
410
- 'in': 'query',
411
- 'name': 'session'
412
- }
413
- }
429
+ authorizations = {"apikey": {"type": "session", "in": "query", "name": "session"}}
414
430
 
415
431
  logger.debug("Creating swagger API..")
416
432
  api = Swagger_Api(
417
433
  app,
418
434
  authorizations=authorizations,
419
- security=['apikey'],
420
- url_prefix=':8000',
421
- prefix='/api',
422
- doc='/doc/'
435
+ security=["apikey"],
436
+ url_prefix=":8000",
437
+ prefix="/api",
438
+ doc="/doc/",
423
439
  )
424
440
 
425
- api.representations['application/json'] = custom_output_json
441
+ api.representations["application/json"] = custom_output_json
426
442
 
427
- port = config['api']['http']['port']
428
- host = config['api']['http']['host']
443
+ port = config["api"]["http"]["port"]
444
+ host = config["api"]["http"]["host"]
429
445
 
430
446
  # NOTE rewrite it, that hotfix to see GUI link
431
447
  if not no_studio:
@@ -438,9 +454,9 @@ def initialize_flask(config, init_static_thread, no_studio):
438
454
  pid = os.getpid()
439
455
  thread = threading.Thread(
440
456
  target=_open_webbrowser,
441
- args=(url, pid, port, init_static_thread, config['paths']['static']),
457
+ args=(url, pid, port, init_static_thread, config["paths"]["static"]),
442
458
  daemon=True,
443
- name='open_webbrowser'
459
+ name="open_webbrowser",
444
460
  )
445
461
  thread.start()
446
462
 
@@ -77,8 +77,8 @@ class QueryAnalysis(Resource):
77
77
  if result.type != SQL_RESPONSE_TYPE.TABLE:
78
78
  return http_error(500, "Error", "Query does not return data")
79
79
 
80
- column_names = [x["name"] for x in result.columns]
81
- df = DataFrame(result.data, columns=column_names)
80
+ column_names = [column.name for column in result.result_set.columns]
81
+ df = result.result_set.to_df()
82
82
  try:
83
83
  analysis = analyze_df(df)
84
84
  except ImportError:
@@ -95,7 +95,7 @@ class QueryAnalysis(Resource):
95
95
  return {
96
96
  "analysis": analysis,
97
97
  "column_names": column_names,
98
- "row_count": len(result.data),
98
+ "row_count": len(result.result_set),
99
99
  "timestamp": time.time(),
100
100
  "tables": query_tables,
101
101
  }
@@ -84,8 +84,14 @@ class File(Resource):
84
84
  parser.finalize()
85
85
  parser.close()
86
86
 
87
- if file_object is not None and not file_object.closed:
88
- file_object.close()
87
+ if file_object is not None:
88
+ if not file_object.closed:
89
+ try:
90
+ file_object.flush()
91
+ except (AttributeError, ValueError, OSError):
92
+ logger.debug("Failed to flush file_object before closing.", exc_info=True)
93
+ file_object.close()
94
+ file_object = None
89
95
  else:
90
96
  data = request.json
91
97
 
@@ -8,6 +8,7 @@ import mindsdb.utilities.hooks as hooks
8
8
  import mindsdb.utilities.profiler as profiler
9
9
  from mindsdb.api.http.utils import http_error
10
10
  from mindsdb.api.http.namespaces.configs.sql import ns_conf
11
+ from mindsdb.api.mysql.mysql_proxy.mysql_proxy import SQLAnswer
11
12
  from mindsdb.api.mysql.mysql_proxy.classes.fake_mysql_proxy import FakeMysqlProxy
12
13
  from mindsdb.api.executor.data_types.response_type import (
13
14
  RESPONSE_TYPE as SQL_RESPONSE_TYPE,
@@ -56,23 +57,8 @@ class Query(Resource):
56
57
  mysql_proxy = FakeMysqlProxy()
57
58
  mysql_proxy.set_context(context)
58
59
  try:
59
- result = mysql_proxy.process_query(query)
60
-
61
- if result.type == SQL_RESPONSE_TYPE.OK:
62
- query_response = {
63
- "type": SQL_RESPONSE_TYPE.OK,
64
- "affected_rows": result.affected_rows
65
- }
66
- elif result.type == SQL_RESPONSE_TYPE.TABLE:
67
- data = result.data.to_lists(json_types=True)
68
- query_response = {
69
- "type": SQL_RESPONSE_TYPE.TABLE,
70
- "data": data,
71
- "column_names": [
72
- x["alias"] or x["name"] if "alias" in x else x["name"]
73
- for x in result.columns
74
- ],
75
- }
60
+ result: SQLAnswer = mysql_proxy.process_query(query)
61
+ query_response: dict = result.dump_http_response()
76
62
  except ExecutorException as e:
77
63
  # classified error
78
64
  error_type = "expected"
@@ -134,7 +120,7 @@ class ListDatabases(Resource):
134
120
  listing_query = "SHOW DATABASES"
135
121
  mysql_proxy = FakeMysqlProxy()
136
122
  try:
137
- result = mysql_proxy.process_query(listing_query)
123
+ result: SQLAnswer = mysql_proxy.process_query(listing_query)
138
124
 
139
125
  # iterate over result.data and perform a query on each item to get the name of the tables
140
126
  if result.type == SQL_RESPONSE_TYPE.ERROR:
@@ -147,15 +133,15 @@ class ListDatabases(Resource):
147
133
  listing_query_response = {"type": "ok"}
148
134
  elif result.type == SQL_RESPONSE_TYPE.TABLE:
149
135
  listing_query_response = {
150
- "data": [
151
- {
152
- "name": x[0],
153
- "tables": mysql_proxy.process_query(
154
- "SHOW TABLES FROM `{}`".format(x[0])
155
- ).data,
156
- }
157
- for x in result.data
158
- ]
136
+ "data": [{
137
+ "name": db_row[0],
138
+ "tables": [
139
+ table_row[0]
140
+ for table_row in mysql_proxy.process_query(
141
+ "SHOW TABLES FROM `{}`".format(db_row[0])
142
+ ).result_set.to_lists()
143
+ ]
144
+ } for db_row in result.result_set.to_lists()]
159
145
  }
160
146
  except Exception as e:
161
147
  listing_query_response = {
mindsdb/api/mcp/start.py CHANGED
@@ -1,9 +1,16 @@
1
+ import os
1
2
  from contextlib import asynccontextmanager
2
3
  from collections.abc import AsyncIterator
3
4
  from typing import Optional, Dict, Any
4
5
  from dataclasses import dataclass
5
6
 
7
+ import uvicorn
8
+ import anyio
6
9
  from mcp.server.fastmcp import FastMCP
10
+ from starlette.middleware.base import BaseHTTPMiddleware
11
+ from starlette.requests import Request
12
+ from starlette.responses import Response
13
+
7
14
  from mindsdb.api.mysql.mysql_proxy.classes.fake_mysql_proxy import FakeMysqlProxy
8
15
  from mindsdb.api.executor.data_types.response_type import RESPONSE_TYPE as SQL_RESPONSE_TYPE
9
16
  from mindsdb.utilities import log
@@ -70,10 +77,10 @@ def query(query: str, context: Optional[Dict] = None) -> Dict[str, Any]:
70
77
  if result.type == SQL_RESPONSE_TYPE.TABLE:
71
78
  return {
72
79
  "type": SQL_RESPONSE_TYPE.TABLE,
73
- "data": result.data.to_lists(json_types=True),
80
+ "data": result.result_set.to_lists(json_types=True),
74
81
  "column_names": [
75
- x["alias"] or x["name"] if "alias" in x else x["name"]
76
- for x in result.columns
82
+ column.alias or column.name
83
+ for column in result.result_set.columns
77
84
  ],
78
85
  }
79
86
  else:
@@ -116,7 +123,7 @@ def list_databases() -> Dict[str, Any]:
116
123
  return {"type": "ok"}
117
124
 
118
125
  elif result.type == SQL_RESPONSE_TYPE.TABLE:
119
- data = result.data.to_lists(json_types=True)
126
+ data = result.result_set.to_lists(json_types=True)
120
127
  return data
121
128
 
122
129
  except Exception as e:
@@ -127,6 +134,36 @@ def list_databases() -> Dict[str, Any]:
127
134
  }
128
135
 
129
136
 
137
+ class CustomAuthMiddleware(BaseHTTPMiddleware):
138
+ """Custom middleware to handle authentication basing on header 'Authorization'
139
+ """
140
+ async def dispatch(self, request: Request, call_next):
141
+ mcp_access_token = os.environ.get('MINDSDB_MCP_ACCESS_TOKEN')
142
+ if mcp_access_token is not None:
143
+ auth_token = request.headers.get('Authorization', '').partition('Bearer ')[-1]
144
+ if mcp_access_token != auth_token:
145
+ return Response(status_code=401, content="Unauthorized", media_type="text/plain")
146
+
147
+ response = await call_next(request)
148
+
149
+ return response
150
+
151
+
152
+ async def run_sse_async() -> None:
153
+ """Run the server using SSE transport."""
154
+ starlette_app = mcp.sse_app()
155
+ starlette_app.add_middleware(CustomAuthMiddleware)
156
+
157
+ config = uvicorn.Config(
158
+ starlette_app,
159
+ host=mcp.settings.host,
160
+ port=mcp.settings.port,
161
+ log_level=mcp.settings.log_level.lower(),
162
+ )
163
+ server = uvicorn.Server(config)
164
+ await server.serve()
165
+
166
+
130
167
  def start(*args, **kwargs):
131
168
  """Start the MCP server
132
169
  Args:
@@ -142,7 +179,7 @@ def start(*args, **kwargs):
142
179
  mcp.settings.port = port
143
180
 
144
181
  try:
145
- mcp.run(transport="sse") # Use SSE transport instead of stdio
182
+ anyio.run(run_sse_async)
146
183
  except Exception as e:
147
184
  logger.error(f"Error starting MCP server: {str(e)}")
148
185
  raise
@@ -77,7 +77,6 @@ class Packet:
77
77
  f"Packet with less than 4 bytes in length: {packet_string}"
78
78
  )
79
79
  return False
80
- break
81
80
  len_header = struct.unpack("i", packet_string[:3] + b"\x00")[0]
82
81
  count_header = int(packet_string[3])
83
82
  if len_header == 0: