forked from noopstudios/interactive-feedback-mcp
-
Notifications
You must be signed in to change notification settings - Fork 32
Expand file tree
/
Copy pathserver.py
More file actions
72 lines (63 loc) · 2.64 KB
/
server.py
File metadata and controls
72 lines (63 loc) · 2.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# Interactive Feedback MCP
# Developed by Fábio Ferreira (https://x.com/fabiomlferreira)
# Inspired by/related to dotcursorrules.com (https://dotcursorrules.com/)
# Enhanced by Pau Oliva (https://x.com/pof) with ideas from https://github.com/ttommyth/interactive-mcp
import os
import sys
import json
import tempfile
import subprocess
from typing import Annotated, Dict
from fastmcp import FastMCP
from pydantic import Field
# The log_level is necessary for Cline to work: https://github.com/jlowin/fastmcp/issues/81
mcp = FastMCP("Interactive Feedback MCP", log_level="ERROR")
def launch_feedback_ui(summary: str, predefinedOptions: list[str] | None = None) -> 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,
"--prompt", summary,
"--output-file", output_file,
"--predefined-options", "|||".join(predefinedOptions) if predefinedOptions else ""
]
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
@mcp.tool()
def interactive_feedback(
message: str = Field(description="The specific question for the user"),
predefined_options: list = Field(default=None, description="Predefined options for the user to choose from (optional)"),
) -> Dict[str, str]:
"""Request interactive feedback from the user"""
predefined_options_list = predefined_options if isinstance(predefined_options, list) else None
return launch_feedback_ui(message, predefined_options_list)
if __name__ == "__main__":
mcp.run(transport="stdio")