@@ -86,16 +86,7 @@ def init_ui(self):
8686 right_panel = QWidget()
8787 right_layout = QVBoxLayout(right_panel)
8888
89- # Add toggle button for view mode
90- toggle_layout = QHBoxLayout()
91- self.show_code_btn = QPushButton("Show Code")
92- self.show_code_btn.setStyleSheet(style_provider.get_button_style("primary"))
93- self.show_code_btn.clicked.connect(self._toggle_view_mode)
94- self.show_code_btn.setEnabled(False) # Disable until selection
95- toggle_layout.addWidget(self.show_code_btn)
96- toggle_layout.addStretch()
97-
98- right_layout.addLayout(toggle_layout)
89+ right_layout.addLayout(QHBoxLayout()) # Empty layout placeholder
9990
10091 # Create stacked widget for switching between form and code views
10192 self.stacked_widget = QStackedWidget()
@@ -172,6 +163,23 @@ def init_ui(self):
172163 self.env_layout.addLayout(env_btn_layout)
173164 env_group.setLayout(self.env_layout)
174165
166+ # Headers section (for streaming servers)
167+ headers_group = QGroupBox("HTTP Headers")
168+ self.headers_group = headers_group # Store reference
169+ self.headers_layout = QVBoxLayout()
170+ self.header_inputs = []
171+
172+ # Add button for headers
173+ headers_btn_layout = QHBoxLayout()
174+ self.add_header_btn = QPushButton("Add Header")
175+ self.add_header_btn.setStyleSheet(style_provider.get_button_style("primary"))
176+ self.add_header_btn.clicked.connect(lambda: self.add_header_field("", ""))
177+ headers_btn_layout.addWidget(self.add_header_btn)
178+ headers_btn_layout.addStretch()
179+
180+ self.headers_layout.addLayout(headers_btn_layout)
181+ headers_group.setLayout(self.headers_layout)
182+
175183 # Enabled for agents section
176184 enabled_group = QGroupBox("Enabled For Agents")
177185 enabled_layout = QVBoxLayout()
@@ -188,18 +196,12 @@ def init_ui(self):
188196
189197 enabled_group.setLayout(enabled_layout)
190198
191- # Save button
192- self.save_btn = QPushButton("Save")
193- self.save_btn.setStyleSheet(style_provider.get_button_style("primary"))
194- self.save_btn.clicked.connect(self.save_mcp)
195- self.save_btn.setEnabled(False) # Disable until selection
196-
197- # Add all components to editor layout
199+ # Add all components to editor layout (Save button moved to right_layout)
198200 self.editor_layout.addLayout(form_layout)
199201 self.editor_layout.addWidget(args_group)
200202 self.editor_layout.addWidget(env_group)
203+ self.editor_layout.addWidget(headers_group)
201204 self.editor_layout.addWidget(enabled_group)
202- self.editor_layout.addWidget(self.save_btn)
203205 self.editor_layout.addStretch()
204206
205207 form_scroll.setWidget(self.editor_widget)
@@ -215,6 +217,26 @@ def init_ui(self):
215217
216218 right_layout.addWidget(self.stacked_widget)
217219
220+ # Button layout with Show Code and Save buttons in same row
221+ button_layout = QHBoxLayout()
222+
223+ # Show Code button (secondary color)
224+ self.show_code_btn = QPushButton("Show Code")
225+ self.show_code_btn.setStyleSheet(style_provider.get_button_style("secondary"))
226+ self.show_code_btn.clicked.connect(self._toggle_view_mode)
227+ self.show_code_btn.setEnabled(False) # Disable until selection
228+
229+ # Save button (primary color)
230+ self.save_btn = QPushButton("Save")
231+ self.save_btn.setStyleSheet(style_provider.get_button_style("primary"))
232+ self.save_btn.clicked.connect(self.save_mcp)
233+ self.save_btn.setEnabled(False) # Disable until selection
234+
235+ button_layout.addWidget(self.show_code_btn)
236+ button_layout.addWidget(self.save_btn)
237+
238+ right_layout.addLayout(button_layout)
239+
218240 # Add panels to splitter
219241 splitter = QSplitter(Qt.Orientation.Horizontal)
220242 splitter.addWidget(left_panel)
@@ -305,6 +327,12 @@ def on_mcp_selected(self, current, previous):
305327 for key, value in env.items():
306328 self.add_env_field(key, value, mark_dirty_on_add=False)
307329
330+ self.clear_header_fields()
331+
332+ headers = server_config.get("headers", {})
333+ for key, value in headers.items():
334+ self.add_header_field(key, value, mark_dirty_on_add=False)
335+
308336 # Set agent checkboxes
309337 enabled_agents = server_config.get("enabledForAgents", [])
310338 for agent, checkbox in self.agent_checkboxes.items():
@@ -323,6 +351,13 @@ def on_mcp_selected(self, current, previous):
323351 def _set_sse_fields_visisble(self, visible: bool):
324352 self.url_input.setVisible(visible)
325353 self.url_label.setVisible(visible)
354+ self.add_header_btn.setVisible(visible)
355+ for header_input in self.header_inputs:
356+ header_input["key_input"].setVisible(visible)
357+ header_input["value_input"].setVisible(visible)
358+ header_input["remove_btn"].setVisible(visible)
359+ if hasattr(self, "headers_group"):
360+ self.headers_group.setVisible(visible)
326361
327362 def _set_stdio_fields_visible(self, visible: bool):
328363 self.command_input.setVisible(visible)
@@ -369,12 +404,15 @@ def set_editor_enabled(self, enabled: bool):
369404 self.args_group.setVisible(False)
370405 if hasattr(self, "env_group"):
371406 self.env_group.setVisible(False)
407+ if hasattr(self, "headers_group"):
408+ self.headers_group.setVisible(False)
372409
373410 # Always enable/disable these regardless of visibility
374411 self.url_input.setEnabled(enabled)
375412 self.command_input.setEnabled(enabled)
376413 self.add_arg_btn.setEnabled(enabled)
377414 self.add_env_btn.setEnabled(enabled)
415+ self.add_header_btn.setEnabled(enabled)
378416
379417 for checkbox in self.agent_checkboxes.values():
380418 checkbox.setEnabled(enabled)
@@ -397,7 +435,16 @@ def set_editor_enabled(self, enabled: bool):
397435 env_input["value_input"].setVisible(not is_streaming)
398436 env_input["remove_btn"].setVisible(not is_streaming)
399437
400- # Enable/disable JSON editor
438+ for header_input in self.header_inputs:
439+ header_input["key_input"].setEnabled(enabled)
440+ header_input["value_input"].setEnabled(enabled)
441+ header_input["remove_btn"].setEnabled(enabled)
442+ if enabled:
443+ is_streaming = self.streaming_server_checkbox.isChecked()
444+ header_input["key_input"].setVisible(is_streaming)
445+ header_input["value_input"].setVisible(is_streaming)
446+ header_input["remove_btn"].setVisible(is_streaming)
447+
401448 self.json_editor.set_read_only(not enabled)
402449
403450 if not enabled:
@@ -518,6 +565,68 @@ def clear_env_fields(self):
518565 while self.env_inputs:
519566 self.remove_env_field(self.env_inputs[0])
520567
568+ def add_header_field(self, key="", value="", mark_dirty_on_add=True):
569+ """Add a field for an HTTP header."""
570+ header_layout = QHBoxLayout()
571+
572+ key_input = QLineEdit()
573+ key_input.setText(str(key))
574+ key_input.setPlaceholderText("Header Name (e.g., Authorization)")
575+ key_input.textChanged.connect(self._mark_dirty)
576+
577+ value_input = QLineEdit()
578+ value_input.setText(str(value))
579+ value_input.setPlaceholderText("Header Value (e.g., Bearer token)")
580+ value_input.textChanged.connect(self._mark_dirty)
581+
582+ remove_btn = QPushButton("Remove")
583+ remove_btn.setMaximumWidth(80)
584+
585+ style_provider = StyleProvider()
586+ remove_btn.setStyleSheet(style_provider.get_button_style("red"))
587+
588+ header_layout.addWidget(key_input)
589+ header_layout.addWidget(value_input)
590+ header_layout.addWidget(remove_btn)
591+
592+ # Insert before the add button
593+ self.headers_layout.insertLayout(len(self.header_inputs), header_layout)
594+
595+ # Store references
596+ header_data = {
597+ "layout": header_layout,
598+ "key_input": key_input,
599+ "value_input": value_input,
600+ "remove_btn": remove_btn,
601+ }
602+ self.header_inputs.append(header_data)
603+
604+ # Connect remove button
605+ remove_btn.clicked.connect(lambda: self.remove_header_field(header_data))
606+
607+ if mark_dirty_on_add:
608+ self._mark_dirty()
609+ return header_data
610+
611+ def remove_header_field(self, header_data):
612+ """Remove an HTTP header field."""
613+ # Remove from layout
614+ self.headers_layout.removeItem(header_data["layout"])
615+
616+ # Delete widgets
617+ header_data["key_input"].deleteLater()
618+ header_data["value_input"].deleteLater()
619+ header_data["remove_btn"].deleteLater()
620+
621+ # Remove from list
622+ self.header_inputs.remove(header_data)
623+ self._mark_dirty()
624+
625+ def clear_header_fields(self):
626+ """Clear all HTTP header fields."""
627+ while self.header_inputs:
628+ self.remove_header_field(self.header_inputs[0])
629+
521630 def add_new_mcp(self):
522631 """Add a new MCP server to the configuration."""
523632 # Create a new server with default values
@@ -530,6 +639,7 @@ def add_new_mcp(self):
530639 "enabledForAgents": [],
531640 "streaming_server": False,
532641 "url": "",
642+ "headers": {},
533643 }
534644
535645 # Add to list
@@ -574,6 +684,7 @@ def remove_mcp(self):
574684 self.command_input.clear()
575685 self.clear_argument_fields()
576686 self.clear_env_fields()
687+ self.clear_header_fields()
577688 for checkbox in self.agent_checkboxes.values():
578689 checkbox.setChecked(False)
579690 self.save_all_mcps()
@@ -672,9 +783,7 @@ def _toggle_view_mode(self):
672783 server_id, server_config = current_item.data(Qt.ItemDataRole.UserRole)
673784
674785 if self.is_code_view:
675- # Switching from code view to form view
676786 try:
677- # Get JSON data from editor and update form
678787 json_data = self.json_editor.get_json()
679788 self._update_form_from_json(json_data, server_id)
680789 self.stacked_widget.setCurrentIndex(0) # Form view
@@ -688,8 +797,6 @@ def _toggle_view_mode(self):
688797 )
689798 return
690799 else:
691- # Switching from form view to code view
692- # Update server data from form and set JSON
693800 server_data = self._get_form_data()
694801 if server_data: # Only proceed if form data is valid
695802 self.json_editor.set_json(server_data)
@@ -720,6 +827,14 @@ def _get_form_data(self) -> dict:
720827 if key:
721828 env[key] = value
722829
830+ # Get headers
831+ headers = {}
832+ for header_data in self.header_inputs:
833+ key = header_data["key_input"].text().strip()
834+ value = header_data["value_input"].text().strip()
835+ if key:
836+ headers[key] = value
837+
723838 # Get enabled agents
724839 enabled_agents = [
725840 agent
@@ -735,6 +850,7 @@ def _get_form_data(self) -> dict:
735850 "enabledForAgents": enabled_agents,
736851 "streaming_server": streaming_server,
737852 "url": url,
853+ "headers": headers,
738854 }
739855
740856 def _update_form_from_json(self, json_data: dict, server_id: str):
@@ -760,6 +876,10 @@ def _update_form_from_json(self, json_data: dict, server_id: str):
760876 for key, value in json_data.get("env", {}).items():
761877 self.add_env_field(key, value, mark_dirty_on_add=False)
762878
879+ self.clear_header_fields()
880+ for key, value in json_data.get("headers", {}).items():
881+ self.add_header_field(key, value, mark_dirty_on_add=False)
882+
763883 enabled_agents = json_data.get("enabledForAgents", [])
764884 for agent, checkbox in self.agent_checkboxes.items():
765885 checkbox.setChecked(agent in enabled_agents)
0 commit comments