feat(docker): add /healthz endpoint and -healthcheck flag (#254)

Adds a Docker healthcheck and the small HTTP/CLI plumbing it needs.

- Expose `GET /healthz` on the HTTP-mode server.
- Add `-healthcheck` to dial `http://127.0.0.1:<port>/healthz` and exit with status.
- Add a Dockerfile `HEALTHCHECK` instruction using `-healthcheck`.
- Document HTTP-mode usage and stdio override guidance.

Closes https://gitea.com/gitea/gitea-mcp/issues/146

Assisted by Codet.

Reviewed-on: https://gitea.com/gitea/gitea-mcp/pulls/254
Reviewed-by: silverwind <2021+silverwind@noreply.gitea.com>
This commit is contained in:
Lunny Xiao
2026-08-26 03:00:05 +00:00
parent 04931d48a3
commit bfe0d4c9b0
10 changed files with 168 additions and 1 deletions
+7
View File
@@ -133,6 +133,7 @@ func newHTTPServer(addr string, s *mcp.Server) *http.Server {
PropagateRequestCancellation: true,
},
)))
mux.HandleFunc("/healthz", handleHealthz)
return &http.Server{
Addr: addr,
Handler: mux,
@@ -140,6 +141,12 @@ func newHTTPServer(addr string, s *mcp.Server) *http.Server {
}
}
func handleHealthz(w http.ResponseWriter, _ *http.Request) {
w.Header().Set("Content-Type", "text/plain; charset=utf-8")
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("ok\n"))
}
func Run() error {
mcpServer = newMCPServer(flag.Version)
RegisterTool(mcpServer)
+20 -1
View File
@@ -1,6 +1,10 @@
package operation
import "testing"
import (
"net/http"
"net/http/httptest"
"testing"
)
func TestNewHTTPServerConfig(t *testing.T) {
server := newHTTPServer(":12345", newMCPServer("test"))
@@ -18,6 +22,21 @@ func TestNewHTTPServerConfig(t *testing.T) {
}
}
func TestHealthzEndpoint(t *testing.T) {
server := newHTTPServer(":0", newMCPServer("test"))
req := httptest.NewRequest(http.MethodGet, "/healthz", nil)
rec := httptest.NewRecorder()
server.Handler.ServeHTTP(rec, req)
if rec.Code != http.StatusOK {
t.Errorf("status = %d, want %d", rec.Code, http.StatusOK)
}
if body := rec.Body.String(); body == "" {
t.Error("body is empty, want a non-empty health message")
}
}
func TestParseAuthToken(t *testing.T) {
tests := []struct {
name string