JOÃO spine — FastAPI + MCP server
Personal automation server that dispatches shell commands to tmux sessions on a home server, processes AI pipelines (audio, vision, text), manages an ...
515@mcp.tool()
516async def joao_learn_url(url: str) -> str:
517 """Fetch any URL, extract clean content, analyze with Claude...
518 Args:
519 url: Full URL to fetch and analyze (http or https)
520 """
521 return await _joao_learn_url(url)// Exploitable by any client that can connect to the MCP endpoint.
245@mcp.tool()
246async def ftp_access(
247 action: str,
248 host: str,
249 remote_path: str,
250 user: str,
251 password: str,
252 port: int = 21,
253 local_path: str = "",
254) -> str:
255 """Access files on a remote FTP server — list, download, upload, or delete."""// Exploitable by any client that can connect to the MCP endpoint. Credentials are also logged in Supabase.
52@mcp.tool()
53async def dispatch_agent(session_name: str, command: str, wait: bool = False) -> str:
54 """Dispatch a shell command to a tmux session on the home server."""
55 ...
56 result = await dispatch.dispatch_raw_to_agent(session_name, command)
57 ...// Exploitable by any client that can connect to the MCP endpoint (SSE or Streamable HTTP). The server is network_exposed via Cloudflare tunnel.
489@mcp.tool()
490async def joao_learn_pdf(file_path: str) -> str:
491 """Extract a PDF, generate an HTML intelligence report...
492 Args:
493 file_path: Absolute path to the .pdf file on the server
494 """
495 return await _joao_learn_pdf(file_path)
496
497@mcp.tool()
498async def joao_learn_excel(file_path: str) -> str:
499 ...
500 Args:
501 file_path: Absolute path to the .xlsx, .xls, or .csv file on the server
502 """
503 return await _joao_learn_excel(file_path)
504
505@mcp.tool()
506async def joao_learn_docx(file_path: str) -> str:
507 ...
508 Args:
509 file_path: Absolute path to the .docx file on the server
510 """
511 return await _joao_learn_docx(file_path)// Exploitable by any client that can connect to the MCP endpoint. The server is network_exposed.
294def _resolve_memory_path(file_key: str) -> Path:
295 if file_key == "master":
296 return _MASTER_FILE
297 return _SESSION_FILE
298
299async def _h_joao_memory(args: dict[str, Any]) -> dict[str, Any]:
300 ...
301 file_key = args.get("file") or "session"
302 if file_key not in ("master", "session"):
303 raise ValueError("file must be 'master' or 'session'")
304 path = _resolve_memory_path(file_key)
305 ...
306 with path.open("a", encoding="utf-8") as fh:
307 fh.write(appendix + "\n")// Exploitable by any client that can connect to the MCP endpoint.
477@mcp.tool()
478async def joao_learn_youtube(url: str) -> str:
479 """Extract a YouTube transcript, analyze with Claude...
480 Args:
481 url: Full YouTube URL (youtube.com or youtu.be)
482 """
483 return await _joao_learn_youtube(url)// Exploitable by any client that can connect to the MCP endpoint.
132@mcp.tool()
133async def capture_idea(text: str, source: str = "mcp", context: str = "") -> str:
134 """Process text through AI and save to idea vault..."""
135 t0 = time.time()
136 ai_result = await ai_processor.process_text(text, context)
137 ...
138 notify_msg = f"*{ai_result.title}*\n{ai_result.summary}\nTags: {', '.join(ai_result.tags)}"
139 await telegram.send_notification(notify_msg)// Exploitable by any client that can connect to the MCP endpoint. The impact depends on the capabilities granted to the AI model.
245elif action == "delete":
246 result_text = await ftp_client.ftp_delete(host, port, user, password, remote_path)// Exploitable by any client that can connect to the MCP endpoint, provided they have FTP credentials.
83except (httpx.ConnectError, httpx.ConnectTimeout) as tunnel_err:
84 # Tunnel unreachable -- try SSH as local-network fallback (with timeout)
85 logger.warning("dispatch_agent tunnel unreachable, trying SSH: %s", tunnel_err)
86 try:
87 ssh_result = await asyncio.wait_for(
88 dispatch.dispatch_command(session_name, command, wait),
89 timeout=15.0,
90 )// Exploitable if the attacker can cause the tunnel to fail (e.g., by network manipulation) or if the MCP server is compromised.
198@mcp.tool()
199async def scout_intel(limit: int = 20, min_score: int = 7) -> str:
200 ...
201 items = scout_service.get_recent_intel(limit=limit, min_score=min_score)
202
203@mcp.tool()
204async def query_memory(query: str, limit: int = 10) -> str:
205 ...
206 results = await supabase_client.query_memory(query, limit)// Exploitable by any client that can connect to the MCP endpoint.
294@app.get("/joao/terminal", include_in_schema=False)
295async def terminal_ui():
296 token = os.environ.get("JOAO_TERMINAL_TOKEN") or os.environ.get("JOAO_DISPATCH_HMAC_SECRET", "")
297 html = (_STATIC_DIR / "terminal.html").read_text()
298 html = html.replace("__TERMINAL_TOKEN__", token)
299 return HTMLResponse(html)// Exploitable by any client that can reach the server. The endpoint is not in the OpenAPI schema but is accessible via direct URL.
308@mcp.tool()
309async def council_dispatch(
310 agent: str,
311 task: str,
312 priority: str = "normal",
313 context: str = "",
314 project: str = "",
315) -> str:
316 ...
317 result = await dispatch.dispatch_to_agent(
318 agent=agent,
319 task=task,
320 ...
321 )// Exploitable by any client that can connect to the MCP endpoint.