code-puppy 0.0.132__tar.gz → 0.0.134__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 (112) hide show
  1. {code_puppy-0.0.132 → code_puppy-0.0.134}/PKG-INFO +1 -1
  2. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/command_line/mcp_commands.py +6 -0
  3. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/mcp/managed_server.py +3 -2
  4. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tui/screens/mcp_install_wizard.py +186 -5
  5. {code_puppy-0.0.132 → code_puppy-0.0.134}/pyproject.toml +1 -1
  6. {code_puppy-0.0.132 → code_puppy-0.0.134}/.gitignore +0 -0
  7. {code_puppy-0.0.132 → code_puppy-0.0.134}/LICENSE +0 -0
  8. {code_puppy-0.0.132 → code_puppy-0.0.134}/README.md +0 -0
  9. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/__init__.py +0 -0
  10. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/__main__.py +0 -0
  11. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/agent.py +0 -0
  12. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/agents/__init__.py +0 -0
  13. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/agents/agent_code_puppy.py +0 -0
  14. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/agents/agent_creator_agent.py +0 -0
  15. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/agents/agent_manager.py +0 -0
  16. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/agents/base_agent.py +0 -0
  17. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/agents/json_agent.py +0 -0
  18. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/agents/runtime_manager.py +0 -0
  19. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/callbacks.py +0 -0
  20. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/command_line/__init__.py +0 -0
  21. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/command_line/command_handler.py +0 -0
  22. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/command_line/file_path_completion.py +0 -0
  23. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/command_line/load_context_completion.py +0 -0
  24. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/command_line/meta_command_handler.py +0 -0
  25. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/command_line/model_picker_completion.py +0 -0
  26. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/command_line/motd.py +0 -0
  27. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/command_line/prompt_toolkit_completion.py +0 -0
  28. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/command_line/utils.py +0 -0
  29. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/config.py +0 -0
  30. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/http_utils.py +0 -0
  31. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/main.py +0 -0
  32. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/mcp/__init__.py +0 -0
  33. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/mcp/async_lifecycle.py +0 -0
  34. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/mcp/blocking_startup.py +0 -0
  35. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/mcp/captured_stdio_server.py +0 -0
  36. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/mcp/circuit_breaker.py +0 -0
  37. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/mcp/config_wizard.py +0 -0
  38. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/mcp/dashboard.py +0 -0
  39. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/mcp/error_isolation.py +0 -0
  40. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/mcp/examples/retry_example.py +0 -0
  41. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/mcp/health_monitor.py +0 -0
  42. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/mcp/manager.py +0 -0
  43. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/mcp/registry.py +0 -0
  44. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/mcp/retry_manager.py +0 -0
  45. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/mcp/server_registry_catalog.py +0 -0
  46. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/mcp/status_tracker.py +0 -0
  47. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/mcp/system_tools.py +0 -0
  48. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/message_history_processor.py +0 -0
  49. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/messaging/__init__.py +0 -0
  50. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/messaging/message_queue.py +0 -0
  51. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/messaging/queue_console.py +0 -0
  52. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/messaging/renderers.py +0 -0
  53. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/messaging/spinner/__init__.py +0 -0
  54. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/messaging/spinner/console_spinner.py +0 -0
  55. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/messaging/spinner/spinner_base.py +0 -0
  56. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/messaging/spinner/textual_spinner.py +0 -0
  57. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/model_factory.py +0 -0
  58. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/models.json +0 -0
  59. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/plugins/__init__.py +0 -0
  60. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/reopenable_async_client.py +0 -0
  61. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/state_management.py +0 -0
  62. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/status_display.py +0 -0
  63. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/summarization_agent.py +0 -0
  64. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/token_utils.py +0 -0
  65. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tools/__init__.py +0 -0
  66. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tools/command_runner.py +0 -0
  67. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tools/common.py +0 -0
  68. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tools/file_modifications.py +0 -0
  69. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tools/file_operations.py +0 -0
  70. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tools/token_check.py +0 -0
  71. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tools/tools_content.py +0 -0
  72. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tui/__init__.py +0 -0
  73. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tui/app.py +0 -0
  74. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tui/components/__init__.py +0 -0
  75. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tui/components/chat_view.py +0 -0
  76. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tui/components/command_history_modal.py +0 -0
  77. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tui/components/copy_button.py +0 -0
  78. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tui/components/custom_widgets.py +0 -0
  79. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tui/components/human_input_modal.py +0 -0
  80. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tui/components/input_area.py +0 -0
  81. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tui/components/sidebar.py +0 -0
  82. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tui/components/status_bar.py +0 -0
  83. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tui/messages.py +0 -0
  84. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tui/models/__init__.py +0 -0
  85. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tui/models/chat_message.py +0 -0
  86. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tui/models/command_history.py +0 -0
  87. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tui/models/enums.py +0 -0
  88. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tui/screens/__init__.py +0 -0
  89. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tui/screens/help.py +0 -0
  90. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tui/screens/settings.py +0 -0
  91. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tui/screens/tools.py +0 -0
  92. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tui/tests/__init__.py +0 -0
  93. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tui/tests/test_agent_command.py +0 -0
  94. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tui/tests/test_chat_message.py +0 -0
  95. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tui/tests/test_chat_view.py +0 -0
  96. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tui/tests/test_command_history.py +0 -0
  97. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tui/tests/test_copy_button.py +0 -0
  98. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tui/tests/test_custom_widgets.py +0 -0
  99. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tui/tests/test_disclaimer.py +0 -0
  100. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tui/tests/test_enums.py +0 -0
  101. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tui/tests/test_file_browser.py +0 -0
  102. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tui/tests/test_help.py +0 -0
  103. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tui/tests/test_history_file_reader.py +0 -0
  104. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tui/tests/test_input_area.py +0 -0
  105. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tui/tests/test_settings.py +0 -0
  106. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tui/tests/test_sidebar.py +0 -0
  107. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tui/tests/test_sidebar_history.py +0 -0
  108. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tui/tests/test_sidebar_history_navigation.py +0 -0
  109. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tui/tests/test_status_bar.py +0 -0
  110. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tui/tests/test_timestamped_history.py +0 -0
  111. {code_puppy-0.0.132 → code_puppy-0.0.134}/code_puppy/tui/tests/test_tools.py +0 -0
  112. {code_puppy-0.0.132 → code_puppy-0.0.134}/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.132
3
+ Version: 0.0.134
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
@@ -597,6 +597,12 @@ class MCPCommandHandler:
597
597
  import uuid
598
598
  group_id = str(uuid.uuid4())
599
599
 
600
+ # Check if in TUI mode and guide user to use Ctrl+T instead
601
+ if is_tui_mode() and not args:
602
+ emit_info("💡 In TUI mode, press Ctrl+T to open the MCP Install Wizard", message_group=group_id)
603
+ emit_info(" The wizard provides a better interface for browsing and installing MCP servers.", message_group=group_id)
604
+ return
605
+
600
606
  try:
601
607
  if args:
602
608
  # Parse JSON from arguments
@@ -18,6 +18,7 @@ from pydantic_ai import RunContext
18
18
 
19
19
  from pydantic_ai.mcp import MCPServerSSE, MCPServerStdio, MCPServerStreamableHTTP, CallToolFunc, ToolResult
20
20
 
21
+ from code_puppy.http_utils import create_async_client
21
22
  from code_puppy.messaging import emit_info
22
23
  from code_puppy.mcp.blocking_startup import BlockingMCPServerStdio
23
24
 
@@ -251,11 +252,11 @@ class ManagedMCPServer:
251
252
  """
252
253
  headers = self.config.config.get("headers", {})
253
254
  timeout = self.config.config.get("timeout", 30)
254
-
255
- return httpx.AsyncClient(
255
+ client = create_async_client(
256
256
  headers=headers,
257
257
  timeout=timeout
258
258
  )
259
+ return client
259
260
 
260
261
  def enable(self) -> None:
261
262
  """Enable server availability."""
@@ -31,8 +31,9 @@ class MCPInstallWizardScreen(ModalScreen):
31
31
  super().__init__(**kwargs)
32
32
  self.selected_server = None
33
33
  self.env_vars = {}
34
- self.step = "search" # search -> configure -> install
34
+ self.step = "search" # search -> configure -> install -> custom_json
35
35
  self.search_counter = 0 # Counter to ensure unique IDs
36
+ self.custom_json_mode = False # Track if we're in custom JSON mode
36
37
 
37
38
  DEFAULT_CSS = """
38
39
  MCPInstallWizardScreen {
@@ -139,6 +140,43 @@ class MCPInstallWizardScreen(ModalScreen):
139
140
  width: 2fr;
140
141
  border: solid $primary;
141
142
  }
143
+
144
+ #custom-json-container {
145
+ width: 100%;
146
+ height: 1fr;
147
+ layout: vertical;
148
+ display: none;
149
+ padding: 1;
150
+ }
151
+
152
+ #custom-json-header {
153
+ width: 100%;
154
+ height: 2;
155
+ text-align: left;
156
+ color: $warning;
157
+ margin-bottom: 1;
158
+ }
159
+
160
+ #custom-name-input {
161
+ width: 100%;
162
+ margin-bottom: 1;
163
+ border: solid $primary;
164
+ }
165
+
166
+ #custom-json-input {
167
+ width: 100%;
168
+ height: 1fr;
169
+ border: solid $primary;
170
+ margin-bottom: 1;
171
+ background: $surface-darken-1;
172
+ }
173
+
174
+ #custom-json-button {
175
+ width: auto;
176
+ height: 3;
177
+ margin: 0 1;
178
+ min-width: 14;
179
+ }
142
180
  """
143
181
 
144
182
  def compose(self) -> ComposeResult:
@@ -157,10 +195,17 @@ class MCPInstallWizardScreen(ModalScreen):
157
195
  yield Container(id="server-info")
158
196
  yield Container(id="env-vars-container")
159
197
 
198
+ # Step 3: Custom JSON configuration (hidden initially)
199
+ with Container(id="custom-json-container"):
200
+ yield Static("📝 Custom JSON Configuration", id="custom-json-header")
201
+ yield Input(placeholder="Server name (e.g. 'my-sqlite-db')", id="custom-name-input")
202
+ yield TextArea(id="custom-json-input")
203
+
160
204
  # Navigation buttons
161
205
  with Horizontal(id="button-container"):
162
206
  yield Button("Cancel", id="cancel-button", variant="default")
163
207
  yield Button("Back", id="back-button", variant="default")
208
+ yield Button("Custom JSON", id="custom-json-button", variant="warning")
164
209
  yield Button("Next", id="next-button", variant="primary")
165
210
  yield Button("Install", id="install-button", variant="success")
166
211
 
@@ -176,40 +221,78 @@ class MCPInstallWizardScreen(ModalScreen):
176
221
  def _show_search_step(self) -> None:
177
222
  """Show the search step."""
178
223
  self.step = "search"
224
+ self.custom_json_mode = False
179
225
  self.query_one("#search-container").display = True
180
226
  self.query_one("#config-container").display = False
227
+ self.query_one("#custom-json-container").display = False
181
228
 
182
229
  self.query_one("#back-button").display = False
230
+ self.query_one("#custom-json-button").display = True
183
231
  self.query_one("#next-button").display = True
184
232
  self.query_one("#install-button").display = False
185
233
 
186
234
  def _show_config_step(self) -> None:
187
235
  """Show the configuration step."""
188
236
  self.step = "configure"
237
+ self.custom_json_mode = False
189
238
  self.query_one("#search-container").display = False
190
239
  self.query_one("#config-container").display = True
240
+ self.query_one("#custom-json-container").display = False
191
241
 
192
242
  self.query_one("#back-button").display = True
243
+ self.query_one("#custom-json-button").display = False
193
244
  self.query_one("#next-button").display = False
194
245
  self.query_one("#install-button").display = True
195
246
 
196
247
  self._setup_server_config()
248
+
249
+ def _show_custom_json_step(self) -> None:
250
+ """Show the custom JSON configuration step."""
251
+ self.step = "custom_json"
252
+ self.custom_json_mode = True
253
+ self.query_one("#search-container").display = False
254
+ self.query_one("#config-container").display = False
255
+ self.query_one("#custom-json-container").display = True
256
+
257
+ self.query_one("#back-button").display = True
258
+ self.query_one("#custom-json-button").display = False
259
+ self.query_one("#next-button").display = False
260
+ self.query_one("#install-button").display = True
261
+
262
+ # Pre-populate with SQLite example
263
+ name_input = self.query_one("#custom-name-input", Input)
264
+ name_input.value = "my-sqlite-db"
265
+
266
+ json_input = self.query_one("#custom-json-input", TextArea)
267
+ json_input.text = """{
268
+ "type": "stdio",
269
+ "command": "npx",
270
+ "args": ["-y", "@modelcontextprotocol/server-sqlite", "./database.db"],
271
+ "timeout": 30
272
+ }"""
273
+
274
+ # Focus the name input
275
+ name_input.focus()
197
276
 
198
277
  def _load_popular_servers(self) -> None:
199
- """Load popular servers into the list."""
278
+ """Load all available servers into the list."""
200
279
  self.search_counter += 1
201
280
  counter = self.search_counter
202
281
 
203
282
  try:
204
283
  from code_puppy.mcp.server_registry_catalog import catalog
205
- servers = catalog.get_popular(10)
284
+ # Load ALL servers instead of just popular ones
285
+ servers = catalog.servers
206
286
 
207
287
  results_list = self.query_one("#results-list", ListView)
208
288
  # Force clear by removing all children
209
289
  results_list.remove_children()
210
290
 
211
291
  if servers:
212
- for i, server in enumerate(servers):
292
+ # Sort servers to show popular and verified first
293
+ sorted_servers = sorted(servers, key=lambda s: (not s.popular, not s.verified, s.display_name))
294
+
295
+ for i, server in enumerate(sorted_servers):
213
296
  indicators = []
214
297
  if server.verified:
215
298
  indicators.append("✓")
@@ -240,7 +323,7 @@ class MCPInstallWizardScreen(ModalScreen):
240
323
  query = event.value.strip()
241
324
 
242
325
  if not query:
243
- self._load_popular_servers()
326
+ self._load_popular_servers() # This now loads all servers
244
327
  return
245
328
 
246
329
  self.search_counter += 1
@@ -301,12 +384,21 @@ class MCPInstallWizardScreen(ModalScreen):
301
384
  """Handle back button click."""
302
385
  if self.step == "configure":
303
386
  self._show_search_step()
387
+ elif self.step == "custom_json":
388
+ self._show_search_step()
304
389
 
390
+ @on(Button.Pressed, "#custom-json-button")
391
+ def on_custom_json_clicked(self) -> None:
392
+ """Handle custom JSON button click."""
393
+ self._show_custom_json_step()
394
+
305
395
  @on(Button.Pressed, "#install-button")
306
396
  def on_install_clicked(self) -> None:
307
397
  """Handle install button click."""
308
398
  if self.step == "configure" and self.selected_server:
309
399
  self._install_server()
400
+ elif self.step == "custom_json":
401
+ self._install_custom_json()
310
402
 
311
403
  @on(Button.Pressed, "#cancel-button")
312
404
  def on_cancel_clicked(self) -> None:
@@ -587,6 +679,95 @@ class MCPInstallWizardScreen(ModalScreen):
587
679
  "message": f"Installation failed: {str(e)}"
588
680
  })
589
681
 
682
+ def _install_custom_json(self) -> None:
683
+ """Install server from custom JSON configuration."""
684
+ try:
685
+ name_input = self.query_one("#custom-name-input", Input)
686
+ json_input = self.query_one("#custom-json-input", TextArea)
687
+
688
+ server_name = name_input.value.strip()
689
+ json_text = json_input.text.strip()
690
+
691
+ if not server_name:
692
+ # Show error - need a name
693
+ return
694
+
695
+ if not json_text:
696
+ # Show error - need JSON config
697
+ return
698
+
699
+ # Parse JSON
700
+ try:
701
+ config_dict = json.loads(json_text)
702
+ except json.JSONDecodeError as e:
703
+ # Show error - invalid JSON
704
+ return
705
+
706
+ # Validate required fields
707
+ if 'type' not in config_dict:
708
+ # Show error - missing type
709
+ return
710
+
711
+ # Extract type and create server config
712
+ server_type = config_dict.pop('type')
713
+
714
+ # Create and register the server
715
+ from code_puppy.mcp import ServerConfig
716
+ from code_puppy.mcp.manager import get_mcp_manager
717
+
718
+ server_config = ServerConfig(
719
+ id=server_name,
720
+ name=server_name,
721
+ type=server_type,
722
+ enabled=True,
723
+ config=config_dict
724
+ )
725
+
726
+ manager = get_mcp_manager()
727
+ server_id = manager.register_server(server_config)
728
+
729
+ if server_id:
730
+ # Save to mcp_servers.json
731
+ from code_puppy.config import MCP_SERVERS_FILE
732
+
733
+ if os.path.exists(MCP_SERVERS_FILE):
734
+ with open(MCP_SERVERS_FILE, 'r') as f:
735
+ data = json.load(f)
736
+ servers = data.get("mcp_servers", {})
737
+ else:
738
+ servers = {}
739
+ data = {"mcp_servers": servers}
740
+
741
+ # Add the full config including type
742
+ full_config = config_dict.copy()
743
+ full_config['type'] = server_type
744
+ servers[server_name] = full_config
745
+
746
+ os.makedirs(os.path.dirname(MCP_SERVERS_FILE), exist_ok=True)
747
+ with open(MCP_SERVERS_FILE, 'w') as f:
748
+ json.dump(data, f, indent=2)
749
+
750
+ # Reload MCP servers
751
+ from code_puppy.agent import reload_mcp_servers
752
+ reload_mcp_servers()
753
+
754
+ self.dismiss({
755
+ "success": True,
756
+ "message": f"Successfully installed custom server '{server_name}'",
757
+ "server_name": server_name
758
+ })
759
+ else:
760
+ self.dismiss({
761
+ "success": False,
762
+ "message": "Failed to register custom server"
763
+ })
764
+
765
+ except Exception as e:
766
+ self.dismiss({
767
+ "success": False,
768
+ "message": f"Installation failed: {str(e)}"
769
+ })
770
+
590
771
  def on_key(self, event) -> None:
591
772
  """Handle key events."""
592
773
  if event.key == "escape":
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "code-puppy"
7
- version = "0.0.132"
7
+ version = "0.0.134"
8
8
  description = "Code generation agent"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
File without changes
File without changes
File without changes