Skip to content

Consider exposing an HTTP /health endpoint for deployments behind load balancers / orchestrators #191

Description

@steveterryp

What

Add a simple HTTP /health endpoint to the server (alongside the MCP protocol endpoint). The handler probes Snowflake with a warehouse-engaging query and returns:

  • HTTP 200 with {"status": "healthy"} when Snowflake is reachable and the account has a usable warehouse
  • HTTP 503 with {"status": "unhealthy", "snowflake": {"connected": false, "error": "..."}} when the probe fails

Why

Three deployment scenarios benefit:

  1. Kubernetes readiness/liveness probes — operators today have to either skip health checks or write external probes that issue MCP protocol calls just to check liveness. A dedicated /health endpoint is the conventional pattern and Kubernetes-native.
  2. Docker HEALTHCHECK directive — the project ships a docker/server Dockerfile but has no built-in health endpoint, so the HEALTHCHECK line either has to be omitted or has to use curl against the MCP endpoint (which isn't designed for GET).
  3. Aggregator / hub patterns — services that proxy or aggregate multiple MCP servers (we built one) need a cheap way to check "is this upstream still useful" without issuing a real MCP tool call. Right now the only signal is "first tool call succeeded or didn't", which is too coarse for proactive monitoring.

Design suggestion

Combine with the fix proposed in #190 (the SELECT CURRENT_WAREHOUSE() probe):

# rough sketch
@app.get("/health")
async def health():
    try:
        with connection.cursor() as cur:
            cur.execute("SELECT CURRENT_WAREHOUSE()")
            row = cur.fetchone()
            warehouse = row[0] if row else None
        if warehouse is None:
            return JSONResponse(
                status_code=503,
                content={"status": "unhealthy", "snowflake": {"connected": True, "warehouse": None, "error": "No warehouse available in current session"}},
            )
        return {"status": "healthy", "snowflake": {"connected": True, "warehouse": warehouse}}
    except Exception as e:
        return JSONResponse(
            status_code=503,
            content={"status": "unhealthy", "snowflake": {"connected": False, "error": str(e)}},
        )

Three design notes from our experience:

  • Return HTTP 503 (not 200) on unhealthy. The conventional probe pattern is curl -f / status-code based; returning 200 with status: unhealthy in the body silently confuses orchestrators that only check status codes.
  • The probe should exercise the same path as real tool calls. SELECT CURRENT_WAREHOUSE() requires the warehouse to actually be resolvable; a string-literal SELECT doesn't (see send_initial_query doesn't verify compute availability — suspended/warehouseless accounts pass the connection check #190).
  • Surface the underlying error. When connected: false, include the exception message in the body. We initially had a silent try/except: return False and spent an embarrassing amount of time guessing why a service was unhealthy; a one-line log.warn and an error field in the body saved every subsequent investigation.

Related

Happy to PR this if it's a direction you'd accept. Otherwise just leaving the shape here for if it's useful.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions