File size: 2,394 Bytes
3ea44d2
 
ef28fc3
 
3ea44d2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ef28fc3
3ea44d2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ef28fc3
 
 
3ea44d2
ef28fc3
3ea44d2
 
 
ef28fc3
 
3ea44d2
ef28fc3
3ea44d2
 
 
ef28fc3
 
3ea44d2
ef28fc3
3ea44d2
 
ef28fc3
3ea44d2
 
 
 
ef28fc3
 
3ea44d2
 
 
ef28fc3
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
from __future__ import annotations

import os
import sys
from pathlib import Path
from typing import Any


PLUGIN_DIR = Path(__file__).resolve().parent / "BioSPPy" / "mcp_output" / "mcp_plugin"
if str(PLUGIN_DIR) not in sys.path:
    sys.path.insert(0, str(PLUGIN_DIR))

try:
    from fastapi import FastAPI  # type: ignore[import-not-found]
except Exception:
    FastAPI = None

try:
    import uvicorn  # type: ignore[import-not-found]
except Exception:
    uvicorn = None


if FastAPI is None:
    raise RuntimeError("fastapi is required to run app.py")

app = FastAPI(title="BioSPPy MCP Supplementary App", version="1.0.0")


def _extract_tool_info(app_obj: Any) -> list[dict[str, str | None]]:
    tools = getattr(app_obj, "tools", None)
    if tools is None:
        return []

    if isinstance(tools, dict):
        iterable = list(tools.values())
    elif isinstance(tools, list):
        iterable = tools
    else:
        try:
            iterable = list(tools)
        except Exception:
            return []

    result: list[dict[str, str | None]] = []
    for tool in iterable:
        name = getattr(tool, "name", None)
        description = getattr(tool, "description", None)

        if name is None and isinstance(tool, dict):
            name = tool.get("name")
            description = tool.get("description")

        result.append({"name": str(name) if name is not None else None, "description": str(description) if description is not None else None})

    return result


@app.get("/")
def root() -> dict[str, Any]:
    return {
        "service": "BioSPPy MCP Deployment",
        "description": "Supplementary FastAPI app for local inspection; MCP server is started by start_mcp.py.",
        "mcp_http_endpoint": "/mcp",
    }


@app.get("/health")
def health() -> dict[str, str]:
    return {"status": "healthy"}


@app.get("/tools")
def tools() -> dict[str, Any]:
    try:
        from mcp_service import create_app  # type: ignore[import-not-found]

        mcp_app = create_app()
        return {"status": "ok", "tools": _extract_tool_info(mcp_app)}
    except Exception as exc:
        return {"status": "error", "tools": [], "error": str(exc)}


if __name__ == "__main__":
    port = int(os.getenv("PORT", "7860"))
    if uvicorn is None:
        raise RuntimeError("uvicorn is required to run app.py directly")
    uvicorn.run(app, host="0.0.0.0", port=port)