mindroot 9.11.0__py3-none-any.whl → 9.13.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 mindroot might be problematic. Click here for more details.

Files changed (417) hide show
  1. mindroot/coreplugins/admin/static/js/model-preferences-v2.js +1 -1
  2. mindroot/coreplugins/home/templates/home.jinja2 +1 -0
  3. mindroot/docs/Makefile +20 -0
  4. mindroot/docs/_build/doctrees/chat_with_assistant.doctree +0 -0
  5. mindroot/docs/_build/doctrees/developer_documentation.doctree +0 -0
  6. mindroot/docs/_build/doctrees/environment.pickle +0 -0
  7. mindroot/docs/_build/doctrees/getting_started.doctree +0 -0
  8. mindroot/docs/_build/doctrees/index.doctree +0 -0
  9. mindroot/docs/_build/doctrees/install_plugins_with_tools.doctree +0 -0
  10. mindroot/docs/_build/doctrees/installation.doctree +0 -0
  11. mindroot/docs/_build/doctrees/llm_api_key.doctree +0 -0
  12. mindroot/docs/_build/doctrees/llm_plugin_installation.doctree +0 -0
  13. mindroot/docs/_build/doctrees/programming_task.doctree +0 -0
  14. mindroot/docs/_build/doctrees/source/ahp.doctree +0 -0
  15. mindroot/docs/_build/doctrees/source/mindroot.coreplugins.admin.doctree +0 -0
  16. mindroot/docs/_build/doctrees/source/mindroot.coreplugins.api_keys.doctree +0 -0
  17. mindroot/docs/_build/doctrees/source/mindroot.coreplugins.chat.doctree +0 -0
  18. mindroot/docs/_build/doctrees/source/mindroot.coreplugins.chat_avatar.doctree +0 -0
  19. mindroot/docs/_build/doctrees/source/mindroot.coreplugins.check_list.doctree +0 -0
  20. mindroot/docs/_build/doctrees/source/mindroot.coreplugins.credits.doctree +0 -0
  21. mindroot/docs/_build/doctrees/source/mindroot.coreplugins.doctree +0 -0
  22. mindroot/docs/_build/doctrees/source/mindroot.coreplugins.email.doctree +0 -0
  23. mindroot/docs/_build/doctrees/source/mindroot.coreplugins.env_manager.doctree +0 -0
  24. mindroot/docs/_build/doctrees/source/mindroot.coreplugins.events.doctree +0 -0
  25. mindroot/docs/_build/doctrees/source/mindroot.coreplugins.index.doctree +0 -0
  26. mindroot/docs/_build/doctrees/source/mindroot.coreplugins.index.handlers.doctree +0 -0
  27. mindroot/docs/_build/doctrees/source/mindroot.coreplugins.jwt_auth.doctree +0 -0
  28. mindroot/docs/_build/doctrees/source/mindroot.coreplugins.l8n.doctree +0 -0
  29. mindroot/docs/_build/doctrees/source/mindroot.coreplugins.mcp_.doctree +0 -0
  30. mindroot/docs/_build/doctrees/source/mindroot.coreplugins.persona.doctree +0 -0
  31. mindroot/docs/_build/doctrees/source/mindroot.coreplugins.startup.doctree +0 -0
  32. mindroot/docs/_build/doctrees/source/mindroot.coreplugins.subscriptions.doctree +0 -0
  33. mindroot/docs/_build/doctrees/source/mindroot.coreplugins.usage.doctree +0 -0
  34. mindroot/docs/_build/doctrees/source/mindroot.coreplugins.user_service.doctree +0 -0
  35. mindroot/docs/_build/doctrees/source/mindroot.doctree +0 -0
  36. mindroot/docs/_build/doctrees/source/mindroot.lib.auth.doctree +0 -0
  37. mindroot/docs/_build/doctrees/source/mindroot.lib.doctree +0 -0
  38. mindroot/docs/_build/doctrees/source/mindroot.lib.json_str_block.doctree +0 -0
  39. mindroot/docs/_build/doctrees/source/mindroot.lib.plugins.doctree +0 -0
  40. mindroot/docs/_build/doctrees/source/mindroot.lib.providers.backup.doctree +0 -0
  41. mindroot/docs/_build/doctrees/source/mindroot.lib.providers.doctree +0 -0
  42. mindroot/docs/_build/doctrees/source/mindroot.registry.doctree +0 -0
  43. mindroot/docs/_build/doctrees/source/modules.doctree +0 -0
  44. mindroot/docs/_build/doctrees/source/mr_agent_expert_instr.doctree +0 -0
  45. mindroot/docs/_build/doctrees/starting_mindroot.doctree +0 -0
  46. mindroot/docs/_build/doctrees/user_documentation.doctree +0 -0
  47. mindroot/docs/_build/html/.buildinfo +4 -0
  48. mindroot/docs/_build/html/.buildinfo.bak +4 -0
  49. mindroot/docs/_build/html/_images/envvar.png +0 -0
  50. mindroot/docs/_build/html/_images/files.png +0 -0
  51. mindroot/docs/_build/html/_images/installopenrouter.png +0 -0
  52. mindroot/docs/_build/html/_images/mood.png +0 -0
  53. mindroot/docs/_build/html/_images/moon.png +0 -0
  54. mindroot/docs/_build/html/_images/openrouter.png +0 -0
  55. mindroot/docs/_build/html/_images/restart.png +0 -0
  56. mindroot/docs/_build/html/_modules/index.html +425 -0
  57. mindroot/docs/_build/html/_modules/mindroot/coreplugins/admin/agent_importer.html +292 -0
  58. mindroot/docs/_build/html/_modules/mindroot/coreplugins/admin/agent_router.html +620 -0
  59. mindroot/docs/_build/html/_modules/mindroot/coreplugins/admin/asset_manager.html +289 -0
  60. mindroot/docs/_build/html/_modules/mindroot/coreplugins/admin/command_router.html +518 -0
  61. mindroot/docs/_build/html/_modules/mindroot/coreplugins/admin/mcp_catalog_routes.html +275 -0
  62. mindroot/docs/_build/html/_modules/mindroot/coreplugins/admin/mcp_publish_routes.html +581 -0
  63. mindroot/docs/_build/html/_modules/mindroot/coreplugins/admin/mcp_registry_routes.html +623 -0
  64. mindroot/docs/_build/html/_modules/mindroot/coreplugins/admin/mcp_routes.html +347 -0
  65. mindroot/docs/_build/html/_modules/mindroot/coreplugins/admin/mod.html +163 -0
  66. mindroot/docs/_build/html/_modules/mindroot/coreplugins/admin/oauth_callback_router.html +188 -0
  67. mindroot/docs/_build/html/_modules/mindroot/coreplugins/admin/persona_handler.html +195 -0
  68. mindroot/docs/_build/html/_modules/mindroot/coreplugins/admin/persona_router.html +428 -0
  69. mindroot/docs/_build/html/_modules/mindroot/coreplugins/admin/plugin_manager.html +610 -0
  70. mindroot/docs/_build/html/_modules/mindroot/coreplugins/admin/plugin_router.html +146 -0
  71. mindroot/docs/_build/html/_modules/mindroot/coreplugins/admin/plugin_routes.html +230 -0
  72. mindroot/docs/_build/html/_modules/mindroot/coreplugins/admin/registry_settings_routes.html +253 -0
  73. mindroot/docs/_build/html/_modules/mindroot/coreplugins/admin/router.html +267 -0
  74. mindroot/docs/_build/html/_modules/mindroot/coreplugins/admin/server_router.html +271 -0
  75. mindroot/docs/_build/html/_modules/mindroot/coreplugins/admin/service_models.html +195 -0
  76. mindroot/docs/_build/html/_modules/mindroot/coreplugins/admin/settings_router.html +403 -0
  77. mindroot/docs/_build/html/_modules/mindroot/coreplugins/api_keys/api_key_manager.html +215 -0
  78. mindroot/docs/_build/html/_modules/mindroot/coreplugins/api_keys/mod.html +127 -0
  79. mindroot/docs/_build/html/_modules/mindroot/coreplugins/api_keys/router.html +170 -0
  80. mindroot/docs/_build/html/_modules/mindroot/coreplugins/chat/commands.html +565 -0
  81. mindroot/docs/_build/html/_modules/mindroot/coreplugins/chat/mod.html +118 -0
  82. mindroot/docs/_build/html/_modules/mindroot/coreplugins/chat/models.html +130 -0
  83. mindroot/docs/_build/html/_modules/mindroot/coreplugins/chat/router.html +571 -0
  84. mindroot/docs/_build/html/_modules/mindroot/coreplugins/chat/services.html +645 -0
  85. mindroot/docs/_build/html/_modules/mindroot/coreplugins/chat/widget_manager.html +258 -0
  86. mindroot/docs/_build/html/_modules/mindroot/coreplugins/chat/widget_routes.html +409 -0
  87. mindroot/docs/_build/html/_modules/mindroot/coreplugins/check_list/mod.html +460 -0
  88. mindroot/docs/_build/html/_modules/mindroot/coreplugins/credits/conversion.html +232 -0
  89. mindroot/docs/_build/html/_modules/mindroot/coreplugins/credits/ledger.html +283 -0
  90. mindroot/docs/_build/html/_modules/mindroot/coreplugins/credits/mod.html +355 -0
  91. mindroot/docs/_build/html/_modules/mindroot/coreplugins/credits/models.html +269 -0
  92. mindroot/docs/_build/html/_modules/mindroot/coreplugins/credits/router.html +306 -0
  93. mindroot/docs/_build/html/_modules/mindroot/coreplugins/credits/storage.html +257 -0
  94. mindroot/docs/_build/html/_modules/mindroot/coreplugins/email/email_provider.html +159 -0
  95. mindroot/docs/_build/html/_modules/mindroot/coreplugins/email/imap_handler.html +343 -0
  96. mindroot/docs/_build/html/_modules/mindroot/coreplugins/email/mod.html +210 -0
  97. mindroot/docs/_build/html/_modules/mindroot/coreplugins/email/services.html +172 -0
  98. mindroot/docs/_build/html/_modules/mindroot/coreplugins/email/smtp_handler.html +188 -0
  99. mindroot/docs/_build/html/_modules/mindroot/coreplugins/email/test_email_service.html +179 -0
  100. mindroot/docs/_build/html/_modules/mindroot/coreplugins/env_manager/mod.html +409 -0
  101. mindroot/docs/_build/html/_modules/mindroot/coreplugins/env_manager/router.html +147 -0
  102. mindroot/docs/_build/html/_modules/mindroot/coreplugins/events/router.html +201 -0
  103. mindroot/docs/_build/html/_modules/mindroot/coreplugins/index/handlers/agent_ops.html +195 -0
  104. mindroot/docs/_build/html/_modules/mindroot/coreplugins/index/handlers/index_ops.html +214 -0
  105. mindroot/docs/_build/html/_modules/mindroot/coreplugins/index/handlers/plugin_ops.html +263 -0
  106. mindroot/docs/_build/html/_modules/mindroot/coreplugins/index/handlers/publish.html +225 -0
  107. mindroot/docs/_build/html/_modules/mindroot/coreplugins/index/mod.html +120 -0
  108. mindroot/docs/_build/html/_modules/mindroot/coreplugins/index/models.html +148 -0
  109. mindroot/docs/_build/html/_modules/mindroot/coreplugins/index/router.html +184 -0
  110. mindroot/docs/_build/html/_modules/mindroot/coreplugins/index/utils.html +166 -0
  111. mindroot/docs/_build/html/_modules/mindroot/coreplugins/jwt_auth/middleware.html +400 -0
  112. mindroot/docs/_build/html/_modules/mindroot/coreplugins/jwt_auth/mod.html +153 -0
  113. mindroot/docs/_build/html/_modules/mindroot/coreplugins/jwt_auth/router.html +134 -0
  114. mindroot/docs/_build/html/_modules/mindroot/coreplugins/l8n/language_detection.html +296 -0
  115. mindroot/docs/_build/html/_modules/mindroot/coreplugins/l8n/middleware.html +258 -0
  116. mindroot/docs/_build/html/_modules/mindroot/coreplugins/l8n/mod.html +393 -0
  117. mindroot/docs/_build/html/_modules/mindroot/coreplugins/l8n/test_enhanced.html +408 -0
  118. mindroot/docs/_build/html/_modules/mindroot/coreplugins/l8n/test_l8n_standalone.html +379 -0
  119. mindroot/docs/_build/html/_modules/mindroot/coreplugins/l8n/test_middleware.html +394 -0
  120. mindroot/docs/_build/html/_modules/mindroot/coreplugins/l8n/utils.html +348 -0
  121. mindroot/docs/_build/html/_modules/mindroot/coreplugins/mcp_/catalog_commands.html +456 -0
  122. mindroot/docs/_build/html/_modules/mindroot/coreplugins/mcp_/catalog_manager.html +409 -0
  123. mindroot/docs/_build/html/_modules/mindroot/coreplugins/mcp_/dynamic_commands.html +267 -0
  124. mindroot/docs/_build/html/_modules/mindroot/coreplugins/mcp_/mcp_manager.html +1186 -0
  125. mindroot/docs/_build/html/_modules/mindroot/coreplugins/mcp_/mod.html +510 -0
  126. mindroot/docs/_build/html/_modules/mindroot/coreplugins/mcp_/oauth_storage.html +260 -0
  127. mindroot/docs/_build/html/_modules/mindroot/coreplugins/mcp_/server_installer.html +195 -0
  128. mindroot/docs/_build/html/_modules/mindroot/coreplugins/mcp_/testmcpclient.html +217 -0
  129. mindroot/docs/_build/html/_modules/mindroot/coreplugins/persona/init_persona.html +117 -0
  130. mindroot/docs/_build/html/_modules/mindroot/coreplugins/persona/mod.html +276 -0
  131. mindroot/docs/_build/html/_modules/mindroot/coreplugins/startup/mod.html +122 -0
  132. mindroot/docs/_build/html/_modules/mindroot/coreplugins/subscriptions/credit_integration.html +163 -0
  133. mindroot/docs/_build/html/_modules/mindroot/coreplugins/subscriptions/mod.html +1089 -0
  134. mindroot/docs/_build/html/_modules/mindroot/coreplugins/subscriptions/models.html +261 -0
  135. mindroot/docs/_build/html/_modules/mindroot/coreplugins/subscriptions/router.html +502 -0
  136. mindroot/docs/_build/html/_modules/mindroot/coreplugins/subscriptions/storage.html +413 -0
  137. mindroot/docs/_build/html/_modules/mindroot/coreplugins/subscriptions/stripe_integration.html +178 -0
  138. mindroot/docs/_build/html/_modules/mindroot/coreplugins/subscriptions/subscription_manager.html +289 -0
  139. mindroot/docs/_build/html/_modules/mindroot/coreplugins/subscriptions/webhook_handler.html +327 -0
  140. mindroot/docs/_build/html/_modules/mindroot/coreplugins/usage/handlers.html +157 -0
  141. mindroot/docs/_build/html/_modules/mindroot/coreplugins/usage/mod.html +253 -0
  142. mindroot/docs/_build/html/_modules/mindroot/coreplugins/usage/models.html +141 -0
  143. mindroot/docs/_build/html/_modules/mindroot/coreplugins/usage/reporting.html +226 -0
  144. mindroot/docs/_build/html/_modules/mindroot/coreplugins/usage/router.html +228 -0
  145. mindroot/docs/_build/html/_modules/mindroot/coreplugins/usage/storage.html +264 -0
  146. mindroot/docs/_build/html/_modules/mindroot/coreplugins/user_service/admin_init.html +234 -0
  147. mindroot/docs/_build/html/_modules/mindroot/coreplugins/user_service/email_service.html +204 -0
  148. mindroot/docs/_build/html/_modules/mindroot/coreplugins/user_service/mod.html +260 -0
  149. mindroot/docs/_build/html/_modules/mindroot/coreplugins/user_service/models.html +148 -0
  150. mindroot/docs/_build/html/_modules/mindroot/coreplugins/user_service/password_reset_service.html +336 -0
  151. mindroot/docs/_build/html/_modules/mindroot/coreplugins/user_service/role_service.html +183 -0
  152. mindroot/docs/_build/html/_modules/mindroot/coreplugins/user_service/router.html +202 -0
  153. mindroot/docs/_build/html/_modules/mindroot/lib/auth/api_key.html +129 -0
  154. mindroot/docs/_build/html/_modules/mindroot/lib/auth/auth.html +203 -0
  155. mindroot/docs/_build/html/_modules/mindroot/lib/buchatlog.html +259 -0
  156. mindroot/docs/_build/html/_modules/mindroot/lib/buchatlog2.html +500 -0
  157. mindroot/docs/_build/html/_modules/mindroot/lib/butemplates.html +415 -0
  158. mindroot/docs/_build/html/_modules/mindroot/lib/chatcontext.html +401 -0
  159. mindroot/docs/_build/html/_modules/mindroot/lib/chatlog.html +619 -0
  160. mindroot/docs/_build/html/_modules/mindroot/lib/chatlog_optimized.html +655 -0
  161. mindroot/docs/_build/html/_modules/mindroot/lib/json_escape.html +138 -0
  162. mindroot/docs/_build/html/_modules/mindroot/lib/json_str_block/json_str_block.html +213 -0
  163. mindroot/docs/_build/html/_modules/mindroot/lib/parent_templates.html +181 -0
  164. mindroot/docs/_build/html/_modules/mindroot/lib/plugins/installation.html +481 -0
  165. mindroot/docs/_build/html/_modules/mindroot/lib/plugins/l8n_static_handler.html +347 -0
  166. mindroot/docs/_build/html/_modules/mindroot/lib/plugins/loader.html +403 -0
  167. mindroot/docs/_build/html/_modules/mindroot/lib/plugins/loader_with_l8n.html +391 -0
  168. mindroot/docs/_build/html/_modules/mindroot/lib/plugins/manifest.html +450 -0
  169. mindroot/docs/_build/html/_modules/mindroot/lib/plugins/mapping.html +127 -0
  170. mindroot/docs/_build/html/_modules/mindroot/lib/plugins/paths.html +215 -0
  171. mindroot/docs/_build/html/_modules/mindroot/lib/plugins_install.html +171 -0
  172. mindroot/docs/_build/html/_modules/mindroot/lib/providers/commands.html +125 -0
  173. mindroot/docs/_build/html/_modules/mindroot/lib/providers/hooks.html +117 -0
  174. mindroot/docs/_build/html/_modules/mindroot/lib/providers/missing.html +169 -0
  175. mindroot/docs/_build/html/_modules/mindroot/lib/providers/model_preferences_v2.html +291 -0
  176. mindroot/docs/_build/html/_modules/mindroot/lib/providers/services.html +122 -0
  177. mindroot/docs/_build/html/_modules/mindroot/lib/providers.html +465 -0
  178. mindroot/docs/_build/html/_modules/mindroot/lib/route_decorators.html +175 -0
  179. mindroot/docs/_build/html/_modules/mindroot/lib/session_files.html +142 -0
  180. mindroot/docs/_build/html/_modules/mindroot/lib/streamcmd.html +246 -0
  181. mindroot/docs/_build/html/_modules/mindroot/lib/templates.html +677 -0
  182. mindroot/docs/_build/html/_modules/mindroot/lib/token_counter.html +326 -0
  183. mindroot/docs/_build/html/_modules/mindroot/migrate.html +153 -0
  184. mindroot/docs/_build/html/_modules/mindroot/registry/component_manager.html +140 -0
  185. mindroot/docs/_build/html/_modules/mindroot/registry/data_access.html +302 -0
  186. mindroot/docs/_build/html/_modules/mindroot/server.html +317 -0
  187. mindroot/docs/_build/html/_modules/mindroot/server_missing_normal_args.html +322 -0
  188. mindroot/docs/_build/html/_modules/mindroot/server_prev.html +298 -0
  189. mindroot/docs/_build/html/_sources/chat_with_assistant.rst.txt +14 -0
  190. mindroot/docs/_build/html/_sources/developer_documentation.rst.txt +26 -0
  191. mindroot/docs/_build/html/_sources/getting_started.rst.txt +139 -0
  192. mindroot/docs/_build/html/_sources/index.rst.txt +38 -0
  193. mindroot/docs/_build/html/_sources/install_plugins_with_tools.rst.txt +25 -0
  194. mindroot/docs/_build/html/_sources/installation.rst.txt +21 -0
  195. mindroot/docs/_build/html/_sources/llm_api_key.rst.txt +22 -0
  196. mindroot/docs/_build/html/_sources/llm_plugin_installation.rst.txt +27 -0
  197. mindroot/docs/_build/html/_sources/programming_task.rst.txt +10 -0
  198. mindroot/docs/_build/html/_sources/source/ahp.rst.txt +7 -0
  199. mindroot/docs/_build/html/_sources/source/mindroot.coreplugins.admin.rst.txt +189 -0
  200. mindroot/docs/_build/html/_sources/source/mindroot.coreplugins.api_keys.rst.txt +45 -0
  201. mindroot/docs/_build/html/_sources/source/mindroot.coreplugins.chat.rst.txt +93 -0
  202. mindroot/docs/_build/html/_sources/source/mindroot.coreplugins.chat_avatar.rst.txt +10 -0
  203. mindroot/docs/_build/html/_sources/source/mindroot.coreplugins.check_list.rst.txt +21 -0
  204. mindroot/docs/_build/html/_sources/source/mindroot.coreplugins.credits.rst.txt +61 -0
  205. mindroot/docs/_build/html/_sources/source/mindroot.coreplugins.email.rst.txt +77 -0
  206. mindroot/docs/_build/html/_sources/source/mindroot.coreplugins.env_manager.rst.txt +29 -0
  207. mindroot/docs/_build/html/_sources/source/mindroot.coreplugins.events.rst.txt +29 -0
  208. mindroot/docs/_build/html/_sources/source/mindroot.coreplugins.index.handlers.rst.txt +45 -0
  209. mindroot/docs/_build/html/_sources/source/mindroot.coreplugins.index.rst.txt +53 -0
  210. mindroot/docs/_build/html/_sources/source/mindroot.coreplugins.jwt_auth.rst.txt +45 -0
  211. mindroot/docs/_build/html/_sources/source/mindroot.coreplugins.l8n.rst.txt +109 -0
  212. mindroot/docs/_build/html/_sources/source/mindroot.coreplugins.mcp_.rst.txt +93 -0
  213. mindroot/docs/_build/html/_sources/source/mindroot.coreplugins.persona.rst.txt +29 -0
  214. mindroot/docs/_build/html/_sources/source/mindroot.coreplugins.rst.txt +35 -0
  215. mindroot/docs/_build/html/_sources/source/mindroot.coreplugins.startup.rst.txt +21 -0
  216. mindroot/docs/_build/html/_sources/source/mindroot.coreplugins.subscriptions.rst.txt +85 -0
  217. mindroot/docs/_build/html/_sources/source/mindroot.coreplugins.usage.rst.txt +61 -0
  218. mindroot/docs/_build/html/_sources/source/mindroot.coreplugins.user_service.rst.txt +69 -0
  219. mindroot/docs/_build/html/_sources/source/mindroot.lib.auth.rst.txt +29 -0
  220. mindroot/docs/_build/html/_sources/source/mindroot.lib.json_str_block.rst.txt +21 -0
  221. mindroot/docs/_build/html/_sources/source/mindroot.lib.plugins.rst.txt +69 -0
  222. mindroot/docs/_build/html/_sources/source/mindroot.lib.providers.backup.rst.txt +10 -0
  223. mindroot/docs/_build/html/_sources/source/mindroot.lib.providers.rst.txt +61 -0
  224. mindroot/docs/_build/html/_sources/source/mindroot.lib.rst.txt +152 -0
  225. mindroot/docs/_build/html/_sources/source/mindroot.registry.rst.txt +29 -0
  226. mindroot/docs/_build/html/_sources/source/mindroot.rst.txt +54 -0
  227. mindroot/docs/_build/html/_sources/source/modules.rst.txt +7 -0
  228. mindroot/docs/_build/html/_sources/source/mr_agent_expert_instr.rst.txt +7 -0
  229. mindroot/docs/_build/html/_sources/starting_mindroot.rst.txt +12 -0
  230. mindroot/docs/_build/html/_sources/user_documentation.rst.txt +16 -0
  231. mindroot/docs/_build/html/_static/_sphinx_javascript_frameworks_compat.js +123 -0
  232. mindroot/docs/_build/html/_static/basic.css +906 -0
  233. mindroot/docs/_build/html/_static/css/badge_only.css +1 -0
  234. mindroot/docs/_build/html/_static/css/fonts/Roboto-Slab-Bold.woff +0 -0
  235. mindroot/docs/_build/html/_static/css/fonts/Roboto-Slab-Bold.woff2 +0 -0
  236. mindroot/docs/_build/html/_static/css/fonts/Roboto-Slab-Regular.woff +0 -0
  237. mindroot/docs/_build/html/_static/css/fonts/Roboto-Slab-Regular.woff2 +0 -0
  238. mindroot/docs/_build/html/_static/css/fonts/fontawesome-webfont.eot +0 -0
  239. mindroot/docs/_build/html/_static/css/fonts/fontawesome-webfont.svg +2671 -0
  240. mindroot/docs/_build/html/_static/css/fonts/fontawesome-webfont.ttf +0 -0
  241. mindroot/docs/_build/html/_static/css/fonts/fontawesome-webfont.woff +0 -0
  242. mindroot/docs/_build/html/_static/css/fonts/fontawesome-webfont.woff2 +0 -0
  243. mindroot/docs/_build/html/_static/css/fonts/lato-bold-italic.woff +0 -0
  244. mindroot/docs/_build/html/_static/css/fonts/lato-bold-italic.woff2 +0 -0
  245. mindroot/docs/_build/html/_static/css/fonts/lato-bold.woff +0 -0
  246. mindroot/docs/_build/html/_static/css/fonts/lato-bold.woff2 +0 -0
  247. mindroot/docs/_build/html/_static/css/fonts/lato-normal-italic.woff +0 -0
  248. mindroot/docs/_build/html/_static/css/fonts/lato-normal-italic.woff2 +0 -0
  249. mindroot/docs/_build/html/_static/css/fonts/lato-normal.woff +0 -0
  250. mindroot/docs/_build/html/_static/css/fonts/lato-normal.woff2 +0 -0
  251. mindroot/docs/_build/html/_static/css/theme.css +4 -0
  252. mindroot/docs/_build/html/_static/custom.css +19 -0
  253. mindroot/docs/_build/html/_static/debug.css +69 -0
  254. mindroot/docs/_build/html/_static/doctools.js +149 -0
  255. mindroot/docs/_build/html/_static/documentation_options.js +13 -0
  256. mindroot/docs/_build/html/_static/file.png +0 -0
  257. mindroot/docs/_build/html/_static/fonts/Lato/lato-bold.eot +0 -0
  258. mindroot/docs/_build/html/_static/fonts/Lato/lato-bold.ttf +0 -0
  259. mindroot/docs/_build/html/_static/fonts/Lato/lato-bold.woff +0 -0
  260. mindroot/docs/_build/html/_static/fonts/Lato/lato-bold.woff2 +0 -0
  261. mindroot/docs/_build/html/_static/fonts/Lato/lato-bolditalic.eot +0 -0
  262. mindroot/docs/_build/html/_static/fonts/Lato/lato-bolditalic.ttf +0 -0
  263. mindroot/docs/_build/html/_static/fonts/Lato/lato-bolditalic.woff +0 -0
  264. mindroot/docs/_build/html/_static/fonts/Lato/lato-bolditalic.woff2 +0 -0
  265. mindroot/docs/_build/html/_static/fonts/Lato/lato-italic.eot +0 -0
  266. mindroot/docs/_build/html/_static/fonts/Lato/lato-italic.ttf +0 -0
  267. mindroot/docs/_build/html/_static/fonts/Lato/lato-italic.woff +0 -0
  268. mindroot/docs/_build/html/_static/fonts/Lato/lato-italic.woff2 +0 -0
  269. mindroot/docs/_build/html/_static/fonts/Lato/lato-regular.eot +0 -0
  270. mindroot/docs/_build/html/_static/fonts/Lato/lato-regular.ttf +0 -0
  271. mindroot/docs/_build/html/_static/fonts/Lato/lato-regular.woff +0 -0
  272. mindroot/docs/_build/html/_static/fonts/Lato/lato-regular.woff2 +0 -0
  273. mindroot/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.eot +0 -0
  274. mindroot/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.ttf +0 -0
  275. mindroot/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff +0 -0
  276. mindroot/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-bold.woff2 +0 -0
  277. mindroot/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.eot +0 -0
  278. mindroot/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.ttf +0 -0
  279. mindroot/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff +0 -0
  280. mindroot/docs/_build/html/_static/fonts/RobotoSlab/roboto-slab-v7-regular.woff2 +0 -0
  281. mindroot/docs/_build/html/_static/jquery.js +2 -0
  282. mindroot/docs/_build/html/_static/js/badge_only.js +1 -0
  283. mindroot/docs/_build/html/_static/js/theme.js +1 -0
  284. mindroot/docs/_build/html/_static/js/versions.js +228 -0
  285. mindroot/docs/_build/html/_static/language_data.js +192 -0
  286. mindroot/docs/_build/html/_static/minus.png +0 -0
  287. mindroot/docs/_build/html/_static/plus.png +0 -0
  288. mindroot/docs/_build/html/_static/pygments.css +232 -0
  289. mindroot/docs/_build/html/_static/scripts/furo-extensions.js +0 -0
  290. mindroot/docs/_build/html/_static/scripts/furo.js +3 -0
  291. mindroot/docs/_build/html/_static/scripts/furo.js.LICENSE.txt +7 -0
  292. mindroot/docs/_build/html/_static/scripts/furo.js.map +1 -0
  293. mindroot/docs/_build/html/_static/searchtools.js +635 -0
  294. mindroot/docs/_build/html/_static/skeleton.css +296 -0
  295. mindroot/docs/_build/html/_static/sphinx_highlight.js +154 -0
  296. mindroot/docs/_build/html/_static/styles/furo-extensions.css +2 -0
  297. mindroot/docs/_build/html/_static/styles/furo-extensions.css.map +1 -0
  298. mindroot/docs/_build/html/_static/styles/furo.css +2 -0
  299. mindroot/docs/_build/html/_static/styles/furo.css.map +1 -0
  300. mindroot/docs/_build/html/chat_with_assistant.html +329 -0
  301. mindroot/docs/_build/html/developer_documentation.html +338 -0
  302. mindroot/docs/_build/html/genindex.html +4690 -0
  303. mindroot/docs/_build/html/getting_started.html +423 -0
  304. mindroot/docs/_build/html/index.html +357 -0
  305. mindroot/docs/_build/html/install_plugins_with_tools.html +336 -0
  306. mindroot/docs/_build/html/installation.html +330 -0
  307. mindroot/docs/_build/html/llm_api_key.html +337 -0
  308. mindroot/docs/_build/html/llm_plugin_installation.html +338 -0
  309. mindroot/docs/_build/html/objects.inv +0 -0
  310. mindroot/docs/_build/html/programming_task.html +326 -0
  311. mindroot/docs/_build/html/py-modindex.html +1307 -0
  312. mindroot/docs/_build/html/search.html +307 -0
  313. mindroot/docs/_build/html/searchindex.js +1 -0
  314. mindroot/docs/_build/html/source/ahp.html +302 -0
  315. mindroot/docs/_build/html/source/mindroot.coreplugins.admin.html +2212 -0
  316. mindroot/docs/_build/html/source/mindroot.coreplugins.api_keys.html +532 -0
  317. mindroot/docs/_build/html/source/mindroot.coreplugins.chat.html +1185 -0
  318. mindroot/docs/_build/html/source/mindroot.coreplugins.chat_avatar.html +311 -0
  319. mindroot/docs/_build/html/source/mindroot.coreplugins.check_list.html +441 -0
  320. mindroot/docs/_build/html/source/mindroot.coreplugins.credits.html +879 -0
  321. mindroot/docs/_build/html/source/mindroot.coreplugins.email.html +554 -0
  322. mindroot/docs/_build/html/source/mindroot.coreplugins.env_manager.html +447 -0
  323. mindroot/docs/_build/html/source/mindroot.coreplugins.events.html +338 -0
  324. mindroot/docs/_build/html/source/mindroot.coreplugins.html +1785 -0
  325. mindroot/docs/_build/html/source/mindroot.coreplugins.index.handlers.html +481 -0
  326. mindroot/docs/_build/html/source/mindroot.coreplugins.index.html +696 -0
  327. mindroot/docs/_build/html/source/mindroot.coreplugins.jwt_auth.html +432 -0
  328. mindroot/docs/_build/html/source/mindroot.coreplugins.l8n.html +933 -0
  329. mindroot/docs/_build/html/source/mindroot.coreplugins.mcp_.html +1271 -0
  330. mindroot/docs/_build/html/source/mindroot.coreplugins.persona.html +386 -0
  331. mindroot/docs/_build/html/source/mindroot.coreplugins.startup.html +327 -0
  332. mindroot/docs/_build/html/source/mindroot.coreplugins.subscriptions.html +1631 -0
  333. mindroot/docs/_build/html/source/mindroot.coreplugins.usage.html +677 -0
  334. mindroot/docs/_build/html/source/mindroot.coreplugins.user_service.html +681 -0
  335. mindroot/docs/_build/html/source/mindroot.html +811 -0
  336. mindroot/docs/_build/html/source/mindroot.lib.auth.html +407 -0
  337. mindroot/docs/_build/html/source/mindroot.lib.html +2027 -0
  338. mindroot/docs/_build/html/source/mindroot.lib.json_str_block.html +344 -0
  339. mindroot/docs/_build/html/source/mindroot.lib.plugins.html +1050 -0
  340. mindroot/docs/_build/html/source/mindroot.lib.providers.backup.html +324 -0
  341. mindroot/docs/_build/html/source/mindroot.lib.providers.html +572 -0
  342. mindroot/docs/_build/html/source/mindroot.registry.html +501 -0
  343. mindroot/docs/_build/html/source/modules.html +377 -0
  344. mindroot/docs/_build/html/source/mr_agent_expert_instr.html +302 -0
  345. mindroot/docs/_build/html/starting_mindroot.html +325 -0
  346. mindroot/docs/_build/html/user_documentation.html +333 -0
  347. mindroot/docs/_static/custom.css +19 -0
  348. mindroot/docs/chat_with_assistant.rst +14 -0
  349. mindroot/docs/conf.py +54 -0
  350. mindroot/docs/data/agents/local/Assistant/agent.json +27 -0
  351. mindroot/docs/data/agents/local/SysAdmin/agent.json +33 -0
  352. mindroot/docs/data/equivalent_flags.json +1 -0
  353. mindroot/docs/data/mcp/servers.json +9 -0
  354. mindroot/docs/data/models.json +57 -0
  355. mindroot/docs/data/plugin_manifest.json +95 -0
  356. mindroot/docs/data/preferred_models.json +12 -0
  357. mindroot/docs/data/providers.json +62 -0
  358. mindroot/docs/developer_documentation.rst +26 -0
  359. mindroot/docs/envvar.png +0 -0
  360. mindroot/docs/files.png +0 -0
  361. mindroot/docs/getting_started.rst +139 -0
  362. mindroot/docs/index.rst +38 -0
  363. mindroot/docs/install_plugins_with_tools.rst +25 -0
  364. mindroot/docs/installation.rst +21 -0
  365. mindroot/docs/installopenrouter.png +0 -0
  366. mindroot/docs/llm_api_key.rst +22 -0
  367. mindroot/docs/llm_plugin_installation.rst +27 -0
  368. mindroot/docs/make.bat +35 -0
  369. mindroot/docs/mood.png +0 -0
  370. mindroot/docs/moon.png +0 -0
  371. mindroot/docs/openrouter.png +0 -0
  372. mindroot/docs/personas/local/Assistant/avatar.png +0 -0
  373. mindroot/docs/personas/local/Assistant/faceref.png +0 -0
  374. mindroot/docs/personas/local/Assistant/persona.json +7 -0
  375. mindroot/docs/programming_task.rst +10 -0
  376. mindroot/docs/restart.png +0 -0
  377. mindroot/docs/source/ahp.rst +7 -0
  378. mindroot/docs/source/mindroot.coreplugins.admin.rst +189 -0
  379. mindroot/docs/source/mindroot.coreplugins.api_keys.rst +45 -0
  380. mindroot/docs/source/mindroot.coreplugins.chat.rst +93 -0
  381. mindroot/docs/source/mindroot.coreplugins.chat_avatar.rst +10 -0
  382. mindroot/docs/source/mindroot.coreplugins.check_list.rst +21 -0
  383. mindroot/docs/source/mindroot.coreplugins.credits.rst +61 -0
  384. mindroot/docs/source/mindroot.coreplugins.email.rst +77 -0
  385. mindroot/docs/source/mindroot.coreplugins.env_manager.rst +29 -0
  386. mindroot/docs/source/mindroot.coreplugins.events.rst +29 -0
  387. mindroot/docs/source/mindroot.coreplugins.index.handlers.rst +45 -0
  388. mindroot/docs/source/mindroot.coreplugins.index.rst +53 -0
  389. mindroot/docs/source/mindroot.coreplugins.jwt_auth.rst +45 -0
  390. mindroot/docs/source/mindroot.coreplugins.l8n.rst +109 -0
  391. mindroot/docs/source/mindroot.coreplugins.mcp_.rst +93 -0
  392. mindroot/docs/source/mindroot.coreplugins.persona.rst +29 -0
  393. mindroot/docs/source/mindroot.coreplugins.rst +35 -0
  394. mindroot/docs/source/mindroot.coreplugins.startup.rst +21 -0
  395. mindroot/docs/source/mindroot.coreplugins.subscriptions.rst +85 -0
  396. mindroot/docs/source/mindroot.coreplugins.usage.rst +61 -0
  397. mindroot/docs/source/mindroot.coreplugins.user_service.rst +69 -0
  398. mindroot/docs/source/mindroot.lib.auth.rst +29 -0
  399. mindroot/docs/source/mindroot.lib.json_str_block.rst +21 -0
  400. mindroot/docs/source/mindroot.lib.plugins.rst +69 -0
  401. mindroot/docs/source/mindroot.lib.providers.backup.rst +10 -0
  402. mindroot/docs/source/mindroot.lib.providers.rst +61 -0
  403. mindroot/docs/source/mindroot.lib.rst +152 -0
  404. mindroot/docs/source/mindroot.registry.rst +29 -0
  405. mindroot/docs/source/mindroot.rst +54 -0
  406. mindroot/docs/source/modules.rst +7 -0
  407. mindroot/docs/source/mr_agent_expert_instr.rst +7 -0
  408. mindroot/docs/starting_mindroot.rst +12 -0
  409. mindroot/docs/user_documentation.rst +16 -0
  410. mindroot/lib/providers/model_preferences_v2.py +5 -3
  411. mindroot/server.py +10 -1
  412. {mindroot-9.11.0.dist-info → mindroot-9.13.0.dist-info}/METADATA +1 -1
  413. {mindroot-9.11.0.dist-info → mindroot-9.13.0.dist-info}/RECORD +417 -10
  414. {mindroot-9.11.0.dist-info → mindroot-9.13.0.dist-info}/WHEEL +0 -0
  415. {mindroot-9.11.0.dist-info → mindroot-9.13.0.dist-info}/entry_points.txt +0 -0
  416. {mindroot-9.11.0.dist-info → mindroot-9.13.0.dist-info}/licenses/LICENSE +0 -0
  417. {mindroot-9.11.0.dist-info → mindroot-9.13.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,1186 @@
1
+
2
+
3
+ <!DOCTYPE html>
4
+ <html class="writer-html5" lang="en" data-content_root="../../../../">
5
+ <head>
6
+ <meta charset="utf-8" />
7
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
8
+ <title>mindroot.coreplugins.mcp_.mcp_manager &mdash; MindRoot 9.10.0 documentation</title>
9
+ <link rel="stylesheet" type="text/css" href="../../../../_static/pygments.css?v=b86133f3" />
10
+ <link rel="stylesheet" type="text/css" href="../../../../_static/css/theme.css?v=e59714d7" />
11
+
12
+
13
+ <script src="../../../../_static/jquery.js?v=5d32c60e"></script>
14
+ <script src="../../../../_static/_sphinx_javascript_frameworks_compat.js?v=2cd50e6c"></script>
15
+ <script src="../../../../_static/documentation_options.js?v=3c16008f"></script>
16
+ <script src="../../../../_static/doctools.js?v=9bcbadda"></script>
17
+ <script src="../../../../_static/sphinx_highlight.js?v=dc90522c"></script>
18
+ <script src="../../../../_static/js/theme.js"></script>
19
+ <link rel="index" title="Index" href="../../../../genindex.html" />
20
+ <link rel="search" title="Search" href="../../../../search.html" />
21
+ </head>
22
+
23
+ <body class="wy-body-for-nav">
24
+ <div class="wy-grid-for-nav">
25
+ <nav data-toggle="wy-nav-shift" class="wy-nav-side">
26
+ <div class="wy-side-scroll">
27
+ <div class="wy-side-nav-search" style="background: #343131" >
28
+
29
+
30
+
31
+ <a href="../../../../index.html" class="icon icon-home">
32
+ MindRoot
33
+ </a>
34
+ <div role="search">
35
+ <form id="rtd-search-form" class="wy-form" action="../../../../search.html" method="get">
36
+ <input type="text" name="q" placeholder="Search docs" aria-label="Search docs" />
37
+ <input type="hidden" name="check_keywords" value="yes" />
38
+ <input type="hidden" name="area" value="default" />
39
+ </form>
40
+ </div>
41
+ </div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
42
+ <!-- Local TOC -->
43
+ <div class="local-toc"></div>
44
+ </div>
45
+ </div>
46
+ </nav>
47
+
48
+ <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" style="background: #343131" >
49
+ <i data-toggle="wy-nav-top" class="fa fa-bars"></i>
50
+ <a href="../../../../index.html">MindRoot</a>
51
+ </nav>
52
+
53
+ <div class="wy-nav-content">
54
+ <div class="rst-content">
55
+ <div role="navigation" aria-label="Page navigation">
56
+ <ul class="wy-breadcrumbs">
57
+ <li><a href="../../../../index.html" class="icon icon-home" aria-label="Home"></a></li>
58
+ <li class="breadcrumb-item"><a href="../../../index.html">Module code</a></li>
59
+ <li class="breadcrumb-item active">mindroot.coreplugins.mcp_.mcp_manager</li>
60
+ <li class="wy-breadcrumbs-aside">
61
+ </li>
62
+ </ul>
63
+ <hr/>
64
+ </div>
65
+ <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
66
+ <div itemprop="articleBody">
67
+
68
+ <h1>Source code for mindroot.coreplugins.mcp_.mcp_manager</h1><div class="highlight"><pre>
69
+ <span></span><span class="kn">import</span><span class="w"> </span><span class="nn">asyncio</span>
70
+ <span class="kn">import</span><span class="w"> </span><span class="nn">os</span>
71
+ <span class="kn">import</span><span class="w"> </span><span class="nn">json</span>
72
+ <span class="kn">import</span><span class="w"> </span><span class="nn">uuid</span>
73
+ <span class="kn">from</span><span class="w"> </span><span class="nn">datetime</span><span class="w"> </span><span class="kn">import</span> <span class="n">datetime</span>
74
+ <span class="kn">from</span><span class="w"> </span><span class="nn">pathlib</span><span class="w"> </span><span class="kn">import</span> <span class="n">Path</span>
75
+ <span class="kn">from</span><span class="w"> </span><span class="nn">typing</span><span class="w"> </span><span class="kn">import</span> <span class="n">Dict</span><span class="p">,</span> <span class="n">List</span><span class="p">,</span> <span class="n">Optional</span><span class="p">,</span> <span class="n">Any</span>
76
+ <span class="kn">from</span><span class="w"> </span><span class="nn">contextlib</span><span class="w"> </span><span class="kn">import</span> <span class="n">AsyncExitStack</span>
77
+ <span class="kn">import</span><span class="w"> </span><span class="nn">re</span>
78
+ <span class="kn">from</span><span class="w"> </span><span class="nn">urllib.parse</span><span class="w"> </span><span class="kn">import</span> <span class="n">parse_qs</span><span class="p">,</span> <span class="n">urlparse</span>
79
+ <span class="kn">import</span><span class="w"> </span><span class="nn">traceback</span>
80
+
81
+ <span class="kn">import</span><span class="w"> </span><span class="nn">httpx</span>
82
+ <span class="kn">from</span><span class="w"> </span><span class="nn">pydantic</span><span class="w"> </span><span class="kn">import</span> <span class="n">BaseModel</span>
83
+
84
+ <span class="kn">from</span><span class="w"> </span><span class="nn">.server_installer</span><span class="w"> </span><span class="kn">import</span> <span class="n">MCPServerInstaller</span>
85
+ <span class="kn">from</span><span class="w"> </span><span class="nn">.dynamic_commands</span><span class="w"> </span><span class="kn">import</span> <span class="n">MCPDynamicCommands</span>
86
+ <span class="kn">from</span><span class="w"> </span><span class="nn">.oauth_storage</span><span class="w"> </span><span class="kn">import</span> <span class="n">MCPTokenStorage</span>
87
+
88
+ <span class="k">try</span><span class="p">:</span>
89
+ <span class="kn">from</span><span class="w"> </span><span class="nn">mcp</span><span class="w"> </span><span class="kn">import</span> <span class="n">ClientSession</span><span class="p">,</span> <span class="n">StdioServerParameters</span>
90
+ <span class="kn">from</span><span class="w"> </span><span class="nn">mcp.client.stdio</span><span class="w"> </span><span class="kn">import</span> <span class="n">stdio_client</span>
91
+ <span class="kn">from</span><span class="w"> </span><span class="nn">mcp.client.streamable_http</span><span class="w"> </span><span class="kn">import</span> <span class="n">streamablehttp_client</span>
92
+ <span class="kn">from</span><span class="w"> </span><span class="nn">mcp.client.sse</span><span class="w"> </span><span class="kn">import</span> <span class="n">sse_client</span>
93
+ <span class="kn">from</span><span class="w"> </span><span class="nn">mcp.client.auth</span><span class="w"> </span><span class="kn">import</span> <span class="n">OAuthClientProvider</span>
94
+ <span class="kn">from</span><span class="w"> </span><span class="nn">mcp.shared.auth</span><span class="w"> </span><span class="kn">import</span> <span class="n">OAuthClientMetadata</span>
95
+ <span class="kn">from</span><span class="w"> </span><span class="nn">pydantic</span><span class="w"> </span><span class="kn">import</span> <span class="n">AnyUrl</span>
96
+ <span class="n">MCP_AVAILABLE</span> <span class="o">=</span> <span class="kc">True</span>
97
+ <span class="k">except</span> <span class="ne">ImportError</span><span class="p">:</span>
98
+ <span class="c1"># MCP not installed yet</span>
99
+ <span class="n">ClientSession</span> <span class="o">=</span> <span class="kc">None</span>
100
+ <span class="n">StdioServerParameters</span> <span class="o">=</span> <span class="kc">None</span>
101
+ <span class="n">stdio_client</span> <span class="o">=</span> <span class="kc">None</span>
102
+ <span class="n">streamablehttp_client</span> <span class="o">=</span> <span class="kc">None</span>
103
+ <span class="n">sse_client</span> <span class="o">=</span> <span class="kc">None</span>
104
+ <span class="n">OAuthClientProvider</span> <span class="o">=</span> <span class="kc">None</span>
105
+ <span class="n">OAuthClientMetadata</span> <span class="o">=</span> <span class="kc">None</span>
106
+ <span class="n">OAuthToken</span> <span class="o">=</span> <span class="kc">None</span>
107
+ <span class="n">OAuthClientInformationFull</span> <span class="o">=</span> <span class="kc">None</span>
108
+ <span class="n">AnyUrl</span> <span class="o">=</span> <span class="kc">None</span>
109
+ <span class="n">MCP_AVAILABLE</span> <span class="o">=</span> <span class="kc">False</span>
110
+
111
+ <span class="k">def</span><span class="w"> </span><span class="nf">_substitute_secrets</span><span class="p">(</span><span class="n">config_item</span><span class="p">:</span> <span class="n">Any</span><span class="p">,</span> <span class="n">secrets</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">str</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="n">Any</span><span class="p">:</span>
112
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">secrets</span> <span class="ow">or</span> <span class="n">config_item</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
113
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;DEBUG: No secrets to substitute or config_item is None, not substituting&quot;</span><span class="p">,</span> <span class="n">config_item</span><span class="p">)</span>
114
+ <span class="k">return</span> <span class="n">config_item</span>
115
+
116
+ <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">config_item</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span>
117
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;String&quot;</span><span class="p">)</span>
118
+ <span class="c1"># Find all placeholders like &lt;SECRET_NAME&gt; or ${SECRET_NAME}</span>
119
+ <span class="c1"># This regex captures the name inside the brackets/braces</span>
120
+ <span class="n">placeholder_keys</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">findall</span><span class="p">(</span><span class="sa">r</span><span class="s1">&#39;&lt;([A-Z0-9_]+)&gt;|\${([A-Z0-9_]+)}&#39;</span><span class="p">,</span> <span class="n">config_item</span><span class="p">)</span>
121
+ <span class="c1"># Flatten list of tuples and remove empty matches</span>
122
+ <span class="n">keys_to_replace</span> <span class="o">=</span> <span class="p">[</span><span class="n">key</span> <span class="k">for</span> <span class="n">tpl</span> <span class="ow">in</span> <span class="n">placeholder_keys</span> <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">tpl</span> <span class="k">if</span> <span class="n">key</span><span class="p">]</span>
123
+
124
+ <span class="n">temp_item</span> <span class="o">=</span> <span class="n">config_item</span>
125
+ <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">keys_to_replace</span><span class="p">:</span>
126
+ <span class="k">if</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">secrets</span><span class="p">:</span>
127
+ <span class="c1"># Replace both placeholder formats</span>
128
+ <span class="n">temp_item</span> <span class="o">=</span> <span class="n">temp_item</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="sa">f</span><span class="s1">&#39;&lt;</span><span class="si">{</span><span class="n">key</span><span class="si">}</span><span class="s1">&gt;&#39;</span><span class="p">,</span> <span class="n">secrets</span><span class="p">[</span><span class="n">key</span><span class="p">])</span>
129
+ <span class="n">temp_item</span> <span class="o">=</span> <span class="n">temp_item</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="sa">f</span><span class="s1">&#39;$</span><span class="se">{{</span><span class="si">{</span><span class="n">key</span><span class="si">}</span><span class="se">}}</span><span class="s1">&#39;</span><span class="p">,</span> <span class="n">secrets</span><span class="p">[</span><span class="n">key</span><span class="p">])</span>
130
+ <span class="k">return</span> <span class="n">temp_item</span>
131
+
132
+ <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">config_item</span><span class="p">,</span> <span class="nb">list</span><span class="p">):</span>
133
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;List&quot;</span><span class="p">)</span>
134
+ <span class="k">return</span> <span class="p">[</span><span class="n">_substitute_secrets</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="n">secrets</span><span class="p">)</span> <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">config_item</span><span class="p">]</span>
135
+
136
+ <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">config_item</span><span class="p">,</span> <span class="nb">dict</span><span class="p">):</span>
137
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;DEBUG: Substituting secrets in config_item (dict)&quot;</span><span class="p">)</span>
138
+ <span class="k">return</span> <span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="n">_substitute_secrets</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="n">secrets</span><span class="p">)</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">config_item</span><span class="o">.</span><span class="n">items</span><span class="p">()}</span>
139
+
140
+ <span class="k">return</span> <span class="n">config_item</span>
141
+
142
+
143
+
144
+ <div class="viewcode-block" id="MCPServer">
145
+ <a class="viewcode-back" href="../../../../source/mindroot.coreplugins.mcp_.html#mindroot.coreplugins.mcp_.mcp_manager.MCPServer">[docs]</a>
146
+ <span class="k">class</span><span class="w"> </span><span class="nc">MCPServer</span><span class="p">(</span><span class="n">BaseModel</span><span class="p">):</span>
147
+ <span class="w"> </span><span class="sd">&quot;&quot;&quot;Model for MCP server configuration&quot;&quot;&quot;</span>
148
+ <span class="n">name</span><span class="p">:</span> <span class="nb">str</span>
149
+ <span class="n">description</span><span class="p">:</span> <span class="nb">str</span>
150
+ <span class="n">command</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
151
+ <span class="n">args</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
152
+ <span class="n">env</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
153
+ <span class="n">transport</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">&quot;stdio&quot;</span> <span class="c1"># stdio, sse, websocket, http</span>
154
+ <span class="n">url</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span> <span class="c1"># for remote servers (legacy single URL)</span>
155
+ <span class="c1"># New: explicit provider vs transport URLs</span>
156
+ <span class="n">provider_url</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span> <span class="c1"># e.g., https://mcp.notion.com</span>
157
+ <span class="n">transport_url</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span> <span class="c1"># e.g., https://mcp.notion.com/sse or /mcp</span>
158
+ <span class="n">transport_type</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span> <span class="c1"># &quot;sse&quot; | &quot;streamable_http&quot;</span>
159
+
160
+ <span class="c1"># OAuth 2.0 Configuration</span>
161
+ <span class="n">auth_type</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">&quot;none&quot;</span> <span class="c1"># none, basic, oauth2</span>
162
+ <span class="n">auth_headers</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span> <span class="c1"># for basic auth or custom headers</span>
163
+
164
+ <span class="c1"># OAuth 2.0 specific fields</span>
165
+ <span class="n">authorization_server_url</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
166
+ <span class="n">client_id</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
167
+ <span class="n">client_secret</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span> <span class="c1"># For confidential clients</span>
168
+ <span class="n">scopes</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
169
+ <span class="n">redirect_uri</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
170
+
171
+ <span class="c1"># Token storage</span>
172
+ <span class="n">access_token</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
173
+ <span class="n">refresh_token</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
174
+ <span class="n">token_expires_at</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span> <span class="c1"># ISO format datetime string</span>
175
+
176
+ <span class="n">status</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">&quot;disconnected&quot;</span> <span class="c1"># connected, disconnected, error</span>
177
+ <span class="n">secrets</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">str</span><span class="p">]]</span> <span class="o">=</span> <span class="kc">None</span>
178
+ <span class="n">capabilities</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
179
+
180
+ <span class="c1"># Installation config (Enhanced features)</span>
181
+ <span class="n">install_method</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="s2">&quot;manual&quot;</span> <span class="c1"># uvx, pip, npm, manual</span>
182
+ <span class="n">install_package</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span>
183
+ <span class="n">auto_install</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span>
184
+ <span class="n">installed</span><span class="p">:</span> <span class="nb">bool</span> <span class="o">=</span> <span class="kc">False</span></div>
185
+
186
+
187
+
188
+ <div class="viewcode-block" id="MCPManager">
189
+ <a class="viewcode-back" href="../../../../source/mindroot.coreplugins.mcp_.html#mindroot.coreplugins.mcp_.mcp_manager.MCPManager">[docs]</a>
190
+ <span class="k">class</span><span class="w"> </span><span class="nc">MCPManager</span><span class="p">:</span>
191
+ <span class="w"> </span><span class="sd">&quot;&quot;&quot;Manages MCP server connections and operations&quot;&quot;&quot;</span>
192
+
193
+ <span class="k">def</span><span class="w"> </span><span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
194
+ <span class="bp">self</span><span class="o">.</span><span class="n">servers</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">MCPServer</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
195
+ <span class="bp">self</span><span class="o">.</span><span class="n">sessions</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">ClientSession</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
196
+ <span class="bp">self</span><span class="o">.</span><span class="n">exit_stacks</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">AsyncExitStack</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
197
+ <span class="bp">self</span><span class="o">.</span><span class="n">background_tasks</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">Task</span><span class="p">]</span> <span class="o">=</span> <span class="p">{}</span>
198
+ <span class="bp">self</span><span class="o">.</span><span class="n">pending_oauth_flows</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]]</span> <span class="o">=</span> <span class="p">{}</span>
199
+ <span class="c1"># Debug/diagnostics: short-lived cache of last discovered capabilities per server</span>
200
+ <span class="bp">self</span><span class="o">.</span><span class="n">last_capabilities</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]]</span> <span class="o">=</span> <span class="p">{}</span>
201
+ <span class="bp">self</span><span class="o">.</span><span class="n">installer</span> <span class="o">=</span> <span class="n">MCPServerInstaller</span><span class="p">()</span>
202
+ <span class="bp">self</span><span class="o">.</span><span class="n">dynamic_commands</span> <span class="o">=</span> <span class="n">MCPDynamicCommands</span><span class="p">()</span>
203
+ <span class="bp">self</span><span class="o">.</span><span class="n">config_file</span> <span class="o">=</span> <span class="n">Path</span><span class="p">(</span><span class="s2">&quot;/tmp/mcp_servers.json&quot;</span><span class="p">)</span>
204
+
205
+ <span class="c1"># Set sessions reference for dynamic commands</span>
206
+ <span class="bp">self</span><span class="o">.</span><span class="n">dynamic_commands</span><span class="o">.</span><span class="n">set_sessions</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">sessions</span><span class="p">)</span>
207
+
208
+ <span class="bp">self</span><span class="o">.</span><span class="n">load_config</span><span class="p">()</span>
209
+
210
+ <span class="c1"># ---- Serialization helpers ----</span>
211
+ <span class="k">def</span><span class="w"> </span><span class="nf">_server_to_jsonable</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">server</span><span class="p">:</span> <span class="n">MCPServer</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]:</span>
212
+ <span class="w"> </span><span class="sd">&quot;&quot;&quot;Convert server model to plain JSON-serializable dict.</span>
213
+ <span class="sd"> Ensures AnyUrl or other exotic types are stringified.</span>
214
+ <span class="sd"> &quot;&quot;&quot;</span>
215
+ <span class="c1"># Start with pydantic dict (already basic types), but normalize URLs just in case</span>
216
+ <span class="n">data</span> <span class="o">=</span> <span class="n">server</span><span class="o">.</span><span class="n">dict</span><span class="p">()</span>
217
+ <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="p">(</span><span class="s2">&quot;url&quot;</span><span class="p">,</span> <span class="s2">&quot;provider_url&quot;</span><span class="p">,</span> <span class="s2">&quot;transport_url&quot;</span><span class="p">,</span> <span class="s2">&quot;authorization_server_url&quot;</span><span class="p">,</span> <span class="s2">&quot;redirect_uri&quot;</span><span class="p">):</span>
218
+ <span class="n">val</span> <span class="o">=</span> <span class="n">data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">key</span><span class="p">)</span>
219
+ <span class="k">if</span> <span class="n">val</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="ow">and</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">val</span><span class="p">,</span> <span class="p">(</span><span class="nb">str</span><span class="p">,</span> <span class="nb">int</span><span class="p">,</span> <span class="nb">float</span><span class="p">,</span> <span class="nb">bool</span><span class="p">)):</span> <span class="c1"># e.g., AnyUrl</span>
220
+ <span class="k">try</span><span class="p">:</span>
221
+ <span class="n">data</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">val</span><span class="p">)</span>
222
+ <span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span>
223
+ <span class="n">data</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">val</span><span class="si">}</span><span class="s2">&quot;</span>
224
+ <span class="k">return</span> <span class="n">data</span>
225
+
226
+ <span class="c1"># ---- URL/Transport helpers ----</span>
227
+ <span class="k">def</span><span class="w"> </span><span class="nf">_infer_urls</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">server</span><span class="p">:</span> <span class="n">MCPServer</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">tuple</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">str</span><span class="p">,</span> <span class="nb">str</span><span class="p">]:</span>
228
+ <span class="w"> </span><span class="sd">&quot;&quot;&quot;Infer provider_url, transport_url, and transport_type from server fields.</span>
229
+
230
+ <span class="sd"> transport_type returns one of: &#39;sse&#39;, &#39;streamable_http&#39;.</span>
231
+ <span class="sd"> &quot;&quot;&quot;</span>
232
+ <span class="c1"># Prefer explicit transport_url, otherwise fallback to legacy url</span>
233
+ <span class="n">turl</span> <span class="o">=</span> <span class="p">(</span><span class="n">server</span><span class="o">.</span><span class="n">transport_url</span> <span class="ow">or</span> <span class="n">server</span><span class="o">.</span><span class="n">url</span> <span class="ow">or</span> <span class="s2">&quot;&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
234
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">turl</span><span class="p">:</span>
235
+ <span class="c1"># As last resort, try to build from provider_url + transport</span>
236
+ <span class="k">if</span> <span class="n">server</span><span class="o">.</span><span class="n">provider_url</span> <span class="ow">and</span> <span class="n">server</span><span class="o">.</span><span class="n">transport</span><span class="p">:</span>
237
+ <span class="n">base</span> <span class="o">=</span> <span class="n">server</span><span class="o">.</span><span class="n">provider_url</span><span class="o">.</span><span class="n">rstrip</span><span class="p">(</span><span class="s1">&#39;/&#39;</span><span class="p">)</span>
238
+ <span class="k">if</span> <span class="n">server</span><span class="o">.</span><span class="n">transport</span> <span class="o">==</span> <span class="s1">&#39;sse&#39;</span><span class="p">:</span>
239
+ <span class="n">turl</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">base</span><span class="si">}</span><span class="s2">/sse&quot;</span>
240
+ <span class="k">elif</span> <span class="n">server</span><span class="o">.</span><span class="n">transport</span> <span class="ow">in</span> <span class="p">(</span><span class="s1">&#39;http&#39;</span><span class="p">,</span> <span class="s1">&#39;streamable_http&#39;</span><span class="p">):</span>
241
+ <span class="n">turl</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">base</span><span class="si">}</span><span class="s2">/mcp&quot;</span>
242
+ <span class="c1"># Determine type from suffix if not set</span>
243
+ <span class="n">ttype</span> <span class="o">=</span> <span class="n">server</span><span class="o">.</span><span class="n">transport_type</span>
244
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">ttype</span><span class="p">:</span>
245
+ <span class="k">if</span> <span class="n">turl</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="s1">&#39;/sse&#39;</span><span class="p">):</span>
246
+ <span class="n">ttype</span> <span class="o">=</span> <span class="s1">&#39;sse&#39;</span>
247
+ <span class="k">elif</span> <span class="n">turl</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="s1">&#39;/mcp&#39;</span><span class="p">):</span>
248
+ <span class="n">ttype</span> <span class="o">=</span> <span class="s1">&#39;streamable_http&#39;</span>
249
+ <span class="k">else</span><span class="p">:</span>
250
+ <span class="c1"># fallback based on declared transport</span>
251
+ <span class="k">if</span> <span class="n">server</span><span class="o">.</span><span class="n">transport</span> <span class="o">==</span> <span class="s1">&#39;sse&#39;</span><span class="p">:</span>
252
+ <span class="n">ttype</span> <span class="o">=</span> <span class="s1">&#39;sse&#39;</span>
253
+ <span class="k">else</span><span class="p">:</span>
254
+ <span class="n">ttype</span> <span class="o">=</span> <span class="s1">&#39;streamable_http&#39;</span>
255
+ <span class="c1"># Determine provider_url</span>
256
+ <span class="n">provider</span> <span class="o">=</span> <span class="n">server</span><span class="o">.</span><span class="n">provider_url</span>
257
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">provider</span><span class="p">:</span>
258
+ <span class="c1"># Strip known suffixes</span>
259
+ <span class="k">if</span> <span class="n">turl</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="s1">&#39;/sse&#39;</span><span class="p">):</span>
260
+ <span class="n">provider</span> <span class="o">=</span> <span class="n">turl</span><span class="p">[:</span> <span class="o">-</span><span class="nb">len</span><span class="p">(</span><span class="s1">&#39;/sse&#39;</span><span class="p">)]</span>
261
+ <span class="k">elif</span> <span class="n">turl</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="s1">&#39;/mcp&#39;</span><span class="p">):</span>
262
+ <span class="n">provider</span> <span class="o">=</span> <span class="n">turl</span><span class="p">[:</span> <span class="o">-</span><span class="nb">len</span><span class="p">(</span><span class="s1">&#39;/mcp&#39;</span><span class="p">)]</span>
263
+ <span class="k">else</span><span class="p">:</span>
264
+ <span class="c1"># Use scheme://host[:port]</span>
265
+ <span class="k">try</span><span class="p">:</span>
266
+ <span class="kn">from</span><span class="w"> </span><span class="nn">urllib.parse</span><span class="w"> </span><span class="kn">import</span> <span class="n">urlsplit</span>
267
+ <span class="n">parts</span> <span class="o">=</span> <span class="n">urlsplit</span><span class="p">(</span><span class="n">turl</span><span class="p">)</span>
268
+ <span class="k">if</span> <span class="n">parts</span><span class="o">.</span><span class="n">scheme</span> <span class="ow">and</span> <span class="n">parts</span><span class="o">.</span><span class="n">netloc</span><span class="p">:</span>
269
+ <span class="n">provider</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">parts</span><span class="o">.</span><span class="n">scheme</span><span class="si">}</span><span class="s2">://</span><span class="si">{</span><span class="n">parts</span><span class="o">.</span><span class="n">netloc</span><span class="si">}</span><span class="s2">&quot;</span>
270
+ <span class="k">else</span><span class="p">:</span>
271
+ <span class="n">provider</span> <span class="o">=</span> <span class="n">turl</span><span class="o">.</span><span class="n">rstrip</span><span class="p">(</span><span class="s1">&#39;/&#39;</span><span class="p">)</span>
272
+ <span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span>
273
+ <span class="n">provider</span> <span class="o">=</span> <span class="n">turl</span><span class="o">.</span><span class="n">rstrip</span><span class="p">(</span><span class="s1">&#39;/&#39;</span><span class="p">)</span>
274
+ <span class="k">return</span> <span class="n">provider</span><span class="o">.</span><span class="n">rstrip</span><span class="p">(</span><span class="s1">&#39;/&#39;</span><span class="p">),</span> <span class="n">turl</span><span class="o">.</span><span class="n">rstrip</span><span class="p">(</span><span class="s1">&#39;/&#39;</span><span class="p">),</span> <span class="n">ttype</span>
275
+
276
+ <span class="k">def</span><span class="w"> </span><span class="nf">_update_server_urls</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">provider_url</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">transport_url</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">transport_type</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
277
+ <span class="w"> </span><span class="sd">&quot;&quot;&quot;Persist inferred URL fields back to the server config if missing/outdated.&quot;&quot;&quot;</span>
278
+ <span class="n">srv</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">servers</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">name</span><span class="p">)</span>
279
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">srv</span><span class="p">:</span>
280
+ <span class="k">return</span>
281
+ <span class="n">changed</span> <span class="o">=</span> <span class="kc">False</span>
282
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">srv</span><span class="o">.</span><span class="n">provider_url</span><span class="p">:</span>
283
+ <span class="n">srv</span><span class="o">.</span><span class="n">provider_url</span> <span class="o">=</span> <span class="n">provider_url</span>
284
+ <span class="n">changed</span> <span class="o">=</span> <span class="kc">True</span>
285
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">srv</span><span class="o">.</span><span class="n">transport_url</span><span class="p">:</span>
286
+ <span class="n">srv</span><span class="o">.</span><span class="n">transport_url</span> <span class="o">=</span> <span class="n">transport_url</span>
287
+ <span class="n">changed</span> <span class="o">=</span> <span class="kc">True</span>
288
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">srv</span><span class="o">.</span><span class="n">transport_type</span><span class="p">:</span>
289
+ <span class="n">srv</span><span class="o">.</span><span class="n">transport_type</span> <span class="o">=</span> <span class="n">transport_type</span>
290
+ <span class="n">changed</span> <span class="o">=</span> <span class="kc">True</span>
291
+ <span class="c1">#if changed:</span>
292
+ <span class="c1">#self.save_config()</span>
293
+ <span class="c1"># Debug log</span>
294
+ <span class="k">try</span><span class="p">:</span>
295
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: _update_server_urls: name=</span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2"> provider=</span><span class="si">{</span><span class="n">provider_url</span><span class="si">}</span><span class="s2"> transport=</span><span class="si">{</span><span class="n">transport_url</span><span class="si">}</span><span class="s2"> type=</span><span class="si">{</span><span class="n">transport_type</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
296
+ <span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span>
297
+ <span class="k">pass</span>
298
+
299
+ <span class="k">def</span><span class="w"> </span><span class="nf">_build_oauth_provider</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">server</span><span class="p">:</span> <span class="n">MCPServer</span><span class="p">,</span> <span class="n">provider_url</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span>
300
+ <span class="w"> </span><span class="sd">&quot;&quot;&quot;Create an OAuthClientProvider bound to this server using persistent storage.&quot;&quot;&quot;</span>
301
+ <span class="n">base_url</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">getenv</span><span class="p">(</span><span class="s1">&#39;BASE_URL&#39;</span><span class="p">,</span> <span class="s1">&#39;http://localhost:3000&#39;</span><span class="p">)</span>
302
+ <span class="n">callback_url</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">base_url</span><span class="o">.</span><span class="n">rstrip</span><span class="p">(</span><span class="s1">&#39;/&#39;</span><span class="p">)</span><span class="si">}</span><span class="s2">/mcp_oauth_cb&quot;</span>
303
+ <span class="c1"># Storage persists tokens into the server record</span>
304
+ <span class="n">storage</span> <span class="o">=</span> <span class="n">MCPTokenStorage</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span>
305
+ <span class="n">metadata</span> <span class="o">=</span> <span class="n">OAuthClientMetadata</span><span class="p">(</span>
306
+ <span class="n">client_name</span><span class="o">=</span><span class="sa">f</span><span class="s2">&quot;MindRoot - </span><span class="si">{</span><span class="n">server</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">,</span>
307
+ <span class="c1"># Use plain string to avoid pydantic AnyUrl leaking into persisted state</span>
308
+ <span class="n">redirect_uris</span><span class="o">=</span><span class="p">[</span><span class="nb">str</span><span class="p">(</span><span class="n">callback_url</span><span class="p">)],</span>
309
+ <span class="n">grant_types</span><span class="o">=</span><span class="p">[</span><span class="s2">&quot;authorization_code&quot;</span><span class="p">,</span> <span class="s2">&quot;refresh_token&quot;</span><span class="p">],</span>
310
+ <span class="n">response_types</span><span class="o">=</span><span class="p">[</span><span class="s2">&quot;code&quot;</span><span class="p">],</span>
311
+ <span class="n">scope</span><span class="o">=</span><span class="s2">&quot; &quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">server</span><span class="o">.</span><span class="n">scopes</span><span class="p">)</span> <span class="k">if</span> <span class="n">server</span><span class="o">.</span><span class="n">scopes</span> <span class="k">else</span> <span class="s2">&quot;user&quot;</span><span class="p">,</span>
312
+ <span class="p">)</span>
313
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;DEBUG: -------------------------------------------------------&quot;</span><span class="p">)</span>
314
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;DEBUG: OAuth provider server_url:&quot;</span><span class="p">,</span> <span class="n">provider_url</span><span class="p">)</span>
315
+
316
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;DEBUG: OAuth provider metadata:&quot;</span><span class="p">,</span> <span class="n">metadata</span><span class="o">.</span><span class="n">dict</span><span class="p">())</span>
317
+ <span class="n">oauth_provider</span> <span class="o">=</span> <span class="n">OAuthClientProvider</span><span class="p">(</span>
318
+ <span class="n">server_url</span><span class="o">=</span><span class="n">provider_url</span><span class="p">,</span>
319
+ <span class="n">client_metadata</span><span class="o">=</span><span class="n">metadata</span><span class="p">,</span>
320
+ <span class="n">storage</span><span class="o">=</span><span class="n">storage</span><span class="p">,</span>
321
+ <span class="n">redirect_handler</span><span class="o">=</span><span class="k">lambda</span> <span class="n">auth_url</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">_handle_oauth_redirect</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">auth_url</span><span class="p">),</span>
322
+ <span class="n">callback_handler</span><span class="o">=</span><span class="k">lambda</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">_handle_oauth_callback</span><span class="p">(</span><span class="n">name</span><span class="p">),</span>
323
+ <span class="p">)</span>
324
+
325
+ <span class="k">return</span> <span class="n">oauth_provider</span>
326
+
327
+ <div class="viewcode-block" id="MCPManager.load_config">
328
+ <a class="viewcode-back" href="../../../../source/mindroot.coreplugins.mcp_.html#mindroot.coreplugins.mcp_.mcp_manager.MCPManager.load_config">[docs]</a>
329
+ <span class="k">def</span><span class="w"> </span><span class="nf">load_config</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
330
+ <span class="w"> </span><span class="sd">&quot;&quot;&quot;Load server configurations from file&quot;&quot;&quot;</span>
331
+ <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">config_file</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span>
332
+ <span class="k">try</span><span class="p">:</span>
333
+ <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">config_file</span><span class="p">,</span> <span class="s1">&#39;r&#39;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
334
+ <span class="n">data</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">load</span><span class="p">(</span><span class="n">f</span><span class="p">)</span>
335
+ <span class="k">for</span> <span class="n">name</span><span class="p">,</span> <span class="n">config</span> <span class="ow">in</span> <span class="n">data</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
336
+ <span class="bp">self</span><span class="o">.</span><span class="n">servers</span><span class="p">[</span><span class="n">name</span><span class="p">]</span> <span class="o">=</span> <span class="n">MCPServer</span><span class="p">(</span><span class="o">**</span><span class="n">config</span><span class="p">)</span>
337
+ <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
338
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Error loading MCP config: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span></div>
339
+
340
+
341
+ <div class="viewcode-block" id="MCPManager.save_config">
342
+ <a class="viewcode-back" href="../../../../source/mindroot.coreplugins.mcp_.html#mindroot.coreplugins.mcp_.mcp_manager.MCPManager.save_config">[docs]</a>
343
+ <span class="k">def</span><span class="w"> </span><span class="nf">save_config</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
344
+ <span class="w"> </span><span class="sd">&quot;&quot;&quot;Save server configurations to file - LOCAL SERVERS ONLY&quot;&quot;&quot;</span>
345
+ <span class="k">try</span><span class="p">:</span>
346
+ <span class="n">data</span> <span class="o">=</span> <span class="p">{}</span>
347
+ <span class="k">for</span> <span class="n">name</span><span class="p">,</span> <span class="n">server</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">servers</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
348
+ <span class="c1"># Only save local servers (stdio transport with no URL)</span>
349
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Determining if server is local:&quot;</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">server</span><span class="o">.</span><span class="n">transport</span><span class="p">,</span> <span class="n">server</span><span class="o">.</span><span class="n">url</span><span class="p">,</span> <span class="n">server</span><span class="o">.</span><span class="n">provider_url</span><span class="p">,</span> <span class="n">server</span><span class="o">.</span><span class="n">transport_url</span><span class="p">,</span> <span class="n">server</span><span class="o">.</span><span class="n">command</span><span class="p">)</span>
350
+ <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_local_server</span><span class="p">(</span><span class="n">server</span><span class="p">):</span>
351
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: Saving local server </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2"> to config&quot;</span><span class="p">)</span>
352
+ <span class="n">data</span><span class="p">[</span><span class="n">name</span><span class="p">]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_server_to_jsonable</span><span class="p">(</span><span class="n">server</span><span class="p">)</span>
353
+ <span class="k">else</span><span class="p">:</span>
354
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: Skipping remote server </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2"> from config&quot;</span><span class="p">)</span>
355
+
356
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: Saving </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">data</span><span class="p">)</span><span class="si">}</span><span class="s2"> local servers to config (filtered out </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">servers</span><span class="p">)</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="nb">len</span><span class="p">(</span><span class="n">data</span><span class="p">)</span><span class="si">}</span><span class="s2"> remote servers)&quot;</span><span class="p">)</span>
357
+ <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">config_file</span><span class="p">,</span> <span class="s1">&#39;w&#39;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
358
+ <span class="n">json</span><span class="o">.</span><span class="n">dump</span><span class="p">(</span><span class="n">data</span><span class="p">,</span> <span class="n">f</span><span class="p">,</span> <span class="n">indent</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>
359
+ <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
360
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Error saving MCP config: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
361
+ <span class="k">raise</span> <span class="n">e</span></div>
362
+
363
+
364
+ <span class="k">def</span><span class="w"> </span><span class="nf">_is_local_server</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">server</span><span class="p">:</span> <span class="n">MCPServer</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
365
+ <span class="w"> </span><span class="sd">&quot;&quot;&quot;Determine if a server is local (should be persisted) or remote (session-only)&quot;&quot;&quot;</span>
366
+ <span class="c1"># Local servers use stdio transport and have no URL</span>
367
+ <span class="k">return</span> <span class="p">(</span><span class="n">server</span><span class="o">.</span><span class="n">transport</span> <span class="o">==</span> <span class="s2">&quot;stdio&quot;</span> <span class="ow">and</span>
368
+ <span class="ow">not</span> <span class="n">server</span><span class="o">.</span><span class="n">url</span> <span class="ow">and</span>
369
+ <span class="ow">not</span> <span class="n">server</span><span class="o">.</span><span class="n">provider_url</span> <span class="ow">and</span>
370
+ <span class="ow">not</span> <span class="n">server</span><span class="o">.</span><span class="n">transport_url</span> <span class="ow">and</span>
371
+ <span class="n">server</span><span class="o">.</span><span class="n">command</span><span class="p">)</span> <span class="c1"># Local servers must have a command</span>
372
+
373
+ <div class="viewcode-block" id="MCPManager.mark_server_as_installed">
374
+ <a class="viewcode-back" href="../../../../source/mindroot.coreplugins.mcp_.html#mindroot.coreplugins.mcp_.mcp_manager.MCPManager.mark_server_as_installed">[docs]</a>
375
+ <span class="k">def</span><span class="w"> </span><span class="nf">mark_server_as_installed</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">registry_id</span><span class="p">:</span> <span class="nb">str</span> <span class="o">=</span> <span class="kc">None</span><span class="p">):</span>
376
+ <span class="w"> </span><span class="sd">&quot;&quot;&quot;Mark server as installed (in-memory only for remote servers)&quot;&quot;&quot;</span>
377
+ <span class="k">if</span> <span class="n">name</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">servers</span><span class="p">:</span>
378
+ <span class="bp">self</span><span class="o">.</span><span class="n">servers</span><span class="p">[</span><span class="n">name</span><span class="p">]</span><span class="o">.</span><span class="n">installed</span> <span class="o">=</span> <span class="kc">True</span>
379
+ <span class="k">if</span> <span class="n">registry_id</span><span class="p">:</span>
380
+ <span class="nb">setattr</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">servers</span><span class="p">[</span><span class="n">name</span><span class="p">],</span> <span class="s1">&#39;registry_id&#39;</span><span class="p">,</span> <span class="n">registry_id</span><span class="p">)</span>
381
+
382
+ <span class="c1"># Only save to config if it&#39;s a local server</span>
383
+ <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_local_server</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">servers</span><span class="p">[</span><span class="n">name</span><span class="p">]):</span>
384
+ <span class="bp">self</span><span class="o">.</span><span class="n">save_config</span><span class="p">()</span></div>
385
+
386
+ <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_persistent_oauth_connection</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
387
+ <span class="w"> </span><span class="sd">&quot;&quot;&quot;Background task to maintain persistent OAuth connection.&quot;&quot;&quot;</span>
388
+ <span class="n">server</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">servers</span><span class="p">[</span><span class="n">name</span><span class="p">]</span>
389
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: Starting persistent OAuth connection task for </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
390
+
391
+ <span class="k">try</span><span class="p">:</span>
392
+ <span class="c1"># Determine transport details and ensure config is updated</span>
393
+ <span class="n">provider_url</span><span class="p">,</span> <span class="n">transport_url</span><span class="p">,</span> <span class="n">transport_type</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_infer_urls</span><span class="p">(</span><span class="n">server</span><span class="p">)</span>
394
+ <span class="bp">self</span><span class="o">.</span><span class="n">_update_server_urls</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">provider_url</span><span class="p">,</span> <span class="n">transport_url</span><span class="p">,</span> <span class="n">transport_type</span><span class="p">)</span>
395
+
396
+ <span class="c1"># Create OAuth client provider using persistent storage</span>
397
+ <span class="n">oauth_provider</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_build_oauth_provider</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">server</span><span class="p">,</span> <span class="n">provider_url</span><span class="p">)</span>
398
+
399
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: Persistent task connecting to </span><span class="si">{</span><span class="n">transport_url</span><span class="si">}</span><span class="s2"> via </span><span class="si">{</span><span class="n">transport_type</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
400
+
401
+ <span class="c1"># Keep connection alive indefinitely using appropriate transport</span>
402
+ <span class="k">if</span> <span class="n">transport_type</span> <span class="o">==</span> <span class="s2">&quot;sse&quot;</span><span class="p">:</span>
403
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: About to create SSE client for </span><span class="si">{</span><span class="n">transport_url</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
404
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: OAuth provider: </span><span class="si">{</span><span class="n">oauth_provider</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
405
+ <span class="k">async</span> <span class="k">with</span> <span class="n">sse_client</span><span class="p">(</span><span class="n">url</span><span class="o">=</span><span class="n">transport_url</span><span class="p">,</span> <span class="n">auth</span><span class="o">=</span><span class="n">oauth_provider</span><span class="p">)</span> <span class="k">as</span> <span class="p">(</span><span class="n">read</span><span class="p">,</span> <span class="n">write</span><span class="p">):</span>
406
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: Persistent SSE transport created for </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
407
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: SSE read: </span><span class="si">{</span><span class="n">read</span><span class="si">}</span><span class="s2">, write: </span><span class="si">{</span><span class="n">write</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
408
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: About to create ClientSession&quot;</span><span class="p">)</span>
409
+ <span class="k">async</span> <span class="k">with</span> <span class="n">ClientSession</span><span class="p">(</span><span class="n">read</span><span class="p">,</span> <span class="n">write</span><span class="p">)</span> <span class="k">as</span> <span class="n">session</span><span class="p">:</span>
410
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: Persistent session created for </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
411
+
412
+ <span class="c1"># Initialize the session</span>
413
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: About to initialize session for </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
414
+ <span class="k">await</span> <span class="n">session</span><span class="o">.</span><span class="n">initialize</span><span class="p">()</span>
415
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: Persistent session initialized for </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
416
+
417
+ <span class="c1"># Store session globally</span>
418
+ <span class="bp">self</span><span class="o">.</span><span class="n">sessions</span><span class="p">[</span><span class="n">name</span><span class="p">]</span> <span class="o">=</span> <span class="n">session</span>
419
+ <span class="n">server</span><span class="o">.</span><span class="n">status</span> <span class="o">=</span> <span class="s2">&quot;connected&quot;</span>
420
+
421
+ <span class="c1"># Get server capabilities</span>
422
+ <span class="k">try</span><span class="p">:</span>
423
+ <span class="n">tools</span> <span class="o">=</span> <span class="p">[]</span>
424
+ <span class="n">resources</span> <span class="o">=</span> <span class="p">[]</span>
425
+ <span class="n">prompts</span> <span class="o">=</span> <span class="p">[]</span>
426
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: About to list tools for </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
427
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;DEBUG: listing tools&quot;</span><span class="p">)</span>
428
+ <span class="n">tools</span> <span class="o">=</span> <span class="k">await</span> <span class="n">session</span><span class="o">.</span><span class="n">list_tools</span><span class="p">()</span>
429
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;DEBUG: tools listed successfully&quot;</span><span class="p">,</span> <span class="n">tools</span><span class="p">)</span>
430
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;DEBUG: listing resources&quot;</span><span class="p">)</span>
431
+ <span class="k">try</span><span class="p">:</span>
432
+ <span class="n">resources</span> <span class="o">=</span> <span class="k">await</span> <span class="n">session</span><span class="o">.</span><span class="n">list_resources</span><span class="p">()</span>
433
+ <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
434
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Error listing resources for </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
435
+ <span class="n">resources</span> <span class="o">=</span> <span class="p">[]</span>
436
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;DEBUG: resources listed successfully&quot;</span><span class="p">,</span> <span class="n">resources</span><span class="p">)</span>
437
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;DEBUG: listing prompts&quot;</span><span class="p">)</span>
438
+ <span class="k">try</span><span class="p">:</span>
439
+ <span class="n">prompts</span> <span class="o">=</span> <span class="k">await</span> <span class="n">session</span><span class="o">.</span><span class="n">list_prompts</span><span class="p">()</span>
440
+ <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
441
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Error listing prompts for </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
442
+
443
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: Processing capabilities - tools type: </span><span class="si">{</span><span class="nb">type</span><span class="p">(</span><span class="n">tools</span><span class="p">)</span><span class="si">}</span><span class="s2">, tools: </span><span class="si">{</span><span class="n">tools</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
444
+ <span class="n">server</span><span class="o">.</span><span class="n">capabilities</span> <span class="o">=</span> <span class="p">{</span>
445
+ <span class="s2">&quot;tools&quot;</span><span class="p">:</span> <span class="p">[</span><span class="n">tool</span><span class="o">.</span><span class="n">dict</span><span class="p">()</span> <span class="k">for</span> <span class="n">tool</span> <span class="ow">in</span> <span class="n">tools</span><span class="o">.</span><span class="n">tools</span><span class="p">]</span>
446
+ <span class="c1">#&quot;resources&quot;: [res.dict() for res in resources.resources]</span>
447
+ <span class="p">}</span>
448
+ <span class="bp">self</span><span class="o">.</span><span class="n">servers</span><span class="p">[</span><span class="n">name</span><span class="p">]</span> <span class="o">=</span> <span class="n">server</span>
449
+ <span class="bp">self</span><span class="o">.</span><span class="n">last_capabilities</span><span class="p">[</span><span class="n">name</span><span class="p">]</span> <span class="o">=</span> <span class="n">server</span><span class="o">.</span><span class="n">capabilities</span>
450
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: Retrieved capabilities for </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">tools</span><span class="o">.</span><span class="n">tools</span><span class="p">)</span><span class="si">}</span><span class="s2"> tools&quot;</span><span class="p">)</span>
451
+
452
+ <span class="c1"># Register dynamic commands</span>
453
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: Registering tools for </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">...&quot;</span><span class="p">)</span>
454
+ <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">dynamic_commands</span><span class="o">.</span><span class="n">register_tools</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">tools</span><span class="o">.</span><span class="n">tools</span><span class="p">)</span>
455
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: Successfully registered </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">tools</span><span class="o">.</span><span class="n">tools</span><span class="p">)</span><span class="si">}</span><span class="s2"> tools for </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
456
+ <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
457
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Error getting capabilities for </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
458
+ <span class="c1"># Don&#39;t set status to error if we got this far - keep it connected</span>
459
+ <span class="k">pass</span>
460
+
461
+ <span class="c1">#self.save_config()</span>
462
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: Capabilities saved for </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">, tools=</span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">server</span><span class="o">.</span><span class="n">capabilities</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;tools&#39;</span><span class="p">,</span><span class="w"> </span><span class="p">[]))</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
463
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: Persistent SSE connection established for </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
464
+
465
+ <span class="c1"># Keep the task alive until cancelled</span>
466
+ <span class="k">try</span><span class="p">:</span>
467
+ <span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
468
+ <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">60</span><span class="p">)</span> <span class="c1"># Heartbeat every minute</span>
469
+ <span class="k">except</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">CancelledError</span><span class="p">:</span>
470
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: Persistent connection task cancelled for </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
471
+ <span class="k">raise</span>
472
+ <span class="k">else</span><span class="p">:</span>
473
+ <span class="k">async</span> <span class="k">with</span> <span class="n">streamablehttp_client</span><span class="p">(</span><span class="n">url</span><span class="o">=</span><span class="n">transport_url</span><span class="p">,</span> <span class="n">auth</span><span class="o">=</span><span class="n">oauth_provider</span><span class="p">)</span> <span class="k">as</span> <span class="p">(</span><span class="n">read</span><span class="p">,</span> <span class="n">write</span><span class="p">,</span> <span class="n">_</span><span class="p">):</span>
474
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: Persistent StreamableHTTP transport created for </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
475
+ <span class="k">async</span> <span class="k">with</span> <span class="n">ClientSession</span><span class="p">(</span><span class="n">read</span><span class="p">,</span> <span class="n">write</span><span class="p">)</span> <span class="k">as</span> <span class="n">session</span><span class="p">:</span>
476
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: Persistent session created for </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
477
+
478
+ <span class="c1"># Initialize the session</span>
479
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: About to initialize session for </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
480
+ <span class="k">await</span> <span class="n">session</span><span class="o">.</span><span class="n">initialize</span><span class="p">()</span>
481
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: Persistent session initialized for </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
482
+
483
+ <span class="c1"># Store session globally</span>
484
+ <span class="bp">self</span><span class="o">.</span><span class="n">sessions</span><span class="p">[</span><span class="n">name</span><span class="p">]</span> <span class="o">=</span> <span class="n">session</span>
485
+ <span class="n">server</span><span class="o">.</span><span class="n">status</span> <span class="o">=</span> <span class="s2">&quot;connected&quot;</span>
486
+
487
+ <span class="c1"># Get server capabilities</span>
488
+ <span class="k">try</span><span class="p">:</span>
489
+ <span class="n">tools</span> <span class="o">=</span> <span class="k">await</span> <span class="n">session</span><span class="o">.</span><span class="n">list_tools</span><span class="p">()</span>
490
+ <span class="n">resources</span> <span class="o">=</span> <span class="k">await</span> <span class="n">session</span><span class="o">.</span><span class="n">list_resources</span><span class="p">()</span>
491
+ <span class="n">prompts</span> <span class="o">=</span> <span class="k">await</span> <span class="n">session</span><span class="o">.</span><span class="n">list_prompts</span><span class="p">()</span>
492
+
493
+ <span class="n">server</span><span class="o">.</span><span class="n">capabilities</span> <span class="o">=</span> <span class="p">{</span>
494
+ <span class="s2">&quot;tools&quot;</span><span class="p">:</span> <span class="p">[</span><span class="n">tool</span><span class="o">.</span><span class="n">dict</span><span class="p">()</span> <span class="k">for</span> <span class="n">tool</span> <span class="ow">in</span> <span class="n">tools</span><span class="o">.</span><span class="n">tools</span><span class="p">],</span>
495
+ <span class="s2">&quot;resources&quot;</span><span class="p">:</span> <span class="p">[</span><span class="n">res</span><span class="o">.</span><span class="n">dict</span><span class="p">()</span> <span class="k">for</span> <span class="n">res</span> <span class="ow">in</span> <span class="n">resources</span><span class="o">.</span><span class="n">resources</span><span class="p">],</span>
496
+ <span class="s2">&quot;prompts&quot;</span><span class="p">:</span> <span class="p">[</span><span class="n">prompt</span><span class="o">.</span><span class="n">dict</span><span class="p">()</span> <span class="k">for</span> <span class="n">prompt</span> <span class="ow">in</span> <span class="n">prompts</span><span class="o">.</span><span class="n">prompts</span><span class="p">]</span>
497
+ <span class="p">}</span>
498
+ <span class="bp">self</span><span class="o">.</span><span class="n">last_capabilities</span><span class="p">[</span><span class="n">name</span><span class="p">]</span> <span class="o">=</span> <span class="n">server</span><span class="o">.</span><span class="n">capabilities</span>
499
+ <span class="c1"># Save to diagnostics cache</span>
500
+ <span class="bp">self</span><span class="o">.</span><span class="n">last_capabilities</span><span class="p">[</span><span class="n">name</span><span class="p">]</span> <span class="o">=</span> <span class="n">server</span><span class="o">.</span><span class="n">capabilities</span>
501
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: Retrieved capabilities for </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">tools</span><span class="o">.</span><span class="n">tools</span><span class="p">)</span><span class="si">}</span><span class="s2"> tools&quot;</span><span class="p">)</span>
502
+
503
+ <span class="c1"># Register dynamic commands</span>
504
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: Registering tools for </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">...&quot;</span><span class="p">)</span>
505
+ <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">dynamic_commands</span><span class="o">.</span><span class="n">register_tools</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">tools</span><span class="o">.</span><span class="n">tools</span><span class="p">)</span>
506
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: Successfully registered </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">tools</span><span class="o">.</span><span class="n">tools</span><span class="p">)</span><span class="si">}</span><span class="s2"> tools for </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
507
+ <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
508
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Error getting capabilities for </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
509
+ <span class="c1"># Don&#39;t set status to error if we got this far - keep it connected</span>
510
+ <span class="k">pass</span>
511
+
512
+ <span class="c1">#self.save_config()</span>
513
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: Capabilities saved for </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">, tools=</span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">server</span><span class="o">.</span><span class="n">capabilities</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;tools&#39;</span><span class="p">,</span><span class="w"> </span><span class="p">[]))</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
514
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: Capabilities saved for </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">, tools=</span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">server</span><span class="o">.</span><span class="n">capabilities</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;tools&#39;</span><span class="p">,</span><span class="w"> </span><span class="p">[]))</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
515
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: Persistent StreamableHTTP connection established for </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
516
+
517
+ <span class="c1"># Keep the task alive until cancelled</span>
518
+ <span class="k">try</span><span class="p">:</span>
519
+ <span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
520
+ <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">60</span><span class="p">)</span> <span class="c1"># Heartbeat every minute</span>
521
+ <span class="k">except</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">CancelledError</span><span class="p">:</span>
522
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: Persistent connection task cancelled for </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
523
+ <span class="k">raise</span>
524
+
525
+ <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
526
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;ERROR: Persistent OAuth connection failed for </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
527
+ <span class="kn">import</span><span class="w"> </span><span class="nn">traceback</span>
528
+ <span class="n">traceback</span><span class="o">.</span><span class="n">print_exc</span><span class="p">()</span>
529
+ <span class="n">t</span> <span class="o">=</span> <span class="n">traceback</span><span class="o">.</span><span class="n">format_exc</span><span class="p">()</span>
530
+ <span class="n">server</span><span class="o">.</span><span class="n">status</span> <span class="o">=</span> <span class="s2">&quot;error&quot;</span>
531
+ <span class="bp">self</span><span class="o">.</span><span class="n">save_config</span><span class="p">()</span>
532
+ <span class="k">raise</span>
533
+
534
+ <div class="viewcode-block" id="MCPManager.connect_oauth_server">
535
+ <a class="viewcode-back" href="../../../../source/mindroot.coreplugins.mcp_.html#mindroot.coreplugins.mcp_.mcp_manager.MCPManager.connect_oauth_server">[docs]</a>
536
+ <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">connect_oauth_server</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
537
+ <span class="w"> </span><span class="sd">&quot;&quot;&quot;Connect to an OAuth-protected MCP server.&quot;&quot;&quot;</span>
538
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Connecting to OAuth server:&quot;</span><span class="p">,</span> <span class="n">name</span><span class="p">)</span>
539
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">MCP_AVAILABLE</span><span class="p">:</span>
540
+ <span class="k">raise</span> <span class="ne">ImportError</span><span class="p">(</span><span class="s2">&quot;MCP SDK not installed. Run: pip install mcp&quot;</span><span class="p">)</span>
541
+ <span class="nb">print</span><span class="p">(</span><span class="s1">&#39;1&#39;</span><span class="p">)</span>
542
+ <span class="k">if</span> <span class="n">name</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">servers</span><span class="p">:</span>
543
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Server not found:&quot;</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="s2">&quot; Known:&quot;</span><span class="p">,</span> <span class="nb">list</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">servers</span><span class="o">.</span><span class="n">keys</span><span class="p">()))</span>
544
+ <span class="k">return</span> <span class="kc">False</span>
545
+
546
+ <span class="n">server</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">servers</span><span class="p">[</span><span class="n">name</span><span class="p">]</span>
547
+ <span class="nb">print</span><span class="p">(</span><span class="s1">&#39;2&#39;</span><span class="p">)</span>
548
+ <span class="k">if</span> <span class="n">server</span><span class="o">.</span><span class="n">auth_type</span> <span class="o">!=</span> <span class="s2">&quot;oauth2&quot;</span><span class="p">:</span>
549
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Server is not configured for OAuth2:&quot;</span><span class="p">,</span> <span class="n">name</span><span class="p">)</span>
550
+ <span class="k">return</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">connect_server</span><span class="p">(</span><span class="n">name</span><span class="p">)</span> <span class="c1"># Fallback to regular connection</span>
551
+
552
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: Starting OAuth connection for </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
553
+
554
+
555
+ <span class="c1"># If already connected via background task, return success</span>
556
+ <span class="k">if</span> <span class="kc">False</span> <span class="ow">and</span> <span class="n">name</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">background_tasks</span> <span class="ow">and</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">background_tasks</span><span class="p">[</span><span class="n">name</span><span class="p">]</span><span class="o">.</span><span class="n">done</span><span class="p">():</span>
557
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: OAuth server </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2"> already connected via background task&quot;</span><span class="p">)</span>
558
+ <span class="k">return</span> <span class="kc">True</span>
559
+
560
+ <span class="c1"># Clean up any old background task</span>
561
+ <span class="k">if</span> <span class="n">name</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">background_tasks</span><span class="p">:</span>
562
+ <span class="bp">self</span><span class="o">.</span><span class="n">background_tasks</span><span class="p">[</span><span class="n">name</span><span class="p">]</span><span class="o">.</span><span class="n">cancel</span><span class="p">()</span>
563
+ <span class="k">del</span> <span class="bp">self</span><span class="o">.</span><span class="n">background_tasks</span><span class="p">[</span><span class="n">name</span><span class="p">]</span>
564
+
565
+ <span class="k">try</span><span class="p">:</span>
566
+ <span class="c1"># Start background task for persistent connection</span>
567
+ <span class="n">task</span> <span class="o">=</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">create_task</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_persistent_oauth_connection</span><span class="p">(</span><span class="n">name</span><span class="p">))</span>
568
+ <span class="bp">self</span><span class="o">.</span><span class="n">background_tasks</span><span class="p">[</span><span class="n">name</span><span class="p">]</span> <span class="o">=</span> <span class="n">task</span>
569
+ <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
570
+
571
+ <span class="c1"># Check if connection was successful or OAuth flow started</span>
572
+ <span class="k">if</span> <span class="n">name</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">sessions</span> <span class="ow">and</span> <span class="n">server</span><span class="o">.</span><span class="n">status</span> <span class="o">==</span> <span class="s2">&quot;connected&quot;</span><span class="p">:</span>
573
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: Background OAuth connection successful for </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
574
+ <span class="k">return</span> <span class="kc">True</span>
575
+ <span class="k">elif</span> <span class="kc">False</span> <span class="ow">and</span> <span class="n">server</span><span class="o">.</span><span class="n">status</span> <span class="o">==</span> <span class="s2">&quot;error&quot;</span><span class="p">:</span>
576
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: Background OAuth connection failed for </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
577
+ <span class="c1"># Check if the background task had an exception</span>
578
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">task</span><span class="o">.</span><span class="n">done</span><span class="p">():</span>
579
+ <span class="n">task</span><span class="o">.</span><span class="n">cancel</span><span class="p">()</span>
580
+ <span class="k">return</span> <span class="kc">False</span>
581
+ <span class="k">elif</span> <span class="n">name</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">pending_oauth_flows</span><span class="p">:</span>
582
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: OAuth flow started for </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">, frontend should handle popup&quot;</span><span class="p">)</span>
583
+ <span class="k">return</span> <span class="kc">False</span> <span class="c1"># This will trigger the OAuth flow check in the calling code</span>
584
+ <span class="k">else</span><span class="p">:</span>
585
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: (X) Background OAuth connection failed for </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">, </span><span class="si">{</span><span class="n">server</span><span class="o">.</span><span class="n">status</span><span class="si">}</span><span class="s2"> </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">sessions</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
586
+ <span class="k">return</span> <span class="kc">False</span>
587
+
588
+ <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
589
+ <span class="n">server</span><span class="o">.</span><span class="n">status</span> <span class="o">=</span> <span class="s2">&quot;error&quot;</span>
590
+ <span class="n">t</span> <span class="o">=</span> <span class="n">traceback</span><span class="o">.</span><span class="n">format_exc</span><span class="p">()</span>
591
+ <span class="bp">self</span><span class="o">.</span><span class="n">save_config</span><span class="p">()</span>
592
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Error starting OAuth connection for </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="se">\n</span><span class="si">{</span><span class="n">t</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
593
+ <span class="k">return</span> <span class="kc">False</span></div>
594
+
595
+
596
+ <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_handle_oauth_redirect</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">server_name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">auth_url</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="kc">None</span><span class="p">:</span>
597
+ <span class="w"> </span><span class="sd">&quot;&quot;&quot;Handle OAuth redirect - store auth URL for frontend to handle.&quot;&quot;&quot;</span>
598
+ <span class="n">flow_id</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">uuid</span><span class="o">.</span><span class="n">uuid4</span><span class="p">())</span>
599
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: Creating OAuth flow for </span><span class="si">{</span><span class="n">server_name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
600
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: Auth URL: </span><span class="si">{</span><span class="n">auth_url</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
601
+ <span class="bp">self</span><span class="o">.</span><span class="n">pending_oauth_flows</span><span class="p">[</span><span class="n">server_name</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
602
+ <span class="s2">&quot;flow_id&quot;</span><span class="p">:</span> <span class="n">flow_id</span><span class="p">,</span>
603
+ <span class="s2">&quot;auth_url&quot;</span><span class="p">:</span> <span class="n">auth_url</span><span class="p">,</span>
604
+ <span class="s2">&quot;status&quot;</span><span class="p">:</span> <span class="s2">&quot;awaiting_authorization&quot;</span><span class="p">,</span>
605
+ <span class="s2">&quot;code&quot;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
606
+ <span class="s2">&quot;state&quot;</span><span class="p">:</span> <span class="kc">None</span>
607
+ <span class="p">}</span>
608
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: OAuth flow created with ID: </span><span class="si">{</span><span class="n">flow_id</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
609
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;OAuth flow started for </span><span class="si">{</span><span class="n">server_name</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">auth_url</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
610
+
611
+ <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">_handle_oauth_callback</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">server_name</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">tuple</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]]:</span>
612
+ <span class="w"> </span><span class="sd">&quot;&quot;&quot;Handle OAuth callback - get code from pending flow.&quot;&quot;&quot;</span>
613
+ <span class="k">if</span> <span class="n">server_name</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">pending_oauth_flows</span><span class="p">:</span>
614
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: No pending OAuth flow found for </span><span class="si">{</span><span class="n">server_name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
615
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: Available flows: </span><span class="si">{</span><span class="nb">list</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">pending_oauth_flows</span><span class="o">.</span><span class="n">keys</span><span class="p">())</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
616
+ <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;No pending OAuth flow for server </span><span class="si">{</span><span class="n">server_name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
617
+
618
+ <span class="n">flow</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">pending_oauth_flows</span><span class="p">[</span><span class="n">server_name</span><span class="p">]</span>
619
+
620
+ <span class="c1"># Wait for callback to be processed by frontend</span>
621
+ <span class="n">max_wait</span> <span class="o">=</span> <span class="mi">300</span> <span class="c1"># 5 minutes</span>
622
+ <span class="n">wait_time</span> <span class="o">=</span> <span class="mi">0</span>
623
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: Waiting for OAuth callback for </span><span class="si">{</span><span class="n">server_name</span><span class="si">}</span><span class="s2">, current status: </span><span class="si">{</span><span class="n">flow</span><span class="p">[</span><span class="s1">&#39;status&#39;</span><span class="p">]</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
624
+
625
+ <span class="k">while</span> <span class="n">flow</span><span class="p">[</span><span class="s2">&quot;status&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;awaiting_authorization&quot;</span> <span class="ow">and</span> <span class="n">wait_time</span> <span class="o">&lt;</span> <span class="n">max_wait</span><span class="p">:</span>
626
+ <span class="k">if</span> <span class="n">wait_time</span> <span class="o">%</span> <span class="mi">10</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span> <span class="c1"># Log every 10 seconds</span>
627
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: Still waiting for OAuth callback... </span><span class="si">{</span><span class="n">wait_time</span><span class="si">}</span><span class="s2">s elapsed&quot;</span><span class="p">)</span>
628
+ <span class="k">await</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
629
+ <span class="n">wait_time</span> <span class="o">+=</span> <span class="mi">1</span>
630
+
631
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: OAuth wait completed. Status: </span><span class="si">{</span><span class="n">flow</span><span class="p">[</span><span class="s1">&#39;status&#39;</span><span class="p">]</span><span class="si">}</span><span class="s2">, wait_time: </span><span class="si">{</span><span class="n">wait_time</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
632
+ <span class="n">code</span> <span class="o">=</span> <span class="n">flow</span><span class="p">[</span><span class="s2">&quot;code&quot;</span><span class="p">]</span>
633
+ <span class="n">state</span> <span class="o">=</span> <span class="n">flow</span><span class="p">[</span><span class="s2">&quot;state&quot;</span><span class="p">]</span>
634
+
635
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: OAuth flow completed for </span><span class="si">{</span><span class="n">server_name</span><span class="si">}</span><span class="s2">, code: </span><span class="si">{</span><span class="n">code</span><span class="si">}</span><span class="s2">, state: </span><span class="si">{</span><span class="n">state</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
636
+
637
+ <span class="k">if</span> <span class="n">flow</span><span class="p">[</span><span class="s2">&quot;status&quot;</span><span class="p">]</span> <span class="o">!=</span> <span class="s2">&quot;callback_received&quot;</span><span class="p">:</span>
638
+ <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">&quot;OAuth authorization timed out or failed&quot;</span><span class="p">)</span>
639
+
640
+ <span class="c1"># Clean up flow</span>
641
+ <span class="k">del</span> <span class="bp">self</span><span class="o">.</span><span class="n">pending_oauth_flows</span><span class="p">[</span><span class="n">server_name</span><span class="p">]</span>
642
+
643
+ <span class="k">return</span> <span class="n">code</span><span class="p">,</span> <span class="n">state</span>
644
+
645
+ <div class="viewcode-block" id="MCPManager.start_oauth_flow">
646
+ <a class="viewcode-back" href="../../../../source/mindroot.coreplugins.mcp_.html#mindroot.coreplugins.mcp_.mcp_manager.MCPManager.start_oauth_flow">[docs]</a>
647
+ <span class="k">def</span><span class="w"> </span><span class="nf">start_oauth_flow</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">server_name</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]:</span>
648
+ <span class="w"> </span><span class="sd">&quot;&quot;&quot;Start OAuth flow and return authorization URL.&quot;&quot;&quot;</span>
649
+ <span class="k">if</span> <span class="n">server_name</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">pending_oauth_flows</span><span class="p">:</span>
650
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: Found existing OAuth flow for </span><span class="si">{</span><span class="n">server_name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
651
+ <span class="n">flow</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">pending_oauth_flows</span><span class="p">[</span><span class="n">server_name</span><span class="p">]</span>
652
+ <span class="k">if</span> <span class="n">flow</span><span class="p">[</span><span class="s2">&quot;status&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;awaiting_authorization&quot;</span><span class="p">:</span>
653
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: Returning existing auth URL: </span><span class="si">{</span><span class="n">flow</span><span class="p">[</span><span class="s1">&#39;auth_url&#39;</span><span class="p">]</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
654
+ <span class="k">return</span> <span class="n">flow</span><span class="p">[</span><span class="s2">&quot;auth_url&quot;</span><span class="p">]</span>
655
+ <span class="k">return</span> <span class="kc">None</span></div>
656
+
657
+
658
+ <div class="viewcode-block" id="MCPManager.complete_oauth_flow">
659
+ <a class="viewcode-back" href="../../../../source/mindroot.coreplugins.mcp_.html#mindroot.coreplugins.mcp_.mcp_manager.MCPManager.complete_oauth_flow">[docs]</a>
660
+ <span class="k">def</span><span class="w"> </span><span class="nf">complete_oauth_flow</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">server_name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">code</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">state</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="nb">str</span><span class="p">]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
661
+ <span class="w"> </span><span class="sd">&quot;&quot;&quot;Complete OAuth flow with authorization code.&quot;&quot;&quot;</span>
662
+ <span class="k">if</span> <span class="n">server_name</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">pending_oauth_flows</span><span class="p">:</span>
663
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: complete_oauth_flow: server_name &#39;</span><span class="si">{</span><span class="n">server_name</span><span class="si">}</span><span class="s2">&#39; not in pending flows. Available: </span><span class="si">{</span><span class="nb">list</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">pending_oauth_flows</span><span class="o">.</span><span class="n">keys</span><span class="p">())</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
664
+ <span class="k">return</span> <span class="kc">False</span>
665
+
666
+ <span class="n">flow</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">pending_oauth_flows</span><span class="p">[</span><span class="n">server_name</span><span class="p">]</span>
667
+ <span class="n">flow</span><span class="p">[</span><span class="s2">&quot;code&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">code</span>
668
+ <span class="n">flow</span><span class="p">[</span><span class="s2">&quot;state&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">state</span>
669
+ <span class="n">flow</span><span class="p">[</span><span class="s2">&quot;status&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="s2">&quot;callback_received&quot;</span>
670
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: complete_oauth_flow: marked callback_received for </span><span class="si">{</span><span class="n">server_name</span><span class="si">}</span><span class="s2">, state=</span><span class="si">{</span><span class="n">state</span><span class="si">}</span><span class="s2"> code_present=</span><span class="si">{</span><span class="nb">bool</span><span class="p">(</span><span class="n">code</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
671
+
672
+ <span class="k">return</span> <span class="kc">True</span></div>
673
+
674
+
675
+ <div class="viewcode-block" id="MCPManager.get_oauth_status">
676
+ <a class="viewcode-back" href="../../../../source/mindroot.coreplugins.mcp_.html#mindroot.coreplugins.mcp_.mcp_manager.MCPManager.get_oauth_status">[docs]</a>
677
+ <span class="k">def</span><span class="w"> </span><span class="nf">get_oauth_status</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">server_name</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]:</span>
678
+ <span class="w"> </span><span class="sd">&quot;&quot;&quot;Get OAuth flow status for a server.&quot;&quot;&quot;</span>
679
+ <span class="k">if</span> <span class="n">server_name</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">servers</span><span class="p">:</span>
680
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: get_oauth_status: Server not found: &#39;</span><span class="si">{</span><span class="n">server_name</span><span class="si">}</span><span class="s2">&#39;. Known servers: </span><span class="si">{</span><span class="nb">list</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">servers</span><span class="o">.</span><span class="n">keys</span><span class="p">())</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
681
+ <span class="k">return</span> <span class="p">{</span><span class="s2">&quot;error&quot;</span><span class="p">:</span> <span class="s2">&quot;Server not found&quot;</span><span class="p">}</span>
682
+
683
+ <span class="n">server</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">servers</span><span class="p">[</span><span class="n">server_name</span><span class="p">]</span>
684
+
685
+ <span class="n">status</span> <span class="o">=</span> <span class="p">{</span>
686
+ <span class="s2">&quot;server_name&quot;</span><span class="p">:</span> <span class="n">server_name</span><span class="p">,</span>
687
+ <span class="s2">&quot;auth_type&quot;</span><span class="p">:</span> <span class="n">server</span><span class="o">.</span><span class="n">auth_type</span><span class="p">,</span>
688
+ <span class="s2">&quot;status&quot;</span><span class="p">:</span> <span class="n">server</span><span class="o">.</span><span class="n">status</span><span class="p">,</span>
689
+ <span class="s2">&quot;has_tokens&quot;</span><span class="p">:</span> <span class="nb">bool</span><span class="p">(</span><span class="n">server</span><span class="o">.</span><span class="n">access_token</span><span class="p">),</span>
690
+ <span class="s2">&quot;token_expires_at&quot;</span><span class="p">:</span> <span class="n">server</span><span class="o">.</span><span class="n">token_expires_at</span><span class="p">,</span>
691
+ <span class="s2">&quot;scopes&quot;</span><span class="p">:</span> <span class="n">server</span><span class="o">.</span><span class="n">scopes</span>
692
+ <span class="p">}</span>
693
+
694
+ <span class="k">if</span> <span class="n">server_name</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">pending_oauth_flows</span><span class="p">:</span>
695
+ <span class="n">flow</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">pending_oauth_flows</span><span class="p">[</span><span class="n">server_name</span><span class="p">]</span>
696
+ <span class="n">status</span><span class="p">[</span><span class="s2">&quot;oauth_flow&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
697
+ <span class="s2">&quot;flow_id&quot;</span><span class="p">:</span> <span class="n">flow</span><span class="p">[</span><span class="s2">&quot;flow_id&quot;</span><span class="p">],</span>
698
+ <span class="s2">&quot;status&quot;</span><span class="p">:</span> <span class="n">flow</span><span class="p">[</span><span class="s2">&quot;status&quot;</span><span class="p">],</span>
699
+ <span class="s2">&quot;auth_url&quot;</span><span class="p">:</span> <span class="n">flow</span><span class="p">[</span><span class="s2">&quot;auth_url&quot;</span><span class="p">]</span> <span class="k">if</span> <span class="n">flow</span><span class="p">[</span><span class="s2">&quot;status&quot;</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;awaiting_authorization&quot;</span> <span class="k">else</span> <span class="kc">None</span>
700
+ <span class="p">}</span>
701
+ <span class="c1"># Add diagnostics: last capabilities snapshot size</span>
702
+ <span class="k">try</span><span class="p">:</span>
703
+ <span class="k">if</span> <span class="n">server_name</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">last_capabilities</span><span class="p">:</span>
704
+ <span class="n">status</span><span class="p">[</span><span class="s2">&quot;last_tools_count&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">last_capabilities</span><span class="p">[</span><span class="n">server_name</span><span class="p">]</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;tools&quot;</span><span class="p">,</span> <span class="p">[]))</span>
705
+ <span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span>
706
+ <span class="k">pass</span>
707
+
708
+ <span class="k">return</span> <span class="n">status</span></div>
709
+
710
+
711
+ <div class="viewcode-block" id="MCPManager.connect_remote_server">
712
+ <a class="viewcode-back" href="../../../../source/mindroot.coreplugins.mcp_.html#mindroot.coreplugins.mcp_.mcp_manager.MCPManager.connect_remote_server">[docs]</a>
713
+ <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">connect_remote_server</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
714
+ <span class="w"> </span><span class="sd">&quot;&quot;&quot;Connect to a remote MCP server (HTTP/SSE).&quot;&quot;&quot;</span>
715
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;remote connect&quot;</span><span class="p">)</span>
716
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">MCP_AVAILABLE</span><span class="p">:</span>
717
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;import error&quot;</span><span class="p">)</span>
718
+ <span class="k">raise</span> <span class="ne">ImportError</span><span class="p">(</span><span class="s2">&quot;MCP SDK not installed. Run: pip install mcp&quot;</span><span class="p">)</span>
719
+
720
+ <span class="k">if</span> <span class="n">name</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">servers</span><span class="p">:</span>
721
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Server not found:&quot;</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="s2">&quot; Known:&quot;</span><span class="p">,</span> <span class="nb">list</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">servers</span><span class="o">.</span><span class="n">keys</span><span class="p">()))</span>
722
+ <span class="k">return</span> <span class="kc">False</span>
723
+
724
+ <span class="n">server</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">servers</span><span class="p">[</span><span class="n">name</span><span class="p">]</span>
725
+
726
+ <span class="k">if</span> <span class="n">server</span><span class="o">.</span><span class="n">auth_type</span> <span class="o">==</span> <span class="s2">&quot;oauth2&quot;</span><span class="p">:</span>
727
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;connect oauth server:&quot;</span><span class="p">,</span> <span class="n">name</span><span class="p">)</span>
728
+ <span class="k">return</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">connect_oauth_server</span><span class="p">(</span><span class="n">name</span><span class="p">)</span>
729
+
730
+ <span class="c1"># Handle basic auth or no auth remote servers</span>
731
+ <span class="k">try</span><span class="p">:</span>
732
+ <span class="c1"># Create exit stack for cleanup</span>
733
+ <span class="n">exit_stack</span> <span class="o">=</span> <span class="n">AsyncExitStack</span><span class="p">()</span>
734
+ <span class="bp">self</span><span class="o">.</span><span class="n">exit_stacks</span><span class="p">[</span><span class="n">name</span><span class="p">]</span> <span class="o">=</span> <span class="n">exit_stack</span>
735
+
736
+ <span class="c1"># Determine transport details</span>
737
+ <span class="n">provider_url</span><span class="p">,</span> <span class="n">transport_url</span><span class="p">,</span> <span class="n">transport_type</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_infer_urls</span><span class="p">(</span><span class="n">server</span><span class="p">)</span>
738
+ <span class="bp">self</span><span class="o">.</span><span class="n">_update_server_urls</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">provider_url</span><span class="p">,</span> <span class="n">transport_url</span><span class="p">,</span> <span class="n">transport_type</span><span class="p">)</span>
739
+
740
+ <span class="c1"># Use appropriate transport based on type</span>
741
+ <span class="k">if</span> <span class="n">transport_type</span> <span class="o">==</span> <span class="s2">&quot;sse&quot;</span><span class="p">:</span>
742
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Connecting via SSE to: </span><span class="si">{</span><span class="n">transport_url</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
743
+ <span class="n">transport</span> <span class="o">=</span> <span class="k">await</span> <span class="n">exit_stack</span><span class="o">.</span><span class="n">enter_async_context</span><span class="p">(</span>
744
+ <span class="n">sse_client</span><span class="p">(</span><span class="n">transport_url</span><span class="p">)</span>
745
+ <span class="p">)</span>
746
+ <span class="c1"># SSE returns (read, write) - no session_id</span>
747
+ <span class="n">session</span> <span class="o">=</span> <span class="k">await</span> <span class="n">exit_stack</span><span class="o">.</span><span class="n">enter_async_context</span><span class="p">(</span>
748
+ <span class="n">ClientSession</span><span class="p">(</span><span class="n">transport</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">transport</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
749
+ <span class="p">)</span>
750
+ <span class="k">else</span><span class="p">:</span> <span class="c1"># streamable_http</span>
751
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Connecting via StreamableHTTP to: </span><span class="si">{</span><span class="n">transport_url</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
752
+ <span class="n">transport</span> <span class="o">=</span> <span class="k">await</span> <span class="n">exit_stack</span><span class="o">.</span><span class="n">enter_async_context</span><span class="p">(</span>
753
+ <span class="n">streamablehttp_client</span><span class="p">(</span><span class="n">transport_url</span><span class="p">)</span>
754
+ <span class="p">)</span>
755
+ <span class="c1"># StreamableHTTP returns (read, write, get_session_id)</span>
756
+ <span class="n">session</span> <span class="o">=</span> <span class="k">await</span> <span class="n">exit_stack</span><span class="o">.</span><span class="n">enter_async_context</span><span class="p">(</span>
757
+ <span class="n">ClientSession</span><span class="p">(</span><span class="n">transport</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">transport</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
758
+ <span class="p">)</span>
759
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Session created:&quot;</span><span class="p">,</span> <span class="n">session</span><span class="p">)</span>
760
+ <span class="c1"># Initialize the session</span>
761
+ <span class="k">await</span> <span class="n">session</span><span class="o">.</span><span class="n">initialize</span><span class="p">()</span>
762
+
763
+ <span class="c1"># Store session</span>
764
+ <span class="bp">self</span><span class="o">.</span><span class="n">sessions</span><span class="p">[</span><span class="n">name</span><span class="p">]</span> <span class="o">=</span> <span class="n">session</span>
765
+
766
+ <span class="c1"># Update server status and capabilities</span>
767
+ <span class="n">server</span><span class="o">.</span><span class="n">status</span> <span class="o">=</span> <span class="s2">&quot;connected&quot;</span>
768
+
769
+ <span class="c1"># Get server capabilities</span>
770
+ <span class="k">try</span><span class="p">:</span>
771
+ <span class="n">tools</span> <span class="o">=</span> <span class="k">await</span> <span class="n">session</span><span class="o">.</span><span class="n">list_tools</span><span class="p">()</span>
772
+ <span class="n">resources</span> <span class="o">=</span> <span class="k">await</span> <span class="n">session</span><span class="o">.</span><span class="n">list_resources</span><span class="p">()</span>
773
+ <span class="n">prompts</span> <span class="o">=</span> <span class="k">await</span> <span class="n">session</span><span class="o">.</span><span class="n">list_prompts</span><span class="p">()</span>
774
+
775
+ <span class="n">server</span><span class="o">.</span><span class="n">capabilities</span> <span class="o">=</span> <span class="p">{</span>
776
+ <span class="s2">&quot;tools&quot;</span><span class="p">:</span> <span class="p">[</span><span class="n">tool</span><span class="o">.</span><span class="n">dict</span><span class="p">()</span> <span class="k">for</span> <span class="n">tool</span> <span class="ow">in</span> <span class="n">tools</span><span class="o">.</span><span class="n">tools</span><span class="p">],</span>
777
+ <span class="s2">&quot;resources&quot;</span><span class="p">:</span> <span class="p">[</span><span class="n">res</span><span class="o">.</span><span class="n">dict</span><span class="p">()</span> <span class="k">for</span> <span class="n">res</span> <span class="ow">in</span> <span class="n">resources</span><span class="o">.</span><span class="n">resources</span><span class="p">],</span>
778
+ <span class="s2">&quot;prompts&quot;</span><span class="p">:</span> <span class="p">[</span><span class="n">prompt</span><span class="o">.</span><span class="n">dict</span><span class="p">()</span> <span class="k">for</span> <span class="n">prompt</span> <span class="ow">in</span> <span class="n">prompts</span><span class="o">.</span><span class="n">prompts</span><span class="p">]</span>
779
+ <span class="p">}</span>
780
+ <span class="bp">self</span><span class="o">.</span><span class="n">last_capabilities</span><span class="p">[</span><span class="n">name</span><span class="p">]</span> <span class="o">=</span> <span class="n">server</span><span class="o">.</span><span class="n">capabilities</span>
781
+ <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
782
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Error getting capabilities for </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
783
+
784
+ <span class="bp">self</span><span class="o">.</span><span class="n">save_config</span><span class="p">()</span>
785
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: connect_remote_server: saved capabilities for </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">, tools=</span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">server</span><span class="o">.</span><span class="n">capabilities</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;tools&#39;</span><span class="p">,</span><span class="w"> </span><span class="p">[]))</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
786
+ <span class="k">return</span> <span class="kc">True</span>
787
+
788
+ <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
789
+ <span class="n">server</span><span class="o">.</span><span class="n">status</span> <span class="o">=</span> <span class="s2">&quot;error&quot;</span>
790
+ <span class="bp">self</span><span class="o">.</span><span class="n">save_config</span><span class="p">()</span>
791
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Error connecting to remote server </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
792
+ <span class="k">return</span> <span class="kc">False</span></div>
793
+
794
+
795
+ <div class="viewcode-block" id="MCPManager.sanity_test">
796
+ <a class="viewcode-back" href="../../../../source/mindroot.coreplugins.mcp_.html#mindroot.coreplugins.mcp_.mcp_manager.MCPManager.sanity_test">[docs]</a>
797
+ <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">sanity_test</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
798
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Basic MCP Manager sanity test&quot;</span><span class="p">)</span>
799
+ <span class="k">return</span> <span class="s2">&quot;OK&quot;</span></div>
800
+
801
+
802
+ <div class="viewcode-block" id="MCPManager.install_server">
803
+ <a class="viewcode-back" href="../../../../source/mindroot.coreplugins.mcp_.html#mindroot.coreplugins.mcp_.mcp_manager.MCPManager.install_server">[docs]</a>
804
+ <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">install_server</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">server_name</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
805
+ <span class="w"> </span><span class="sd">&quot;&quot;&quot;Install an MCP server&quot;&quot;&quot;</span>
806
+ <span class="k">if</span> <span class="n">server_name</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">servers</span><span class="p">:</span>
807
+ <span class="k">return</span> <span class="kc">False</span>
808
+
809
+ <span class="n">server</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">servers</span><span class="p">[</span><span class="n">server_name</span><span class="p">]</span>
810
+
811
+ <span class="k">if</span> <span class="n">server</span><span class="o">.</span><span class="n">install_method</span> <span class="o">==</span> <span class="s2">&quot;manual&quot;</span><span class="p">:</span>
812
+ <span class="k">return</span> <span class="kc">True</span>
813
+
814
+ <span class="k">if</span> <span class="n">server</span><span class="o">.</span><span class="n">install_method</span> <span class="o">==</span> <span class="s2">&quot;uvx&quot;</span><span class="p">:</span>
815
+ <span class="n">success</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">installer</span><span class="o">.</span><span class="n">install_with_uvx</span><span class="p">(</span>
816
+ <span class="n">server</span><span class="o">.</span><span class="n">install_package</span> <span class="ow">or</span> <span class="n">server_name</span>
817
+ <span class="p">)</span>
818
+ <span class="k">elif</span> <span class="n">server</span><span class="o">.</span><span class="n">install_method</span> <span class="o">==</span> <span class="s2">&quot;pip&quot;</span><span class="p">:</span>
819
+ <span class="n">success</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">installer</span><span class="o">.</span><span class="n">install_with_pip</span><span class="p">(</span>
820
+ <span class="n">server</span><span class="o">.</span><span class="n">install_package</span> <span class="ow">or</span> <span class="n">server_name</span>
821
+ <span class="p">)</span>
822
+ <span class="k">elif</span> <span class="n">server</span><span class="o">.</span><span class="n">install_method</span> <span class="o">==</span> <span class="s2">&quot;npm&quot;</span><span class="p">:</span>
823
+ <span class="n">success</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">installer</span><span class="o">.</span><span class="n">install_with_npm</span><span class="p">(</span>
824
+ <span class="n">server</span><span class="o">.</span><span class="n">install_package</span> <span class="ow">or</span> <span class="n">server_name</span>
825
+ <span class="p">)</span>
826
+ <span class="k">elif</span> <span class="n">server</span><span class="o">.</span><span class="n">install_method</span> <span class="o">==</span> <span class="s2">&quot;npx&quot;</span><span class="p">:</span>
827
+ <span class="n">success</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">installer</span><span class="o">.</span><span class="n">install_with_npx</span><span class="p">(</span>
828
+ <span class="n">server</span><span class="o">.</span><span class="n">install_package</span> <span class="ow">or</span> <span class="n">server_name</span>
829
+ <span class="p">)</span>
830
+ <span class="k">else</span><span class="p">:</span>
831
+ <span class="k">return</span> <span class="kc">False</span>
832
+
833
+ <span class="k">if</span> <span class="n">success</span><span class="p">:</span>
834
+ <span class="n">server</span><span class="o">.</span><span class="n">installed</span> <span class="o">=</span> <span class="kc">True</span>
835
+ <span class="c1"># Only save config for local servers</span>
836
+ <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_local_server</span><span class="p">(</span><span class="n">server</span><span class="p">):</span>
837
+ <span class="bp">self</span><span class="o">.</span><span class="n">save_config</span><span class="p">()</span>
838
+
839
+ <span class="k">return</span> <span class="n">success</span></div>
840
+
841
+
842
+ <div class="viewcode-block" id="MCPManager.connect_server">
843
+ <a class="viewcode-back" href="../../../../source/mindroot.coreplugins.mcp_.html#mindroot.coreplugins.mcp_.mcp_manager.MCPManager.connect_server">[docs]</a>
844
+ <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">connect_server</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">secrets</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">str</span><span class="p">]]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
845
+ <span class="w"> </span><span class="sd">&quot;&quot;&quot;Connect to an MCP server&quot;&quot;&quot;</span>
846
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Connecting to MCP server:&quot;</span><span class="p">,</span> <span class="n">name</span><span class="p">)</span>
847
+ <span class="k">if</span> <span class="n">name</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">servers</span><span class="p">:</span>
848
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Server not found:&quot;</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="s2">&quot; Known:&quot;</span><span class="p">,</span> <span class="nb">list</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">servers</span><span class="o">.</span><span class="n">keys</span><span class="p">()))</span>
849
+ <span class="k">return</span> <span class="kc">False</span>
850
+ <span class="k">if</span> <span class="n">ClientSession</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
851
+ <span class="k">raise</span> <span class="ne">ImportError</span><span class="p">(</span><span class="s2">&quot;MCP SDK not installed. Run: pip install mcp&quot;</span><span class="p">)</span>
852
+
853
+ <span class="n">server</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">servers</span><span class="p">[</span><span class="n">name</span><span class="p">]</span>
854
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;DEBUG: secrets passed in connect_server:&quot;</span><span class="p">,</span> <span class="n">secrets</span><span class="p">)</span>
855
+ <span class="c1"># Auto-install if needed</span>
856
+ <span class="k">if</span> <span class="n">server</span><span class="o">.</span><span class="n">auto_install</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">server</span><span class="o">.</span><span class="n">installed</span><span class="p">:</span>
857
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Auto-installing </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">...&quot;</span><span class="p">)</span>
858
+ <span class="k">if</span> <span class="ow">not</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">install_server</span><span class="p">(</span><span class="n">name</span><span class="p">):</span>
859
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Failed to auto-install </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
860
+ <span class="k">return</span> <span class="kc">False</span>
861
+
862
+ <span class="c1"># Route to appropriate connection method based on transport</span>
863
+ <span class="k">if</span> <span class="n">server</span><span class="o">.</span><span class="n">transport</span> <span class="ow">in</span> <span class="p">[</span><span class="s2">&quot;http&quot;</span><span class="p">,</span> <span class="s2">&quot;sse&quot;</span><span class="p">,</span> <span class="s2">&quot;websocket&quot;</span><span class="p">]</span> <span class="ow">or</span> <span class="n">server</span><span class="o">.</span><span class="n">url</span><span class="p">:</span>
864
+ <span class="k">return</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">connect_remote_server</span><span class="p">(</span><span class="n">name</span><span class="p">)</span>
865
+
866
+ <span class="k">try</span><span class="p">:</span>
867
+ <span class="k">if</span> <span class="n">server</span><span class="o">.</span><span class="n">transport</span> <span class="o">==</span> <span class="s2">&quot;stdio&quot;</span><span class="p">:</span>
868
+ <span class="kn">import</span><span class="w"> </span><span class="nn">copy</span>
869
+
870
+ <span class="c1"># Combine stored secrets with any provided for this session</span>
871
+ <span class="n">all_secrets</span> <span class="o">=</span> <span class="p">(</span><span class="n">server</span><span class="o">.</span><span class="n">secrets</span> <span class="ow">or</span> <span class="p">{})</span><span class="o">.</span><span class="n">copy</span><span class="p">()</span>
872
+ <span class="k">if</span> <span class="n">secrets</span><span class="p">:</span>
873
+ <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">secrets</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
874
+ <span class="k">if</span> <span class="n">v</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="ow">and</span> <span class="n">v</span> <span class="o">!=</span> <span class="s2">&quot;&quot;</span><span class="p">:</span>
875
+ <span class="n">all_secrets</span><span class="p">[</span><span class="n">k</span><span class="p">]</span> <span class="o">=</span> <span class="n">v</span>
876
+
877
+ <span class="n">final_command</span> <span class="o">=</span> <span class="n">_substitute_secrets</span><span class="p">(</span><span class="n">server</span><span class="o">.</span><span class="n">command</span><span class="p">,</span> <span class="n">all_secrets</span><span class="p">)</span>
878
+ <span class="n">args_</span> <span class="o">=</span> <span class="n">_substitute_secrets</span><span class="p">(</span><span class="n">copy</span><span class="o">.</span><span class="n">deepcopy</span><span class="p">(</span><span class="n">server</span><span class="o">.</span><span class="n">args</span><span class="p">),</span> <span class="n">all_secrets</span><span class="p">)</span>
879
+ <span class="n">env_</span> <span class="o">=</span> <span class="n">_substitute_secrets</span><span class="p">(</span><span class="n">copy</span><span class="o">.</span><span class="n">deepcopy</span><span class="p">(</span><span class="n">server</span><span class="o">.</span><span class="n">env</span><span class="p">),</span> <span class="n">all_secrets</span><span class="p">)</span>
880
+ <span class="k">for</span> <span class="n">key</span><span class="p">,</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">all_secrets</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
881
+ <span class="k">if</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">env_</span><span class="p">:</span>
882
+ <span class="k">if</span> <span class="n">value</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="ow">and</span> <span class="n">value</span> <span class="ow">is</span> <span class="ow">not</span> <span class="s2">&quot;&quot;</span><span class="p">:</span>
883
+ <span class="n">env_</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span>
884
+ <span class="n">final_env</span> <span class="o">=</span> <span class="p">{</span><span class="n">k</span><span class="p">:</span> <span class="n">v</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="n">env_</span><span class="o">.</span><span class="n">items</span><span class="p">()</span> <span class="k">if</span> <span class="n">v</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">}</span>
885
+ <span class="n">final_args</span> <span class="o">=</span> <span class="p">[</span><span class="nb">str</span><span class="p">(</span><span class="n">arg</span><span class="p">)</span> <span class="k">for</span> <span class="n">arg</span> <span class="ow">in</span> <span class="n">args_</span> <span class="k">if</span> <span class="n">arg</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">]</span>
886
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;DEBUG: server secrets:&quot;</span><span class="p">,</span> <span class="n">server</span><span class="o">.</span><span class="n">secrets</span><span class="p">)</span>
887
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: connect_server: final_command=</span><span class="si">{</span><span class="n">final_command</span><span class="si">}</span><span class="s2">, final_args=</span><span class="si">{</span><span class="n">final_args</span><span class="si">}</span><span class="s2">, final_env=</span><span class="si">{</span><span class="n">final_env</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
888
+ <span class="c1"># Create server parameters</span>
889
+ <span class="n">server_params</span> <span class="o">=</span> <span class="n">StdioServerParameters</span><span class="p">(</span>
890
+ <span class="n">command</span><span class="o">=</span><span class="n">final_command</span><span class="p">,</span>
891
+ <span class="n">args</span><span class="o">=</span><span class="n">final_args</span><span class="p">,</span>
892
+ <span class="n">env</span><span class="o">=</span><span class="n">final_env</span>
893
+ <span class="p">)</span>
894
+
895
+ <span class="c1"># Create exit stack for cleanup</span>
896
+ <span class="n">exit_stack</span> <span class="o">=</span> <span class="n">AsyncExitStack</span><span class="p">()</span>
897
+ <span class="bp">self</span><span class="o">.</span><span class="n">exit_stacks</span><span class="p">[</span><span class="n">name</span><span class="p">]</span> <span class="o">=</span> <span class="n">exit_stack</span>
898
+
899
+ <span class="c1"># Connect via stdio</span>
900
+ <span class="n">stdio_transport</span> <span class="o">=</span> <span class="k">await</span> <span class="n">exit_stack</span><span class="o">.</span><span class="n">enter_async_context</span><span class="p">(</span>
901
+ <span class="n">stdio_client</span><span class="p">(</span><span class="n">server_params</span><span class="p">)</span>
902
+ <span class="p">)</span>
903
+
904
+ <span class="c1"># Create session</span>
905
+ <span class="n">session</span> <span class="o">=</span> <span class="k">await</span> <span class="n">exit_stack</span><span class="o">.</span><span class="n">enter_async_context</span><span class="p">(</span>
906
+ <span class="n">ClientSession</span><span class="p">(</span><span class="n">stdio_transport</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">stdio_transport</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
907
+ <span class="p">)</span>
908
+
909
+ <span class="c1"># Initialize the session</span>
910
+ <span class="k">await</span> <span class="n">session</span><span class="o">.</span><span class="n">initialize</span><span class="p">()</span>
911
+
912
+ <span class="c1"># Store session</span>
913
+ <span class="bp">self</span><span class="o">.</span><span class="n">sessions</span><span class="p">[</span><span class="n">name</span><span class="p">]</span> <span class="o">=</span> <span class="n">session</span>
914
+
915
+ <span class="c1"># Update server status and capabilities</span>
916
+ <span class="n">server</span><span class="o">.</span><span class="n">status</span> <span class="o">=</span> <span class="s2">&quot;connected&quot;</span>
917
+
918
+ <span class="c1"># Get server capabilities</span>
919
+ <span class="k">try</span><span class="p">:</span>
920
+ <span class="n">tools</span> <span class="o">=</span> <span class="k">await</span> <span class="n">session</span><span class="o">.</span><span class="n">list_tools</span><span class="p">()</span>
921
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: Retrieved </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">tools</span><span class="o">.</span><span class="n">tools</span><span class="p">)</span><span class="si">}</span><span class="s2"> tools from </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
922
+ <span class="k">for</span> <span class="n">tool</span> <span class="ow">in</span> <span class="n">tools</span><span class="o">.</span><span class="n">tools</span><span class="p">:</span>
923
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot; Tool: </span><span class="si">{</span><span class="n">tool</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2"> - </span><span class="si">{</span><span class="n">tool</span><span class="o">.</span><span class="n">description</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
924
+
925
+ <span class="c1">#resources = await session.list_resources()</span>
926
+ <span class="c1">#prompts = await session.list_prompts()</span>
927
+
928
+ <span class="c1"># Safely serialize tools, resources, and prompts</span>
929
+ <span class="k">try</span><span class="p">:</span>
930
+ <span class="n">tools_data</span> <span class="o">=</span> <span class="p">[]</span>
931
+ <span class="k">for</span> <span class="n">tool</span> <span class="ow">in</span> <span class="n">tools</span><span class="o">.</span><span class="n">tools</span><span class="p">:</span>
932
+ <span class="k">try</span><span class="p">:</span>
933
+ <span class="n">tools_data</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">tool</span><span class="o">.</span><span class="n">dict</span><span class="p">())</span>
934
+ <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
935
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot; Warning: Failed to serialize tool </span><span class="si">{</span><span class="n">tool</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
936
+ <span class="c1"># Fallback to basic info</span>
937
+ <span class="n">tools_data</span><span class="o">.</span><span class="n">append</span><span class="p">({</span>
938
+ <span class="s2">&quot;name&quot;</span><span class="p">:</span> <span class="n">tool</span><span class="o">.</span><span class="n">name</span><span class="p">,</span>
939
+ <span class="s2">&quot;description&quot;</span><span class="p">:</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">tool</span><span class="p">,</span> <span class="s1">&#39;description&#39;</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">),</span>
940
+ <span class="s2">&quot;inputSchema&quot;</span><span class="p">:</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">tool</span><span class="p">,</span> <span class="s1">&#39;inputSchema&#39;</span><span class="p">,</span> <span class="p">{})</span>
941
+ <span class="p">})</span>
942
+
943
+ <span class="n">server</span><span class="o">.</span><span class="n">capabilities</span> <span class="o">=</span> <span class="p">{</span>
944
+ <span class="s2">&quot;tools&quot;</span><span class="p">:</span> <span class="n">tools_data</span> <span class="c1">#,</span>
945
+ <span class="c1">#&quot;resources&quot;: [res.dict() for res in resources.resources],</span>
946
+ <span class="c1">#&quot;prompts&quot;: [prompt.dict() for prompt in prompts.prompts]</span>
947
+ <span class="p">}</span>
948
+ <span class="bp">self</span><span class="o">.</span><span class="n">servers</span><span class="p">[</span><span class="n">name</span><span class="p">]</span> <span class="o">=</span> <span class="n">server</span>
949
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: Saved </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">tools_data</span><span class="p">)</span><span class="si">}</span><span class="s2"> tools to server capabilities&quot;</span><span class="p">)</span>
950
+ <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
951
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: Error serializing capabilities: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
952
+ <span class="c1"># Set basic capabilities even if serialization fails</span>
953
+ <span class="n">server</span><span class="o">.</span><span class="n">capabilities</span> <span class="o">=</span> <span class="p">{</span>
954
+ <span class="s2">&quot;tools&quot;</span><span class="p">:</span> <span class="p">[{</span><span class="s2">&quot;name&quot;</span><span class="p">:</span> <span class="n">t</span><span class="o">.</span><span class="n">name</span><span class="p">,</span> <span class="s2">&quot;description&quot;</span><span class="p">:</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">t</span><span class="p">,</span> <span class="s1">&#39;description&#39;</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">)}</span> <span class="k">for</span> <span class="n">t</span> <span class="ow">in</span> <span class="n">tools</span><span class="o">.</span><span class="n">tools</span><span class="p">],</span>
955
+ <span class="s2">&quot;resources&quot;</span><span class="p">:</span> <span class="p">[],</span>
956
+ <span class="s2">&quot;prompts&quot;</span><span class="p">:</span> <span class="p">[]</span>
957
+ <span class="p">}</span>
958
+
959
+ <span class="c1"># Register dynamic commands</span>
960
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: Registering tools for </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">...&quot;</span><span class="p">)</span>
961
+ <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">dynamic_commands</span><span class="o">.</span><span class="n">register_tools</span><span class="p">(</span><span class="n">name</span><span class="p">,</span> <span class="n">tools</span><span class="o">.</span><span class="n">tools</span><span class="p">)</span>
962
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: Successfully registered </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">tools</span><span class="o">.</span><span class="n">tools</span><span class="p">)</span><span class="si">}</span><span class="s2"> tools for </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
963
+
964
+ <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
965
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Error getting capabilities for </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
966
+
967
+ <span class="c1"># Only save config for local servers</span>
968
+ <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_local_server</span><span class="p">(</span><span class="n">server</span><span class="p">):</span>
969
+ <span class="bp">self</span><span class="o">.</span><span class="n">save_config</span><span class="p">()</span>
970
+
971
+ <span class="k">return</span> <span class="kc">True</span>
972
+
973
+ <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
974
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;DEBUG: Error connecting to MCP server:&quot;</span><span class="p">,</span> <span class="n">name</span><span class="p">,</span> <span class="n">e</span><span class="p">)</span>
975
+ <span class="kn">import</span><span class="w"> </span><span class="nn">traceback</span>
976
+ <span class="n">traceback</span><span class="o">.</span><span class="n">print_exc</span><span class="p">()</span>
977
+ <span class="n">server</span><span class="o">.</span><span class="n">status</span> <span class="o">=</span> <span class="s2">&quot;error&quot;</span>
978
+ <span class="bp">self</span><span class="o">.</span><span class="n">save_config</span><span class="p">()</span>
979
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Error connecting to </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
980
+ <span class="k">return</span> <span class="kc">False</span></div>
981
+
982
+
983
+ <div class="viewcode-block" id="MCPManager.test_local_server_capabilities">
984
+ <a class="viewcode-back" href="../../../../source/mindroot.coreplugins.mcp_.html#mindroot.coreplugins.mcp_.mcp_manager.MCPManager.test_local_server_capabilities">[docs]</a>
985
+ <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">test_local_server_capabilities</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">command</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">args</span><span class="p">:</span> <span class="n">List</span><span class="p">[</span><span class="nb">str</span><span class="p">],</span> <span class="n">env</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">str</span><span class="p">],</span> <span class="n">secrets</span><span class="p">:</span> <span class="n">Optional</span><span class="p">[</span><span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="nb">str</span><span class="p">]]</span> <span class="o">=</span> <span class="kc">None</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">]:</span>
986
+ <span class="w"> </span><span class="sd">&quot;&quot;&quot;Test connection to a local MCP server and return its capabilities.</span>
987
+ <span class="sd"> </span>
988
+ <span class="sd"> This method creates a temporary server, connects to it, extracts capabilities,</span>
989
+ <span class="sd"> and cleans up. It follows the same pattern as the working catalog system.</span>
990
+ <span class="sd"> </span>
991
+ <span class="sd"> Args:</span>
992
+ <span class="sd"> name: Display name for the server (for error messages)</span>
993
+ <span class="sd"> command: Command to run the MCP server</span>
994
+ <span class="sd"> args: Arguments for the command</span>
995
+ <span class="sd"> env: Environment variables</span>
996
+ <span class="sd"> secrets: A dictionary of secrets to substitute into placeholders.</span>
997
+ <span class="sd"> </span>
998
+ <span class="sd"> Returns:</span>
999
+ <span class="sd"> Dict containing success status, message, and capabilities (tools, resources, prompts)</span>
1000
+ <span class="sd"> </span>
1001
+ <span class="sd"> Raises:</span>
1002
+ <span class="sd"> Exception: If MCP SDK is not available or connection fails</span>
1003
+ <span class="sd"> &quot;&quot;&quot;</span>
1004
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">MCP_AVAILABLE</span><span class="p">:</span>
1005
+ <span class="k">raise</span> <span class="ne">ImportError</span><span class="p">(</span><span class="s2">&quot;MCP SDK not installed. Run: pip install mcp&quot;</span><span class="p">)</span>
1006
+
1007
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">command</span><span class="p">:</span>
1008
+ <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">&quot;Command is required for local servers&quot;</span><span class="p">)</span>
1009
+
1010
+ <span class="c1"># Generate unique temporary server name</span>
1011
+ <span class="n">temp_server_name</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;temp_local_test_</span><span class="si">{</span><span class="n">uuid</span><span class="o">.</span><span class="n">uuid4</span><span class="p">()</span><span class="o">.</span><span class="n">hex</span><span class="p">[:</span><span class="mi">8</span><span class="p">]</span><span class="si">}</span><span class="s2">&quot;</span>
1012
+
1013
+ <span class="k">try</span><span class="p">:</span>
1014
+ <span class="c1"># Create temporary server configuration (following catalog pattern)</span>
1015
+ <span class="n">temp_server</span> <span class="o">=</span> <span class="n">MCPServer</span><span class="p">(</span>
1016
+ <span class="n">name</span><span class="o">=</span><span class="n">temp_server_name</span><span class="p">,</span>
1017
+ <span class="n">description</span><span class="o">=</span><span class="sa">f</span><span class="s2">&quot;Temporary local server for testing </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">,</span>
1018
+ <span class="n">command</span><span class="o">=</span><span class="n">command</span><span class="p">,</span>
1019
+ <span class="n">args</span><span class="o">=</span><span class="n">args</span><span class="p">,</span>
1020
+ <span class="n">env</span><span class="o">=</span><span class="n">env</span><span class="p">,</span>
1021
+ <span class="n">transport</span><span class="o">=</span><span class="s2">&quot;stdio&quot;</span><span class="p">,</span> <span class="c1"># Explicitly set stdio transport</span>
1022
+ <span class="c1"># Explicitly do NOT set url field for local servers</span>
1023
+ <span class="p">)</span>
1024
+
1025
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: test_local_server_capabilities: Created temp server </span><span class="si">{</span><span class="n">temp_server_name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
1026
+
1027
+ <span class="c1"># Add temporary server to MCP manager</span>
1028
+ <span class="bp">self</span><span class="o">.</span><span class="n">add_server</span><span class="p">(</span><span class="n">temp_server_name</span><span class="p">,</span> <span class="n">temp_server</span><span class="p">)</span>
1029
+
1030
+ <span class="c1"># Connect to server (this will use stdio connection)</span>
1031
+ <span class="n">success</span> <span class="o">=</span> <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">connect_server</span><span class="p">(</span><span class="n">temp_server_name</span><span class="p">,</span> <span class="n">secrets</span><span class="o">=</span><span class="n">secrets</span><span class="p">)</span>
1032
+ <span class="k">if</span> <span class="ow">not</span> <span class="n">success</span><span class="p">:</span>
1033
+ <span class="k">raise</span> <span class="ne">Exception</span><span class="p">(</span><span class="s2">&quot;Failed to connect to local server&quot;</span><span class="p">)</span>
1034
+
1035
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: test_local_server_capabilities: Connected to </span><span class="si">{</span><span class="n">temp_server_name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
1036
+
1037
+ <span class="c1"># Get server capabilities</span>
1038
+ <span class="n">server</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">servers</span><span class="p">[</span><span class="n">temp_server_name</span><span class="p">]</span>
1039
+ <span class="n">tools</span> <span class="o">=</span> <span class="n">server</span><span class="o">.</span><span class="n">capabilities</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;tools&quot;</span><span class="p">,</span> <span class="p">[])</span>
1040
+ <span class="n">resources</span> <span class="o">=</span> <span class="n">server</span><span class="o">.</span><span class="n">capabilities</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;resources&quot;</span><span class="p">,</span> <span class="p">[])</span>
1041
+ <span class="n">prompts</span> <span class="o">=</span> <span class="n">server</span><span class="o">.</span><span class="n">capabilities</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;prompts&quot;</span><span class="p">,</span> <span class="p">[])</span>
1042
+
1043
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: test_local_server_capabilities: Found </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">tools</span><span class="p">)</span><span class="si">}</span><span class="s2"> tools, </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">resources</span><span class="p">)</span><span class="si">}</span><span class="s2"> resources, </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">prompts</span><span class="p">)</span><span class="si">}</span><span class="s2"> prompts&quot;</span><span class="p">)</span>
1044
+
1045
+ <span class="k">return</span> <span class="p">{</span>
1046
+ <span class="s2">&quot;success&quot;</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span>
1047
+ <span class="s2">&quot;message&quot;</span><span class="p">:</span> <span class="sa">f</span><span class="s2">&quot;Successfully connected to local server. Found </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">tools</span><span class="p">)</span><span class="si">}</span><span class="s2"> tools, </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">resources</span><span class="p">)</span><span class="si">}</span><span class="s2"> resources, </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">prompts</span><span class="p">)</span><span class="si">}</span><span class="s2"> prompts.&quot;</span><span class="p">,</span>
1048
+ <span class="s2">&quot;tools&quot;</span><span class="p">:</span> <span class="n">tools</span><span class="p">,</span>
1049
+ <span class="s2">&quot;resources&quot;</span><span class="p">:</span> <span class="n">resources</span><span class="p">,</span>
1050
+ <span class="s2">&quot;prompts&quot;</span><span class="p">:</span> <span class="n">prompts</span>
1051
+ <span class="p">}</span>
1052
+
1053
+ <span class="k">finally</span><span class="p">:</span>
1054
+ <span class="c1"># Clean up temporary server</span>
1055
+ <span class="k">try</span><span class="p">:</span>
1056
+ <span class="k">if</span> <span class="n">temp_server_name</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">sessions</span><span class="p">:</span>
1057
+ <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">disconnect_server</span><span class="p">(</span><span class="n">temp_server_name</span><span class="p">)</span>
1058
+ <span class="k">if</span> <span class="n">temp_server_name</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">servers</span><span class="p">:</span>
1059
+ <span class="bp">self</span><span class="o">.</span><span class="n">remove_server</span><span class="p">(</span><span class="n">temp_server_name</span><span class="p">)</span>
1060
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: test_local_server_capabilities: Cleaned up </span><span class="si">{</span><span class="n">temp_server_name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
1061
+ <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">cleanup_error</span><span class="p">:</span>
1062
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Error cleaning up temporary server </span><span class="si">{</span><span class="n">temp_server_name</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">cleanup_error</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span></div>
1063
+
1064
+
1065
+ <div class="viewcode-block" id="MCPManager.disconnect_server">
1066
+ <a class="viewcode-back" href="../../../../source/mindroot.coreplugins.mcp_.html#mindroot.coreplugins.mcp_.mcp_manager.MCPManager.disconnect_server">[docs]</a>
1067
+ <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">disconnect_server</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">bool</span><span class="p">:</span>
1068
+ <span class="w"> </span><span class="sd">&quot;&quot;&quot;Disconnect from an MCP server&quot;&quot;&quot;</span>
1069
+ <span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Attempting to disconnect from MCP server:&quot;</span><span class="p">,</span> <span class="n">name</span><span class="p">)</span>
1070
+ <span class="k">if</span> <span class="n">name</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">sessions</span><span class="p">:</span>
1071
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: Disconnecting from server </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2"> with session </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">sessions</span><span class="p">[</span><span class="n">name</span><span class="p">]</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
1072
+ <span class="k">try</span><span class="p">:</span>
1073
+ <span class="c1"># Unregister dynamic commands</span>
1074
+ <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">dynamic_commands</span><span class="o">.</span><span class="n">unregister_server_tools</span><span class="p">(</span><span class="n">name</span><span class="p">)</span>
1075
+
1076
+ <span class="c1"># Cancel background task if it exists</span>
1077
+ <span class="k">if</span> <span class="n">name</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">background_tasks</span><span class="p">:</span>
1078
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;DEBUG: Cancelling background task for </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
1079
+ <span class="bp">self</span><span class="o">.</span><span class="n">background_tasks</span><span class="p">[</span><span class="n">name</span><span class="p">]</span><span class="o">.</span><span class="n">cancel</span><span class="p">()</span>
1080
+ <span class="k">try</span><span class="p">:</span>
1081
+ <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">background_tasks</span><span class="p">[</span><span class="n">name</span><span class="p">]</span>
1082
+ <span class="k">except</span> <span class="n">asyncio</span><span class="o">.</span><span class="n">CancelledError</span><span class="p">:</span>
1083
+ <span class="k">pass</span>
1084
+ <span class="k">del</span> <span class="bp">self</span><span class="o">.</span><span class="n">background_tasks</span><span class="p">[</span><span class="n">name</span><span class="p">]</span>
1085
+
1086
+ <span class="c1"># Clean up exit stack (this will close the session)</span>
1087
+ <span class="k">if</span> <span class="n">name</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">exit_stacks</span><span class="p">:</span>
1088
+ <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">exit_stacks</span><span class="p">[</span><span class="n">name</span><span class="p">]</span><span class="o">.</span><span class="n">aclose</span><span class="p">()</span>
1089
+ <span class="k">del</span> <span class="bp">self</span><span class="o">.</span><span class="n">exit_stacks</span><span class="p">[</span><span class="n">name</span><span class="p">]</span>
1090
+
1091
+ <span class="k">del</span> <span class="bp">self</span><span class="o">.</span><span class="n">sessions</span><span class="p">[</span><span class="n">name</span><span class="p">]</span>
1092
+
1093
+ <span class="k">if</span> <span class="n">name</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">servers</span><span class="p">:</span>
1094
+ <span class="bp">self</span><span class="o">.</span><span class="n">servers</span><span class="p">[</span><span class="n">name</span><span class="p">]</span><span class="o">.</span><span class="n">status</span> <span class="o">=</span> <span class="s2">&quot;disconnected&quot;</span>
1095
+ <span class="bp">self</span><span class="o">.</span><span class="n">save_config</span><span class="p">()</span>
1096
+
1097
+ <span class="k">return</span> <span class="kc">True</span>
1098
+ <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
1099
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Error disconnecting from </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">e</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
1100
+ <span class="k">return</span> <span class="kc">False</span>
1101
+ <span class="k">else</span><span class="p">:</span>
1102
+ <span class="nb">print</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;No active session found for </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2">. Trying to disconnect with </span><span class="si">{</span><span class="n">name</span><span class="si">}</span><span class="s2"> as server name.&quot;</span><span class="p">)</span>
1103
+ <span class="k">if</span> <span class="n">name</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">servers</span><span class="p">:</span>
1104
+ <span class="k">await</span> <span class="bp">self</span><span class="o">.</span><span class="n">dynamic_commands</span><span class="o">.</span><span class="n">unregister_server_tools</span><span class="p">(</span><span class="n">name</span><span class="p">)</span>
1105
+
1106
+ <span class="bp">self</span><span class="o">.</span><span class="n">servers</span><span class="p">[</span><span class="n">name</span><span class="p">]</span><span class="o">.</span><span class="n">status</span> <span class="o">=</span> <span class="s2">&quot;disconnected&quot;</span>
1107
+ <span class="bp">self</span><span class="o">.</span><span class="n">save_config</span><span class="p">()</span>
1108
+ <span class="k">return</span> <span class="kc">True</span></div>
1109
+
1110
+
1111
+ <div class="viewcode-block" id="MCPManager.call_tool">
1112
+ <a class="viewcode-back" href="../../../../source/mindroot.coreplugins.mcp_.html#mindroot.coreplugins.mcp_.mcp_manager.MCPManager.call_tool">[docs]</a>
1113
+ <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">call_tool</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">server_name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">tool_name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">arguments</span><span class="p">:</span> <span class="n">Dict</span><span class="p">[</span><span class="nb">str</span><span class="p">,</span> <span class="n">Any</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="n">Any</span><span class="p">:</span>
1114
+ <span class="w"> </span><span class="sd">&quot;&quot;&quot;Call a tool on an MCP server&quot;&quot;&quot;</span>
1115
+ <span class="k">if</span> <span class="n">server_name</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">sessions</span><span class="p">:</span>
1116
+ <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Server </span><span class="si">{</span><span class="n">server_name</span><span class="si">}</span><span class="s2"> not connected&quot;</span><span class="p">)</span>
1117
+
1118
+ <span class="n">session</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">sessions</span><span class="p">[</span><span class="n">server_name</span><span class="p">]</span>
1119
+ <span class="n">result</span> <span class="o">=</span> <span class="k">await</span> <span class="n">session</span><span class="o">.</span><span class="n">call_tool</span><span class="p">(</span><span class="n">tool_name</span><span class="p">,</span> <span class="n">arguments</span><span class="p">)</span>
1120
+ <span class="k">return</span> <span class="n">result</span></div>
1121
+
1122
+
1123
+ <div class="viewcode-block" id="MCPManager.read_resource">
1124
+ <a class="viewcode-back" href="../../../../source/mindroot.coreplugins.mcp_.html#mindroot.coreplugins.mcp_.mcp_manager.MCPManager.read_resource">[docs]</a>
1125
+ <span class="k">async</span> <span class="k">def</span><span class="w"> </span><span class="nf">read_resource</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">server_name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">uri</span><span class="p">:</span> <span class="nb">str</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">Any</span><span class="p">:</span>
1126
+ <span class="w"> </span><span class="sd">&quot;&quot;&quot;Read a resource from an MCP server&quot;&quot;&quot;</span>
1127
+ <span class="k">if</span> <span class="n">server_name</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">sessions</span><span class="p">:</span>
1128
+ <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Server </span><span class="si">{</span><span class="n">server_name</span><span class="si">}</span><span class="s2"> not connected&quot;</span><span class="p">)</span>
1129
+
1130
+ <span class="n">session</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">sessions</span><span class="p">[</span><span class="n">server_name</span><span class="p">]</span>
1131
+ <span class="n">result</span> <span class="o">=</span> <span class="k">await</span> <span class="n">session</span><span class="o">.</span><span class="n">read_resource</span><span class="p">(</span><span class="n">uri</span><span class="p">)</span>
1132
+ <span class="k">return</span> <span class="n">result</span></div>
1133
+
1134
+
1135
+ <div class="viewcode-block" id="MCPManager.add_server">
1136
+ <a class="viewcode-back" href="../../../../source/mindroot.coreplugins.mcp_.html#mindroot.coreplugins.mcp_.mcp_manager.MCPManager.add_server">[docs]</a>
1137
+ <span class="k">def</span><span class="w"> </span><span class="nf">add_server</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">,</span> <span class="n">server</span><span class="p">:</span> <span class="n">MCPServer</span><span class="p">):</span>
1138
+ <span class="w"> </span><span class="sd">&quot;&quot;&quot;Add a new server configuration&quot;&quot;&quot;</span>
1139
+ <span class="bp">self</span><span class="o">.</span><span class="n">servers</span><span class="p">[</span><span class="n">name</span><span class="p">]</span> <span class="o">=</span> <span class="n">server</span>
1140
+ <span class="c1"># Only save config for local servers</span>
1141
+ <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_local_server</span><span class="p">(</span><span class="n">server</span><span class="p">):</span>
1142
+ <span class="bp">self</span><span class="o">.</span><span class="n">save_config</span><span class="p">()</span> </div>
1143
+
1144
+ <div class="viewcode-block" id="MCPManager.remove_server">
1145
+ <a class="viewcode-back" href="../../../../source/mindroot.coreplugins.mcp_.html#mindroot.coreplugins.mcp_.mcp_manager.MCPManager.remove_server">[docs]</a>
1146
+ <span class="k">def</span><span class="w"> </span><span class="nf">remove_server</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">name</span><span class="p">:</span> <span class="nb">str</span><span class="p">):</span>
1147
+ <span class="w"> </span><span class="sd">&quot;&quot;&quot;Remove a server configuration&quot;&quot;&quot;</span>
1148
+ <span class="k">if</span> <span class="n">name</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">servers</span><span class="p">:</span>
1149
+ <span class="c1"># Disconnect first if connected</span>
1150
+ <span class="k">if</span> <span class="n">name</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">sessions</span><span class="p">:</span>
1151
+ <span class="n">asyncio</span><span class="o">.</span><span class="n">create_task</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">disconnect_server</span><span class="p">(</span><span class="n">name</span><span class="p">))</span>
1152
+
1153
+ <span class="k">del</span> <span class="bp">self</span><span class="o">.</span><span class="n">servers</span><span class="p">[</span><span class="n">name</span><span class="p">]</span>
1154
+ <span class="bp">self</span><span class="o">.</span><span class="n">save_config</span><span class="p">()</span></div>
1155
+ </div>
1156
+
1157
+ </pre></div>
1158
+
1159
+ </div>
1160
+ </div>
1161
+ <footer>
1162
+
1163
+ <hr/>
1164
+
1165
+ <div role="contentinfo">
1166
+ <p>&#169; Copyright 2025, Jason Livesay.</p>
1167
+ </div>
1168
+
1169
+ Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
1170
+ <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
1171
+ provided by <a href="https://readthedocs.org">Read the Docs</a>.
1172
+
1173
+
1174
+ </footer>
1175
+ </div>
1176
+ </div>
1177
+ </section>
1178
+ </div>
1179
+ <script>
1180
+ jQuery(function () {
1181
+ SphinxRtdTheme.Navigation.enable(true);
1182
+ });
1183
+ </script>
1184
+
1185
+ </body>
1186
+ </html>