Docker healthchecks now ask the server's own /health route in intervals-icu-mcp 5.7.0

1 hour ago

Version 5.7 of the Intervals.icu MCP server changes how its Docker image checks that the server is alive. HTTP servers now answer a health route of their own. It also retires a sport settings tool that stopped working when Intervals.icu removed its endpoint. Before you upgrade, check whether you mount MCP at /health, or run the container behind an init wrapper.

Ask about this presentation

Chapters

  1. 0:00Docker healthchecks now ask /health
  2. 0:26The /health route
  3. 0:49The Dockerfile HEALTHCHECK
  4. 1:06Which check runs
  5. 1:29Behind docker run --init
  6. 1:48--path /health is refused
  7. 2:10icu_apply_sport_settings retired
  8. 2:35Before you upgrade
Show transcript
  1. Version 5.7 of the Intervals.icu MCP server changes how its Docker image checks that the server is alive. HTTP servers now answer a health route of their own. It also retires a sport settings tool that stopped working when Intervals.icu removed its endpoint. Before you upgrade, check whether you mount MCP at /health, or run the container behind an init wrapper.

    Slide text
    intervals-icu-mcp 5.7.0

    Docker healthchecks now ask the server's own /health route

    And icu_apply_sport_settings is retired.

    intervals-icu-mcp building a training week in Claude Desktop
    v5.7.0 · Lighter Docker healthcheck health route what to check retired tool upgrade
  2. The server now has a static route at /health. On the HTTP, streamable HTTP and SSE transports, a GET request gets back status ok, as JSON. That's the whole handler. It doesn't open an MCP session, check your credentials, or call Intervals.icu. And it stays at /health whatever path you mount MCP under.

    Slide text

    GET /health answers without touching MCP or Intervals.icu

    GET /health → 200 {"status":"ok"}
    src/intervals_icu_mcp/server.py
    @mcp.custom_route("/health", methods=["GET"], include_in_schema=False)
    async def health(request: Request) -> JSONResponse:
        """Return static HTTP liveness without accessing MCP or upstream APIs."""
        return JSONResponse({"status": "ok"})
    GET /health → 200 · contributed by @FabioCamin8 (#151) health route what to check retired tool upgrade
  3. The Dockerfile changed to match. Its healthcheck now runs the healthcheck module, built only on the Python standard library. It still runs every 30 seconds, with 3 retries. Docker's timeout goes from 3 seconds to 5, and the probe allows itself 2.

    Slide text

    The image's HEALTHCHECK now runs a probe module

    Dockerfile
    HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 \
        CMD python -m intervals_icu_mcp.healthcheck
    every 30 s 3 retries Docker timeout 3 s → 5 s probe deadline 2 s
    HEALTHCHECK --interval=30s --timeout=5s health route what to check retired tool upgrade
  4. The probe picks its check from the command line of the container's first process. An HTTP, streamable HTTP or SSE server gets a real request to /health, and passes only on a 200 with status ok. A stdio server keeps the old import check. And anything the probe can't recognise falls back to that import check too.

    Slide text

    Which check runs depends on how the server was started

    The container's first process
    /proc/1/cmdline
    python -m intervals_icu_mcp.server …
    HTTP · streamable HTTP · SSE
    GET /health, passes only on 200 and {"status":"ok"}
    stdio
    Import check, as before
    Unrecognised or wrapped
    Falls back to the import check
    reading /proc/1/cmdline health route what to check retired tool upgrade
  5. The first thing to check is wrappers. With Docker's --init flag, the first process is the init wrapper, so the probe falls back to the import check, which doesn't test HTTP. Pass a host, a port, or both to the healthcheck, as in this compose example, and it checks HTTP directly.

    Slide text

    Behind docker run --init, give the healthcheck a host and port

    The wrapper hides the server's command line, so the probe falls back to the import check.

    docs/remote-deployment.md · compose example
    services:
      intervals-icu-mcp:
        image: ghcr.io/hhopke/intervals-icu-mcp:latest
        command: ["--transport", "http", "--host", "0.0.0.0", "--port", "8000"]
        # Supply credentials using your existing environment/secret configuration.
        healthcheck:
          test: ["CMD", "python", "-m", "intervals_icu_mcp.healthcheck", "--host", "0.0.0.0", "--port", "8000"]
    --init → import-only check health route what to check retired tool upgrade
  6. The second is the MCP path, because /health is now reserved. Start an HTTP server with --path set to /health, with or without a trailing slash, and it stops with this error. A stdio server doesn't use the path, so it still accepts it. If you mounted MCP at /health, move it before you upgrade.

    Slide text

    --path /health is now refused on HTTP transports

    src/intervals_icu_mcp/server.py · _parse_args
    args = parser.parse_args(argv)
    if args.transport != "stdio" and args.path is not None:
        if args.path.removesuffix("/") == "/health":
            parser.error("--path cannot be /health because it conflicts with the health route")
    http · sse · streamable-http: exits with code 2 stdio: still accepted
    --path /health → exit 2 health route what to check retired tool upgrade
  7. The other change is a removal. Intervals.icu removed the API endpoint behind the apply sport settings tool, so it failed on every call. It's gone. The server now registers 69 tools, or 66 in the default safe mode. To re-zone past activities, use Update zones in the Intervals.icu activity list. Zones you set with the update tool still apply to new activities.

    Slide text

    Intervals.icu removed the endpoint, so icu_apply_sport_settings is gone

    Sport settings tools
    • icu_get_sport_settings
    • icu_update_sport_settings
    • icu_apply_sport_settings PUT /athlete/{id}/sport-settings/{id}/apply → 404
    • icu_create_sport_settings
    • icu_delete_sport_settings
    70 → 69
    tools in all
    safe (default) 67 → 66 · none 62 → 61
    Re-zone past activities with Update zones in the Intervals.icu activity list. Per-activity rebuild: help wanted, #159
    70 → 69 tools health route what to check retired tool upgrade
  8. One limit before you upgrade. The new check proves the web server answers. It doesn't verify MCP setup, your credentials, or the Intervals.icu API. So check three things: move MCP off /health, give the healthcheck a host and port if you run HTTP behind an init wrapper, and re-zone past activities with Update zones. Then upgrade to 5.7.0, and your Docker healthcheck asks the server's own /health route.

    Slide text

    Check three things, then upgrade to 5.7.0

    The new check proves the web server answers. It doesn't verify MCP setup, credentials or the Intervals.icu API.
    MCP mounted at /health? Move it to another path.
    HTTP behind --init? Add --host and --port to the healthcheck.
    Re-zoning past activities? Use Update zones in Intervals.icu.
    github.com/hhopke/intervals-icu-mcp/releases/tag/v5.7.0 health route what to check retired tool upgrade

What happened in AI today, in your inbox

One short email each evening. Read it and you’re caught up.

Built in New York with ❤️