infra(deploy): serve MCP on multiple domains + SKIP_BUILD #4

Merged
kianiadee merged 2 commits from infra/deploy-multidomain into main 2026-06-26 13:56:53 +00:00
Owner

This PR carries two changes for the read-only Analytics MCP, both reflecting what is already running in prod on twala:

1. Multi-domain routing (fae4094) — serve the MCP on both fleetmcp.rahamafresh.com and fleetmcp.fivetitude.com from one Traefik router/cert, plus SKIP_BUILD=1 for label/env-only redeploys. The live container already answers on both domains; main did not, so a redeploy from main would drop the second domain.

2. Caller attribution in query logs (af6fdbc) — BearerAuth matched a per-analyst token but only stashed it on request.state, which FastMCP tools never see, so query() logged with no caller. Bridge it through a ContextVar and log caller=<name> per query, so the per-token attribution the auth design promises actually shows up in the logs.

Note: merging only aligns source with prod; the running container still needs a manual deploy.sh (or SKIP_BUILD=0 rebuild) to pick up the logging change.

🤖 Generated with Claude Code

This PR carries two changes for the read-only Analytics MCP, both reflecting what is already running in prod on twala: **1. Multi-domain routing (`fae4094`)** — serve the MCP on both `fleetmcp.rahamafresh.com` and `fleetmcp.fivetitude.com` from one Traefik router/cert, plus `SKIP_BUILD=1` for label/env-only redeploys. The live container already answers on both domains; `main` did not, so a redeploy from `main` would drop the second domain. **2. Caller attribution in query logs (`af6fdbc`)** — BearerAuth matched a per-analyst token but only stashed it on `request.state`, which FastMCP tools never see, so `query()` logged with no caller. Bridge it through a ContextVar and log `caller=<name>` per query, so the per-token attribution the auth design promises actually shows up in the logs. Note: merging only aligns source with prod; the running container still needs a manual `deploy.sh` (or `SKIP_BUILD=0` rebuild) to pick up the logging change. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
kianiadee added 1 commit 2026-06-23 18:35:58 +00:00
The prod connector domain (fleetmcp.rahamafresh.com) had no Traefik router —
deploy.sh only ever set one HOST_DOMAIN (defaulting to fleetmcp.fivetitude.com),
so requests to the prod domain returned 503 "no available server" even with the
container healthy.

- HOST_DOMAINS: comma-separated list folded into one Traefik router rule
  (Host(`a`) || Host(`b`)). One LE cert covers all names (SANs), so connectors
  on either domain keep working. Defaults to HOST_DOMAIN (back-compatible).
- SKIP_BUILD=1: reuse the existing image for a labels/env-only redeploy, so a
  routing change can't accidentally bake in new/stale code.

Deployed to prod with HOST_DOMAINS="fleetmcp.rahamafresh.com,fleetmcp.fivetitude.com";
both domains verified (healthz 200, /mcp 401, valid SAN cert).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
kianiadee added 1 commit 2026-06-26 13:54:11 +00:00
The BearerAuth middleware matched a per-analyst token but only stashed it on
request.state, which the FastMCP tools never see — so the query log line logged
rows/sql with no caller, defeating the per-token attribution the auth design
promises. Bridge the caller name through a ContextVar (anyio propagates it into
the worker thread that runs each sync tool) and include it in the query() log.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
kianiadee merged commit 2f421d7439 into main 2026-06-26 13:56:53 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: kianiadee/fleetanalytics_mcp#4
No description provided.