|
6 | 6 | "log/slog" |
7 | 7 | "time" |
8 | 8 |
|
| 9 | + "github.com/localrivet/gomcp/client" |
9 | 10 | "github.com/localrivet/gomcp/events" |
10 | 11 | "github.com/localrivet/gomcp/server" |
11 | 12 | ) |
@@ -102,6 +103,31 @@ type RequestFailedEvent struct { |
102 | 103 | Metadata map[string]any `json:"metadata,omitempty"` |
103 | 104 | } |
104 | 105 |
|
| 106 | +// Client-side event types |
| 107 | +type ClientInitializedEvent struct { |
| 108 | + ClientName string `json:"clientName"` |
| 109 | + ServerURL string `json:"serverUrl"` |
| 110 | + ProtocolVersion string `json:"protocolVersion"` |
| 111 | + InitializedAt time.Time `json:"initializedAt"` |
| 112 | + Capabilities map[string]any `json:"capabilities"` |
| 113 | + Metadata map[string]any `json:"metadata,omitempty"` |
| 114 | +} |
| 115 | + |
| 116 | +type ClientConnectionEvent struct { |
| 117 | + Status string `json:"status"` |
| 118 | + ServerURL string `json:"serverUrl"` |
| 119 | + Timestamp time.Time `json:"timestamp"` |
| 120 | + Error string `json:"error,omitempty"` |
| 121 | + Metadata map[string]any `json:"metadata,omitempty"` |
| 122 | +} |
| 123 | + |
| 124 | +type ClientErrorEvent struct { |
| 125 | + Operation string `json:"operation"` |
| 126 | + Error string `json:"error"` |
| 127 | + OccurredAt time.Time `json:"occurredAt"` |
| 128 | + Metadata map[string]any `json:"metadata,omitempty"` |
| 129 | +} |
| 130 | + |
105 | 131 | func main() { |
106 | 132 | // Create a server with events |
107 | 133 | srv := server.NewServer("events-demo") |
@@ -130,18 +156,28 @@ func main() { |
130 | 156 | logger.Info(" 💭 prompt execution", "topic", events.TopicPromptExecuted) |
131 | 157 | logger.Info(" ❌ request failures", "topic", events.TopicRequestFailed) |
132 | 158 | logger.Info("") |
133 | | - logger.Info("🧪 Testing Event System:") |
| 159 | + logger.Info("🧪 Testing Server Event System:") |
134 | 160 |
|
135 | | - // Demonstrate event publishing with some test events |
| 161 | + // Demonstrate server event publishing with some test events |
136 | 162 | demonstrateEvents(srv, logger) |
137 | 163 |
|
| 164 | + logger.Info("") |
| 165 | + logger.Info("🧪 Testing Client Event System:") |
| 166 | + |
| 167 | + // Demonstrate client events |
| 168 | + demonstrateClientEvents(logger) |
| 169 | + |
138 | 170 | logger.Info("") |
139 | 171 | logger.Info("✅ Events integration example complete!") |
140 | 172 | logger.Info("💡 In a real MCP server, these events fire automatically when:") |
141 | 173 | logger.Info(" - Server starts and clients connect") |
142 | 174 | logger.Info(" - Tools and resources are registered") |
143 | 175 | logger.Info(" - Clients execute tools, access resources, or use prompts") |
144 | 176 | logger.Info(" - Errors occur during request processing") |
| 177 | + logger.Info("💡 In a real MCP client, events fire when:") |
| 178 | + logger.Info(" - Client initializes and connects to servers") |
| 179 | + logger.Info(" - Connection status changes") |
| 180 | + logger.Info(" - Errors occur during client operations") |
145 | 181 | } |
146 | 182 |
|
147 | 183 | func setupEventSubscriptions(srv server.Server, logger *slog.Logger) { |
@@ -422,3 +458,88 @@ func demonstrateEvents(srv server.Server, logger *slog.Logger) { |
422 | 458 | // Give events time to process |
423 | 459 | time.Sleep(50 * time.Millisecond) |
424 | 460 | } |
| 461 | + |
| 462 | +func demonstrateClientEvents(logger *slog.Logger) { |
| 463 | + logger.Info("📢 Demonstrating client events system...") |
| 464 | + |
| 465 | + // Create a simple client to demonstrate client-side events |
| 466 | + c, err := client.NewClient("test-client", client.WithStdio()) |
| 467 | + if err != nil { |
| 468 | + logger.Info("Failed to create client", "error", err) |
| 469 | + return |
| 470 | + } |
| 471 | + |
| 472 | + // Get the client's events subject |
| 473 | + clientEvents := c.Events() |
| 474 | + |
| 475 | + // Subscribe to client events (if the topics exist, otherwise demonstrate with custom topics) |
| 476 | + events.Subscribe[ClientInitializedEvent](clientEvents, "client.initialized", |
| 477 | + func(ctx context.Context, evt ClientInitializedEvent) error { |
| 478 | + logger.Info("🚀 Client initialized", |
| 479 | + "clientName", evt.ClientName, |
| 480 | + "serverURL", evt.ServerURL, |
| 481 | + "protocolVersion", evt.ProtocolVersion) |
| 482 | + return nil |
| 483 | + }) |
| 484 | + |
| 485 | + events.Subscribe[ClientConnectionEvent](clientEvents, "client.connection", |
| 486 | + func(ctx context.Context, evt ClientConnectionEvent) error { |
| 487 | + logger.Info("🔌 Client connection status", |
| 488 | + "status", evt.Status, |
| 489 | + "serverURL", evt.ServerURL) |
| 490 | + return nil |
| 491 | + }) |
| 492 | + |
| 493 | + events.Subscribe[ClientErrorEvent](clientEvents, "client.error", |
| 494 | + func(ctx context.Context, evt ClientErrorEvent) error { |
| 495 | + logger.Info("❌ Client error", |
| 496 | + "operation", evt.Operation, |
| 497 | + "error", evt.Error) |
| 498 | + return nil |
| 499 | + }) |
| 500 | + |
| 501 | + // Publish test client events |
| 502 | + testClientEvent := ClientInitializedEvent{ |
| 503 | + ClientName: "test-client", |
| 504 | + ServerURL: "stdio://server", |
| 505 | + ProtocolVersion: "2025-03-26", |
| 506 | + InitializedAt: time.Now(), |
| 507 | + Capabilities: map[string]any{"supports": []string{"greet", "calculate"}}, |
| 508 | + Metadata: make(map[string]any), |
| 509 | + } |
| 510 | + |
| 511 | + if err := events.Publish[ClientInitializedEvent](clientEvents, "client.initialized", testClientEvent); err != nil { |
| 512 | + logger.Info("Failed to publish client initialized event", "error", err) |
| 513 | + } |
| 514 | + |
| 515 | + time.Sleep(10 * time.Millisecond) |
| 516 | + |
| 517 | + testClientConnectionEvent := ClientConnectionEvent{ |
| 518 | + Status: "connected", |
| 519 | + ServerURL: "stdio://server", |
| 520 | + Timestamp: time.Now(), |
| 521 | + Metadata: make(map[string]any), |
| 522 | + } |
| 523 | + |
| 524 | + if err := events.Publish[ClientConnectionEvent](clientEvents, "client.connection", testClientConnectionEvent); err != nil { |
| 525 | + logger.Info("Failed to publish client connection event", "error", err) |
| 526 | + } |
| 527 | + |
| 528 | + time.Sleep(10 * time.Millisecond) |
| 529 | + |
| 530 | + testClientErrorEvent := ClientErrorEvent{ |
| 531 | + Operation: "tool_call", |
| 532 | + Error: "Demonstration client error", |
| 533 | + OccurredAt: time.Now(), |
| 534 | + Metadata: make(map[string]any), |
| 535 | + } |
| 536 | + |
| 537 | + if err := events.Publish[ClientErrorEvent](clientEvents, "client.error", testClientErrorEvent); err != nil { |
| 538 | + logger.Info("Failed to publish client error event", "error", err) |
| 539 | + } |
| 540 | + |
| 541 | + // Give events time to process |
| 542 | + time.Sleep(50 * time.Millisecond) |
| 543 | + |
| 544 | + logger.Info("✅ Client events demonstration complete") |
| 545 | +} |
0 commit comments