园艺规划工具集

提供天气预测、植物识别、园艺搜索等功能的园艺规划工具集,适用于家庭园艺和农业规划。

  • by Day-in-the-Country-LLC
  • Python
  • 本地部署
  • 更新于
在 GitHub 查看 Day-in-the-Country-LLC/garden-mcp-server

使用说明

花园mcp服务器

MCP服务器为园艺问题和规划提供工具。

当前工具集(fastMCP):

  • 天气预报:获取某个地点的每日天气预报(Open‑Meteo)。
  • 天气档案:通过Open‑Meteo ERA5档案提供的历史每日数据。
  • 气象站历史:具有公共字段(tavg/tmin/tmax/prcp)的台站观测(每日)。
  • 识别植物:使用Plant.id从图像中识别植物(带细节的首选)。
  • 丰富植物:获取候选学名的额外信息(iNaturalist+维基百科)。
  • 获取URL文本:获取网页并提取可读文本(用于客户端RAG)。
  • 花园搜索:在网上搜索园艺主题(DuckDuckGo)。
  • 床布局规划器:计算植物数量和简单的网格布局。

快速启动(使用紫外线)

  • 要求:Python 3.11+和 uv 已安装(macOS: brew install uv).
  • 创建虚拟环境并安装项目(使用开发工具):
    • uv venv --python 3.11
    • uv pip install -e .[dev]
  • 通过stdio运行MCP服务器:
    • uv run garden-mcp-server

测试和起毛(紫外线)

  • 运行测试: uv run pytest
  • 棉绒: uv run ruff check .

配置

  • 天气预报使用Open‑Meteo的免费API(无需密钥)。
  • 天气档案使用Open‑Meteo ERA5档案(无需密钥)。
  • Meteostat工具使用免费的Meteostat客户端(不需要密钥)。
  • 花园搜索使用DuckDuckGo通过 duckduckgo-search.

整合

该服务器使用fastMCP框架,通过stdio传输MCP。将支持MCP的客户端(例如IDE或代理运行时)指向 garden-mcp-server 可执行(或调用 uv run garden-mcp-server).有关配置MCP服务器的信息,请参阅客户端的文档。

身份验证和机密

  • 请勿将API密钥或机密提交到此存储库。它是公共的设计。
  • 所有需要身份验证的工具都必须从环境变量中读取凭据。建议命名: GARDEN_<SERVICE>_API_KEY (例如。, GARDEN_WEATHER_API_KEY).
  • 服务器自动加载本地 .env 为了方便起见,请在启动时打开文件。 .env 已在 .gitignore.
  • 示例用法:
    • One‑off: GARDEN_WEATHER_API_KEY=sk_live_... uv run garden-mcp-server
    • 使用.env:
      • 创建 .env 在项目根目录中(未提交):
        • GARDEN_WEATHER_API_KEY=sk_live_...
      • 运行: uv run garden-mcp-server
  • 我们的默认天气工具使用Open‑Meteo(无键)。如果切换到基于密钥的提供程序,请遵循上面的env-var模式。
  • 植物标识使用Plant.id,并且需要API密钥。BYOT/K政策适用:
    • 公众:呼叫者通行证 plant_id_api_key 根据请求。
    • 私人/内部:设置 GARDEN_PLANT_ID_API_KEY 在env中;具有作用域的经过身份验证的调用者 GARDEN_INTERNAL_SCOPE (默认值 internal)可以省略 plant_id_api_key.
    • 不要记录或存储用户提供的密钥。

客户示例

  • Python(通过uv进行stdio):

    • pip install fastmcp
    • 例子:
      • import asyncio
        from fastmcp.client import Client
        from fastmcp.client.transports import UvStdioTransport
        
        async def main():
            # Launch the server in a subprocess via uv run
            transport = UvStdioTransport(
                command="garden-mcp-server",
                project_directory=".",  # repo root with pyproject.toml
            )
            client = Client(transport)
            async with client:
                # List available tools
                tools = await client.list_tools()
                print([t.name for t in tools])
        
                # Call forecast tool
                res = await client.call_tool(
                    "tool_get_weather_forecast",
                    {"location": "Portland, OR", "days": 3},
                )
                print(res)
        
                # Call Open-Meteo archive tool
                res = await client.call_tool(
                    "tool_open_meteo_archive",
                    {
                        "location": "Portland, OR",
                        "start_date": "2024-01-01",
                        "end_date": "2024-01-07",
                        "daily_vars": [
                            "temperature_2m_max",
                            "temperature_2m_min",
                            "precipitation_sum",
                        ],
                    },
                )
                print(res)
        
                # Call Meteostat history tool
                res = await client.call_tool(
                    "tool_meteostat_history",
                    {
                        "location": "Portland, OR",
                        "start_date": "2024-01-01",
                        "end_date": "2024-01-07",
                        "fields": ["tavg", "tmin", "tmax", "prcp"],
                    },
                )
                print(res)
        
                # Identify a plant by image URL (BYOK or env-based)
                res = await client.call_tool(
                    "tool_identify_plant",
                    {
                        "image_url": "https://example.com/photo.jpg",
                        "top_n": 3,
                        # Public deployment (BYOK): pass your Plant.id key here
                        # "plant_id_api_key": "pk_live_...",
                    },
                )
                print(res)
        
                # Enrich the first two scientific names via iNaturalist/Wikipedia
                names = [c["scientific_name"] for c in res["candidates"][:2]]
                enriched = await client.call_tool(
                    "tool_enrich_plants",
                    {"scientific_names": names, "max_results": 2},
                )
                print(enriched)
        
                # Fetch page text for RAG (LLM summarization stays client-side)
                page = await client.call_tool(
                    "tool_fetch_url_text",
                    {"url": "https://example.com/garden-guide", "max_chars": 12000},
                )
                print(page["title"], len(page["text"]))
        
        asyncio.run(main())
        
  • 错误处理和验证:

    • 工具验证ISO日期格式(YYYY-MM-DD)并强制执行 start_date <= end_date.
    • Open‑Meteo存档检查变量名的简单标识符格式。
    • Meteostat历史根据已知列验证所请求的字段(例如。, tavg, tmin, tmax, prcp, snow, wdir, wspd, wpgt, pres, tsun).

云运行部署

  • 在本地构建容器:
    • docker build -t gcr.io/PROJECT_ID/garden-mcp-server:latest .
    • docker push gcr.io/PROJECT_ID/garden-mcp-server:latest
  • 或者使用gcloud(推荐):
    • gcloud builds submit --tag gcr.io/PROJECT_ID/garden-mcp-server:latest
  • 部署到云运行:
    • gcloud run deploy garden-mcp-server --image gcr.io/PROJECT_ID/garden-mcp-server:latest --region REGION --platform managed --allow-unauthenticated
    • 根据需要设置环境变量:
      • FASTMCP_HOST=0.0.0.0 (默认)
      • GARDEN_MCP_HTTP_TRANSPORT=streamable-http 或 sse (默认:可流式传输http)
      • 可选路径: FASTMCP_STREAMABLE_HTTP_PATH=/mcp, FASTMCP_SSE_PATH=/sse, FASTMCP_MESSAGE_PATH=/messages/
  • 从客户端连接:
    • 流式HTTP: Client("https://SERVICE.run.app/mcp")
    • SSE: Client("https://SERVICE.run.app/sse")
    • 如果启用身份验证(JWT或OAuth),请包含相应的 auth 在客户端(例如。, Client(url, auth="<bearer-token>")).

移动上传(地面军事系统预签名网址)

  • HTTP服务器公开了一个助手路由,用于在不公开凭据的情况下从移动应用程序上传图像:
    • POST /upload-url 使用JSON: { "file_name": "uploads/uuid.jpg", "content_type": "image/jpeg" }
    • 回复:已签名 upload_url (PUT)和签名 get_url (GET)在短时间内有效。
    • 需要环境: GARDEN_GCS_BUCKET 和Cloud Run服务帐户 storage.objects.create 许可。
  • 流量:
    1. 移动请求 /upload-url 以获取URL。
    2. 移动 PUT 图像字节数 upload_url 带标题 Content-Type 集。
    3. 客户电话 tool_identify_plant 随着 image_url = get_url (临时访问)。
    4. (可选)稍后根据保留策略删除或旋转对象。

上传URL策略(默认情况下使用您自己的存储)

  • 控制访问 /upload-url 通过 GARDEN_UPLOAD_URL_POLICY:
    • disabled:不提供上传URL(仅限公共BYOS)。
    • internal (默认):仅允许具有以下条件的呼叫者 GARDEN_INTERNAL_SCOPE (默认值 internal).
    • public:允许任何人(不建议用于共享bucket)。
  • BYOS(自带存储):客户端可以跳过 /upload-url 完全通过:
    • 发送 image_base64 (小/中图像),或
    • 通过A image_url 其指向其存储器(GCS/S3/等)中自己的签名URL。
    • 这确保了第三方永远不会使用你的水桶。

Cloud Run的推荐身份验证(JWT)

  • 具有共享密钥的对称JWT(HS256)(如果通过密钥管理器管理,则简单安全):
    • 创建一个秘密: echo -n 'a-strong-shared-secret' | gcloud secrets create garden-jwt-secret --data-file=-
    • 启用身份验证进行部署:
      • gcloud run deploy garden-mcp-server \ --image gcr.io/PROJECT_ID/garden-mcp-server:latest \ --region REGION --platform managed --allow-unauthenticated \ --set-env-vars=FASTMCP_HOST=0.0.0.0,GARDEN_MCP_HTTP_TRANSPORT=streamable-http,FASTMCP_SERVER_AUTH=JWT,FASTMCP_SERVER_AUTH_JWT_ALGORITHM=HS256 \ --update-secrets=FASTMCP_SERVER_AUTH_JWT_PUBLIC_KEY=garden-jwt-secret:latest
    • 客户端使用:使用共享密钥传递用HS256签名的Bearer令牌。

默认值和端点

  • Cloud Run的默认传输方式为 streamable-http (健壮,与Cloud Run请求模型配合良好)。使用 sse 如果您的客户端明确要求SSE,并且您的服务并发/超时已针对长期连接进行了调优。
  • 在HTTP模式下运行时提供健康终结点:
    • GET /healthz → JSON {"status":"ok"}
    • GET /readyz → ok

公共MCP+BYOK(自带密钥)

  • 为了保持MCP的公开性,同时确保其他人为自己的Plant.id使用付费:
    • 公共实例:不设置 GARDEN_PLANT_ID_API_KEY 所以呼叫者必须通过 plant_id_api_key 根据请求(BYOK)。
    • 私有/内部实例:set GARDEN_PLANT_ID_API_KEY 对于您自己的应用程序。
    • 具有策略的单个实例:set GARDEN_PLANT_ID_API_KEY 并且需要一个身份验证范围(默认值 internal)使用它。其他人必须通过 plant_id_api_key.
      • 通过配置所需的作用域 GARDEN_INTERNAL_SCOPE (默认值: internal).
  • 适用于此仓库中的所有付费提供商工具。当用户传递密钥(例如。, plant_id_api_key),服务器仅将其用于上游API调用,而从不记录/存储它。