interactive_feedback
Request user feedback or ask a question through a pop-up dialog to prevent speculative actions and reduce resource usage by confirming steps before proceeding.
Instructions
Request interactive feedback or ask the user a question by popping up a UI dialog.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| project_directory | Yes | Full path to the project directory or current working directory | |
| summary | Yes | Short summary of your work, OR the question you want to ask the user |
Implementation Reference
- server.py:62-68 (handler)The tool handler function for 'interactive_feedback'. Decorated with @mcp.tool(), it takes a project_directory and summary, and launches a feedback UI dialog via launch_feedback_ui().
@mcp.tool() def interactive_feedback( project_directory: Annotated[str, Field(description="Full path to the project directory or current working directory")], summary: Annotated[str, Field(description="Short summary of your work, OR the question you want to ask the user")], ) -> Dict[str, str]: """Request interactive feedback or ask the user a question by popping up a UI dialog.""" return launch_feedback_ui(first_line(project_directory), first_line(summary)) - server.py:62-68 (schema)Input schema defined via Annotated[str, Field(...)] for project_directory and summary parameters with descriptions.
@mcp.tool() def interactive_feedback( project_directory: Annotated[str, Field(description="Full path to the project directory or current working directory")], summary: Annotated[str, Field(description="Short summary of your work, OR the question you want to ask the user")], ) -> Dict[str, str]: """Request interactive feedback or ask the user a question by popping up a UI dialog.""" return launch_feedback_ui(first_line(project_directory), first_line(summary)) - server.py:62-68 (registration)Tool registration via @mcp.tool() decorator on the interactive_feedback function, using FastMCP instance defined on line 14.
@mcp.tool() def interactive_feedback( project_directory: Annotated[str, Field(description="Full path to the project directory or current working directory")], summary: Annotated[str, Field(description="Short summary of your work, OR the question you want to ask the user")], ) -> Dict[str, str]: """Request interactive feedback or ask the user a question by popping up a UI dialog.""" return launch_feedback_ui(first_line(project_directory), first_line(summary)) - server.py:16-57 (helper)Helper function launch_feedback_ui() that launches feedback_ui.py as a subprocess, writing results to a temp JSON file.
def launch_feedback_ui(project_directory: str, summary: str) -> dict[str, str]: # Create a temporary file for the feedback result with tempfile.NamedTemporaryFile(suffix=".json", delete=False) as tmp: output_file = tmp.name try: # Get the path to feedback_ui.py relative to this script script_dir = os.path.dirname(os.path.abspath(__file__)) feedback_ui_path = os.path.join(script_dir, "feedback_ui.py") # Run feedback_ui.py as a separate process # NOTE: There appears to be a bug in uv, so we need # to pass a bunch of special flags to make this work args = [ sys.executable, "-u", feedback_ui_path, "--project-directory", project_directory, "--prompt", summary, "--output-file", output_file ] result = subprocess.run( args, check=False, shell=False, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, stdin=subprocess.DEVNULL, close_fds=True ) if result.returncode != 0: raise Exception(f"Failed to launch feedback UI: {result.returncode}") # Read the result from the temporary file with open(output_file, 'r') as f: result = json.load(f) os.unlink(output_file) return result except Exception as e: if os.path.exists(output_file): os.unlink(output_file) raise e - feedback_ui.py:488-569 (helper)The _submit_feedback method in FeedbackUI that creates a FeedbackResult dict with 'interactive_feedback' key containing the user's text input.
def _submit_feedback(self): self.feedback_result = FeedbackResult( logs="".join(self.log_buffer), interactive_feedback=self.feedback_text.toPlainText().strip(), ) self.close() def clear_logs(self): self.log_buffer = [] self.log_text.clear() def _save_config(self): # Save run_command and execute_automatically to QSettings under project group self.settings.beginGroup(self.project_group_name) self.settings.setValue("run_command", self.config["run_command"]) self.settings.setValue("execute_automatically", self.config["execute_automatically"]) self.settings.endGroup() self._append_log("Configuration saved for this project.\n") def closeEvent(self, event): # Save general UI settings for the main window (geometry, state) self.settings.beginGroup("MainWindow_General") self.settings.setValue("geometry", self.saveGeometry()) self.settings.setValue("windowState", self.saveState()) self.settings.endGroup() # Save project-specific command section visibility (this is now slightly redundant due to immediate save in toggle, but harmless) self.settings.beginGroup(self.project_group_name) self.settings.setValue("commandSectionVisible", self.command_group.isVisible()) self.settings.endGroup() if self.process: kill_tree(self.process) super().closeEvent(event) def run(self) -> FeedbackResult: self.show() QApplication.instance().exec() if self.process: kill_tree(self.process) if not self.feedback_result: return FeedbackResult(logs="".join(self.log_buffer), interactive_feedback="") return self.feedback_result def get_project_settings_group(project_dir: str) -> str: # Create a safe, unique group name from the project directory path # Using only the last component + hash of full path to keep it somewhat readable but unique basename = os.path.basename(os.path.normpath(project_dir)) full_hash = hashlib.md5(project_dir.encode('utf-8')).hexdigest()[:8] return f"{basename}_{full_hash}" def feedback_ui(project_directory: str, prompt: str, output_file: Optional[str] = None) -> Optional[FeedbackResult]: app = QApplication.instance() or QApplication() app.setPalette(get_dark_mode_palette(app)) app.setStyle("Fusion") ui = FeedbackUI(project_directory, prompt) result = ui.run() if output_file and result: # Ensure the directory exists os.makedirs(os.path.dirname(output_file) if os.path.dirname(output_file) else ".", exist_ok=True) # Save the result to the output file with open(output_file, "w") as f: json.dump(result, f) return None return result if __name__ == "__main__": parser = argparse.ArgumentParser(description="Run the feedback UI") parser.add_argument("--project-directory", default=os.getcwd(), help="The project directory to run the command in") parser.add_argument("--prompt", default="I implemented the changes you requested.", help="The prompt to show to the user") parser.add_argument("--output-file", help="Path to save the feedback result as JSON") args = parser.parse_args() result = feedback_ui(args.project_directory, args.prompt, args.output_file) if result: print(f"\nLogs collected: \n{result['logs']}") print(f"\nFeedback received:\n{result['interactive_feedback']}")