Spaces:
Running
Running
File size: 4,250 Bytes
ab37e84 0314ff4 ab37e84 0314ff4 09a6947 0314ff4 ab37e84 3d2c52e ab37e84 0314ff4 ab37e84 0314ff4 ab37e84 0314ff4 e9a0985 0314ff4 a455076 0314ff4 09a6947 0314ff4 ab37e84 |
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 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
"""
MCP SSE Transport for HuggingFace Spaces
Manual SSE setup that works behind HF's proxy
"""
from mcp.server.fastmcp import FastMCP
from mcp.server.sse import SseServerTransport
from starlette.applications import Starlette
from starlette.routing import Route, Mount
from starlette.requests import Request
from starlette.responses import Response
import sys
import os
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from src.servers.weather import WeatherServer
from src.servers.soil import SoilPropertiesServer
from src.servers.water import WaterServer
from src.servers.elevation import ElevationServer
from src.servers.pests import PestsServer
# Create MCP server
mcp = FastMCP("farmer-chat")
# Initialize data servers
weather = WeatherServer()
soil = SoilPropertiesServer()
water = WaterServer()
elevation = ElevationServer()
pests = PestsServer()
# ============================================================================
# MCP TOOLS
# ============================================================================
@mcp.tool()
async def get_weather(latitude: float, longitude: float) -> dict:
"""Get current weather and 7-day forecast from Open-Meteo API."""
return await weather.get_data(latitude, longitude)
@mcp.tool()
async def get_soil_properties(latitude: float, longitude: float) -> dict:
"""Get soil composition (clay, sand, silt, pH, organic carbon) from Google Earth Engine."""
return await soil.get_data(latitude, longitude)
@mcp.tool()
async def get_groundwater(latitude: float, longitude: float) -> dict:
"""Get groundwater levels and drought status from NASA GRACE satellite data."""
return await water.get_data(latitude, longitude)
@mcp.tool()
async def get_elevation(latitude: float, longitude: float) -> dict:
"""Get terrain elevation from OpenElevation API."""
return await elevation.get_data(latitude, longitude)
@mcp.tool()
async def get_pest_observations(latitude: float, longitude: float) -> dict:
"""Get recent pest/insect observations within 50km from iNaturalist."""
return await pests.get_data(latitude, longitude)
@mcp.tool()
async def get_all_farm_data(latitude: float, longitude: float) -> dict:
"""Get data from all sources in parallel (weather, soil, water, elevation, pests)."""
import asyncio
results = await asyncio.gather(
weather.get_data(latitude, longitude),
soil.get_data(latitude, longitude),
water.get_data(latitude, longitude),
elevation.get_data(latitude, longitude),
pests.get_data(latitude, longitude),
return_exceptions=True
)
def safe(r):
return r if not isinstance(r, Exception) else {"status": "error", "error": str(r)}
return {
"weather": safe(results[0]),
"soil": safe(results[1]),
"groundwater": safe(results[2]),
"elevation": safe(results[3]),
"pests": safe(results[4])
}
# ============================================================================
# SSE TRANSPORT SETUP (Works with HF Spaces)
# ============================================================================
def create_sse_app():
"""Create Starlette app with proper SSE transport for remote hosting."""
sse_transport = SseServerTransport("/messages/")
async def handle_sse(request: Request):
async with sse_transport.connect_sse(
request.scope,
request.receive,
request._send,
) as (read_stream, write_stream):
await mcp._mcp_server.run(
read_stream,
write_stream,
mcp._mcp_server.create_initialization_options(),
)
return Response()
return Starlette(
debug=True,
routes=[
Route("/sse", endpoint=handle_sse),
Mount("/messages/", app=sse_transport.handle_post_message),
],
)
# Create the SSE app for mounting
sse_app = create_sse_app()
# ============================================================================
# STANDALONE RUN (for local testing)
# ============================================================================
if __name__ == "__main__":
mcp.run(transport="stdio") |