refactor(cli): consolidate the gateway into micro gateway - #4876
Conversation
Rename `micro server` to `micro gateway` and fold the standalone micro-mcp-gateway binary into it, so there is one gateway with one name. - Rename command server -> gateway (package cmd/micro/server -> cmd/micro/gateway; update the run and main importers). - `micro gateway` gains the MCP production controls the standalone binary had: --rate-limit/--rate-burst, --auth, --audit, --scope, --circuit-breaker[-timeout], and --x402-*. When --mcp-address is set it runs the full gateway/mcp with those options; registry selection uses the CLI global --registry/--registry_address flags. - `micro server` stays as a hidden, deprecated alias that warns and delegates, so existing invocations keep working. - Delete cmd/micro-mcp-gateway (binary + Dockerfile). goreleaser only builds ./cmd/micro, so releases are unaffected. - Repoint deploy/refs at the micro CLI image: Dockerfile CMD -> gateway; Helm chart runs `micro gateway --mcp-address` with registry via MICRO_REGISTRY env, image ghcr.io/micro/go-micro; drop the v6 micro-mcp-gateway vanity entry and rename server -> gateway; update the docs guides and CLAUDE.md. Build, vet, gofmt, and the run/gateway/cmd tests pass; `micro gateway` and the hidden `micro server` alias both resolve.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9ada17f859
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| # `micro gateway --mcp-address ...` (see the deployment template). | ||
| image: | ||
| repository: ghcr.io/micro/mcp-gateway | ||
| repository: ghcr.io/micro/go-micro |
There was a problem hiding this comment.
Use a published tag for the CLI image
With the default empty image.tag, the deployment template combines this repository with Chart.AppVersion, which remains 0.1.0; however, .goreleaser.yml publishes this image only as v{{ .Version }}, latest, or nightly. A default Helm install therefore requests ghcr.io/micro/go-micro:0.1.0 rather than a tag produced by this repository's release workflow and will enter ImagePullBackOff; update the chart app version/tag convention when switching repositories.
Useful? React with 👍 / 👎.
| imagePullPolicy: {{ .Values.image.pullPolicy }} | ||
| args: | ||
| - "--address" | ||
| - "gateway" |
There was a problem hiding this comment.
Provide writable storage for gateway JWT keys
The chart now starts micro gateway, whose Run path always enables dashboard authentication and whose StartGateway writes JWT keys beneath the user's home directory before starting either listener. The same chart still sets readOnlyRootFilesystem: true, runs as UID 65534, and mounts no writable key volume, so once a valid image tag is supplied this command fails while reading the keys it could not create and the pod crash-loops instead of serving MCP. Mount a writable key directory or allow an MCP-only mode that skips dashboard key initialization.
Useful? React with 👍 / 👎.
| go func() { | ||
| if err := mcp.ListenAndServe(mcpAddr, mcpOpts); err != nil { | ||
| log.Printf("[mcp] gateway error: %v", err) | ||
| } |
There was a problem hiding this comment.
Propagate MCP startup failures to the command
When --mcp-address is requested and service discovery fails (for example, Consul is unavailable) or the address cannot bind, mcp.ListenAndServe returns here but the goroutine only logs the error; RunGateway continues serving the dashboard indefinitely and the command still appears healthy despite having no MCP listener. The removed standalone gateway returned this error through errCh, allowing supervisors and users to detect and restart a failed production gateway, so preserve that failure propagation in the consolidated command.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Pull request overview
This PR consolidates gateway entrypoints in the micro CLI by introducing micro gateway as the primary production gateway command, keeping micro server as a hidden deprecated alias, and folding the standalone micro-mcp-gateway binary’s production MCP controls into the CLI.
Changes:
- Rename/relocate the production gateway command implementation to
cmd/micro/gateway, updatingmicro runandcmd/micro/main.goto import it. - Fold MCP production controls (rate limiting, scopes, JWT auth, audit, circuit breaker, x402) into
micro gatewayand removecmd/micro-mcp-gateway(binary + Dockerfile). - Repoint deployment/docs/vanity modules to the CLI-based
micro gatewayand update the MCP gateway Helm chart image/args.
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| internal/website/scripts/data/vanity.yaml | Remove v6 micro-mcp-gateway module and rename v6 cmd/micro/server → cmd/micro/gateway module. |
| internal/website/data/vanity.yaml | Same vanity module updates as the scripts copy. |
| internal/website/content/en/docs/guides/x402-payments.md | Update docs to reference micro gateway instead of the standalone gateway binary. |
| internal/website/content/en/docs/guides/ai-native-services.md | Update production deployment example to use micro gateway with global registry flags. |
| internal/website/content/en/docs/guides/agent-patterns.md | Update diagrams/examples and Docker guidance to use the micro CLI image + gateway subcommand. |
| gateway/mcp/deploy/helm/mcp-gateway/values.yaml | Switch default image to ghcr.io/micro/go-micro and clarify MCP address semantics. |
| gateway/mcp/deploy/helm/mcp-gateway/templates/deployment.yaml | Run micro gateway --mcp-address ... and move registry selection to env. |
| gateway/mcp/deploy/helm/mcp-gateway/README.md | Update chart documentation to reflect new image repository. |
| Dockerfile | Change default container command from server to gateway. |
| cmd/micro/run/run.go | Update embedded gateway import/types to the new cmd/micro/gateway package. |
| cmd/micro/main.go | Import cmd/micro/gateway and wire embedded HTML FS into gateway.HTML. |
| cmd/micro/gateway/util_jwt.go | Rename package from server → gateway (part of directory move/rename). |
| cmd/micro/gateway/server.go | Register gateway command, keep hidden server alias, and add MCP production-control flags + MCP serving logic. |
| cmd/micro/gateway/gateway.go | Rename package from server → gateway (compat wrapper around gateway/api). |
| cmd/micro-mcp-gateway/main.go | Delete the standalone MCP gateway binary implementation. |
| cmd/micro-mcp-gateway/Dockerfile | Delete the standalone MCP gateway Dockerfile. |
| CLAUDE.md | Update project guide to reflect the consolidated micro gateway approach. |
Suppressed comments (4)
cmd/micro/gateway/server.go:1726
- The gateway command introduces an
--authbool flag for MCP JWT auth, but the micro CLI already has a global--authstring flag (provider selection). Reusing the same flag name risks ambiguous parsing/overriding and makesmicro gateway --auth jwt/micro --auth jwt gateway ...behavior unclear or broken. Prefer a distinct subcommand flag name (e.g.--mcp-auth) and update Helm/docs accordingly (optionally keep a deprecated alias if the CLI supports it).
cmd/micro/gateway/server.go:1510 micro gatewayclaims registry selection comes from the global--registry/--registry_addressflags, butGatewayOptionsis created without aRegistry, sogateway/apifalls back toregistry.DefaultRegistry(which is not updated bycmd.Before). This means the gateway can ignore the user-selected registry backend/address.
This issue also appears on line 1538 of the same file.
cmd/micro/gateway/server.go:1542
- The MCP gateway is configured with
registry.DefaultRegistry, which does not reflect the CLI-selected registry (--registry/--registry_address) because the cmd package uses per-app local copies. This causesmicro gateway --registry ... --mcp-address ...to potentially discover services from the wrong registry.
cmd/micro/gateway/server.go:1526 - When
--mcp-addressis set, the MCP server runs in a fire-and-forget goroutine and any startup failure (e.g., port already in use) is only logged while the process keeps running the HTTP gateway. This can lead to a seemingly healthy deployment that is missing the MCP endpoint. Consider running both servers under a shared wait/select so an MCP failure stops the command (or is at least returned).
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| args: | ||
| - "--address" | ||
| - "gateway" | ||
| - "--mcp-address" | ||
| - {{ .Values.gateway.address | quote }} |
| | `image.repository` | Container image | `ghcr.io/micro/mcp-gateway` | | ||
| | `image.repository` | Container image | `ghcr.io/micro/go-micro` | | ||
| | `image.tag` | Image tag (defaults to appVersion) | `""` | | ||
| | `gateway.address` | Listen address | `:3000` | |
Why
We had three doors to the same gateway —
micro run(embeds it),micro server(a deprecated wrapper), and the standalonemicro-mcp-gatewaybinary — and "server" was a vague name that collided withrun. This gives us one gateway with one name:micro gateway.Changes
Command
micro server→micro gateway(packagecmd/micro/server→cmd/micro/gateway; update therunandmainimporters).micro serverstays as a hidden, deprecated alias that prints a warning and delegates — existing scripts/Dockerfiles keep working.Fold in the standalone binary's functionality
micro gatewaygains the MCP production controls that only lived inmicro-mcp-gateway:--rate-limit/--rate-burst,--auth,--audit,--scope,--circuit-breaker[-timeout], and--x402-*. When--mcp-addressis set it runs the fullgateway/mcpwith those options (previouslygateway/apistarted a bare MCP listener with none of them).--registry/--registry_addressflags (env-backed), so no per-command registry flags needed.cmd/micro-mcp-gateway(binary + its Dockerfile). goreleaser only builds./cmd/micro, so releases are unaffected.Deploy / refs repointed at the micro CLI image
Dockerfile:CMD ["gateway"].micro gateway --mcp-address …, registry viaMICRO_REGISTRY/MICRO_REGISTRY_ADDRESSenv (global flags must precede the subcommand), imageghcr.io/micro/go-micro.vanity.yaml: drop the v6cmd/micro-mcp-gatewayentry, renamecmd/micro/server→cmd/micro/gateway(v5 left frozen).CLAUDE.md.Verification
go build ./...,go vet ./cmd/micro/...,gofmt, andgo test ./cmd/micro/…(incl.-raceonrun) all pass.micro gateway --helprenders;micro serveris hidden from the command list but still runs and prints the deprecation warning.Notes for review
ghcr.io/micro/go-micro(the published micro CLI image per.goreleaser.yaml). If the intended deploy image differs, it's a one-linevalues.yamlchange.--mcp-address); the dashboard (:8080) isn't published by the chart — say the word if you want both.micro-mcp-gatewaywere left as historical records; only living docs were updated.🤖 Generated with Claude Code
Generated by Claude Code