code-puppy 0.0.315__tar.gz → 0.0.316__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 (164) hide show
  1. {code_puppy-0.0.315 → code_puppy-0.0.316}/PKG-INFO +1 -1
  2. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/agents/base_agent.py +14 -29
  3. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/mcp_/blocking_startup.py +11 -3
  4. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/mcp_/managed_server.py +22 -2
  5. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/mcp_/manager.py +65 -0
  6. {code_puppy-0.0.315 → code_puppy-0.0.316}/pyproject.toml +1 -1
  7. {code_puppy-0.0.315 → code_puppy-0.0.316}/.gitignore +0 -0
  8. {code_puppy-0.0.315 → code_puppy-0.0.316}/LICENSE +0 -0
  9. {code_puppy-0.0.315 → code_puppy-0.0.316}/README.md +0 -0
  10. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/__init__.py +0 -0
  11. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/__main__.py +0 -0
  12. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/agents/__init__.py +0 -0
  13. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/agents/agent_c_reviewer.py +0 -0
  14. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/agents/agent_code_puppy.py +0 -0
  15. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/agents/agent_code_reviewer.py +0 -0
  16. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/agents/agent_cpp_reviewer.py +0 -0
  17. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/agents/agent_creator_agent.py +0 -0
  18. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/agents/agent_golang_reviewer.py +0 -0
  19. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/agents/agent_javascript_reviewer.py +0 -0
  20. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/agents/agent_manager.py +0 -0
  21. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/agents/agent_planning.py +0 -0
  22. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/agents/agent_python_programmer.py +0 -0
  23. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/agents/agent_python_reviewer.py +0 -0
  24. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/agents/agent_qa_expert.py +0 -0
  25. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/agents/agent_qa_kitten.py +0 -0
  26. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/agents/agent_security_auditor.py +0 -0
  27. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/agents/agent_typescript_reviewer.py +0 -0
  28. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/agents/json_agent.py +0 -0
  29. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/agents/prompt_reviewer.py +0 -0
  30. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/callbacks.py +0 -0
  31. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/chatgpt_codex_client.py +0 -0
  32. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/claude_cache_client.py +0 -0
  33. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/cli_runner.py +0 -0
  34. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/command_line/__init__.py +0 -0
  35. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/command_line/add_model_menu.py +0 -0
  36. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/command_line/attachments.py +0 -0
  37. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/command_line/autosave_menu.py +0 -0
  38. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/command_line/colors_menu.py +0 -0
  39. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/command_line/command_handler.py +0 -0
  40. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/command_line/command_registry.py +0 -0
  41. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/command_line/config_commands.py +0 -0
  42. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/command_line/core_commands.py +0 -0
  43. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/command_line/diff_menu.py +0 -0
  44. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/command_line/file_path_completion.py +0 -0
  45. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/command_line/load_context_completion.py +0 -0
  46. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/command_line/mcp/__init__.py +0 -0
  47. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/command_line/mcp/add_command.py +0 -0
  48. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/command_line/mcp/base.py +0 -0
  49. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/command_line/mcp/catalog_server_installer.py +0 -0
  50. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/command_line/mcp/custom_server_form.py +0 -0
  51. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/command_line/mcp/custom_server_installer.py +0 -0
  52. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/command_line/mcp/edit_command.py +0 -0
  53. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/command_line/mcp/handler.py +0 -0
  54. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/command_line/mcp/help_command.py +0 -0
  55. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/command_line/mcp/install_command.py +0 -0
  56. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/command_line/mcp/install_menu.py +0 -0
  57. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/command_line/mcp/list_command.py +0 -0
  58. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/command_line/mcp/logs_command.py +0 -0
  59. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/command_line/mcp/remove_command.py +0 -0
  60. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/command_line/mcp/restart_command.py +0 -0
  61. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/command_line/mcp/search_command.py +0 -0
  62. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/command_line/mcp/start_all_command.py +0 -0
  63. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/command_line/mcp/start_command.py +0 -0
  64. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/command_line/mcp/status_command.py +0 -0
  65. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/command_line/mcp/stop_all_command.py +0 -0
  66. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/command_line/mcp/stop_command.py +0 -0
  67. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/command_line/mcp/test_command.py +0 -0
  68. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/command_line/mcp/utils.py +0 -0
  69. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/command_line/mcp/wizard_utils.py +0 -0
  70. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/command_line/mcp_completion.py +0 -0
  71. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/command_line/model_picker_completion.py +0 -0
  72. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/command_line/model_settings_menu.py +0 -0
  73. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/command_line/motd.py +0 -0
  74. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/command_line/pin_command_completion.py +0 -0
  75. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/command_line/prompt_toolkit_completion.py +0 -0
  76. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/command_line/session_commands.py +0 -0
  77. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/command_line/utils.py +0 -0
  78. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/config.py +0 -0
  79. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/error_logging.py +0 -0
  80. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/gemini_code_assist.py +0 -0
  81. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/http_utils.py +0 -0
  82. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/keymap.py +0 -0
  83. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/main.py +0 -0
  84. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/mcp_/__init__.py +0 -0
  85. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/mcp_/async_lifecycle.py +0 -0
  86. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/mcp_/captured_stdio_server.py +0 -0
  87. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/mcp_/circuit_breaker.py +0 -0
  88. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/mcp_/config_wizard.py +0 -0
  89. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/mcp_/dashboard.py +0 -0
  90. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/mcp_/error_isolation.py +0 -0
  91. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/mcp_/examples/retry_example.py +0 -0
  92. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/mcp_/health_monitor.py +0 -0
  93. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/mcp_/registry.py +0 -0
  94. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/mcp_/retry_manager.py +0 -0
  95. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/mcp_/server_registry_catalog.py +0 -0
  96. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/mcp_/status_tracker.py +0 -0
  97. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/mcp_/system_tools.py +0 -0
  98. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/messaging/__init__.py +0 -0
  99. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/messaging/bus.py +0 -0
  100. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/messaging/commands.py +0 -0
  101. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/messaging/message_queue.py +0 -0
  102. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/messaging/messages.py +0 -0
  103. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/messaging/queue_console.py +0 -0
  104. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/messaging/renderers.py +0 -0
  105. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/messaging/rich_renderer.py +0 -0
  106. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/messaging/spinner/__init__.py +0 -0
  107. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/messaging/spinner/console_spinner.py +0 -0
  108. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/messaging/spinner/spinner_base.py +0 -0
  109. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/model_factory.py +0 -0
  110. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/model_utils.py +0 -0
  111. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/models.json +0 -0
  112. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/models_dev_api.json +0 -0
  113. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/models_dev_parser.py +0 -0
  114. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/plugins/__init__.py +0 -0
  115. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/plugins/chatgpt_oauth/__init__.py +0 -0
  116. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/plugins/chatgpt_oauth/config.py +0 -0
  117. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/plugins/chatgpt_oauth/oauth_flow.py +0 -0
  118. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/plugins/chatgpt_oauth/register_callbacks.py +0 -0
  119. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/plugins/chatgpt_oauth/test_plugin.py +0 -0
  120. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/plugins/chatgpt_oauth/utils.py +0 -0
  121. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/plugins/claude_code_oauth/README.md +0 -0
  122. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/plugins/claude_code_oauth/SETUP.md +0 -0
  123. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/plugins/claude_code_oauth/__init__.py +0 -0
  124. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/plugins/claude_code_oauth/config.py +0 -0
  125. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/plugins/claude_code_oauth/register_callbacks.py +0 -0
  126. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/plugins/claude_code_oauth/test_plugin.py +0 -0
  127. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/plugins/claude_code_oauth/utils.py +0 -0
  128. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/plugins/customizable_commands/__init__.py +0 -0
  129. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/plugins/customizable_commands/register_callbacks.py +0 -0
  130. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/plugins/example_custom_command/README.md +0 -0
  131. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/plugins/example_custom_command/register_callbacks.py +0 -0
  132. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/plugins/file_permission_handler/__init__.py +0 -0
  133. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/plugins/file_permission_handler/register_callbacks.py +0 -0
  134. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/plugins/oauth_puppy_html.py +0 -0
  135. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/plugins/shell_safety/__init__.py +0 -0
  136. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/plugins/shell_safety/agent_shell_safety.py +0 -0
  137. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/plugins/shell_safety/command_cache.py +0 -0
  138. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/plugins/shell_safety/register_callbacks.py +0 -0
  139. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/prompts/codex_system_prompt.md +0 -0
  140. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/pydantic_patches.py +0 -0
  141. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/reopenable_async_client.py +0 -0
  142. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/round_robin_model.py +0 -0
  143. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/session_storage.py +0 -0
  144. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/status_display.py +0 -0
  145. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/summarization_agent.py +0 -0
  146. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/terminal_utils.py +0 -0
  147. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/tools/__init__.py +0 -0
  148. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/tools/agent_tools.py +0 -0
  149. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/tools/browser/__init__.py +0 -0
  150. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/tools/browser/browser_control.py +0 -0
  151. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/tools/browser/browser_interactions.py +0 -0
  152. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/tools/browser/browser_locators.py +0 -0
  153. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/tools/browser/browser_navigation.py +0 -0
  154. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/tools/browser/browser_screenshot.py +0 -0
  155. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/tools/browser/browser_scripts.py +0 -0
  156. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/tools/browser/browser_workflows.py +0 -0
  157. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/tools/browser/camoufox_manager.py +0 -0
  158. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/tools/browser/vqa_agent.py +0 -0
  159. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/tools/command_runner.py +0 -0
  160. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/tools/common.py +0 -0
  161. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/tools/file_modifications.py +0 -0
  162. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/tools/file_operations.py +0 -0
  163. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/tools/tools_content.py +0 -0
  164. {code_puppy-0.0.315 → code_puppy-0.0.316}/code_puppy/version_checker.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: code-puppy
3
- Version: 0.0.315
3
+ Version: 0.0.316
4
4
  Summary: Code generation agent
5
5
  Project-URL: repository, https://github.com/mpfaffenberger/code_puppy
6
6
  Project-URL: HomePage, https://github.com/mpfaffenberger/code_puppy
@@ -47,11 +47,10 @@ from code_puppy.config import (
47
47
  get_protected_token_count,
48
48
  get_use_dbos,
49
49
  get_value,
50
- load_mcp_server_configs,
51
50
  )
52
51
  from code_puppy.error_logging import log_error
53
52
  from code_puppy.keymap import cancel_agent_uses_signal, get_cancel_agent_char_code
54
- from code_puppy.mcp_ import ServerConfig, get_mcp_manager
53
+ from code_puppy.mcp_ import get_mcp_manager
55
54
  from code_puppy.messaging import (
56
55
  emit_error,
57
56
  emit_info,
@@ -989,45 +988,31 @@ class BaseAgent(ABC):
989
988
  return self._puppy_rules
990
989
 
991
990
  def load_mcp_servers(self, extra_headers: Optional[Dict[str, str]] = None):
992
- """Load MCP servers through the manager and return pydantic-ai compatible servers."""
991
+ """Load MCP servers through the manager and return pydantic-ai compatible servers.
992
+
993
+ Note: The manager automatically syncs from mcp_servers.json during initialization,
994
+ so we don't need to sync here. Use reload_mcp_servers() to force a re-sync.
995
+ """
993
996
 
994
997
  mcp_disabled = get_value("disable_mcp_servers")
995
998
  if mcp_disabled and str(mcp_disabled).lower() in ("1", "true", "yes", "on"):
996
999
  return []
997
1000
 
998
1001
  manager = get_mcp_manager()
999
- configs = load_mcp_server_configs()
1000
- if not configs:
1001
- existing_servers = manager.list_servers()
1002
- if not existing_servers:
1003
- return []
1004
- else:
1005
- for name, conf in configs.items():
1006
- try:
1007
- server_config = ServerConfig(
1008
- id=conf.get("id", f"{name}_{hash(name)}"),
1009
- name=name,
1010
- type=conf.get("type", "sse"),
1011
- enabled=conf.get("enabled", True),
1012
- config=conf,
1013
- )
1014
- existing = manager.get_server_by_name(name)
1015
- if not existing:
1016
- manager.register_server(server_config)
1017
- else:
1018
- if existing.config != server_config.config:
1019
- manager.update_server(existing.id, server_config)
1020
- except Exception:
1021
- continue
1022
-
1023
1002
  return manager.get_servers_for_agent()
1024
1003
 
1025
1004
  def reload_mcp_servers(self):
1026
- """Reload MCP servers and return updated servers."""
1005
+ """Reload MCP servers and return updated servers.
1006
+
1007
+ Forces a re-sync from mcp_servers.json to pick up any configuration changes.
1008
+ """
1027
1009
  # Clear the MCP tool cache when servers are reloaded
1028
1010
  self._mcp_tool_definitions_cache = []
1029
- self.load_mcp_servers()
1011
+
1012
+ # Force re-sync from mcp_servers.json
1030
1013
  manager = get_mcp_manager()
1014
+ manager.sync_from_config()
1015
+
1031
1016
  return manager.get_servers_for_agent()
1032
1017
 
1033
1018
  def _load_model_with_fallback(
@@ -201,15 +201,23 @@ class BlockingMCPServerStdio(SimpleCapturedMCPServerStdio):
201
201
 
202
202
  return result
203
203
 
204
- except Exception as e:
204
+ except BaseException as e:
205
205
  # Store error and mark as initialized (with error)
206
- self._init_error = e
206
+ # Unwrap ExceptionGroup if present (Python 3.11+)
207
+ if type(e).__name__ == "ExceptionGroup" and hasattr(e, "exceptions"):
208
+ # Use the first exception as the primary cause
209
+ self._init_error = e.exceptions[0]
210
+ error_details = f"{e.exceptions[0]}"
211
+ else:
212
+ self._init_error = e
213
+ error_details = str(e)
214
+
207
215
  self._initialized.set()
208
216
 
209
217
  # Emit error message
210
218
  server_name = getattr(self, "tool_prefix", self.command)
211
219
  emit_info(
212
- f"❌ MCP Server '{server_name}' failed to initialize: {e}",
220
+ f"❌ MCP Server '{server_name}' failed to initialize: {error_details}",
213
221
  style="red",
214
222
  message_group=self.message_group,
215
223
  )
@@ -6,6 +6,7 @@ that adds management capabilities while maintaining 100% compatibility.
6
6
  """
7
7
 
8
8
  import json
9
+ import os
9
10
  import uuid
10
11
  from dataclasses import dataclass, field
11
12
  from datetime import datetime, timedelta
@@ -222,7 +223,16 @@ class ManagedMCPServer:
222
223
  if "read_timeout" in config:
223
224
  http_kwargs["read_timeout"] = config["read_timeout"]
224
225
  if "headers" in config:
225
- http_kwargs["headers"] = config.get("headers")
226
+ # Expand environment variables in headers
227
+ headers = config.get("headers")
228
+ resolved_headers = {}
229
+ if isinstance(headers, dict):
230
+ for k, v in headers.items():
231
+ if isinstance(v, str):
232
+ resolved_headers[k] = os.path.expandvars(v)
233
+ else:
234
+ resolved_headers[k] = v
235
+ http_kwargs["headers"] = resolved_headers
226
236
  # Create HTTP client if headers are provided but no client specified
227
237
 
228
238
  self._pydantic_server = MCPServerStreamableHTTP(
@@ -243,8 +253,18 @@ class ManagedMCPServer:
243
253
  Configured async HTTP client with custom headers
244
254
  """
245
255
  headers = self.config.config.get("headers", {})
256
+
257
+ # Expand environment variables in headers
258
+ resolved_headers = {}
259
+ if isinstance(headers, dict):
260
+ for k, v in headers.items():
261
+ if isinstance(v, str):
262
+ resolved_headers[k] = os.path.expandvars(v)
263
+ else:
264
+ resolved_headers[k] = v
265
+
246
266
  timeout = self.config.config.get("timeout", 30)
247
- client = create_async_client(headers=headers, timeout=timeout)
267
+ client = create_async_client(headers=resolved_headers, timeout=timeout)
248
268
  return client
249
269
 
250
270
  def enable(self) -> None:
@@ -78,11 +78,76 @@ class MCPManager:
78
78
  # Active managed servers (server_id -> ManagedMCPServer)
79
79
  self._managed_servers: Dict[str, ManagedMCPServer] = {}
80
80
 
81
+ # Sync servers from mcp_servers.json into registry
82
+ self.sync_from_config()
83
+
81
84
  # Load existing servers from registry
82
85
  self._initialize_servers()
83
86
 
84
87
  logger.info("MCPManager initialized with core components")
85
88
 
89
+ def sync_from_config(self) -> None:
90
+ """Sync servers from mcp_servers.json into the registry.
91
+
92
+ This public method ensures that servers defined in the user's
93
+ configuration file are automatically registered with the manager.
94
+ It can be called during initialization or manually to reload
95
+ server configurations.
96
+
97
+ This is the single source of truth for syncing mcp_servers.json
98
+ into the registry, avoiding duplication with base_agent.py.
99
+ """
100
+ try:
101
+ from code_puppy.config import load_mcp_server_configs
102
+
103
+ configs = load_mcp_server_configs()
104
+ if not configs:
105
+ logger.debug("No servers found in mcp_servers.json")
106
+ return
107
+
108
+ synced_count = 0
109
+ updated_count = 0
110
+
111
+ for name, conf in configs.items():
112
+ try:
113
+ # Create ServerConfig from the loaded configuration
114
+ server_config = ServerConfig(
115
+ id=conf.get("id", ""), # Empty ID will be auto-generated
116
+ name=name,
117
+ type=conf.get("type", "sse"),
118
+ enabled=conf.get("enabled", True),
119
+ config=conf,
120
+ )
121
+
122
+ # Check if server already exists by name
123
+ existing = self.registry.get_by_name(name)
124
+
125
+ if not existing:
126
+ # Register new server
127
+ self.registry.register(server_config)
128
+ synced_count += 1
129
+ logger.debug(f"Synced new server from config: {name}")
130
+ else:
131
+ # Update existing server if config has changed
132
+ if existing.config != server_config.config:
133
+ server_config.id = existing.id # Keep existing ID
134
+ self.registry.update(existing.id, server_config)
135
+ updated_count += 1
136
+ logger.debug(f"Updated server from config: {name}")
137
+
138
+ except Exception as e:
139
+ logger.warning(f"Failed to sync server '{name}' from config: {e}")
140
+ continue
141
+
142
+ if synced_count > 0 or updated_count > 0:
143
+ logger.info(
144
+ f"Synced {synced_count} new and updated {updated_count} servers from mcp_servers.json"
145
+ )
146
+
147
+ except Exception as e:
148
+ logger.error(f"Failed to sync from mcp_servers.json: {e}")
149
+ # Don't fail initialization if sync fails
150
+
86
151
  def _initialize_servers(self) -> None:
87
152
  """Initialize managed servers from registry configurations."""
88
153
  configs = self.registry.list_all()
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "code-puppy"
7
- version = "0.0.315"
7
+ version = "0.0.316"
8
8
  description = "Code generation agent"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11,<3.14"
File without changes
File without changes
File without changes