mindroot 9.3.0__py3-none-any.whl → 9.5.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.
Files changed (183) hide show
  1. mindroot/coreplugins/admin/__init__.py +3 -1
  2. mindroot/coreplugins/admin/agent_router.py +250 -7
  3. mindroot/coreplugins/admin/asset_manager.py +164 -0
  4. mindroot/coreplugins/admin/command_router.py +236 -1
  5. mindroot/coreplugins/admin/mcp_catalog_routes.py +156 -0
  6. mindroot/coreplugins/admin/mcp_publish_routes.py +450 -0
  7. mindroot/coreplugins/admin/mcp_registry_routes.py +495 -0
  8. mindroot/coreplugins/admin/mcp_routes.py +216 -0
  9. mindroot/coreplugins/admin/mod.py +62 -0
  10. mindroot/coreplugins/admin/oauth_callback_router.py +84 -0
  11. mindroot/coreplugins/admin/persona_handler.py +15 -6
  12. mindroot/coreplugins/admin/persona_router.py +158 -2
  13. mindroot/coreplugins/admin/plugin_manager.py +63 -0
  14. mindroot/coreplugins/admin/plugin_router_fixed.py +23 -0
  15. mindroot/coreplugins/admin/plugin_router_new_not_working.py +145 -0
  16. mindroot/coreplugins/admin/plugin_routes.py +114 -0
  17. mindroot/coreplugins/admin/registry_settings_routes.py +140 -0
  18. mindroot/coreplugins/admin/router.py +116 -15
  19. mindroot/coreplugins/admin/service_models.py +1 -1
  20. mindroot/coreplugins/admin/settings_router.py +1 -0
  21. mindroot/coreplugins/admin/static/css/admin-custom.css +357 -2
  22. mindroot/coreplugins/admin/static/css/dark.css +1 -0
  23. mindroot/coreplugins/admin/static/css/default.css +4 -0
  24. mindroot/coreplugins/admin/static/js/about-info.js +367 -0
  25. mindroot/coreplugins/admin/static/js/agent-form.js +83 -3
  26. mindroot/coreplugins/admin/static/js/api-key-script.js +307 -0
  27. mindroot/coreplugins/admin/static/js/mcp-manager.js +348 -0
  28. mindroot/coreplugins/admin/static/js/mcp-publisher.js +780 -0
  29. mindroot/coreplugins/admin/static/js/persona-editor.js +34 -5
  30. mindroot/coreplugins/admin/static/js/plugin-toggle.js +1 -1
  31. mindroot/coreplugins/admin/static/js/recommended-plugin-install.js +63 -0
  32. mindroot/coreplugins/admin/static/js/registry-auth-section.js +132 -0
  33. mindroot/coreplugins/admin/static/js/registry-manager-base.js +613 -0
  34. mindroot/coreplugins/admin/static/js/registry-manager-old.js +385 -0
  35. mindroot/coreplugins/admin/static/js/registry-manager-publish-old-delete.js +166 -0
  36. mindroot/coreplugins/admin/static/js/registry-manager.js +351 -0
  37. mindroot/coreplugins/admin/static/js/registry-publish-section.js +377 -0
  38. mindroot/coreplugins/admin/static/js/registry-search-section.js +400 -0
  39. mindroot/coreplugins/admin/static/js/registry-search-section.js.bak +3 -0
  40. mindroot/coreplugins/admin/static/js/registry-settings.js +69 -0
  41. mindroot/coreplugins/admin/static/js/registry-shared-services.js +857 -0
  42. mindroot/coreplugins/admin/static/js/registry-simple-sections.js +85 -0
  43. mindroot/coreplugins/admin/static/js/secure-widget-manager.js +438 -0
  44. mindroot/coreplugins/admin/static/logo.png +0 -0
  45. mindroot/coreplugins/admin/templates/admin.jinja2 +275 -110
  46. mindroot/coreplugins/agent/Assistant/agent.json +27 -11
  47. mindroot/coreplugins/agent/agent.py +2 -2
  48. mindroot/coreplugins/agent/command_parser.py +25 -10
  49. mindroot/coreplugins/agent/templates/system.jinja2 +0 -12
  50. mindroot/coreplugins/chat/__init__.py +4 -1
  51. mindroot/coreplugins/chat/router.py +132 -20
  52. mindroot/coreplugins/chat/router_dedup_patch.py +20 -0
  53. mindroot/coreplugins/chat/services.py +31 -1
  54. mindroot/coreplugins/chat/static/css/action-fix.css +32 -0
  55. mindroot/coreplugins/chat/static/css/admin-custom.css +5 -3
  56. mindroot/coreplugins/chat/static/css/dark.css +24 -3
  57. mindroot/coreplugins/chat/static/css/default.css +24 -3
  58. mindroot/coreplugins/chat/static/css/main.css +1 -0
  59. mindroot/coreplugins/chat/static/js/action.js +137 -60
  60. mindroot/coreplugins/chat/static/js/chat-history.js +3 -0
  61. mindroot/coreplugins/chat/static/js/chat.js +59 -16
  62. mindroot/coreplugins/chat/static/js/chat.js.diff +221 -0
  63. mindroot/coreplugins/chat/static/js/chatform.js +2 -2
  64. mindroot/coreplugins/chat/static/site.webmanifest +1 -1
  65. mindroot/coreplugins/chat/templates/chat.jinja2 +3 -3
  66. mindroot/coreplugins/chat/widget_manager.py +139 -0
  67. mindroot/coreplugins/chat/widget_routes.py +287 -0
  68. mindroot/coreplugins/check_list/inject/admin.jinja2 +1 -1
  69. mindroot/coreplugins/email/__init__.py +2 -0
  70. mindroot/coreplugins/email/email_provider.py +2 -2
  71. mindroot/coreplugins/email/mod.py +100 -0
  72. mindroot/coreplugins/email/services.py +5 -3
  73. mindroot/coreplugins/email/smtp_handler.py +9 -3
  74. mindroot/coreplugins/email/test_email_service.py +75 -0
  75. mindroot/coreplugins/env_manager/mod.py +61 -25
  76. mindroot/coreplugins/home/router.py +37 -2
  77. mindroot/coreplugins/home/static/imgs/logo.png +0 -0
  78. mindroot/coreplugins/home/static/imgs/logo.png.bak +0 -0
  79. mindroot/coreplugins/home/static/imgs/logo_teal.png +0 -0
  80. mindroot/coreplugins/home/static/imgs/logo_teal2.png +0 -0
  81. mindroot/coreplugins/home/static/imgs/logo_teal_detailed.png +0 -0
  82. mindroot/coreplugins/home/static/imgs/logo_teal_python.png +0 -0
  83. mindroot/coreplugins/home/templates/home.jinja2 +15 -6
  84. mindroot/coreplugins/index/indices/default/index.json +6 -6
  85. mindroot/coreplugins/jwt_auth/middleware.py +47 -2
  86. mindroot/coreplugins/jwt_auth/mod.py +40 -17
  87. mindroot/coreplugins/l8n/__init__.py +6 -0
  88. mindroot/coreplugins/l8n/debug_loader.py +85 -0
  89. mindroot/coreplugins/l8n/debug_middleware.py +74 -0
  90. mindroot/coreplugins/l8n/l8n_constants.py +19 -0
  91. mindroot/coreplugins/l8n/language_detection.py +183 -0
  92. mindroot/coreplugins/l8n/middleware.py +151 -0
  93. mindroot/coreplugins/l8n/mod.py +277 -0
  94. mindroot/coreplugins/l8n/monkey_patch_to_delete.py +186 -0
  95. mindroot/coreplugins/l8n/test_enhanced.py +298 -0
  96. mindroot/coreplugins/l8n/test_l8n.py +95 -0
  97. mindroot/coreplugins/l8n/test_l8n_standalone.py +251 -0
  98. mindroot/coreplugins/l8n/test_middleware.py +272 -0
  99. mindroot/coreplugins/l8n/utils.py +232 -0
  100. mindroot/coreplugins/mcp_/__init__.py +14 -0
  101. mindroot/coreplugins/mcp_/catalog_commands.py +328 -0
  102. mindroot/coreplugins/mcp_/catalog_manager.py +263 -0
  103. mindroot/coreplugins/mcp_/dynamic_commands.py +154 -0
  104. mindroot/coreplugins/mcp_/mcp_manager.py +1031 -0
  105. mindroot/coreplugins/mcp_/mod.py +367 -0
  106. mindroot/coreplugins/mcp_/oauth_storage.py +144 -0
  107. mindroot/coreplugins/mcp_/server_installer.py +79 -0
  108. mindroot/coreplugins/mcp_/setup.py +26 -0
  109. mindroot/coreplugins/mcp_/test_dynamic_commands.py +134 -0
  110. mindroot/coreplugins/mcp_/testmcpclient.py +92 -0
  111. mindroot/coreplugins/persona/mod.py +12 -7
  112. mindroot/coreplugins/signup/templates/signup.jinja2 +1 -1
  113. mindroot/coreplugins/subscriptions/__init__.py +1 -0
  114. mindroot/coreplugins/subscriptions/mod.py +14 -3
  115. mindroot/coreplugins/subscriptions/router.py +3 -0
  116. mindroot/coreplugins/user_service/__init__.py +1 -2
  117. mindroot/coreplugins/user_service/admin_init.py +1 -0
  118. mindroot/coreplugins/user_service/email_service.py +72 -17
  119. mindroot/coreplugins/user_service/mod.py +10 -2
  120. mindroot/coreplugins/user_service/router.py +2 -0
  121. mindroot/lib/auth/api_key.py +28 -0
  122. mindroot/lib/cli/plugins.py +94 -0
  123. mindroot/lib/plugins/default_plugin_manifest.json +20 -0
  124. mindroot/lib/plugins/installation.py +5 -5
  125. mindroot/lib/plugins/l8n_static_handler.py +225 -0
  126. mindroot/lib/plugins/loader.py +33 -3
  127. mindroot/lib/plugins/loader_with_l8n.py +281 -0
  128. mindroot/lib/plugins/manifest.py +236 -24
  129. mindroot/lib/providers/commands.py +3 -1
  130. mindroot/lib/route_decorators.py +5 -5
  131. mindroot/lib/templates.py +183 -11
  132. mindroot/lib/utils/merge_arrays.py +1 -1
  133. mindroot/migrate.py +39 -20
  134. mindroot/registry/data_access.py +1 -1
  135. mindroot/server.py +42 -13
  136. mindroot/server_missing_normal_args.py +197 -0
  137. mindroot/server_prev.py +173 -0
  138. {mindroot-9.3.0.dist-info → mindroot-9.5.0.dist-info}/METADATA +7 -2
  139. {mindroot-9.3.0.dist-info → mindroot-9.5.0.dist-info}/RECORD +144 -112
  140. mindroot/coreplugins/admin/static/favicon/about.txt +0 -6
  141. mindroot/coreplugins/admin/static/favicon/android-chrome-512x512.png +0 -0
  142. mindroot/coreplugins/admin/static/favicon/apple-touch-icon.png +0 -0
  143. mindroot/coreplugins/admin/static/favicon/favicon-16x16.png +0 -0
  144. mindroot/coreplugins/admin/static/favicon/favicon-32x32.png +0 -0
  145. mindroot/coreplugins/admin/static/favicon/favicon.ico +0 -0
  146. mindroot/coreplugins/admin/static/favicon/favicon_io (1)/about.txt +0 -6
  147. mindroot/coreplugins/admin/static/favicon/favicon_io (1)/android-chrome-192x192.png +0 -0
  148. mindroot/coreplugins/admin/static/favicon/favicon_io (1)/android-chrome-512x512.png +0 -0
  149. mindroot/coreplugins/admin/static/favicon/favicon_io (1)/apple-touch-icon.png +0 -0
  150. mindroot/coreplugins/admin/static/favicon/favicon_io (1)/favicon-16x16.png +0 -0
  151. mindroot/coreplugins/admin/static/favicon/favicon_io (1)/favicon-32x32.png +0 -0
  152. mindroot/coreplugins/admin/static/favicon/favicon_io (1)/favicon.ico +0 -0
  153. mindroot/coreplugins/admin/static/favicon/favicon_io (1)/site.webmanifest +0 -1
  154. mindroot/coreplugins/admin/static/favicon/logo.png +0 -0
  155. mindroot/coreplugins/admin/static/favicon/site.webmanifest +0 -1
  156. mindroot/coreplugins/admin/static/js/backup/agent-editor.js +0 -186
  157. mindroot/coreplugins/admin/static/js/backup/agent-form.js +0 -1133
  158. mindroot/coreplugins/admin/static/js/backup/agent-list.js +0 -94
  159. mindroot/coreplugins/chat/static/favicon/about.txt +0 -6
  160. mindroot/coreplugins/chat/static/favicon/android-chrome-192x192.png +0 -0
  161. mindroot/coreplugins/chat/static/favicon/android-chrome-512x512.png +0 -0
  162. mindroot/coreplugins/chat/static/favicon/apple-touch-icon.png +0 -0
  163. mindroot/coreplugins/chat/static/favicon/favicon-16x16.png +0 -0
  164. mindroot/coreplugins/chat/static/favicon/favicon-32x32.png +0 -0
  165. mindroot/coreplugins/chat/static/favicon/favicon.ico +0 -0
  166. mindroot/coreplugins/chat/static/favicon/favicon_io (1)/about.txt +0 -6
  167. mindroot/coreplugins/chat/static/favicon/favicon_io (1)/android-chrome-192x192.png +0 -0
  168. mindroot/coreplugins/chat/static/favicon/favicon_io (1)/android-chrome-512x512.png +0 -0
  169. mindroot/coreplugins/chat/static/favicon/favicon_io (1)/apple-touch-icon.png +0 -0
  170. mindroot/coreplugins/chat/static/favicon/favicon_io (1)/favicon-16x16.png +0 -0
  171. mindroot/coreplugins/chat/static/favicon/favicon_io (1)/favicon-32x32.png +0 -0
  172. mindroot/coreplugins/chat/static/favicon/favicon_io (1)/favicon.ico +0 -0
  173. mindroot/coreplugins/chat/static/favicon/favicon_io (1)/site.webmanifest +0 -1
  174. mindroot/coreplugins/chat/static/favicon/logo.png +0 -0
  175. mindroot/coreplugins/chat/static/favicon/site.webmanifest +0 -1
  176. mindroot/coreplugins/index/default.json +0 -76
  177. mindroot/coreplugins/user_service/file_trigger_service.py +0 -12
  178. mindroot/coreplugins/user_service/hooks.py +0 -23
  179. /mindroot/coreplugins/{admin/static/favicon/android-chrome-192x192.png → home/static/imgs/backuplogo.png} +0 -0
  180. {mindroot-9.3.0.dist-info → mindroot-9.5.0.dist-info}/WHEEL +0 -0
  181. {mindroot-9.3.0.dist-info → mindroot-9.5.0.dist-info}/entry_points.txt +0 -0
  182. {mindroot-9.3.0.dist-info → mindroot-9.5.0.dist-info}/licenses/LICENSE +0 -0
  183. {mindroot-9.3.0.dist-info → mindroot-9.5.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,263 @@
1
+ import json
2
+ import os
3
+ import psutil
4
+ import subprocess
5
+ from pathlib import Path
6
+ from typing import Dict, List, Optional, Any
7
+
8
+ class MCPCatalogManager:
9
+ """Manages MCP server catalog and process detection"""
10
+
11
+ def __init__(self, plugin_dir: str = None, working_dir: str = None):
12
+ # Default plugin_dir to the directory containing this module
13
+ if plugin_dir is None:
14
+ plugin_dir = Path(__file__).parent.parent.parent
15
+ self.plugin_dir = Path(plugin_dir)
16
+
17
+ # Use process working directory for data files
18
+ if working_dir is None:
19
+ working_dir = os.getcwd()
20
+ self.working_dir = Path(working_dir)
21
+
22
+ self.catalog_file = self.working_dir / "data" / "mcp" / "servers.json"
23
+ self.default_file = Path(__file__).parent / "data" / "default_mcp_servers.json"
24
+ self.ensure_catalog_exists()
25
+
26
+
27
+ def ensure_catalog_exists(self):
28
+ """Ensure catalog file exists, create from default if needed"""
29
+ if not self.catalog_file.exists():
30
+ if self.default_file.exists():
31
+ self.init_catalog_from_default()
32
+ else:
33
+ self.create_empty_catalog()
34
+
35
+ def init_catalog_from_default(self):
36
+ """Initialize catalog from default servers"""
37
+ # Ensure the target directory exists
38
+ self.catalog_file.parent.mkdir(parents=True, exist_ok=True)
39
+
40
+ try:
41
+ with open(self.default_file, 'r') as f:
42
+ default_servers = json.load(f)
43
+
44
+ catalog = {
45
+ "_metadata": {
46
+ "version": "1.0.0",
47
+ "last_updated": "2025-06-02",
48
+ "description": "MCP Server Catalog for MindRoot",
49
+ "categories": ["utilities", "system", "development", "search", "database", "communication", "cloud", "automation", "ai"]
50
+ },
51
+ "servers": {}
52
+ }
53
+
54
+ for name, server in default_servers.items():
55
+ server["status"] = "available"
56
+ server["installed"] = False
57
+ server["running"] = False
58
+ catalog["servers"][name] = server
59
+
60
+ with open(self.catalog_file, 'w') as f:
61
+ json.dump(catalog, f, indent=2)
62
+
63
+ except Exception as e:
64
+ print(f"Error initializing catalog: {e}")
65
+ self.create_empty_catalog()
66
+
67
+ def create_empty_catalog(self):
68
+ """Create empty catalog structure"""
69
+ catalog = {
70
+ "_metadata": {
71
+ "version": "1.0.0",
72
+ "last_updated": "2025-06-02",
73
+ "description": "MCP Server Catalog for MindRoot",
74
+ "categories": []
75
+ },
76
+ "servers": {}
77
+ }
78
+
79
+ self.catalog_file.parent.mkdir(parents=True, exist_ok=True)
80
+ with open(self.catalog_file, 'w') as f:
81
+ json.dump(catalog, f, indent=2)
82
+
83
+ def load_catalog(self) -> Dict[str, Any]:
84
+ """Load the server catalog"""
85
+ try:
86
+ with open(self.catalog_file, 'r') as f:
87
+ return json.load(f)
88
+ except Exception as e:
89
+ print(f"Error loading catalog: {e}")
90
+ return {"_metadata": {}, "servers": {}}
91
+
92
+ def save_catalog(self, catalog: Dict[str, Any]):
93
+ """Save the server catalog"""
94
+ try:
95
+ with open(self.catalog_file, 'w') as f:
96
+ json.dump(catalog, f, indent=2)
97
+ except Exception as e:
98
+ print(f"Error saving catalog: {e}")
99
+
100
+ def get_running_processes(self) -> List[Dict[str, Any]]:
101
+ """Get list of running processes with details"""
102
+ processes = []
103
+ try:
104
+ for proc in psutil.process_iter(['pid', 'name', 'cmdline']):
105
+ try:
106
+ processes.append({
107
+ 'pid': proc.info['pid'],
108
+ 'name': proc.info['name'],
109
+ 'cmdline': proc.info['cmdline'] or []
110
+ })
111
+ except (psutil.NoSuchProcess, psutil.AccessDenied):
112
+ continue
113
+ except Exception as e:
114
+ print(f"Error getting processes: {e}")
115
+
116
+ return processes
117
+
118
+ def detect_running_servers(self) -> Dict[str, bool]:
119
+ """Detect which MCP servers are currently running"""
120
+ catalog = self.load_catalog()
121
+ running_status = {}
122
+ processes = self.get_running_processes()
123
+
124
+ for server_name, server_info in catalog.get("servers", {}).items():
125
+ is_running = False
126
+ process_names = server_info.get("process_names", [])
127
+
128
+ for proc in processes:
129
+ # Check process name
130
+ if proc['name'] in process_names:
131
+ is_running = True
132
+ break
133
+
134
+ # Check command line for MCP server patterns
135
+ cmdline_str = ' '.join(proc['cmdline'])
136
+ for process_name in process_names:
137
+ if process_name in cmdline_str:
138
+ is_running = True
139
+ break
140
+
141
+ # Check for specific patterns
142
+ if server_name in cmdline_str or server_info.get('install_package', '') in cmdline_str:
143
+ is_running = True
144
+ break
145
+
146
+ if is_running:
147
+ break
148
+
149
+ running_status[server_name] = is_running
150
+
151
+ return running_status
152
+
153
+ def update_server_status(self):
154
+ """Update running status for all servers in catalog"""
155
+ catalog = self.load_catalog()
156
+ running_status = self.detect_running_servers()
157
+
158
+ for server_name, is_running in running_status.items():
159
+ if server_name in catalog.get("servers", {}):
160
+ catalog["servers"][server_name]["running"] = is_running
161
+
162
+ self.save_catalog(catalog)
163
+ return catalog
164
+
165
+ def get_servers_by_category(self, category: str = None) -> Dict[str, Any]:
166
+ """Get servers filtered by category"""
167
+ catalog = self.load_catalog()
168
+ servers = catalog.get("servers", {})
169
+
170
+ if category is None:
171
+ return servers
172
+
173
+ filtered = {}
174
+ for name, server in servers.items():
175
+ if server.get("category") == category:
176
+ filtered[name] = server
177
+
178
+ return filtered
179
+
180
+ def get_server_info(self, server_name: str) -> Optional[Dict[str, Any]]:
181
+ """Get detailed info for a specific server"""
182
+ catalog = self.load_catalog()
183
+ return catalog.get("servers", {}).get(server_name)
184
+
185
+ def mark_server_installed(self, server_name: str, installed: bool = True):
186
+ """Mark a server as installed or not"""
187
+ catalog = self.load_catalog()
188
+ if server_name in catalog.get("servers", {}):
189
+ catalog["servers"][server_name]["installed"] = installed
190
+ self.save_catalog(catalog)
191
+
192
+ def add_custom_server(self, server_info: Dict[str, Any]):
193
+ """Add a custom server to the catalog"""
194
+ catalog = self.load_catalog()
195
+ server_name = server_info.get("name")
196
+
197
+ if server_name:
198
+ # Add default fields if missing
199
+ server_info.setdefault("status", "custom")
200
+ server_info.setdefault("installed", False)
201
+ server_info.setdefault("running", False)
202
+ server_info.setdefault("category", "custom")
203
+ server_info.setdefault("tags", [])
204
+
205
+ catalog["servers"][server_name] = server_info
206
+ self.save_catalog(catalog)
207
+ return True
208
+
209
+ return False
210
+
211
+ def remove_server(self, server_name: str):
212
+ """Remove a server from the catalog"""
213
+ catalog = self.load_catalog()
214
+ if server_name in catalog.get("servers", {}):
215
+ del catalog["servers"][server_name]
216
+ self.save_catalog(catalog)
217
+ return True
218
+ return False
219
+
220
+ def search_servers(self, query: str) -> Dict[str, Any]:
221
+ """Search servers by name, description, or tags"""
222
+ catalog = self.load_catalog()
223
+ servers = catalog.get("servers", {})
224
+ results = {}
225
+
226
+ query_lower = query.lower()
227
+
228
+ for name, server in servers.items():
229
+ # Search in name
230
+ if query_lower in name.lower():
231
+ results[name] = server
232
+ continue
233
+
234
+ # Search in display name
235
+ if query_lower in server.get("display_name", "").lower():
236
+ results[name] = server
237
+ continue
238
+
239
+ # Search in description
240
+ if query_lower in server.get("description", "").lower():
241
+ results[name] = server
242
+ continue
243
+
244
+ # Search in tags
245
+ tags = server.get("tags", [])
246
+ if any(query_lower in tag.lower() for tag in tags):
247
+ results[name] = server
248
+ continue
249
+
250
+ return results
251
+
252
+ def get_categories(self) -> List[str]:
253
+ """Get list of all categories"""
254
+ catalog = self.load_catalog()
255
+ categories = set(catalog.get("_metadata", {}).get("categories", []))
256
+
257
+ # Add categories from servers
258
+ for server in catalog.get("servers", {}).values():
259
+ category = server.get("category")
260
+ if category:
261
+ categories.add(category)
262
+
263
+ return sorted(list(categories))
@@ -0,0 +1,154 @@
1
+ from typing import Dict, List, Any
2
+ import json
3
+ import inspect
4
+ from lib.providers.commands import command_manager
5
+
6
+ class MCPDynamicCommands:
7
+ """Handles dynamic registration of MCP tools as MindRoot commands"""
8
+
9
+ def __init__(self):
10
+ self.registered_commands: Dict[str, str] = {} # cmd_name -> server_name
11
+ self.sessions: Dict[str, Any] = {} # Reference to sessions
12
+
13
+ def set_sessions(self, sessions: Dict[str, Any]):
14
+ """Set reference to MCP sessions"""
15
+ self.sessions = sessions
16
+
17
+ async def register_tools(self, server_name: str, tools: List[Any]):
18
+ """Register MCP tools as dynamic MindRoot commands"""
19
+ for tool in tools:
20
+ try:
21
+ tool_name = tool.name
22
+ #cmd_name = f"mcp_{server_name}_{tool_name}"
23
+ cmd_name = "mcp_"+tool_name
24
+
25
+ self.registered_commands[cmd_name] = server_name
26
+
27
+ # Create wrapper function with closure to capture current values
28
+ def create_wrapper(srv_name, tl_name):
29
+ async def mcp_tool_wrapper(*args, context=None, **kwargs):
30
+ if srv_name not in self.sessions:
31
+ return f"MCP server {srv_name} not connected"
32
+
33
+ session = self.sessions[srv_name]
34
+
35
+ # Convert arguments to MCP format
36
+ if len(args) == 1 and isinstance(args[0], dict):
37
+ arguments = args[0]
38
+ elif kwargs:
39
+ # Filter out context from kwargs
40
+ arguments = {k: v for k, v in kwargs.items() if k != 'context'}
41
+ else:
42
+ arguments = {}
43
+
44
+ try:
45
+ result = await session.call_tool(tl_name, arguments)
46
+
47
+ # Extract content from CallToolResult object
48
+ if hasattr(result, 'content'):
49
+ if isinstance(result.content, list) and len(result.content) > 0:
50
+ # Return the text content of the first item
51
+ first_item = result.content[0]
52
+ return first_item.text if hasattr(first_item, 'text') else str(first_item)
53
+ else:
54
+ return str(result.content)
55
+ else:
56
+ return str(result)
57
+ except Exception as e:
58
+ return f"Error calling MCP tool {tl_name}: {str(e)}"
59
+
60
+ return mcp_tool_wrapper
61
+
62
+ wrapper = create_wrapper(server_name, tool_name)
63
+
64
+ # Create docstring with parameter information
65
+ description = getattr(tool, 'description', 'No description available')
66
+
67
+ # Extract parameter schema if available
68
+ param_info = ""
69
+ example_args = {}
70
+
71
+ if hasattr(tool, 'inputSchema') and tool.inputSchema:
72
+ schema = tool.inputSchema
73
+ if isinstance(schema, dict) and 'properties' in schema:
74
+ properties = schema['properties']
75
+ required = schema.get('required', [])
76
+
77
+ param_lines = []
78
+ for param_name, param_def in properties.items():
79
+ param_type = param_def.get('type', 'any')
80
+ param_desc = param_def.get('description', '')
81
+ is_required = param_name in required
82
+ req_text = ' (required)' if is_required else ' (optional)'
83
+ param_lines.append(f" {param_name} ({param_type}){req_text}: {param_desc}")
84
+
85
+ # Create example value based on type
86
+ if param_type == 'string':
87
+ example_args[param_name] = f"example_{param_name}"
88
+ elif param_type == 'number':
89
+ example_args[param_name] = 42
90
+ elif param_type == 'boolean':
91
+ example_args[param_name] = True
92
+ else:
93
+ example_args[param_name] = f"value_for_{param_name}"
94
+
95
+ if param_lines:
96
+ param_info = "\n\nParameters:\n" + "\n".join(param_lines)
97
+
98
+ # Use actual parameter names in example if available
99
+ example_json = json.dumps(example_args, indent=2) if example_args else '{"arg1": "value1"}'
100
+
101
+ docstring = f"""MCP Tool: {tool_name} from {server_name}
102
+
103
+ {description}{param_info}
104
+
105
+ {description}
106
+
107
+ Example:
108
+ {{ "{cmd_name}": {example_json} }}
109
+ """
110
+
111
+ # Register with command manager
112
+ try:
113
+ command_manager.register_function(
114
+ name=cmd_name,
115
+ provider="mcp",
116
+ implementation=wrapper,
117
+ signature=inspect.signature(wrapper),
118
+ docstring=docstring,
119
+ flags=[]
120
+ )
121
+ print(f"Registered MCP command: {cmd_name}")
122
+
123
+ # Verify registration
124
+ if cmd_name in command_manager.functions:
125
+ print(f" ✅ Verified: {cmd_name} is in command manager")
126
+ else:
127
+ print(f" ❌ Warning: {cmd_name} not found in command manager after registration")
128
+ except Exception as e:
129
+ print(f"Error registering {cmd_name}: {e}")
130
+
131
+ except Exception as e:
132
+ print(f"Error processing tool {getattr(tool, 'name', 'unknown')}: {e}")
133
+ continue
134
+
135
+ async def unregister_server_tools(self, server_name: str):
136
+ """Unregister all tools for a server"""
137
+ commands_to_remove = []
138
+ for cmd_name, srv_name in self.registered_commands.items():
139
+ if srv_name == server_name:
140
+ commands_to_remove.append(cmd_name)
141
+
142
+ for cmd_name in commands_to_remove:
143
+ try:
144
+ if cmd_name in command_manager.functions:
145
+ del command_manager.functions[cmd_name]
146
+ del self.registered_commands[cmd_name]
147
+ print(f"Unregistered MCP command: {cmd_name}")
148
+ except Exception as e:
149
+ print(f"Error unregistering {cmd_name}: {e}")
150
+
151
+ def get_registered_commands(self) -> List[str]:
152
+ """Get list of registered command names"""
153
+ return list(self.registered_commands.keys())
154
+