Skip to content

Commit 9ffdbc7

Browse files
committed
add example golang server
1 parent ae38e18 commit 9ffdbc7

File tree

13 files changed

+1633
-1
lines changed

13 files changed

+1633
-1
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
.vscode/
22
.idea/
33

4-
.DS_Store
4+
.DS_Store
5+
**/.DS_Store
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"errors"
6+
"fmt"
7+
"os"
8+
"os/signal"
9+
"syscall"
10+
"time"
11+
12+
"github.com/ag-ui-protocol/ag-ui/sdks/community/go/example/server/internal/config"
13+
"github.com/ag-ui-protocol/ag-ui/sdks/community/go/example/server/internal/mcp"
14+
"github.com/ag-ui-protocol/ag-ui/sdks/community/go/example/server/internal/routes"
15+
"github.com/gofiber/fiber/v3"
16+
"github.com/gofiber/fiber/v3/middleware/cors"
17+
"github.com/gofiber/fiber/v3/middleware/requestid"
18+
"github.com/sirupsen/logrus"
19+
)
20+
21+
func newErrorHandler() fiber.ErrorHandler {
22+
return func(c fiber.Ctx, err error) error {
23+
code := fiber.StatusInternalServerError
24+
var ferr *fiber.Error
25+
if errors.As(err, &ferr) {
26+
code = ferr.Code
27+
}
28+
29+
entry := logrus.NewEntry(logrus.StandardLogger())
30+
entry.WithFields(logrus.Fields{
31+
"error": err.Error(),
32+
"status": code,
33+
}).Error("Request error")
34+
35+
return c.Status(code).JSON(fiber.Map{
36+
"error": true,
37+
"message": err.Error(),
38+
})
39+
}
40+
}
41+
42+
func registerRoutes(app *fiber.App, cfg *config.Config) {
43+
44+
// Basic info route
45+
app.Get("/", func(c fiber.Ctx) error {
46+
return c.JSON(fiber.Map{
47+
"message": "AG-UI Go Example Server is running!",
48+
"path": c.Path(),
49+
"method": c.Method(),
50+
"headers": c.GetReqHeaders(),
51+
})
52+
})
53+
54+
if !cfg.EnableSSE {
55+
return
56+
}
57+
58+
// Feature routes
59+
app.Post("/agentic", routes.AgenticHandler(cfg))
60+
}
61+
62+
func logConfig(logger *logrus.Logger, cfg *config.Config) {
63+
logger.WithFields(logrus.Fields{
64+
"host": cfg.Host,
65+
"port": cfg.Port,
66+
"log_level": cfg.LogLevel,
67+
"enable_sse": cfg.EnableSSE,
68+
"read_timeout": cfg.ReadTimeout,
69+
"write_timeout": cfg.WriteTimeout,
70+
"sse_keepalive": cfg.SSEKeepAlive,
71+
"cors_enabled": cfg.CORSEnabled,
72+
"streaming_chunk_delay": cfg.StreamingChunkDelay,
73+
}).Info("Server configuration loaded")
74+
}
75+
76+
func createApp(cfg *config.Config, logger *logrus.Logger) *fiber.App {
77+
app := fiber.New(fiber.Config{
78+
AppName: "AG-UI Example Server",
79+
ReadTimeout: cfg.ReadTimeout,
80+
WriteTimeout: cfg.WriteTimeout,
81+
ErrorHandler: newErrorHandler(),
82+
})
83+
84+
// Middleware
85+
app.Use(requestid.New())
86+
87+
// CORS
88+
if cfg.CORSEnabled {
89+
app.Use(cors.New(cors.Config{
90+
AllowOrigins: cfg.CORSAllowedOrigins,
91+
AllowMethods: []string{"GET", "POST", "HEAD", "PUT", "DELETE", "PATCH", "OPTIONS"},
92+
AllowHeaders: []string{"Origin", "Content-Type", "Accept", "Authorization", "X-Request-ID"},
93+
AllowCredentials: false,
94+
}))
95+
}
96+
97+
// Content negotiation
98+
//app.Use(encoding.ContentNegotiationMiddleware(encoding.ContentNegotiationConfig{
99+
// DefaultContentType: "application/json",
100+
// SupportedTypes: []string{"application/json", "application/vnd.ag-ui+json"},
101+
// EnableLogging: cfg.LogLevel == "debug",
102+
//}))
103+
104+
// Routes
105+
registerRoutes(app, cfg)
106+
107+
return app
108+
}
109+
110+
func main() {
111+
// Load configuration with proper precedence: flags > env > defaults
112+
cfg, err := config.LoadConfig()
113+
if err != nil {
114+
fmt.Fprintf(os.Stderr, "Failed to load configuration: %v\n", err)
115+
os.Exit(1)
116+
}
117+
118+
// Set up structured logging with logrus
119+
logger := logrus.New()
120+
121+
// Log the effective configuration
122+
logConfig(logger, cfg)
123+
124+
app := createApp(cfg, logger)
125+
126+
// Start server in a goroutine
127+
serverAddr := fmt.Sprintf("%s:%d", cfg.Host, cfg.Port)
128+
129+
go func() {
130+
logger.WithField("address", serverAddr).Info("Starting server")
131+
if err := app.Listen(serverAddr); err != nil {
132+
logger.WithError(err).Error("Server failed to start")
133+
os.Exit(1)
134+
}
135+
}()
136+
137+
logger.WithField("address", serverAddr).Info("Server started successfully")
138+
139+
// Start mcp in a goroutine
140+
mcpServer, err := mcp.NewServer(mcp.DefaultPort)
141+
if err != nil {
142+
logger.WithError(err).Error("Failed to create MCP server")
143+
os.Exit(1)
144+
}
145+
go func() {
146+
err := mcpServer.Start()
147+
if err != nil {
148+
logger.WithError(err).Error("MCP server failed to start")
149+
os.Exit(1)
150+
}
151+
}()
152+
153+
// Wait for interrupt signal to gracefully shutdown the server
154+
quit := make(chan os.Signal, 1)
155+
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
156+
<-quit
157+
158+
logger.Info("Shutting down server...")
159+
160+
// Graceful shutdown with timeout
161+
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
162+
defer cancel()
163+
164+
err = mcpServer.Shutdown(ctx)
165+
if err != nil {
166+
logger.WithError(err).Error("MCP server shutdown error")
167+
}
168+
169+
if err = app.ShutdownWithContext(ctx); err != nil {
170+
logger.WithError(err).Error("Server shutdown error")
171+
os.Exit(1)
172+
}
173+
174+
logger.Info("Server shutdown complete")
175+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
module github.com/ag-ui-protocol/ag-ui/sdks/community/go/example/server
2+
3+
go 1.24.4
4+
5+
require (
6+
github.com/ag-ui-protocol/ag-ui/sdks/community/go v0.0.0-00010101000000-000000000000
7+
github.com/gofiber/fiber/v3 v3.0.0-beta.5
8+
github.com/i2y/langchaingo-mcp-adapter v0.0.0-20250623114610-a01671e1c8df
9+
github.com/mark3labs/mcp-go v0.32.0
10+
github.com/sirupsen/logrus v1.9.3
11+
github.com/stretchr/testify v1.10.0
12+
github.com/tmc/langchaingo v0.1.13
13+
golang.org/x/sync v0.16.0
14+
)
15+
16+
require (
17+
github.com/Masterminds/goutils v1.1.1 // indirect
18+
github.com/Masterminds/semver/v3 v3.2.0 // indirect
19+
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
20+
github.com/andybalholm/brotli v1.2.0 // indirect
21+
github.com/davecgh/go-spew v1.1.1 // indirect
22+
github.com/dlclark/regexp2 v1.10.0 // indirect
23+
github.com/dustin/go-humanize v1.0.1 // indirect
24+
github.com/go-logr/logr v1.4.3 // indirect
25+
github.com/gofiber/schema v1.6.0 // indirect
26+
github.com/gofiber/utils/v2 v2.0.0-beta.13 // indirect
27+
github.com/google/go-cmp v0.7.0 // indirect
28+
github.com/google/uuid v1.6.0 // indirect
29+
github.com/goph/emperror v0.17.2 // indirect
30+
github.com/huandu/xstrings v1.3.3 // indirect
31+
github.com/imdario/mergo v0.3.13 // indirect
32+
github.com/json-iterator/go v1.1.12 // indirect
33+
github.com/klauspost/compress v1.18.0 // indirect
34+
github.com/mattn/go-colorable v0.1.14 // indirect
35+
github.com/mattn/go-isatty v0.0.20 // indirect
36+
github.com/mitchellh/copystructure v1.0.0 // indirect
37+
github.com/mitchellh/reflectwalk v1.0.0 // indirect
38+
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
39+
github.com/modern-go/reflect2 v1.0.2 // indirect
40+
github.com/nikolalohinski/gonja v1.5.3 // indirect
41+
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
42+
github.com/philhofer/fwd v1.2.0 // indirect
43+
github.com/pkg/errors v0.9.1 // indirect
44+
github.com/pkoukk/tiktoken-go v0.1.6 // indirect
45+
github.com/pmezard/go-difflib v1.0.0 // indirect
46+
github.com/rogpeppe/go-internal v1.13.1 // indirect
47+
github.com/shopspring/decimal v1.2.0 // indirect
48+
github.com/spf13/cast v1.7.1 // indirect
49+
github.com/tinylib/msgp v1.3.0 // indirect
50+
github.com/valyala/bytebufferpool v1.0.0 // indirect
51+
github.com/valyala/fasthttp v1.64.0 // indirect
52+
github.com/yargevad/filepathx v1.0.0 // indirect
53+
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
54+
go.opentelemetry.io/otel v1.35.0 // indirect
55+
go.opentelemetry.io/otel/metric v1.35.0 // indirect
56+
go.opentelemetry.io/otel/trace v1.35.0 // indirect
57+
go.starlark.net v0.0.0-20230302034142-4b1e35fe2254 // indirect
58+
golang.org/x/crypto v0.40.0 // indirect
59+
golang.org/x/exp v0.0.0-20230713183714-613f0c0eb8a1 // indirect
60+
golang.org/x/net v0.42.0 // indirect
61+
golang.org/x/sys v0.34.0 // indirect
62+
golang.org/x/text v0.27.0 // indirect
63+
google.golang.org/protobuf v1.36.6 // indirect
64+
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
65+
gopkg.in/yaml.v3 v3.0.1 // indirect
66+
)

0 commit comments

Comments
 (0)