André Oliveira commited on
Commit
188a5d8
·
1 Parent(s): 7f8656a

added tool mcp upload

Browse files
Files changed (2) hide show
  1. api.py +1 -0
  2. app.py +33 -56
api.py CHANGED
@@ -73,6 +73,7 @@ async def upload_docs(
73
  saved_files.append(file.filename)
74
  return {"status": "ok", "uploaded_files": saved_files, "docs_path": docs_path}
75
 
 
76
  @app.post("/optimize_rag")
77
  def optimize_rag(req: OptimizeRequest):
78
  logger.info("Received optimize_rag request: %s", req.json())
 
73
  saved_files.append(file.filename)
74
  return {"status": "ok", "uploaded_files": saved_files, "docs_path": docs_path}
75
 
76
+
77
  @app.post("/optimize_rag")
78
  def optimize_rag(req: OptimizeRequest):
79
  logger.info("Received optimize_rag request: %s", req.json())
app.py CHANGED
@@ -6,6 +6,8 @@ import threading
6
  from models import OptimizeRequest, AutotuneRequest, QARequest
7
  from api import start_api
8
 
 
 
9
  # Start FastAPI server in background
10
  threading.Thread(target=start_api, daemon=True).start()
11
 
@@ -29,39 +31,53 @@ def upload_docs_tool(files, docs_path="data/docs"):
29
  - URLs (str)
30
  - file-like objects (from Cursor attachment)
31
  """
32
- import shutil
33
 
34
  os.makedirs(docs_path, exist_ok=True)
35
  files_payload = []
36
 
37
- for f in files:
38
- if isinstance(f, str) and (f.startswith("http://") or f.startswith("https://")):
39
- # Download URL temporarily
40
- fname = f.split("/")[-1]
41
- tmp_path = os.path.join("/tmp", fname)
42
- r = requests.get(f, stream=True)
43
- with open(tmp_path, "wb") as out_file:
44
- shutil.copyfileobj(r.raw, out_file)
45
- files_payload.append(("files", open(tmp_path, "rb")))
46
- elif isinstance(f, str):
47
- # Local file path
48
- files_payload.append(("files", open(f, "rb")))
49
- else:
50
- # Assume file-like object (Cursor attachment)
51
- files_payload.append(("files", f))
52
 
53
  try:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  resp = requests.post(
55
  f"{BASE_INTERNAL}/upload_docs",
56
  files=files_payload,
57
  data={"docs_path": docs_path}
58
  )
 
59
  return resp.json()
 
60
  finally:
61
  # Close all file handles
62
  for _, file_obj in files_payload:
63
  if not file_obj.closed:
64
  file_obj.close()
 
 
 
 
 
 
 
65
 
66
 
67
  def optimize_rag_tool(payload: str) -> str:
@@ -86,33 +102,7 @@ generate_qa_tool.__doc__ = QARequest.__doc__
86
 
87
 
88
  def model_to_json(model_cls) -> str:
89
- return json.dumps({k: v.default for k, v in model_cls.__fields__.items()}, indent=2)
90
-
91
-
92
- def upload_docs_tool_mcp(payload: str, files=None):
93
- """
94
- 📦 Upload documents to the server's docs folder via FastAPI /upload_docs.
95
- Accepts:
96
- - attached file(s) from Cursor MCP agent
97
- - 'docs_path' in JSON payload
98
- """
99
- data = json.loads(payload) if payload else {}
100
- docs_path = data.get("docs_path", DEFAULT_UPLOAD_PATH)
101
-
102
- if not files:
103
- return {"error": "No files provided to upload_docs_tool_mcp"}
104
-
105
- os.makedirs(docs_path, exist_ok=True)
106
-
107
- files_payload = [("files", (f.name, f, "application/octet-stream")) for f in files]
108
-
109
- resp = requests.post(
110
- f"{BASE_INTERNAL}/upload_docs",
111
- files=files_payload,
112
- data={"docs_path": docs_path}
113
- )
114
-
115
- return resp.json()
116
 
117
 
118
  # Default inputs
@@ -167,19 +157,6 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
167
  gr.Markdown("---")
168
 
169
  if __name__ == "__main__":
170
- # Register MCP tools
171
- demo.add_mcp_tool(
172
- name="ragmint_upload_docs_mcp",
173
- func=upload_docs_tool_mcp,
174
- description="📂 Upload documents to data/docs for use in RAG optimization and autotuning",
175
- parameters={
176
- "type": "object",
177
- "properties": {
178
- "docs_path": {"type": "string", "description": "Target directory for uploaded docs"}
179
- }
180
- },
181
- file_input=True # <<< enables file attachments from Cursor
182
- )
183
 
184
  demo.launch(
185
  server_name="0.0.0.0",
 
6
  from models import OptimizeRequest, AutotuneRequest, QARequest
7
  from api import start_api
8
 
9
+
10
+
11
  # Start FastAPI server in background
12
  threading.Thread(target=start_api, daemon=True).start()
13
 
 
31
  - URLs (str)
32
  - file-like objects (from Cursor attachment)
33
  """
34
+ import shutil, tempfile
35
 
36
  os.makedirs(docs_path, exist_ok=True)
37
  files_payload = []
38
 
39
+ temp_files = []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
 
41
  try:
42
+ for f in files:
43
+ if isinstance(f, str) and f.startswith(("http://", "https://")):
44
+ # Download URL to a temp file
45
+ fname = os.path.basename(f)
46
+ tmp = tempfile.NamedTemporaryFile(delete=False)
47
+ r = requests.get(f, stream=True)
48
+ shutil.copyfileobj(r.raw, tmp)
49
+ tmp.close()
50
+ temp_files.append(tmp.name)
51
+ files_payload.append(("files", open(tmp.name, "rb")))
52
+
53
+ elif isinstance(f, str):
54
+ # Local file path
55
+ files_payload.append(("files", open(f, "rb")))
56
+
57
+ else:
58
+ # File-like object
59
+ files_payload.append(("files", f))
60
+
61
  resp = requests.post(
62
  f"{BASE_INTERNAL}/upload_docs",
63
  files=files_payload,
64
  data={"docs_path": docs_path}
65
  )
66
+ resp.raise_for_status()
67
  return resp.json()
68
+
69
  finally:
70
  # Close all file handles
71
  for _, file_obj in files_payload:
72
  if not file_obj.closed:
73
  file_obj.close()
74
+ # Clean up temp files
75
+ for tmp_file in temp_files:
76
+ try:
77
+ os.unlink(tmp_file)
78
+ except Exception:
79
+ pass
80
+
81
 
82
 
83
  def optimize_rag_tool(payload: str) -> str:
 
102
 
103
 
104
  def model_to_json(model_cls) -> str:
105
+ return json.dumps({k: v.default for k, v in model_cls.model_fields.items()}, indent=2)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
 
107
 
108
  # Default inputs
 
157
  gr.Markdown("---")
158
 
159
  if __name__ == "__main__":
 
 
 
 
 
 
 
 
 
 
 
 
 
160
 
161
  demo.launch(
162
  server_name="0.0.0.0",