Skip to content

Commit 4221007

Browse files
committed
feat: Improve MCP server management with event-driven updates
Refactor the MCP ConnectionManager to subscribe to backend events (ServerAdded, ServerRemoved) instead of polling the API for server lists. Introduce internal state (`permanentlyRemoved`) to correctly handle explicit server removal and prevent background reconnection goroutines from interfering. Add and publish a new `ServerStatusChangedEvent` from the backend service (`UpdateMCPServerStatus`) when a server's connection status is updated in the database. This allows listeners (e.g., UI components) to react directly to connectivity changes.
1 parent c2f51ba commit 4221007

File tree

20 files changed

+1669
-1198
lines changed

20 files changed

+1669
-1198
lines changed

go.mod

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,28 @@ go 1.24.1
44

55
require (
66
github.com/a-h/templ v0.3.857
7+
github.com/jmoiron/sqlx v1.4.0
8+
github.com/mark3labs/mcp-go v0.20.1
79
github.com/mattn/go-sqlite3 v1.14.27
8-
github.com/mark3labs/mcp-go v0.18.0
10+
github.com/prometheus/client_golang v1.22.0
911
github.com/rs/zerolog v1.34.0
1012
go.uber.org/fx v1.23.0
1113
)
1214

1315
require (
16+
github.com/beorn7/perks v1.0.1 // indirect
17+
github.com/cespare/xxhash/v2 v2.3.0 // indirect
1418
github.com/google/uuid v1.6.0 // indirect
1519
github.com/mattn/go-colorable v0.1.14 // indirect
1620
github.com/mattn/go-isatty v0.0.20 // indirect
21+
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
22+
github.com/prometheus/client_model v0.6.1 // indirect
23+
github.com/prometheus/common v0.62.0 // indirect
24+
github.com/prometheus/procfs v0.15.1 // indirect
1725
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
1826
go.uber.org/dig v1.18.1 // indirect
1927
go.uber.org/multierr v1.11.0 // indirect
2028
go.uber.org/zap v1.27.0 // indirect
2129
golang.org/x/sys v0.32.0 // indirect
22-
github.com/google/uuid v1.6.0 // indirect
23-
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
24-
gopkg.in/yaml.v3 v3.0.1 // indirect
30+
google.golang.org/protobuf v1.36.5 // indirect
2531
)

go.sum

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,63 @@
1+
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
2+
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
13
github.com/a-h/templ v0.3.857 h1:6EqcJuGZW4OL+2iZ3MD+NnIcG7nGkaQeF2Zq5kf9ZGg=
24
github.com/a-h/templ v0.3.857/go.mod h1:qhrhAkRFubE7khxLZHsBFHfX+gWwVNKbzKeF9GlPV4M=
5+
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
6+
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
7+
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
8+
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
39
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
410
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
511
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
12+
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
13+
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
614
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
7-
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
8-
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
15+
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
16+
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
917
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
1018
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
11-
github.com/mark3labs/mcp-go v0.18.0 h1:YuhgIVjNlTG2ZOwmrkORWyPTp0dz1opPEqvsPtySXao=
12-
github.com/mark3labs/mcp-go v0.18.0/go.mod h1:KmJndYv7GIgcPVwEKJjNcbhVQ+hJGJhrCCB/9xITzpE=
13-
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
19+
github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o=
20+
github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
21+
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
22+
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
23+
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
24+
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
25+
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
26+
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
27+
github.com/mark3labs/mcp-go v0.20.1 h1:E1Bbx9K8d8kQmDZ1QHblM38c7UU2evQ2LlkANk1U/zw=
28+
github.com/mark3labs/mcp-go v0.20.1/go.mod h1:KmJndYv7GIgcPVwEKJjNcbhVQ+hJGJhrCCB/9xITzpE=
1429
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
1530
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
1631
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
1732
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
1833
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
1934
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
2035
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
36+
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
2137
github.com/mattn/go-sqlite3 v1.14.27 h1:drZCnuvf37yPfs95E5jd9s3XhdVWLal+6BOK6qrv6IU=
2238
github.com/mattn/go-sqlite3 v1.14.27/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
39+
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
40+
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
2341
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
2442
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
2543
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
44+
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
45+
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
46+
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
47+
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
48+
github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
49+
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
50+
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
51+
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
2652
github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
2753
github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY=
2854
github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ=
29-
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
30-
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
55+
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
56+
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
3157
github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4=
3258
github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4=
33-
go.uber.org/dig v1.18.0 h1:imUL1UiY0Mg4bqbFfsRQO5G4CGRBec/ZujWTvSVp3pw=
34-
go.uber.org/dig v1.18.0/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE=
59+
go.uber.org/dig v1.18.1 h1:rLww6NuajVjeQn+49u5NcezUJEGwd5uXmyoCKW2g5Es=
60+
go.uber.org/dig v1.18.1/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE=
3561
go.uber.org/fx v1.23.0 h1:lIr/gYWQGfTwGcSXWXu4vP5Ws6iqnNEIY+F/aFzCKTg=
3662
go.uber.org/fx v1.23.0/go.mod h1:o/D9n+2mLP6v1EG+qsdT1O8wKopYAsqZasju97SDFCU=
3763
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
@@ -45,7 +71,7 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
4571
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
4672
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
4773
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
48-
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
49-
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
74+
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
75+
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
5076
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
5177
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

internal/app/app.go

Lines changed: 113 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -4,45 +4,33 @@ package app
44
import (
55
"context"
66
"net/http"
7-
"time"
87

98
"github.com/co-browser/agent-browser/internal/backend"
109
"github.com/co-browser/agent-browser/internal/backend/database"
11-
"github.com/co-browser/agent-browser/internal/config"
1210
"github.com/co-browser/agent-browser/internal/events"
1311
"github.com/co-browser/agent-browser/internal/log"
1412
"github.com/co-browser/agent-browser/internal/mcp"
1513
"github.com/co-browser/agent-browser/internal/web"
14+
"github.com/co-browser/agent-browser/internal/web/client"
1615
"github.com/co-browser/agent-browser/internal/web/handlers"
1716

1817
"go.uber.org/fx"
1918
)
2019

21-
// CoreModules bundles the main application components for fx.
22-
var CoreModules = fx.Options(
23-
LogModule,
24-
DatabaseModule,
25-
ConfigModule,
26-
EventsModule,
27-
BackendModule,
28-
MCPClientModule,
29-
UpdaterModule,
30-
WebModule,
31-
// TODO: Add MCP Server Frontend module
32-
// TODO: Add Sync Daemon module
33-
)
20+
// --- Core Application Modules ---
3421

35-
// LogModule provides common dependencies like logging.
22+
// LogModule provides common logging components.
3623
var LogModule = fx.Module("logger",
3724
fx.Provide(
3825
log.NewLogger,
3926
),
4027
)
4128

42-
// DatabaseModule provides the database dependency.
29+
// DatabaseModule provides the database dependency and manages its lifecycle.
4330
var DatabaseModule = fx.Module("database",
4431
fx.Provide(
4532
func(lc fx.Lifecycle, logger log.Logger) (database.DBInterface, error) {
33+
// TODO: Make dbPath configurable
4634
dbPath := "agent-browser.db"
4735
db, err := database.New(dbPath)
4836
if err != nil {
@@ -63,77 +51,149 @@ var DatabaseModule = fx.Module("database",
6351
)
6452

6553
// ConfigModule provides configuration loading services.
54+
// Currently loads MCP configuration.
6655
var ConfigModule = fx.Module("config",
6756
fx.Provide(
6857
mcp.NewMCPConfig,
6958
),
7059
)
7160

72-
// EventsModule provides the event bus.
61+
// EventsModule provides the application-wide event bus.
7362
var EventsModule = fx.Module("events",
7463
fx.Provide(events.NewBus),
7564
)
7665

77-
// BackendModule provides the backend service.
66+
// BackendModule provides the core backend service logic, abstracting database interactions.
7867
var BackendModule = fx.Module("backend",
7968
fx.Provide(
69+
// Provide the backend service implementation, satisfying the backend.Service interface.
8070
func(db database.DBInterface, bus events.Bus, logger log.Logger) backend.Service {
8171
return backend.NewService(db, bus, logger)
8272
},
8373
),
8474
)
8575

86-
// MCPClientModule provides the MCP client (distinct from server frontend).
76+
// MCPClientModule provides the components responsible for connecting *to* remote MCP servers.
77+
// This includes the ConnectionManager and the API client used by the ConnectionManager
78+
// to update this agent's status and sync tools via its own web API.
8779
var MCPClientModule = fx.Module("mcp_client",
8880
fx.Provide(
81+
// Provide the web API client used by MCP components
82+
func(logger log.Logger) *client.Client {
83+
// TODO: Make API client base URL configurable
84+
config := client.DefaultConfig()
85+
// DefaultConfig likely points to localhost, which is correct for the agent
86+
// calling its own API.
87+
return client.NewClient(config, logger)
88+
},
89+
// Provide MCP components (like ConnectionManager)
8990
mcp.NewMCPComponents,
9091
),
92+
// Register lifecycle hooks for starting/stopping the MCP ConnectionManager
9193
fx.Invoke(mcp.RegisterMCPServerHooks),
9294
)
9395

94-
// UpdaterModule provides the tool and server updater service.
95-
var UpdaterModule = fx.Module("updater",
96-
fx.Provide(
97-
func(bs backend.Service, mc client.Client, bus events.Bus, logger log.Logger) updater.Service {
98-
pollInterval := 5 * time.Minute
99-
logger.Info().Dur("pollInterval", pollInterval).Msg("Creating Updater Service")
100-
return updater.NewService(bs, mc, bus, logger, pollInterval)
101-
},
102-
),
103-
fx.Invoke(func(lc fx.Lifecycle, us updater.Service, logger log.Logger) {
104-
lc.Append(fx.Hook{
105-
OnStart: func(_ctx context.Context) error {
106-
logger.Info().Msg("Registering Updater Service start hook")
107-
us.Start(_ctx)
108-
return nil
109-
},
110-
OnStop: func(_ctx context.Context) error {
111-
logger.Info().Msg("Registering Updater Service stop hook")
112-
us.Stop()
113-
return nil
114-
},
115-
})
116-
}),
117-
)
118-
119-
// WebModule provides the web server components
96+
// WebModule provides the HTTP server, API handlers, and UI handlers (if any).
97+
// It serves the API used internally by the MCPClient and potentially by external UIs.
12098
var WebModule = fx.Module("web",
12199
fx.Provide(
122-
// Provide UI handler
100+
// Provide UI handler (if applicable)
123101
handlers.NewUIHandler,
124102
// Provide API handlers
125-
func(bs backend.Service, us updater.Service, ce *config.Exporter, logger log.Logger) *handlers.APIHandlers {
126-
return handlers.NewAPIHandlers(bs, us, ce, logger)
103+
func(bs backend.Service, logger log.Logger) *handlers.APIHandlers {
104+
return handlers.NewAPIHandlers(bs, logger)
127105
},
128-
// Provide HTTP mux using web package
106+
// Provide the HTTP request router (ServeMux)
129107
web.NewMux,
130-
// Provide HTTP server using web package
108+
// Provide the HTTP server itself
131109
web.NewServer,
132110
),
133-
// Register API handlers with the router
111+
// Register API handler routes with the router
134112
fx.Invoke(func(router *http.ServeMux, apiHandlers *handlers.APIHandlers) {
135113
apiHandlers.RegisterRoutes(router)
136114
}),
137-
// Register web server lifecycle hooks
115+
// Register web server lifecycle hooks for starting/stopping the server
138116
fx.Invoke(web.RegisterWebServerHooks),
139117
)
118+
119+
// InitModule performs initial setup tasks, like seeding the database with default servers.
120+
// It runs once during application startup if needed.
121+
var InitModule = fx.Module("init",
122+
fx.Invoke(func(bs backend.Service, logger log.Logger) {
123+
// Check if any servers already exist in the database.
124+
servers, err := bs.ListMCPServers()
125+
if err != nil {
126+
logger.Error().Err(err).Msg("Failed to check existing servers during initialization")
127+
// Decide if this should be fatal. For now, we continue, but defaults won't be added.
128+
return
129+
}
130+
131+
// Only add default servers if the database is empty.
132+
if len(servers) == 0 {
133+
logger.Info().Msg("No MCP servers found in the database. Adding default servers...")
134+
135+
// Define the default servers to add.
136+
// TODO: Consider moving these defaults to configuration.
137+
defaultServers := []struct {
138+
name string
139+
url string
140+
description string
141+
}{
142+
{
143+
name: "Local Test Server",
144+
url: "http://0.0.0.0:8001/sse", // Assumes local test server runs on 8001
145+
description: "Local MCP test server",
146+
},
147+
{
148+
name: "API Gateway",
149+
url: "https://api-gateway.cobrowser.xyz/mcp/api/sse?api_key=REDACTED_API_KEY",
150+
description: "API Gateway MCP server",
151+
},
152+
}
153+
154+
// Add each default server via the backend service.
155+
for _, server := range defaultServers {
156+
_, err := bs.AddMCPServer(server.name, server.url) // Description is not stored via AddMCPServer currently
157+
if err != nil {
158+
// Log error but continue trying to add others.
159+
logger.Error().
160+
Err(err).
161+
Str("name", server.name).
162+
Str("url", server.url).
163+
// Str("description", server.description). // Not used by AddMCPServer
164+
Msg("Failed to add default server")
165+
continue // Skip logging success for this server
166+
}
167+
logger.Info().
168+
Str("name", server.name).
169+
Str("url", server.url).
170+
// Str("description", server.description). // Not stored
171+
Msg("Added default server")
172+
}
173+
} else {
174+
logger.Info().Int("count", len(servers)).Msg("Servers already exist, skipping default server initialization")
175+
}
176+
}),
177+
)
178+
179+
// --- Application Bootstrap ---
180+
181+
// CoreModules bundles the main application components for fx.
182+
// The order generally doesn't matter for Fx, but grouping can improve readability.
183+
var CoreModules = fx.Options(
184+
// Foundational Modules
185+
LogModule,
186+
ConfigModule, // Provides config values needed by others
187+
EventsModule,
188+
DatabaseModule,
189+
190+
// Core Service Logic
191+
BackendModule, // Depends on DB, Events, Log
192+
193+
// Interface Layers & Clients
194+
WebModule, // Provides the API/UI server (depends on Backend)
195+
MCPClientModule, // Connects *out* to other MCPs (depends on Backend, WebClient, Log, Config)
196+
197+
// Initialization Logic (runs after dependencies are ready)
198+
InitModule,
199+
)

0 commit comments

Comments
 (0)