http.go 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. package agentmcp
  2. import (
  3. "context"
  4. "crypto/subtle"
  5. "errors"
  6. "net/http"
  7. "strings"
  8. "time"
  9. "github.com/mark3labs/mcp-go/server"
  10. "go.uber.org/zap"
  11. )
  12. // Handler 返回 HTTP 处理器:/mcp(Streamable HTTP,无状态,需 Bearer 令牌)与 /healthz。
  13. func Handler(s *server.MCPServer, token string) http.Handler {
  14. mcpHandler := server.NewStreamableHTTPServer(s,
  15. server.WithStateLess(true),
  16. server.WithEndpointPath("/mcp"),
  17. )
  18. mux := http.NewServeMux()
  19. mux.Handle("/mcp", bearerAuth(token, mcpHandler))
  20. mux.HandleFunc("/healthz", func(w http.ResponseWriter, _ *http.Request) {
  21. w.WriteHeader(http.StatusOK)
  22. _, _ = w.Write([]byte("ok"))
  23. })
  24. return mux
  25. }
  26. // bearerAuth 校验 Authorization: Bearer <token>,常量时间比较。
  27. func bearerAuth(token string, next http.Handler) http.Handler {
  28. want := []byte("Bearer " + token)
  29. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  30. got := []byte(strings.TrimSpace(r.Header.Get("Authorization")))
  31. if subtle.ConstantTimeCompare(got, want) != 1 {
  32. w.Header().Set("Content-Type", "application/json")
  33. w.WriteHeader(http.StatusUnauthorized)
  34. _, _ = w.Write([]byte(`{"jsonrpc":"2.0","error":{"code":-32001,"message":"unauthorized"},"id":null}`))
  35. return
  36. }
  37. next.ServeHTTP(w, r)
  38. })
  39. }
  40. // Serve 启动 HTTP 服务,ctx 取消时优雅关闭。
  41. func Serve(ctx context.Context, addr string, h http.Handler, log *zap.Logger) error {
  42. srv := &http.Server{
  43. Addr: addr,
  44. Handler: h,
  45. ReadHeaderTimeout: 10 * time.Second,
  46. }
  47. errCh := make(chan error, 1)
  48. go func() { errCh <- srv.ListenAndServe() }()
  49. log.Info("[agent-mcp] HTTP 服务已启动", zap.String("addr", addr))
  50. select {
  51. case <-ctx.Done():
  52. shutdownCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
  53. defer cancel()
  54. return srv.Shutdown(shutdownCtx)
  55. case err := <-errCh:
  56. if errors.Is(err, http.ErrServerClosed) {
  57. return nil
  58. }
  59. return err
  60. }
  61. }