legate 0.1.0

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 (317) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +345 -0
  4. data/bin/legate +13 -0
  5. data/examples/00_quickstart.rb +51 -0
  6. data/examples/01_simple_agent.rb +105 -0
  7. data/examples/02_multi_tool_agent.rb +140 -0
  8. data/examples/03_custom_tool.rb +93 -0
  9. data/examples/04_agent_instructions.rb +84 -0
  10. data/examples/05_state_and_sessions.rb +91 -0
  11. data/examples/06_callbacks.rb +186 -0
  12. data/examples/07_async_jobs.rb +112 -0
  13. data/examples/08_loop_agent.rb +197 -0
  14. data/examples/09_sequential_workflow.rb +40 -0
  15. data/examples/10_parallel_workflow.rb +34 -0
  16. data/examples/11_agent_delegation.rb +24 -0
  17. data/examples/12_http_client_tool.rb +156 -0
  18. data/examples/13_authentication.rb +220 -0
  19. data/examples/14_mcp_client.rb +154 -0
  20. data/examples/15_mcp_server.rb +79 -0
  21. data/examples/16_webhooks.rb +91 -0
  22. data/examples/README_sequential_agents.md +164 -0
  23. data/examples/advanced/auth/cookie_auth_tool.rb +146 -0
  24. data/examples/advanced/auth/custom_auth_flows_example.rb +626 -0
  25. data/examples/advanced/auth/excon_middleware.rb +317 -0
  26. data/examples/advanced/auth/excon_middleware_auth.rb +399 -0
  27. data/examples/advanced/auth/fiber_auth_example.rb +281 -0
  28. data/examples/advanced/auth/fiber_oidc_example.rb +403 -0
  29. data/examples/advanced/auth/httpbin_bearer_tool.rb +159 -0
  30. data/examples/advanced/auth/oauth2_auth.rb +419 -0
  31. data/examples/advanced/auth/oidc_auth.rb +514 -0
  32. data/examples/advanced/auth/openweather_api.rb +251 -0
  33. data/examples/advanced/auth/openweather_tool.rb +153 -0
  34. data/examples/advanced/auth/query_param_middleware_test.rb +138 -0
  35. data/examples/advanced/auth/service_account.rb +135 -0
  36. data/examples/advanced/auth/test_with_httpbin.rb +202 -0
  37. data/examples/advanced/auth/token_lifecycle_example.rb +428 -0
  38. data/examples/advanced/callback_monitoring.rb +679 -0
  39. data/examples/advanced/mas/fixed_delegation_example.rb +191 -0
  40. data/examples/advanced/mas/loop_workflow.rb +28 -0
  41. data/examples/advanced/mas/mock_planner.rb +77 -0
  42. data/examples/advanced/mas/proper_delegation_example.rb +276 -0
  43. data/examples/advanced/mcp/legate_mcp_server_resource_example.rb +182 -0
  44. data/examples/advanced/mcp/mcp_resource_server_example.rb +309 -0
  45. data/examples/advanced/mcp/mcp_server_async.rb +76 -0
  46. data/examples/advanced/mcp/mcp_server_async_tools.rb +122 -0
  47. data/examples/advanced/mcp/mcp_server_legate_agent.rb +95 -0
  48. data/examples/advanced/mcp/mcp_server_rack.rb +89 -0
  49. data/examples/advanced/random_calculator.rb +104 -0
  50. data/examples/advanced/sleep_agent.rb +153 -0
  51. data/examples/advanced/webhooks/webhook_e2e_runner.rb +110 -0
  52. data/examples/advanced/webhooks/webhook_receiver_agent.rb +58 -0
  53. data/examples/advanced/workflows/task_refinement_loop_agent.rb +278 -0
  54. data/examples/advanced/workflows/travel_planner_auto_sequential.rb +444 -0
  55. data/examples/advanced/workflows/travel_planner_parallel.rb +656 -0
  56. data/examples/advanced/workflows/travel_planner_sequential.rb +512 -0
  57. data/examples/tools/oauth2_example.rb +136 -0
  58. data/examples/tools/sleepy_tool.rb +42 -0
  59. data/lib/legate/activity_log.rb +71 -0
  60. data/lib/legate/agent.rb +959 -0
  61. data/lib/legate/agent_code_generator.rb +185 -0
  62. data/lib/legate/agent_definition.rb +812 -0
  63. data/lib/legate/agentic/decision.rb +49 -0
  64. data/lib/legate/agentic/loop.rb +134 -0
  65. data/lib/legate/agentic.rb +5 -0
  66. data/lib/legate/agents/loop_agent.rb +248 -0
  67. data/lib/legate/agents/parallel_agent.rb +163 -0
  68. data/lib/legate/agents/sequential_agent.rb +190 -0
  69. data/lib/legate/agents.rb +14 -0
  70. data/lib/legate/auth/config.rb +148 -0
  71. data/lib/legate/auth/coordinator.rb +218 -0
  72. data/lib/legate/auth/coordinators/oauth2_coordinator.rb +99 -0
  73. data/lib/legate/auth/coordinators/oidc_coordinator.rb +68 -0
  74. data/lib/legate/auth/coordinators/service_account_coordinator.rb +122 -0
  75. data/lib/legate/auth/credential.rb +157 -0
  76. data/lib/legate/auth/encryption.rb +108 -0
  77. data/lib/legate/auth/error.rb +94 -0
  78. data/lib/legate/auth/exchanged_credential.rb +180 -0
  79. data/lib/legate/auth/excon_middleware.rb +285 -0
  80. data/lib/legate/auth/http_client_utils.rb +364 -0
  81. data/lib/legate/auth/manager.rb +531 -0
  82. data/lib/legate/auth/manager_store.rb +394 -0
  83. data/lib/legate/auth/middleware_factory.rb +290 -0
  84. data/lib/legate/auth/runner.rb +279 -0
  85. data/lib/legate/auth/scheme.rb +125 -0
  86. data/lib/legate/auth/schemes/api_key.rb +212 -0
  87. data/lib/legate/auth/schemes/google_service_account.rb +108 -0
  88. data/lib/legate/auth/schemes/http_bearer.rb +98 -0
  89. data/lib/legate/auth/schemes/oauth2.rb +396 -0
  90. data/lib/legate/auth/schemes/openid_connect.rb +346 -0
  91. data/lib/legate/auth/schemes/service_account.rb +388 -0
  92. data/lib/legate/auth/schemes.rb +40 -0
  93. data/lib/legate/auth/token_manager.rb +362 -0
  94. data/lib/legate/auth/token_store.rb +86 -0
  95. data/lib/legate/auth/tool_context_extension.rb +97 -0
  96. data/lib/legate/auth/tool_integration.rb +188 -0
  97. data/lib/legate/auth/url_guard.rb +81 -0
  98. data/lib/legate/auth.rb +453 -0
  99. data/lib/legate/callbacks/callback_context.rb +71 -0
  100. data/lib/legate/cli/agent_commands.rb +950 -0
  101. data/lib/legate/cli/auth_commands.rb +520 -0
  102. data/lib/legate/cli/base_command.rb +24 -0
  103. data/lib/legate/cli/deployment_commands.rb +934 -0
  104. data/lib/legate/cli/output_helper.rb +108 -0
  105. data/lib/legate/cli/session_commands.rb +138 -0
  106. data/lib/legate/cli/skaffold_commands.rb +223 -0
  107. data/lib/legate/cli/tool_commands.rb +261 -0
  108. data/lib/legate/cli/web_commands.rb +182 -0
  109. data/lib/legate/cli.rb +40 -0
  110. data/lib/legate/configuration/webhooks.rb +113 -0
  111. data/lib/legate/configuration.rb +39 -0
  112. data/lib/legate/definition_store.rb +23 -0
  113. data/lib/legate/errors.rb +118 -0
  114. data/lib/legate/event.rb +161 -0
  115. data/lib/legate/gemini_ai_beta_patch.rb +39 -0
  116. data/lib/legate/generators/agent_generator.rb +412 -0
  117. data/lib/legate/generators/code_validator.rb +48 -0
  118. data/lib/legate/generators/legate/install_generator.rb +35 -0
  119. data/lib/legate/generators/legate/templates/create_legate_tables.rb.tt +36 -0
  120. data/lib/legate/generators/legate/templates/initializer.rb +18 -0
  121. data/lib/legate/generators/runtime_tool_loader.rb +76 -0
  122. data/lib/legate/generators/tool_generator.rb +408 -0
  123. data/lib/legate/generators.rb +11 -0
  124. data/lib/legate/global_definition_registry.rb +506 -0
  125. data/lib/legate/global_tool_manager.rb +135 -0
  126. data/lib/legate/llm/adapter.rb +69 -0
  127. data/lib/legate/llm/gemini.rb +172 -0
  128. data/lib/legate/llm/ollama.rb +80 -0
  129. data/lib/legate/llm.rb +34 -0
  130. data/lib/legate/mcp/client.rb +320 -0
  131. data/lib/legate/mcp/connection/sse.rb +292 -0
  132. data/lib/legate/mcp/connection/stdio.rb +273 -0
  133. data/lib/legate/mcp/connection_manager.rb +103 -0
  134. data/lib/legate/mcp/server/legate_agent_adapter.rb +170 -0
  135. data/lib/legate/mcp/server/legate_direct_agent_adapter.rb +140 -0
  136. data/lib/legate/mcp/server/legate_tool_adapter.rb +119 -0
  137. data/lib/legate/mcp/tool_wrapper.rb +138 -0
  138. data/lib/legate/mcp/util/schema_converter.rb +134 -0
  139. data/lib/legate/mcp.rb +23 -0
  140. data/lib/legate/plan_executor.rb +375 -0
  141. data/lib/legate/planner.rb +839 -0
  142. data/lib/legate/rails/railtie.rb +43 -0
  143. data/lib/legate/rails.rb +9 -0
  144. data/lib/legate/redaction.rb +32 -0
  145. data/lib/legate/session.rb +299 -0
  146. data/lib/legate/session_service/active_record.rb +300 -0
  147. data/lib/legate/session_service/base.rb +68 -0
  148. data/lib/legate/session_service/event_broadcast.rb +74 -0
  149. data/lib/legate/session_service/in_memory.rb +188 -0
  150. data/lib/legate/tool/metadata_dsl.rb +122 -0
  151. data/lib/legate/tool.rb +276 -0
  152. data/lib/legate/tool_code_generator.rb +103 -0
  153. data/lib/legate/tool_context.rb +350 -0
  154. data/lib/legate/tool_loader.rb +39 -0
  155. data/lib/legate/tool_registry.rb +73 -0
  156. data/lib/legate/tool_result.rb +61 -0
  157. data/lib/legate/tools/agent_tool.rb +187 -0
  158. data/lib/legate/tools/base/http_client.rb +319 -0
  159. data/lib/legate/tools/base/safe_url.rb +56 -0
  160. data/lib/legate/tools/base_async_job_tool.rb +91 -0
  161. data/lib/legate/tools/calculator.rb +89 -0
  162. data/lib/legate/tools/cat_facts.rb +81 -0
  163. data/lib/legate/tools/check_job_status_tool.rb +48 -0
  164. data/lib/legate/tools/current_time_tool.rb +64 -0
  165. data/lib/legate/tools/echo.rb +43 -0
  166. data/lib/legate/tools/http_request_tool.rb +105 -0
  167. data/lib/legate/tools/random_number_tool.rb +64 -0
  168. data/lib/legate/tools/read_webpage_tool.rb +92 -0
  169. data/lib/legate/tools/sleepy_tool.rb +74 -0
  170. data/lib/legate/tools/webhook_tool.rb +146 -0
  171. data/lib/legate/version.rb +5 -0
  172. data/lib/legate/web/app.rb +984 -0
  173. data/lib/legate/web/public/css/main.css +4980 -0
  174. data/lib/legate/web/public/images/favicon-256.png +0 -0
  175. data/lib/legate/web/public/images/favicon-32.png +0 -0
  176. data/lib/legate/web/public/images/legate-logo-dark.png +0 -0
  177. data/lib/legate/web/public/images/legate-logo-light.png +0 -0
  178. data/lib/legate/web/public/js/legate.js +616 -0
  179. data/lib/legate/web/public/styles/main.scss +4402 -0
  180. data/lib/legate/web/routes/agent_authentication_routes.rb +530 -0
  181. data/lib/legate/web/routes/agent_definition_routes.rb +803 -0
  182. data/lib/legate/web/routes/agent_generator_routes.rb +80 -0
  183. data/lib/legate/web/routes/agent_interaction_routes.rb +734 -0
  184. data/lib/legate/web/routes/agent_runtime_routes.rb +323 -0
  185. data/lib/legate/web/routes/api_routes.rb +56 -0
  186. data/lib/legate/web/routes/authentication_routes.rb +1541 -0
  187. data/lib/legate/web/routes/core_routes.rb +111 -0
  188. data/lib/legate/web/routes/documentation_routes.rb +220 -0
  189. data/lib/legate/web/routes/tool_generator_routes.rb +81 -0
  190. data/lib/legate/web/routes/tools_ui_routes.rb +207 -0
  191. data/lib/legate/web/sass_compiler.rb +73 -0
  192. data/lib/legate/web/views/_active_session_info.slim +25 -0
  193. data/lib/legate/web/views/_activity_list.slim +55 -0
  194. data/lib/legate/web/views/_agent_card.slim +56 -0
  195. data/lib/legate/web/views/_agent_generator_modal.slim +382 -0
  196. data/lib/legate/web/views/_agent_status_controls.slim +71 -0
  197. data/lib/legate/web/views/_agent_tool_table.slim +74 -0
  198. data/lib/legate/web/views/_chat_message.slim +95 -0
  199. data/lib/legate/web/views/_display_agent_configuration.slim +26 -0
  200. data/lib/legate/web/views/_display_agent_description.slim +11 -0
  201. data/lib/legate/web/views/_display_agent_fallback.slim +15 -0
  202. data/lib/legate/web/views/_display_agent_hierarchy.slim +93 -0
  203. data/lib/legate/web/views/_display_agent_instruction.slim +17 -0
  204. data/lib/legate/web/views/_display_agent_mcp.slim +13 -0
  205. data/lib/legate/web/views/_display_agent_model.slim +17 -0
  206. data/lib/legate/web/views/_display_agent_name.slim +42 -0
  207. data/lib/legate/web/views/_display_agent_output_key.slim +26 -0
  208. data/lib/legate/web/views/_display_agent_type.slim +65 -0
  209. data/lib/legate/web/views/_edit_agent_configuration.slim +74 -0
  210. data/lib/legate/web/views/_edit_agent_description.slim +16 -0
  211. data/lib/legate/web/views/_edit_agent_fallback.slim +25 -0
  212. data/lib/legate/web/views/_edit_agent_hierarchy.slim +98 -0
  213. data/lib/legate/web/views/_edit_agent_instruction.slim +49 -0
  214. data/lib/legate/web/views/_edit_agent_mcp.slim +33 -0
  215. data/lib/legate/web/views/_edit_agent_model.slim +23 -0
  216. data/lib/legate/web/views/_edit_agent_output_key.slim +36 -0
  217. data/lib/legate/web/views/_edit_agent_tools.slim +40 -0
  218. data/lib/legate/web/views/_edit_agent_type.slim +67 -0
  219. data/lib/legate/web/views/_session_error.slim +4 -0
  220. data/lib/legate/web/views/_skeleton.slim +69 -0
  221. data/lib/legate/web/views/_tool_card.slim +9 -0
  222. data/lib/legate/web/views/_tool_generator_modal.slim +311 -0
  223. data/lib/legate/web/views/agent.slim +436 -0
  224. data/lib/legate/web/views/agent_auth.slim +562 -0
  225. data/lib/legate/web/views/agents.slim +369 -0
  226. data/lib/legate/web/views/auth.slim +112 -0
  227. data/lib/legate/web/views/auth_credential_detail.slim +327 -0
  228. data/lib/legate/web/views/auth_credentials.slim +261 -0
  229. data/lib/legate/web/views/auth_debug.slim +94 -0
  230. data/lib/legate/web/views/auth_mapping_detail.slim +151 -0
  231. data/lib/legate/web/views/auth_mapping_new.slim +123 -0
  232. data/lib/legate/web/views/auth_mappings.slim +120 -0
  233. data/lib/legate/web/views/auth_scheme_detail.slim +274 -0
  234. data/lib/legate/web/views/auth_schemes.slim +259 -0
  235. data/lib/legate/web/views/auth_test.slim +418 -0
  236. data/lib/legate/web/views/chat.slim +192 -0
  237. data/lib/legate/web/views/docs_index.slim +105 -0
  238. data/lib/legate/web/views/docs_show.slim +105 -0
  239. data/lib/legate/web/views/error_404.slim +5 -0
  240. data/lib/legate/web/views/index.slim +148 -0
  241. data/lib/legate/web/views/layout.slim +144 -0
  242. data/lib/legate/web/views/tool_detail.slim +87 -0
  243. data/lib/legate/web/views/tools.slim +50 -0
  244. data/lib/legate/web/webhook_listener.rb +367 -0
  245. data/lib/legate/web.rb +9 -0
  246. data/lib/legate.rb +220 -0
  247. data/public/docs/advanced/callbacks.md +828 -0
  248. data/public/docs/advanced/mcp_schema_conversion.md +59 -0
  249. data/public/docs/authentication/api_reference/config.md +210 -0
  250. data/public/docs/authentication/api_reference/credential.md +246 -0
  251. data/public/docs/authentication/api_reference/encryption.md +218 -0
  252. data/public/docs/authentication/api_reference/exchanged_credential.md +271 -0
  253. data/public/docs/authentication/api_reference/excon_middleware.md +175 -0
  254. data/public/docs/authentication/api_reference/index.md +30 -0
  255. data/public/docs/authentication/api_reference/scheme.md +250 -0
  256. data/public/docs/authentication/api_reference/schemes/api_key.md +175 -0
  257. data/public/docs/authentication/api_reference/schemes/google_service_account.md +221 -0
  258. data/public/docs/authentication/api_reference/schemes/http_bearer.md +169 -0
  259. data/public/docs/authentication/api_reference/schemes/oauth2.md +343 -0
  260. data/public/docs/authentication/api_reference/schemes/oidc.md +73 -0
  261. data/public/docs/authentication/api_reference/schemes/openid_connect.md +311 -0
  262. data/public/docs/authentication/api_reference/schemes/service_account.md +287 -0
  263. data/public/docs/authentication/api_reference/token_manager.md +221 -0
  264. data/public/docs/authentication/api_reference/token_store.md +146 -0
  265. data/public/docs/authentication/api_reference/tool_context_extension.md +166 -0
  266. data/public/docs/authentication/guides/api_key.md +190 -0
  267. data/public/docs/authentication/guides/bearer.md +172 -0
  268. data/public/docs/authentication/guides/configuration.md +255 -0
  269. data/public/docs/authentication/guides/custom_flow.md +523 -0
  270. data/public/docs/authentication/guides/index.md +24 -0
  271. data/public/docs/authentication/guides/migration.md +435 -0
  272. data/public/docs/authentication/guides/oauth2.md +252 -0
  273. data/public/docs/authentication/guides/oidc.md +241 -0
  274. data/public/docs/authentication/guides/overview.md +155 -0
  275. data/public/docs/authentication/guides/secure_storage.md +301 -0
  276. data/public/docs/authentication/guides/service_account.md +228 -0
  277. data/public/docs/authentication/guides/token_lifecycle.md +295 -0
  278. data/public/docs/authentication/guides/web_ui_integration.md +504 -0
  279. data/public/docs/authentication/index.md +58 -0
  280. data/public/docs/authentication/troubleshooting/credential_storage.md +550 -0
  281. data/public/docs/authentication/troubleshooting/environment_variables.md +540 -0
  282. data/public/docs/authentication/troubleshooting/index.md +11 -0
  283. data/public/docs/authentication/troubleshooting/oauth2_issues.md +220 -0
  284. data/public/docs/authentication/troubleshooting/oidc_issues.md +412 -0
  285. data/public/docs/authentication/troubleshooting/token_refresh.md +338 -0
  286. data/public/docs/cli/legate_cli_usage.md +363 -0
  287. data/public/docs/core_concepts/legate_agent_lifecycle.md +124 -0
  288. data/public/docs/core_concepts/legate_architecture_overview.md +110 -0
  289. data/public/docs/core_concepts/legate_configuration.md +116 -0
  290. data/public/docs/core_concepts/legate_definition_store.md +102 -0
  291. data/public/docs/core_concepts/legate_planner.md +94 -0
  292. data/public/docs/core_concepts/legate_session_service.md +104 -0
  293. data/public/docs/error_handling/legate_error_handling.md +122 -0
  294. data/public/docs/examples.md +199 -0
  295. data/public/docs/getting_started.md +111 -0
  296. data/public/docs/guides/agentic_agents.md +137 -0
  297. data/public/docs/guides/ai_code_generators.md +437 -0
  298. data/public/docs/guides/auto_loading.md +326 -0
  299. data/public/docs/guides/configuring_agent_webhooks.md +219 -0
  300. data/public/docs/guides/http_client_usage.md +264 -0
  301. data/public/docs/guides/llm_providers.md +137 -0
  302. data/public/docs/guides/mcp_client_integration.md +232 -0
  303. data/public/docs/guides/mcp_server_exposure.md +206 -0
  304. data/public/docs/guides/rails_integration.md +128 -0
  305. data/public/docs/guides/sending_outbound_webhooks.md +227 -0
  306. data/public/docs/guides/streaming.md +112 -0
  307. data/public/docs/guides/webhooks.md +288 -0
  308. data/public/docs/introduction.md +51 -0
  309. data/public/docs/multi_agent_systems/advanced_features.md +57 -0
  310. data/public/docs/multi_agent_systems/agent_delegation.md +190 -0
  311. data/public/docs/multi_agent_systems/agent_hierarchy.md +49 -0
  312. data/public/docs/multi_agent_systems/state_management.md +47 -0
  313. data/public/docs/multi_agent_systems/workflow_agents.md +72 -0
  314. data/public/docs/tools/legate_built_in_tools.md +332 -0
  315. data/public/docs/tools/legate_tools_and_registry.md +263 -0
  316. data/public/docs/web_ui/legate_web_ui.md +137 -0
  317. metadata +823 -0
@@ -0,0 +1,182 @@
1
+ # File: ./examples/advanced/mcp/legate_mcp_server_resource_example.rb
2
+ # !/usr/bin/env ruby
3
+ # frozen_string_literal: true
4
+
5
+ # --- Example: Exposing a multi-tool Legate Agent via MCP ---
6
+ # -------------------------------------------------------------
7
+
8
+ ENV['LEGATE_LOG_LEVEL'] = 'ERROR'
9
+ ENV['LEGATE_LOG_TARGET'] = 'STDERR'
10
+
11
+ $LOAD_PATH.unshift File.expand_path('../../lib', __dir__)
12
+ require 'legate'
13
+ Legate.load_environment # Handle Bundler, Dotenv, etc.
14
+ require 'fast_mcp'
15
+ # require 'thread' # No longer needed
16
+ # require 'json' # No longer needed
17
+ # require 'singleton' # No longer needed
18
+ require 'logger'
19
+ require 'securerandom'
20
+ require 'net/http' # Needed for CatFactResource
21
+ require 'uri' # Needed for CatFactResource
22
+
23
+ # Load the necessary Legate MCP components
24
+ require 'legate/mcp'
25
+ require 'legate/mcp/server/legate_direct_agent_adapter'
26
+
27
+ # Load Legate components for direct agent instantiation
28
+ require 'legate/agent'
29
+ require 'legate/session_service/in_memory'
30
+
31
+ # --- Load ALL required Legate Tool Classes ---
32
+ require 'legate/tools/calculator'
33
+ require 'legate/tools/agent_tool'
34
+ require 'legate/tools/random_number_tool'
35
+ require 'legate/tools/sleepy_tool'
36
+ require 'legate/tools/cat_facts'
37
+ require 'legate/tools/check_job_status_tool'
38
+ require 'legate/tools/echo'
39
+ # ------------------------------------------
40
+
41
+ # === FastMcp Components Setup ===
42
+
43
+ # --- NEW: Define MCP Resources based on Legate Tool functionality ---
44
+
45
+ # 1. Random Number Resource
46
+ class RandomNumberResource < FastMcp::Resource
47
+ include Singleton
48
+ uri 'random_number'
49
+ resource_name 'RandomNumber'
50
+ description 'Provides a random floating-point number between 0 and 1.'
51
+ mime_type 'application/json'
52
+
53
+ def read
54
+ # Generate a new random number on each read
55
+ { value: rand }
56
+ end
57
+
58
+ def content
59
+ JSON.generate(read)
60
+ end
61
+ end
62
+
63
+ # 2. Cat Fact Resource
64
+ class CatFactResource < FastMcp::Resource
65
+ include Singleton
66
+ uri 'catfact'
67
+ resource_name 'CurrentCatFact'
68
+ description 'Provides a random cat fact from catfact.ninja.'
69
+ mime_type 'application/json'
70
+
71
+ CATFACT_API_URI = URI('https://catfact.ninja/fact')
72
+
73
+ def read
74
+ # Fetch a new fact on each read
75
+ response = Net::HTTP.get_response(CATFACT_API_URI)
76
+ if response.is_a?(Net::HTTPSuccess)
77
+ data = JSON.parse(response.body)
78
+ { fact: data['fact'] || 'Could not retrieve fact.' }
79
+ else
80
+ Legate.logger.error("CatFactResource: Failed to fetch cat fact. Status: #{response.code}")
81
+ { fact: "Error fetching fact: #{response.code}" }
82
+ end
83
+ rescue StandardError => e
84
+ Legate.logger.error("CatFactResource: Error fetching cat fact: #{e.message}")
85
+ { fact: "Error fetching fact: #{e.message}" }
86
+ end
87
+
88
+ def content
89
+ JSON.generate(read)
90
+ end
91
+ end
92
+
93
+ # --- NEW: Define MCP Tools to explicitly interact with the new Resources ---
94
+
95
+ class GetNewRandomNumberTool < FastMcp::Tool
96
+ description 'Gets a new random number from the RandomNumber resource.'
97
+ tool_name 'getrandomnumber'
98
+ arguments {}
99
+ def call(**_args)
100
+ # Access the singleton instance and read its current state
101
+ RandomNumberResource.instance.read[:value]
102
+ end
103
+ end
104
+
105
+ class GetNewCatFactTool < FastMcp::Tool
106
+ description 'Gets a new cat fact from the CatFact resource.'
107
+ tool_name 'getcatfact'
108
+ arguments {}
109
+ def call(**_args)
110
+ # Access the singleton instance and trigger a read
111
+ CatFactResource.instance.read[:fact]
112
+ end
113
+ end
114
+
115
+ # --- 1. Instantiate Master Legate Agent and Wrap it ---
116
+ begin
117
+ # List all the tool CLASSES to be given to the agent
118
+ all_tool_classes = [
119
+ Legate::Tools::Calculator,
120
+ Legate::Tools::AgentTool,
121
+ Legate::Tools::RandomNumberTool,
122
+ Legate::Tools::SleepyTool,
123
+ Legate::Tools::CatFacts,
124
+ Legate::Tools::CheckJobStatusTool,
125
+ Legate::Tools::Echo,
126
+ GetNewRandomNumberTool,
127
+ GetNewCatFactTool
128
+ ]
129
+
130
+ # Create the Legate::Agent instance with all tools
131
+ master_agent = Legate::Agent.new(
132
+ name: 'master_agent',
133
+ description: 'An agent with access to all built-in Legate tools.',
134
+ model_name: 'gemini-3.5-flash',
135
+ tool_classes: all_tool_classes
136
+ )
137
+
138
+ # Create a session service instance
139
+ session_service = Legate::SessionService::InMemory.new
140
+
141
+ # Use the direct adapter to wrap the master agent instance
142
+ AdaptedMasterAgentTool = Legate::Mcp::Server::LegateDirectAgentAdapter.wrap(master_agent, session_service)
143
+ rescue StandardError => e
144
+ warn "Error setting up Legate Master Agent or Adapter: #{e.message}"
145
+ warn e.backtrace.join("\n")
146
+ exit(1)
147
+ end
148
+ # === End FastMcp Components Setup ===
149
+
150
+ # === Setup and Start the MCP Server ===
151
+
152
+ mcp_server = FastMcp::Server.new(
153
+ name: 'Legate Master Agent Server', # Updated server name
154
+ version: Legate::VERSION
155
+ )
156
+
157
+ # Register the new Resources
158
+ mcp_server.register_resource(RandomNumberResource)
159
+ mcp_server.register_resource(CatFactResource)
160
+
161
+ # Register the Tools (Master Agent + Resource-specific tools)
162
+ mcp_server.register_tools(
163
+ AdaptedMasterAgentTool,
164
+ GetNewRandomNumberTool,
165
+ GetNewCatFactTool
166
+ )
167
+
168
+ # Start the server using STDIO transport
169
+ warn '--- Starting Legate Master Agent MCP Server (STDIO) ---'
170
+ warn "Resources: #{[RandomNumberResource.uri, CatFactResource.uri].join(', ')}"
171
+ warn "Tools Available: #{[AdaptedMasterAgentTool.tool_name, GetNewRandomNumberTool.tool_name,
172
+ GetNewCatFactTool.tool_name].join(', ')}"
173
+ warn 'Waiting for MCP client requests on STDIN...'
174
+ begin
175
+ mcp_server.start
176
+ rescue Interrupt
177
+ rescue StandardError => e
178
+ warn "MCP server crashed: #{e.class} - #{e.message}"
179
+ warn e.backtrace.join("\n")
180
+ ensure
181
+ warn "\n--- Legate Master Agent MCP Server Stopped ---"
182
+ end
@@ -0,0 +1,309 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # --- Usage ---
5
+ # 1. Run this script from your project root:
6
+ # bundle exec ruby examples/advanced/mcp/mcp_resource_server_example.rb
7
+ #
8
+ # 2. In another terminal, inspect using mcp-inspector:
9
+ # npx mcp-inspector --stdio 'bundle exec ruby examples/advanced/mcp/mcp_resource_server_example.rb'
10
+ #
11
+ # 3. Example inspector commands:
12
+ # > resources/list
13
+ # > resources/read {"uri": "counter"}
14
+ # > tools/list # Should show counter tools AND run_calculator_agent
15
+ # > tools/call {"name": "run_calculator_agent", "arguments": {"prompt": "What is 5 * 8?"}}
16
+ # > tools/call {"name": "run_calculator_agent", "arguments": {"prompt": "Add 100 and 23"}}
17
+ # > tools/call {"name": "incrementcounter", "arguments": {}}
18
+ # -------------------------------------------------------------
19
+
20
+ # --- IMPORTANT: Configure Legate logging for MCP compatibility ---
21
+ # Configure ENV variables before requiring Legate to control logging
22
+ ENV['LEGATE_LOG_LEVEL'] = 'ERROR' # Set high level to minimize Legate output
23
+ ENV['LEGATE_LOG_TARGET'] = 'STDERR' # Redirect Legate logs to STDERR
24
+
25
+ # Now load the libraries
26
+ $LOAD_PATH.unshift File.expand_path('../../lib', __dir__)
27
+ require 'legate'
28
+ Legate.load_environment # Handle Bundler, Dotenv, etc.
29
+ require 'fast_mcp' # Load the fast-mcp library
30
+ require 'json' # Needed for JSON generation in #content
31
+ require 'singleton' # Needed for Singleton pattern
32
+ require 'logger' # For Logger constant access
33
+ # ---------------------------------------------
34
+
35
+ # === Legate Components Setup ===
36
+
37
+ # 1. Define the Legate Agent that uses the Calculator
38
+ calculator_agent = Legate::Agent.new(
39
+ name: 'calculator_agent_instance', # Runtime instance name
40
+ description: 'An agent that can perform calculations.',
41
+ model_name: 'gemini-test-model', # Specify a model (even if dummy for this example)
42
+ tool_classes: [Legate::Tools::Calculator] # Provide the CLASS
43
+ )
44
+ # Start the agent runtime (needed for run_task)
45
+ calculator_agent.start
46
+
47
+ # 2. Create a Session Service for the Agent
48
+ # Using InMemory for this self-contained example
49
+ session_service = Legate::SessionService::InMemory.new
50
+
51
+ # === End Legate Components Setup ===
52
+
53
+ # === FastMcp Components Setup ===
54
+
55
+ # --- 1. Define the Counter Resource ---
56
+ class CounterResource < FastMcp::Resource
57
+ include Singleton # Use Singleton pattern
58
+
59
+ # --- Define metadata via class methods ---
60
+ def self.uri
61
+ 'counter'
62
+ end
63
+
64
+ def self.resource_name
65
+ 'Counter' # Changed back to capitalized as per original example convention
66
+ end
67
+
68
+ def self.description
69
+ 'A simple counter resource'
70
+ end
71
+
72
+ def self.mime_type
73
+ 'application/json'
74
+ end
75
+ # --- End metadata via class methods ---
76
+
77
+ attr_reader :count
78
+
79
+ def initialize # Singleton's initialize
80
+ # Removed super call
81
+ @count = 0
82
+ @lock = Mutex.new
83
+ end
84
+
85
+ def read; @lock.synchronize { { value: @count } }; end
86
+ def content; JSON.generate(read); end
87
+
88
+ def increment
89
+ new_value = nil
90
+ @lock.synchronize {
91
+ @count += 1
92
+ new_value = @count
93
+ }
94
+ notify_change # Moved here
95
+ new_value
96
+ end
97
+
98
+ def decrement
99
+ new_value = nil
100
+ @lock.synchronize {
101
+ @count -= 1
102
+ new_value = @count
103
+ }
104
+ notify_change # Moved here
105
+ new_value
106
+ end
107
+
108
+ def get_value; @lock.synchronize { @count }; end
109
+ end
110
+
111
+ # --- 2. Define Counter Tools ---
112
+ class IncrementCounterTool < FastMcp::Tool
113
+ # --- Define metadata via class methods ---
114
+ def self.tool_name
115
+ 'incrementcounter'
116
+ end
117
+
118
+ def self.description
119
+ 'Increments the counter resource by 1'
120
+ end
121
+ # --- End metadata via class methods ---
122
+
123
+ # Server accessor needed by FastMcp for notify_change
124
+ attr_accessor :server
125
+
126
+ arguments {} # Define arguments block
127
+ def call(**_args)
128
+ counter = CounterResource.instance
129
+ new_value = counter.increment # Resource handles notify_change
130
+ "Counter incremented. New value: #{new_value}"
131
+ end
132
+ end
133
+
134
+ class DecrementCounterTool < FastMcp::Tool
135
+ # --- Define metadata via class methods ---
136
+ def self.tool_name
137
+ 'decrementcounter'
138
+ end
139
+
140
+ def self.description
141
+ 'Decrements the counter resource by 1'
142
+ end
143
+ # --- End metadata via class methods ---
144
+
145
+ # Server accessor needed by FastMcp for notify_change
146
+ attr_accessor :server
147
+
148
+ arguments {} # Define arguments block
149
+ def call(**_args)
150
+ counter = CounterResource.instance
151
+ new_value = counter.decrement # Resource handles notify_change
152
+ "Counter decremented. New value: #{new_value}"
153
+ end
154
+ end
155
+
156
+ class GetCounterTool < FastMcp::Tool
157
+ # --- Define metadata via class methods ---
158
+ def self.tool_name
159
+ 'getcounter'
160
+ end
161
+
162
+ def self.description
163
+ 'Gets the current value of the counter resource'
164
+ end
165
+ # --- End metadata via class methods ---
166
+
167
+ # Server accessor needed by FastMcp
168
+ attr_accessor :server
169
+
170
+ arguments {} # Define arguments block
171
+ def call(**_args)
172
+ counter = CounterResource.instance
173
+ counter.get_value
174
+ end
175
+ end
176
+
177
+ # --- 3. Define the Legate Agent Adapter Tool ---
178
+ class InlineAgentToolAdapter < FastMcp::Tool
179
+ # --- Define metadata via class methods ---
180
+ def self.tool_name
181
+ 'run_calculator_agent'
182
+ end
183
+
184
+ def self.description
185
+ 'Runs the internal Legate Calculator Agent with the given prompt.'
186
+ end
187
+ # --- End metadata via class methods ---
188
+
189
+ # Server accessor needed by FastMcp
190
+ attr_accessor :server
191
+
192
+ # --- Define arguments using DSL block ---
193
+ arguments do
194
+ required(:prompt).filled(:string).description('The user input/prompt for the agent')
195
+ end
196
+ # --- End arguments block ---
197
+
198
+ # --- Use class variables for dependencies (workaround for class-based registration) ---
199
+ @@agent = nil
200
+ @@session_service = nil
201
+
202
+ # Class method to set up the references needed *before* registration
203
+ def self.setup(agent, session_service)
204
+ @@agent = agent
205
+ @@session_service = session_service
206
+ end
207
+ # --- End class variables setup ---
208
+
209
+ # No instance initialize needed if dependencies are class-level
210
+
211
+ def call(prompt:)
212
+ # Make sure dependencies are set up via the class method
213
+ raise 'Agent not configured via InlineAgentToolAdapter.setup' unless @@agent
214
+ raise 'Session service not configured via InlineAgentToolAdapter.setup' unless @@session_service
215
+
216
+ temp_session = nil
217
+ # Legate logs are silenced via ENV var setup
218
+
219
+ begin
220
+ temp_session = @@session_service.create_session(
221
+ app_name: @@agent.name, # Use agent name from class variable
222
+ user_id: "mcp_inline_#{SecureRandom.hex(4)}"
223
+ )
224
+
225
+ final_event = @@agent.run_task( # Use agent from class variable
226
+ session_id: temp_session.id,
227
+ user_input: prompt,
228
+ session_service: @@session_service # Use service from class variable
229
+ )
230
+
231
+ raise StandardError, "Agent task finished with unexpected event format: #{final_event.inspect}" unless final_event.is_a?(Legate::Event) && final_event.role == :agent && final_event.content.is_a?(Hash)
232
+
233
+ result_content = final_event.content
234
+
235
+ case result_content[:status]
236
+ when :success
237
+ result_content[:result]
238
+ when :error
239
+ err_msg = result_content[:error_message] || 'Agent execution failed.'
240
+ raise StandardError, "Agent Error: #{err_msg}"
241
+ when :pending
242
+ job_id = result_content[:job_id]
243
+ msg = result_content[:message] || 'Agent task resulted in a pending job.'
244
+ { status: 'pending', job_id: job_id, message: msg }
245
+ else
246
+ raise StandardError, "Agent task finished with unknown status: #{result_content[:status]}"
247
+ end
248
+ rescue StandardError => e
249
+ # Log error to STDERR since Legate logger might be fully silenced
250
+ warn "InlineAgentToolAdapter Error during call: #{e.class} - #{e.message}"
251
+ warn e.backtrace.first(5).join("\n")
252
+ raise # Re-raise the error for fast-mcp to handle
253
+ ensure
254
+ if temp_session && @@session_service
255
+ begin
256
+ @@session_service.delete_session(session_id: temp_session.id)
257
+ rescue StandardError => e
258
+ # Log deletion error to STDERR
259
+ warn "InlineAgentToolAdapter: Error deleting temp session #{temp_session.id}: #{e.message}"
260
+ end
261
+ end
262
+ end
263
+ end
264
+ end
265
+ # --- End Legate Agent Adapter Tool ---
266
+
267
+ # === Setup and Start the MCP Server ===
268
+
269
+ # --- Configure the adapter class BEFORE registration ---
270
+ InlineAgentToolAdapter.setup(calculator_agent, session_service)
271
+ # --- END Configure Adapter ---
272
+
273
+ # --- Create server without logger (following sample) ---
274
+ mcp_server = FastMcp::Server.new(
275
+ name: 'Legate Combined Example Server',
276
+ version: Legate::VERSION
277
+ )
278
+ # --- END ---
279
+
280
+ # Register the resource class
281
+ mcp_server.register_resource(CounterResource)
282
+
283
+ # --- Register TOOL CLASSES ---
284
+ mcp_server.register_tools(
285
+ IncrementCounterTool,
286
+ DecrementCounterTool,
287
+ GetCounterTool,
288
+ InlineAgentToolAdapter # Register the adapter class
289
+ )
290
+ # --- END Registration ---
291
+
292
+ # Start the server (defaults to STDIO transport)
293
+ # Output status messages to STDERR so they don't interfere with STDOUT protocol
294
+ warn '--- Starting Legate Combined MCP Server (STDIO) ---'
295
+ warn 'Resource: counter'
296
+ warn 'Tools: incrementcounter, decrementcounter, getcounter, run_calculator_agent'
297
+ warn 'Waiting for MCP client requests on STDIN...'
298
+ begin
299
+ mcp_server.start # This uses STDIO by default
300
+ rescue Interrupt
301
+ # Expected on Ctrl+C
302
+ rescue StandardError => e
303
+ warn "MCP server crashed: #{e.class} - #{e.message}"
304
+ warn e.backtrace.join("\n")
305
+ ensure
306
+ warn "\n--- Legate Combined MCP Server Stopped ---"
307
+ # Ensure the Legate agent runtime is stopped on exit
308
+ calculator_agent.stop if calculator_agent&.running?
309
+ end
@@ -0,0 +1,76 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # --- Configure Logging First! ---
5
+ # Set log level and target *before* requiring Legate to ensure logger initializes correctly.
6
+ ENV['LEGATE_LOG_LEVEL'] = 'ERROR' # Or INFO/DEBUG for more verbose output
7
+ ENV['LEGATE_LOG_TARGET'] = 'STDERR' # Send logs to STDERR to avoid interfering with MCP STDOUT communication
8
+ # -------------------------------
9
+
10
+ # Example: Exposing Async Legate Tools via MCP using fast-mcp
11
+ #
12
+ # This example demonstrates how to wrap an asynchronous Legate tool (like SleepyTool)
13
+ # and the necessary Legate::Tools::CheckJobStatusTool using the LegateToolAdapter
14
+ # so they can be called by an MCP client.
15
+ #
16
+ # Requires:
17
+ # - legate gem with MCP support installed
18
+ # - fast-mcp gem installed
19
+ #
20
+ # To Run:
21
+ # 1. Execute this script: `bundle exec ruby examples/advanced/mcp/mcp_server_async.rb`
22
+ # 2. In another terminal, use mcp-inspector: `npx @modelcontextprotocol/inspector examples/advanced/mcp/mcp_server_async.rb`
23
+ # 3. In the inspector:
24
+ # - Call 'start_sleepy_job' (tool name from SleepyTool metadata) with duration (e.g., 5 seconds).
25
+ # - Observe the pending response with a job_id.
26
+ # - Call 'check_job_status' with the received job_id.
27
+ # - Check status repeatedly until it shows success or error.
28
+
29
+ $LOAD_PATH.unshift File.expand_path('../../lib', __dir__)
30
+ require 'legate'
31
+ Legate.load_environment # Handle Bundler, Dotenv, etc.
32
+ require 'fast_mcp' # Load fast-mcp gem
33
+
34
+ # Ensure required Legate components are loaded
35
+ require 'legate/tools/base_async_job_tool'
36
+ require 'legate/tools/sleepy_tool' # Example async tool
37
+ require 'legate/tools/check_job_status_tool' # Tool to check job status
38
+ require 'legate/mcp/server/legate_tool_adapter' # The adapter itself
39
+
40
+ # --- Create the FastMcp Server Instance ---
41
+ Legate.logger.info('Creating fast-mcp server...')
42
+ # Use the logger from Legate for consistency
43
+ mcp_server = FastMcp::Server.new(name: 'legate-async-mcp-server', version: '1.0.0')
44
+
45
+ # --- Wrap the Legate Tools using the Adapter ---
46
+ Legate.logger.info('Wrapping Legate tools for MCP...')
47
+
48
+ begin
49
+ # Wrap the asynchronous tool (SleepyTool)
50
+ wrapped_sleepy_tool = Legate::Mcp::Server::LegateToolAdapter.wrap(Legate::Tools::SleepyTool)
51
+ Legate.logger.info("Wrapped SleepyTool as: #{wrapped_sleepy_tool.tool_name}")
52
+
53
+ # Wrap the CheckJobStatusTool
54
+ wrapped_check_job_tool = Legate::Mcp::Server::LegateToolAdapter.wrap(Legate::Tools::CheckJobStatusTool)
55
+ Legate.logger.info("Wrapped CheckJobStatusTool as: #{wrapped_check_job_tool.tool_name}")
56
+
57
+ # --- Register Wrapped Tools with the FastMcp Server ---
58
+ Legate.logger.info('Registering wrapped tools with fast-mcp server...')
59
+ mcp_server.register_tool(wrapped_sleepy_tool)
60
+ mcp_server.register_tool(wrapped_check_job_tool)
61
+ rescue ArgumentError => e
62
+ Legate.logger.fatal("Failed to wrap Legate tools: #{e.message}")
63
+ Legate.logger.fatal('Ensure the Legate::Tool classes have complete metadata.')
64
+ exit(1)
65
+ rescue StandardError => e
66
+ Legate.logger.fatal("An unexpected error occurred during setup: #{e.message}")
67
+ Legate.logger.fatal(e.backtrace.join("\n"))
68
+ exit(1)
69
+ end
70
+
71
+ # --- Start the Server (using STDIO transport) ---
72
+ Legate.logger.info('Starting fast-mcp server with STDIO transport...')
73
+ # This will block and listen for JSON-RPC messages on STDIN/STDOUT
74
+ mcp_server.start
75
+
76
+ Legate.logger.info('Server finished.')
@@ -0,0 +1,122 @@
1
+ # File: examples/advanced/mcp/mcp_server_async_tools.rb
2
+ # frozen_string_literal: true
3
+
4
+ # --- Example: MCP Server with Async Legate Tools ---
5
+ #
6
+ # This script demonstrates how to expose both async tools and the
7
+ # CheckJobStatusTool via MCP. It shows:
8
+ # 1. How to wrap async tools for MCP exposure
9
+ # 2. How to expose the CheckJobStatusTool
10
+ # 3. How to use both tools together via MCP
11
+ #
12
+ # Prerequisites:
13
+ # - Run `bundle install` to install dependencies
14
+ # - Run this script: bundle exec ruby examples/advanced/mcp/mcp_server_async_tools.rb
15
+ #
16
+ # Example MCP client interactions:
17
+ # Initialize server:
18
+ # {"jsonrpc": "2.0", "method": "initialize", "params": {}, "id": 1}
19
+ #
20
+ # List tools:
21
+ # {"jsonrpc": "2.0", "method": "listTools", "params": {}, "id": 2}
22
+ #
23
+ # Call SleepyTool:
24
+ # {"jsonrpc": "2.0", "method": "callTool", "params": {"name": "sleepy_tool", "parameters": {"duration": 5}}, "id": 3}
25
+ #
26
+ # Check job status:
27
+ # {"jsonrpc": "2.0", "method": "callTool", "params": {"name": "check_job_status", "parameters": {"job_id": "job_id_from_sleepy_tool"}}, "id": 4}
28
+ #
29
+ # -------------------------------------------------------------
30
+
31
+ $LOAD_PATH.unshift File.expand_path('../../lib', __dir__)
32
+ require 'legate'
33
+ Legate.load_environment # Handle Bundler, Dotenv, etc.
34
+
35
+ require 'legate'
36
+ require 'legate/mcp'
37
+ require 'fast_mcp'
38
+ require 'legate/tools/sleepy_tool'
39
+ require 'legate/tools/check_job_status_tool'
40
+
41
+ # Configure Legate logger
42
+ Legate.logger.level = Logger::INFO
43
+
44
+ # Create and register the SleepyTool
45
+ class SleepyToolWrapper < FastMcp::Tool
46
+ description 'Sleep for a specified duration'
47
+
48
+ arguments do
49
+ required(:duration).filled(:integer, gt?: 0).description('Duration to sleep in seconds')
50
+ required(:message).filled(:string).description('A message to include in the final result')
51
+ end
52
+
53
+ def call(args)
54
+ tool = Legate::Tools::SleepyTool.new
55
+ context = Legate::ToolContext.new(
56
+ session_id: 'mcp-session',
57
+ user_id: 'mcp-user',
58
+ app_name: 'mcp-server',
59
+ tool_registry: Legate::ToolRegistry.new
60
+ )
61
+ result = tool.execute({ duration: args[:duration], message: args[:message] }, context)
62
+
63
+ case result[:status]
64
+ when :success
65
+ result[:result]
66
+ when :pending
67
+ {
68
+ status: 'pending',
69
+ job_id: result[:job_id],
70
+ message: "Sleepy job started with duration #{args[:duration]}s and message: #{args[:message]}"
71
+ }
72
+ when :error
73
+ raise StandardError, result[:error_message]
74
+ end
75
+ end
76
+ end
77
+
78
+ # Create and register the CheckJobStatusTool
79
+ class CheckJobStatusToolWrapper < FastMcp::Tool
80
+ description 'Check the status of a background job'
81
+
82
+ arguments do
83
+ required(:job_id).filled(:string, min_size?: 1).description('The ID of the job to check')
84
+ end
85
+
86
+ def call(args)
87
+ tool = Legate::Tools::CheckJobStatusTool.new
88
+ context = Legate::ToolContext.new(
89
+ session_id: 'mcp-session',
90
+ user_id: 'mcp-user',
91
+ app_name: 'mcp-server',
92
+ tool_registry: Legate::ToolRegistry.new
93
+ )
94
+ result = tool.execute({ job_id: args[:job_id] }, context)
95
+
96
+ case result[:status]
97
+ when :success
98
+ result[:result]
99
+ when :pending
100
+ { status: 'pending', job_id: args[:job_id], message: result[:message] }
101
+ when :error
102
+ raise StandardError, result[:error_message]
103
+ end
104
+ end
105
+ end
106
+
107
+ # Register the tools with the server
108
+ server = FastMcp::Server.new(
109
+ name: 'async-tools',
110
+ version: '1.0.0'
111
+ )
112
+
113
+ server.register_tool(SleepyToolWrapper)
114
+ server.register_tool(CheckJobStatusToolWrapper)
115
+
116
+ # Start the server
117
+ Legate.logger.info('Starting MCP server with async tools...')
118
+ begin
119
+ server.start
120
+ rescue Interrupt
121
+ Legate.logger.info('Shutting down MCP server...')
122
+ end