sunholo 0.144.0__tar.gz → 0.144.2__tar.gz

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 (204) hide show
  1. {sunholo-0.144.0/src/sunholo.egg-info → sunholo-0.144.2}/PKG-INFO +1 -1
  2. {sunholo-0.144.0 → sunholo-0.144.2}/pyproject.toml +1 -1
  3. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/agents/fastapi/vac_routes.py +403 -138
  4. sunholo-0.144.2/src/sunholo/mcp/extensible_mcp_server.py +271 -0
  5. sunholo-0.144.2/src/sunholo/mcp/vac_mcp_server_fastmcp.py +130 -0
  6. sunholo-0.144.2/src/sunholo/mcp/vac_tools.py +249 -0
  7. {sunholo-0.144.0 → sunholo-0.144.2/src/sunholo.egg-info}/PKG-INFO +1 -1
  8. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo.egg-info/SOURCES.txt +2 -0
  9. sunholo-0.144.0/src/sunholo/mcp/vac_mcp_server_fastmcp.py +0 -193
  10. {sunholo-0.144.0 → sunholo-0.144.2}/LICENSE.txt +0 -0
  11. {sunholo-0.144.0 → sunholo-0.144.2}/MANIFEST.in +0 -0
  12. {sunholo-0.144.0 → sunholo-0.144.2}/README.md +0 -0
  13. {sunholo-0.144.0 → sunholo-0.144.2}/setup.cfg +0 -0
  14. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/__init__.py +0 -0
  15. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/a2a/__init__.py +0 -0
  16. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/a2a/agent_card.py +0 -0
  17. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/a2a/task_manager.py +0 -0
  18. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/a2a/vac_a2a_agent.py +0 -0
  19. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/agents/__init__.py +0 -0
  20. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/agents/chat_history.py +0 -0
  21. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/agents/dispatch_to_qa.py +0 -0
  22. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/agents/fastapi/__init__.py +0 -0
  23. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/agents/fastapi/base.py +0 -0
  24. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/agents/fastapi/qna_routes.py +0 -0
  25. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/agents/flask/__init__.py +0 -0
  26. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/agents/flask/base.py +0 -0
  27. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/agents/flask/vac_routes.py +0 -0
  28. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/agents/langserve.py +0 -0
  29. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/agents/pubsub.py +0 -0
  30. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/agents/route.py +0 -0
  31. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/agents/special_commands.py +0 -0
  32. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/agents/swagger.py +0 -0
  33. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/archive/__init__.py +0 -0
  34. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/archive/archive.py +0 -0
  35. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/auth/__init__.py +0 -0
  36. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/auth/gcloud.py +0 -0
  37. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/auth/refresh.py +0 -0
  38. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/auth/run.py +0 -0
  39. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/azure/__init__.py +0 -0
  40. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/azure/auth.py +0 -0
  41. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/azure/blobs.py +0 -0
  42. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/azure/event_grid.py +0 -0
  43. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/bots/__init__.py +0 -0
  44. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/bots/discord.py +0 -0
  45. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/bots/github_webhook.py +0 -0
  46. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/bots/webapp.py +0 -0
  47. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/chunker/__init__.py +0 -0
  48. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/chunker/azure.py +0 -0
  49. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/chunker/doc_handling.py +0 -0
  50. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/chunker/encode_metadata.py +0 -0
  51. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/chunker/images.py +0 -0
  52. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/chunker/loaders.py +0 -0
  53. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/chunker/message_data.py +0 -0
  54. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/chunker/pdfs.py +0 -0
  55. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/chunker/process_chunker_data.py +0 -0
  56. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/chunker/publish.py +0 -0
  57. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/chunker/pubsub.py +0 -0
  58. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/chunker/splitter.py +0 -0
  59. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/cli/__init__.py +0 -0
  60. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/cli/chat_vac.py +0 -0
  61. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/cli/cli.py +0 -0
  62. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/cli/cli_init.py +0 -0
  63. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/cli/configs.py +0 -0
  64. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/cli/deploy.py +0 -0
  65. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/cli/embedder.py +0 -0
  66. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/cli/merge_texts.py +0 -0
  67. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/cli/run_proxy.py +0 -0
  68. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/cli/sun_rich.py +0 -0
  69. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/cli/swagger.py +0 -0
  70. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/cli/vertex.py +0 -0
  71. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/components/__init__.py +0 -0
  72. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/components/llm.py +0 -0
  73. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/components/retriever.py +0 -0
  74. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/components/vectorstore.py +0 -0
  75. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/custom_logging.py +0 -0
  76. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/database/__init__.py +0 -0
  77. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/database/alloydb.py +0 -0
  78. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/database/alloydb_client.py +0 -0
  79. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/database/database.py +0 -0
  80. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/database/lancedb.py +0 -0
  81. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/database/sql/sb/create_function.sql +0 -0
  82. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/database/sql/sb/create_function_time.sql +0 -0
  83. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/database/sql/sb/create_table.sql +0 -0
  84. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/database/sql/sb/delete_source_row.sql +0 -0
  85. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/database/sql/sb/return_sources.sql +0 -0
  86. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/database/sql/sb/setup.sql +0 -0
  87. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/database/static_dbs.py +0 -0
  88. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/database/uuid.py +0 -0
  89. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/discovery_engine/__init__.py +0 -0
  90. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/discovery_engine/chunker_handler.py +0 -0
  91. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/discovery_engine/cli.py +0 -0
  92. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/discovery_engine/create_new.py +0 -0
  93. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/discovery_engine/discovery_engine_client.py +0 -0
  94. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/discovery_engine/get_ai_search_chunks.py +0 -0
  95. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/embedder/__init__.py +0 -0
  96. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/embedder/embed_chunk.py +0 -0
  97. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/embedder/embed_metadata.py +0 -0
  98. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/excel/__init__.py +0 -0
  99. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/excel/plugin.py +0 -0
  100. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/gcs/__init__.py +0 -0
  101. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/gcs/add_file.py +0 -0
  102. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/gcs/download_folder.py +0 -0
  103. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/gcs/download_gcs_text.py +0 -0
  104. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/gcs/download_url.py +0 -0
  105. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/gcs/extract_and_sign.py +0 -0
  106. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/gcs/metadata.py +0 -0
  107. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/genai/__init__.py +0 -0
  108. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/genai/file_handling.py +0 -0
  109. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/genai/genaiv2.py +0 -0
  110. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/genai/images.py +0 -0
  111. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/genai/init.py +0 -0
  112. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/genai/process_funcs_cls.py +0 -0
  113. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/genai/safety.py +0 -0
  114. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/invoke/__init__.py +0 -0
  115. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/invoke/async_class.py +0 -0
  116. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/invoke/direct_vac_func.py +0 -0
  117. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/invoke/invoke_vac_utils.py +0 -0
  118. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/langchain_types.py +0 -0
  119. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/langfuse/__init__.py +0 -0
  120. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/langfuse/callback.py +0 -0
  121. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/langfuse/evals.py +0 -0
  122. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/langfuse/prompts.py +0 -0
  123. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/llamaindex/__init__.py +0 -0
  124. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/llamaindex/get_files.py +0 -0
  125. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/llamaindex/import_files.py +0 -0
  126. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/llamaindex/llamaindex_class.py +0 -0
  127. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/llamaindex/user_history.py +0 -0
  128. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/lookup/__init__.py +0 -0
  129. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/lookup/model_lookup.yaml +0 -0
  130. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/mcp/__init__.py +0 -0
  131. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/mcp/cli.py +0 -0
  132. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/mcp/cli_fastmcp.py +0 -0
  133. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/mcp/mcp_manager.py +0 -0
  134. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/mcp/stdio_http_bridge.py +0 -0
  135. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/mcp/vac_mcp_server.py +0 -0
  136. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/ollama/__init__.py +0 -0
  137. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/ollama/ollama_images.py +0 -0
  138. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/pubsub/__init__.py +0 -0
  139. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/pubsub/process_pubsub.py +0 -0
  140. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/pubsub/pubsub_manager.py +0 -0
  141. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/qna/__init__.py +0 -0
  142. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/qna/parsers.py +0 -0
  143. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/qna/retry.py +0 -0
  144. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/senses/__init__.py +0 -0
  145. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/senses/stream_voice.py +0 -0
  146. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/streaming/__init__.py +0 -0
  147. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/streaming/content_buffer.py +0 -0
  148. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/streaming/langserve.py +0 -0
  149. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/streaming/stream_lookup.py +0 -0
  150. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/streaming/streaming.py +0 -0
  151. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/summarise/__init__.py +0 -0
  152. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/summarise/summarise.py +0 -0
  153. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/templates/agent/__init__.py +0 -0
  154. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/templates/agent/agent_service.py +0 -0
  155. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/templates/agent/app.py +0 -0
  156. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/templates/agent/my_log.py +0 -0
  157. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/templates/agent/tools/__init__.py +0 -0
  158. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/templates/agent/tools/your_agent.py +0 -0
  159. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/templates/agent/vac_service.py +0 -0
  160. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/templates/project/__init__.py +0 -0
  161. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/templates/project/app.py +0 -0
  162. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/templates/project/my_log.py +0 -0
  163. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/templates/project/vac_service.py +0 -0
  164. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/templates/system_services/__init__.py +0 -0
  165. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/templates/system_services/app.py +0 -0
  166. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/templates/system_services/my_log.py +0 -0
  167. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/terraform/__init__.py +0 -0
  168. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/terraform/tfvars_editor.py +0 -0
  169. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/tools/__init__.py +0 -0
  170. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/tools/web_browser.py +0 -0
  171. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/utils/__init__.py +0 -0
  172. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/utils/api_key.py +0 -0
  173. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/utils/big_context.py +0 -0
  174. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/utils/config.py +0 -0
  175. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/utils/config_class.py +0 -0
  176. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/utils/config_schema.py +0 -0
  177. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/utils/gcp.py +0 -0
  178. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/utils/gcp_project.py +0 -0
  179. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/utils/mime.py +0 -0
  180. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/utils/parsers.py +0 -0
  181. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/utils/proto_convert.py +0 -0
  182. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/utils/timedelta.py +0 -0
  183. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/utils/user_ids.py +0 -0
  184. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/utils/version.py +0 -0
  185. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/vertex/__init__.py +0 -0
  186. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/vertex/extensions_call.py +0 -0
  187. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/vertex/extensions_class.py +0 -0
  188. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/vertex/genai_functions.py +0 -0
  189. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/vertex/init.py +0 -0
  190. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/vertex/memory_tools.py +0 -0
  191. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/vertex/safety.py +0 -0
  192. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo/vertex/type_dict_to_json.py +0 -0
  193. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo.egg-info/dependency_links.txt +0 -0
  194. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo.egg-info/entry_points.txt +0 -0
  195. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo.egg-info/requires.txt +0 -0
  196. {sunholo-0.144.0 → sunholo-0.144.2}/src/sunholo.egg-info/top_level.txt +0 -0
  197. {sunholo-0.144.0 → sunholo-0.144.2}/tests/test_async.py +0 -0
  198. {sunholo-0.144.0 → sunholo-0.144.2}/tests/test_async_genai2.py +0 -0
  199. {sunholo-0.144.0 → sunholo-0.144.2}/tests/test_chat_history.py +0 -0
  200. {sunholo-0.144.0 → sunholo-0.144.2}/tests/test_config.py +0 -0
  201. {sunholo-0.144.0 → sunholo-0.144.2}/tests/test_genai2.py +0 -0
  202. {sunholo-0.144.0 → sunholo-0.144.2}/tests/test_unstructured.py +0 -0
  203. {sunholo-0.144.0 → sunholo-0.144.2}/tests/test_vac_routes_fastapi.py +0 -0
  204. {sunholo-0.144.0 → sunholo-0.144.2}/tests/test_vac_routes_mcp.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sunholo
3
- Version: 0.144.0
3
+ Version: 0.144.2
4
4
  Summary: AI DevOps - a package to help deploy GenAI to the Cloud.
5
5
  Author-email: Holosun ApS <multivac@sunholo.com>
6
6
  License: Apache License, Version 2.0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "sunholo"
7
- version = "0.144.0"
7
+ version = "0.144.2"
8
8
  description = "AI DevOps - a package to help deploy GenAI to the Cloud."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -22,6 +22,7 @@ import inspect
22
22
  import asyncio
23
23
  from typing import Dict, List, Optional, Callable, Any, TYPE_CHECKING
24
24
  from functools import partial
25
+ from contextlib import asynccontextmanager
25
26
 
26
27
  if TYPE_CHECKING:
27
28
  from fastapi import FastAPI, Request, Response, HTTPException
@@ -57,7 +58,7 @@ except ImportError:
57
58
  MCPClientManager = None
58
59
 
59
60
  try:
60
- from ...mcp.vac_mcp_server import VACMCPServer
61
+ from ...mcp.vac_mcp_server_fastmcp import VACMCPServer
61
62
  except ImportError:
62
63
  VACMCPServer = None
63
64
 
@@ -80,31 +81,205 @@ class VACRequest(BaseModel):
80
81
 
81
82
  class VACRoutesFastAPI:
82
83
  """
83
- FastAPI implementation of VAC routes with streaming support.
84
+ FastAPI implementation of VAC routes with streaming support and extensible MCP integration.
84
85
 
85
- This class provides a FastAPI-compatible version of the Flask VACRoutes,
86
- with proper async streaming support using callbacks.
86
+ This class provides a comprehensive FastAPI application with:
87
+ - VAC (Virtual Agent Computer) endpoints for AI chat and streaming
88
+ - OpenAI-compatible API endpoints
89
+ - Extensible MCP (Model Context Protocol) server integration for Claude Desktop/Code
90
+ - MCP client support for connecting to external MCP servers
91
+ - A2A (Agent-to-Agent) protocol support
92
+ - Server-Sent Events (SSE) streaming capabilities
93
+
94
+ ## Key Features
95
+
96
+ ### 1. VAC Endpoints
97
+ - `/vac/{vector_name}` - Non-streaming VAC responses
98
+ - `/vac/streaming/{vector_name}` - Plain text streaming responses
99
+ - `/vac/streaming/{vector_name}/sse` - Server-Sent Events streaming
100
+
101
+ ### 2. OpenAI Compatible API
102
+ - `/openai/v1/chat/completions` - OpenAI-compatible chat completions
103
+ - Supports both streaming and non-streaming modes
104
+
105
+ ### 3. MCP Integration
106
+ - **MCP Server**: Expose your VAC as MCP tools for Claude Desktop/Code
107
+ - **MCP Client**: Connect to external MCP servers and use their tools
108
+ - **Custom Tools**: Easily add your own MCP tools using decorators
109
+
110
+ ### 4. A2A Agent Protocol
111
+ - Agent discovery and task execution
112
+ - Compatible with multi-agent workflows
113
+
114
+ ## Basic Usage
87
115
 
88
- Usage Example:
89
116
  ```python
90
117
  from fastapi import FastAPI
91
118
  from sunholo.agents.fastapi import VACRoutesFastAPI
92
119
 
93
120
  app = FastAPI()
94
121
 
95
- async def stream_interpreter(question, vector_name, chat_history, callback, **kwargs):
96
- # Implement your streaming logic with callbacks
97
- ...
122
+ async def my_stream_interpreter(question, vector_name, chat_history, callback, **kwargs):
123
+ # Your streaming VAC logic here
124
+ # Use callback.async_on_llm_new_token(token) for streaming
125
+ # Return final result with sources
126
+ return {"answer": "Response", "sources": []}
127
+
128
+ # Create VAC routes with MCP server enabled
129
+ vac_routes = VACRoutesFastAPI(
130
+ app=app,
131
+ stream_interpreter=my_stream_interpreter,
132
+ enable_mcp_server=True # Enable MCP server for Claude Desktop/Code
133
+ )
134
+
135
+ # Your FastAPI app now includes:
136
+ # - All VAC endpoints
137
+ # - MCP server at /mcp (for Claude Desktop/Code to connect)
138
+ # - Built-in VAC tools: vac_stream, vac_query, list_available_vacs, get_vac_info
139
+ ```
140
+
141
+ ## Adding Custom MCP Tools
142
+
143
+ ### Method 1: Using Decorators
144
+ ```python
145
+ vac_routes = VACRoutesFastAPI(app, stream_interpreter, enable_mcp_server=True)
146
+
147
+ @vac_routes.add_mcp_tool
148
+ async def get_weather(city: str) -> str:
149
+ '''Get weather information for a city.'''
150
+ # Your weather API logic
151
+ return f"Weather in {city}: Sunny, 22°C"
152
+
153
+ @vac_routes.add_mcp_tool("custom_search", "Search our database")
154
+ async def search_database(query: str, limit: int = 10) -> list:
155
+ '''Search internal database with custom name and description.'''
156
+ # Your database search logic
157
+ return [{"result": f"Found: {query}"}]
158
+ ```
159
+
160
+ ### Method 2: Programmatic Registration
161
+ ```python
162
+ async def my_business_tool(param: str) -> dict:
163
+ return {"processed": param}
164
+
165
+ # Add tool with custom name and description
166
+ vac_routes.add_mcp_tool(
167
+ my_business_tool,
168
+ "process_business_data",
169
+ "Process business data with our custom logic"
170
+ )
171
+ ```
172
+
173
+ ### Method 3: Advanced MCP Server Access
174
+ ```python
175
+ # Get direct access to MCP server for advanced customization
176
+ mcp_server = vac_routes.get_mcp_server()
177
+
178
+ @mcp_server.add_tool
179
+ async def advanced_tool(complex_param: dict) -> str:
180
+ return f"Advanced processing: {complex_param}"
181
+
182
+ # List all registered tools
183
+ print("Available MCP tools:", vac_routes.list_mcp_tools())
184
+ ```
185
+
186
+ ## MCP Client Integration
187
+
188
+ Connect to external MCP servers and use their tools:
189
+
190
+ ```python
191
+ mcp_servers = [
192
+ {
193
+ "name": "filesystem-server",
194
+ "command": "npx",
195
+ "args": ["@modelcontextprotocol/server-filesystem", "/path/to/files"]
196
+ }
197
+ ]
198
+
199
+ vac_routes = VACRoutesFastAPI(
200
+ app, stream_interpreter,
201
+ mcp_servers=mcp_servers, # Connect to external MCP servers
202
+ enable_mcp_server=True # Also expose our own MCP server
203
+ )
204
+
205
+ # External MCP tools available at:
206
+ # GET /mcp/tools - List all external tools
207
+ # POST /mcp/call - Call external MCP tools
208
+ ```
209
+
210
+ ## Claude Desktop Integration
211
+
212
+ ### Option 1: Remote Integration (Recommended for Development)
213
+ ```python
214
+ # Run your FastAPI app
215
+ uvicorn.run(vac_routes.app, host="0.0.0.0", port=8000)
216
+
217
+ # Configure Claude Desktop (Settings > Connectors > Add custom connector):
218
+ # URL: http://localhost:8000/mcp
219
+ ```
220
+
221
+ ### Option 2: Local Integration
222
+ Create a standalone script for Claude Desktop:
223
+ ```python
224
+ # claude_mcp_server.py
225
+ from sunholo.mcp.extensible_mcp_server import create_mcp_server
226
+
227
+ server = create_mcp_server("my-app", include_vac_tools=True)
98
228
 
99
- async def vac_interpreter(question, vector_name, chat_history, **kwargs):
100
- # Implement your static VAC logic
101
- ...
229
+ @server.add_tool
230
+ async def my_app_tool(param: str) -> str:
231
+ return f"My app processed: {param}"
102
232
 
233
+ if __name__ == "__main__":
234
+ server.run()
235
+
236
+ # Install: fastmcp install claude-desktop claude_mcp_server.py --with sunholo[anthropic]
237
+ ```
238
+
239
+ ## Available Built-in MCP Tools
240
+
241
+ When `enable_mcp_server=True`, these tools are automatically available:
242
+
243
+ - **`vac_stream`**: Stream responses from any configured VAC
244
+ - **`vac_query`**: Query VACs with non-streaming responses
245
+ - **`list_available_vacs`**: List all available VAC configurations
246
+ - **`get_vac_info`**: Get detailed information about a specific VAC
247
+
248
+ ## Error Handling and Best Practices
249
+
250
+ ```python
251
+ @vac_routes.add_mcp_tool
252
+ async def robust_tool(user_input: str) -> str:
253
+ '''Example of robust tool implementation.'''
254
+ try:
255
+ # Validate input
256
+ if not user_input or len(user_input) > 1000:
257
+ return "Error: Invalid input length"
258
+
259
+ # Your business logic
260
+ result = await process_user_input(user_input)
261
+
262
+ return f"Processed: {result}"
263
+
264
+ except Exception as e:
265
+ # Log error and return user-friendly message
266
+ log.error(f"Tool error: {e}")
267
+ return f"Error processing request: {str(e)}"
268
+ ```
269
+
270
+ ## Configuration Options
271
+
272
+ ```python
103
273
  vac_routes = VACRoutesFastAPI(
104
- app,
105
- stream_interpreter,
106
- vac_interpreter,
107
- enable_mcp_server=True
274
+ app=app,
275
+ stream_interpreter=my_stream_func,
276
+ vac_interpreter=my_vac_func, # Optional non-streaming function
277
+ additional_routes=[], # Custom FastAPI routes
278
+ mcp_servers=[], # External MCP servers to connect to
279
+ add_langfuse_eval=True, # Enable Langfuse evaluation
280
+ enable_mcp_server=True, # Enable MCP server for Claude
281
+ enable_a2a_agent=False, # Enable A2A agent protocol
282
+ a2a_vac_names=None # VACs available for A2A
108
283
  )
109
284
  ```
110
285
  """
@@ -122,18 +297,86 @@ class VACRoutesFastAPI:
122
297
  a2a_vac_names: Optional[List[str]] = None
123
298
  ):
124
299
  """
125
- Initialize FastAPI VAC routes.
300
+ Initialize FastAPI VAC routes with comprehensive AI and MCP integration.
126
301
 
127
302
  Args:
128
- app: FastAPI application instance
129
- stream_interpreter: Async or sync function for streaming responses
130
- vac_interpreter: Optional function for non-streaming responses
131
- additional_routes: List of additional routes to register
132
- mcp_servers: List of MCP server configurations
133
- add_langfuse_eval: Whether to add Langfuse evaluation
134
- enable_mcp_server: Whether to enable MCP server endpoint
135
- enable_a2a_agent: Whether to enable A2A agent endpoints
136
- a2a_vac_names: List of VAC names for A2A agent
303
+ app: FastAPI application instance to register routes on
304
+ stream_interpreter: Function for streaming VAC responses. Can be async or sync.
305
+ Called with (question, vector_name, chat_history, callback, **kwargs)
306
+ vac_interpreter: Optional function for non-streaming VAC responses. If not provided,
307
+ will use stream_interpreter without streaming callbacks.
308
+ additional_routes: List of custom route dictionaries to register:
309
+ [{"path": "/custom", "handler": func, "methods": ["GET"]}]
310
+ mcp_servers: List of external MCP server configurations to connect to:
311
+ [{"name": "server-name", "command": "python", "args": ["server.py"]}]
312
+ add_langfuse_eval: Whether to enable Langfuse evaluation and tracing
313
+ enable_mcp_server: Whether to enable the MCP server at /mcp endpoint for
314
+ Claude Desktop/Code integration. When True, automatically
315
+ includes built-in VAC tools and supports custom tool registration.
316
+ enable_a2a_agent: Whether to enable A2A (Agent-to-Agent) protocol endpoints
317
+ a2a_vac_names: List of VAC names available for A2A agent interactions
318
+
319
+ ## Stream Interpreter Function
320
+
321
+ Your stream_interpreter should handle streaming responses:
322
+
323
+ ```python
324
+ async def my_stream_interpreter(question: str, vector_name: str,
325
+ chat_history: list, callback, **kwargs):
326
+ # Process the question using your AI/RAG pipeline
327
+
328
+ # For streaming tokens:
329
+ await callback.async_on_llm_new_token("partial response...")
330
+
331
+ # Return final result with sources:
332
+ return {
333
+ "answer": "Final complete answer",
334
+ "sources": [{"title": "Source 1", "url": "..."}]
335
+ }
336
+ ```
337
+
338
+ ## MCP Server Integration
339
+
340
+ When enable_mcp_server=True, the following happens:
341
+ 1. MCP server is mounted at /mcp endpoint
342
+ 2. Built-in VAC tools are automatically registered:
343
+ - vac_stream, vac_query, list_available_vacs, get_vac_info
344
+ 3. You can add custom MCP tools using add_mcp_tool()
345
+ 4. Claude Desktop/Code can connect to http://your-server/mcp
346
+
347
+ ## Complete Example
348
+
349
+ ```python
350
+ app = FastAPI(title="My VAC Application")
351
+
352
+ async def my_vac_logic(question, vector_name, chat_history, callback, **kwargs):
353
+ # Your AI/RAG implementation
354
+ result = await process_with_ai(question)
355
+ return {"answer": result, "sources": []}
356
+
357
+ # External MCP servers to connect to
358
+ external_mcp = [
359
+ {"name": "filesystem", "command": "mcp-server-fs", "args": ["/data"]}
360
+ ]
361
+
362
+ vac_routes = VACRoutesFastAPI(
363
+ app=app,
364
+ stream_interpreter=my_vac_logic,
365
+ mcp_servers=external_mcp,
366
+ enable_mcp_server=True # Enable for Claude integration
367
+ )
368
+
369
+ # Add custom MCP tools for your business logic
370
+ @vac_routes.add_mcp_tool
371
+ async def get_customer_info(customer_id: str) -> dict:
372
+ return await fetch_customer(customer_id)
373
+
374
+ # Your app now has:
375
+ # - VAC endpoints: /vac/{vector_name}, /vac/streaming/{vector_name}
376
+ # - OpenAI API: /openai/v1/chat/completions
377
+ # - MCP server: /mcp (with built-in + custom tools)
378
+ # - MCP client: /mcp/tools, /mcp/call (for external servers)
379
+ ```
137
380
  """
138
381
  self.app = app
139
382
  self.stream_interpreter = stream_interpreter
@@ -151,11 +394,17 @@ class VACRoutesFastAPI:
151
394
  # MCP server initialization
152
395
  self.enable_mcp_server = enable_mcp_server
153
396
  self.vac_mcp_server = None
397
+ self._custom_mcp_tools = []
398
+ self._custom_mcp_resources = []
399
+
154
400
  if self.enable_mcp_server and VACMCPServer:
155
401
  self.vac_mcp_server = VACMCPServer(
156
- stream_interpreter=self.stream_interpreter,
157
- vac_interpreter=self.vac_interpreter
402
+ server_name="sunholo-vac-fastapi-server",
403
+ include_vac_tools=True
158
404
  )
405
+
406
+ # Add any pre-registered custom tools
407
+ self._register_custom_tools()
159
408
 
160
409
  # A2A agent initialization
161
410
  self.enable_a2a_agent = enable_a2a_agent
@@ -231,10 +480,15 @@ class VACRoutesFastAPI:
231
480
  self.app.get("/mcp/resources")(self.handle_mcp_list_resources)
232
481
  self.app.post("/mcp/resources/read")(self.handle_mcp_read_resource)
233
482
 
234
- # MCP server endpoint
483
+ # MCP server endpoint - mount the FastMCP app
235
484
  if self.enable_mcp_server and self.vac_mcp_server:
236
- self.app.post("/mcp")(self.handle_mcp_server)
237
- self.app.get("/mcp")(self.handle_mcp_server_info)
485
+ try:
486
+ mcp_app = self.vac_mcp_server.get_http_app()
487
+ self.app.mount("/mcp", mcp_app)
488
+ log.info("MCP server mounted at /mcp endpoint")
489
+ except Exception as e:
490
+ log.error(f"Failed to mount MCP server: {e}")
491
+ raise RuntimeError(f"MCP server initialization failed: {e}")
238
492
 
239
493
  # A2A agent endpoints
240
494
  if self.enable_a2a_agent:
@@ -253,12 +507,36 @@ class VACRoutesFastAPI:
253
507
  methods=route.get("methods", ["GET"])
254
508
  )
255
509
 
256
- # Register startup event for MCP initialization
257
- @self.app.on_event("startup")
258
- async def startup_event():
259
- if self.mcp_servers and self.mcp_client_manager and not self._mcp_initialized:
510
+ # Set up lifespan for MCP initialization
511
+ self._setup_lifespan()
512
+
513
+ def _setup_lifespan(self):
514
+ """Set up lifespan context manager for app initialization."""
515
+ # Only set lifespan if we have MCP servers to initialize
516
+ if not (self.mcp_servers and self.mcp_client_manager):
517
+ return
518
+
519
+ # Store the existing lifespan if any
520
+ existing_lifespan = getattr(self.app, 'router', self.app).lifespan_context
521
+
522
+ @asynccontextmanager
523
+ async def lifespan(app: FastAPI):
524
+ # Startup
525
+ if not self._mcp_initialized:
260
526
  await self._initialize_mcp_servers()
261
527
  self._mcp_initialized = True
528
+
529
+ # Call existing lifespan startup if any
530
+ if existing_lifespan:
531
+ async with existing_lifespan(app) as lifespan_state:
532
+ yield lifespan_state
533
+ else:
534
+ yield
535
+
536
+ # Shutdown (no cleanup needed for now)
537
+
538
+ # Set the new lifespan
539
+ self.app.router.lifespan_context = lifespan
262
540
 
263
541
  async def home(self):
264
542
  """Home endpoint."""
@@ -762,109 +1040,6 @@ class VACRoutesFastAPI:
762
1040
  except Exception as e:
763
1041
  raise HTTPException(status_code=500, detail=str(e))
764
1042
 
765
- async def handle_mcp_server(self, request: Request):
766
- """Handle MCP server requests."""
767
- if not self.vac_mcp_server:
768
- raise HTTPException(status_code=501, detail="MCP server not enabled")
769
-
770
- data = await request.json()
771
- log.info(f"MCP server received: {data}")
772
-
773
- # Process MCP request - simplified version
774
- # Full implementation would handle all MCP protocol methods
775
- method = data.get("method")
776
- params = data.get("params", {})
777
- request_id = data.get("id")
778
-
779
- try:
780
- if method == "initialize":
781
- response = {
782
- "jsonrpc": "2.0",
783
- "result": {
784
- "protocolVersion": "2025-06-18",
785
- "capabilities": {"tools": {}},
786
- "serverInfo": {
787
- "name": "sunholo-vac-server",
788
- "version": sunholo_version()
789
- }
790
- },
791
- "id": request_id
792
- }
793
- elif method == "tools/list":
794
- tools = [
795
- {
796
- "name": "vac_stream",
797
- "description": "Stream responses from a Sunholo VAC",
798
- "inputSchema": {
799
- "type": "object",
800
- "properties": {
801
- "vector_name": {"type": "string"},
802
- "user_input": {"type": "string"},
803
- "chat_history": {"type": "array", "default": []}
804
- },
805
- "required": ["vector_name", "user_input"]
806
- }
807
- }
808
- ]
809
- if self.vac_interpreter:
810
- tools.append({
811
- "name": "vac_query",
812
- "description": "Query a Sunholo VAC (non-streaming)",
813
- "inputSchema": {
814
- "type": "object",
815
- "properties": {
816
- "vector_name": {"type": "string"},
817
- "user_input": {"type": "string"},
818
- "chat_history": {"type": "array", "default": []}
819
- },
820
- "required": ["vector_name", "user_input"]
821
- }
822
- })
823
- response = {
824
- "jsonrpc": "2.0",
825
- "result": {"tools": tools},
826
- "id": request_id
827
- }
828
- elif method == "tools/call":
829
- tool_name = params.get("name")
830
- arguments = params.get("arguments", {})
831
-
832
- if tool_name == "vac_stream":
833
- result = await self.vac_mcp_server._handle_vac_stream(arguments)
834
- elif tool_name == "vac_query":
835
- result = await self.vac_mcp_server._handle_vac_query(arguments)
836
- else:
837
- raise ValueError(f"Unknown tool: {tool_name}")
838
-
839
- response = {
840
- "jsonrpc": "2.0",
841
- "result": {"content": [item.model_dump() for item in result]},
842
- "id": request_id
843
- }
844
- else:
845
- raise ValueError(f"Unknown method: {method}")
846
-
847
- except Exception as e:
848
- response = {
849
- "jsonrpc": "2.0",
850
- "error": {
851
- "code": -32603,
852
- "message": str(e)
853
- },
854
- "id": request_id
855
- }
856
-
857
- return JSONResponse(content=response)
858
-
859
- async def handle_mcp_server_info(self):
860
- """Return MCP server information."""
861
- return JSONResponse(content={
862
- "name": "sunholo-vac-server",
863
- "version": "1.0.0",
864
- "transport": "http",
865
- "endpoint": "/mcp",
866
- "tools": ["vac_stream", "vac_query"] if self.vac_interpreter else ["vac_stream"]
867
- })
868
1043
 
869
1044
  def _get_or_create_a2a_agent(self, request: Request):
870
1045
  """Get or create the A2A agent instance with current request context."""
@@ -1014,4 +1189,94 @@ class VACRoutesFastAPI:
1014
1189
  "id": data.get("id") if 'data' in locals() else None
1015
1190
  },
1016
1191
  status_code=500
1017
- )
1192
+ )
1193
+
1194
+ # MCP Tool Registration Methods
1195
+
1196
+ def _register_custom_tools(self):
1197
+ """Register any custom tools that were added before MCP server initialization."""
1198
+ if self.vac_mcp_server:
1199
+ for tool_func, name, description in self._custom_mcp_tools:
1200
+ self.vac_mcp_server.add_tool(tool_func, name, description)
1201
+ for resource_func, name, description in self._custom_mcp_resources:
1202
+ self.vac_mcp_server.add_resource(resource_func, name, description)
1203
+
1204
+ def add_mcp_tool(self, func: Callable, name: str = None, description: str = None):
1205
+ """
1206
+ Add a custom MCP tool to the server.
1207
+
1208
+ Args:
1209
+ func: The tool function
1210
+ name: Optional custom name for the tool
1211
+ description: Optional description (uses docstring if not provided)
1212
+
1213
+ Example:
1214
+ @app.add_mcp_tool
1215
+ async def my_custom_tool(param: str) -> str:
1216
+ '''Custom tool that does something useful.'''
1217
+ return f"Result: {param}"
1218
+
1219
+ # Or with custom name and description
1220
+ app.add_mcp_tool(my_function, "custom_name", "Custom description")
1221
+ """
1222
+ if self.vac_mcp_server:
1223
+ self.vac_mcp_server.add_tool(func, name, description)
1224
+ else:
1225
+ # Store for later registration
1226
+ self._custom_mcp_tools.append((func, name, description))
1227
+
1228
+ return func # Allow use as decorator
1229
+
1230
+ def add_mcp_resource(self, func: Callable, name: str = None, description: str = None):
1231
+ """
1232
+ Add a custom MCP resource to the server.
1233
+
1234
+ Args:
1235
+ func: The resource function
1236
+ name: Optional custom name for the resource
1237
+ description: Optional description (uses docstring if not provided)
1238
+
1239
+ Example:
1240
+ @app.add_mcp_resource
1241
+ async def my_custom_resource(uri: str) -> str:
1242
+ '''Custom resource that provides data.'''
1243
+ return f"Resource data for: {uri}"
1244
+ """
1245
+ if self.vac_mcp_server:
1246
+ self.vac_mcp_server.add_resource(func, name, description)
1247
+ else:
1248
+ # Store for later registration
1249
+ self._custom_mcp_resources.append((func, name, description))
1250
+
1251
+ return func # Allow use as decorator
1252
+
1253
+ def get_mcp_server(self):
1254
+ """
1255
+ Get the MCP server instance for advanced customization.
1256
+
1257
+ Returns:
1258
+ VACMCPServer instance or None if MCP server is not enabled
1259
+ """
1260
+ return self.vac_mcp_server
1261
+
1262
+ def list_mcp_tools(self) -> List[str]:
1263
+ """
1264
+ List all registered MCP tools.
1265
+
1266
+ Returns:
1267
+ List of tool names
1268
+ """
1269
+ if self.vac_mcp_server:
1270
+ return self.vac_mcp_server.list_tools()
1271
+ return []
1272
+
1273
+ def list_mcp_resources(self) -> List[str]:
1274
+ """
1275
+ List all registered MCP resources.
1276
+
1277
+ Returns:
1278
+ List of resource names
1279
+ """
1280
+ if self.vac_mcp_server:
1281
+ return self.vac_mcp_server.list_resources()
1282
+ return []