generated from rmcguire/go-server-with-otel
77 lines
2.3 KiB
Go
77 lines
2.3 KiB
Go
package econetmcp
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/modelcontextprotocol/go-sdk/mcp"
|
|
"k8s.io/utils/ptr"
|
|
|
|
pb "gitea.libretechconsulting.com/rmcguire/econet-exporter/api/econet/v1alpha1"
|
|
)
|
|
|
|
var ListDevicesTool = &mcp.Tool{
|
|
Name: "list_water_heaters",
|
|
Title: "List EcoNet Water Heaters",
|
|
Description: "Lists Rheem EcoNet devices and their current state (mode, setpoint, " +
|
|
"hot water availability, connectivity). Optionally filter to one serial number.",
|
|
Annotations: &mcp.ToolAnnotations{
|
|
ReadOnlyHint: true,
|
|
OpenWorldHint: ptr.To(true),
|
|
},
|
|
}
|
|
|
|
type ListDevicesParams struct {
|
|
SerialNumber string `json:"serial_number,omitempty" jsonschema:"Optional device serial number to return a single device"`
|
|
}
|
|
|
|
func (m *EconetMCPServer) addListDevicesTool() {
|
|
mcp.AddTool(m.server, ListDevicesTool, m.listDevicesHandler)
|
|
}
|
|
|
|
func (m *EconetMCPServer) listDevicesHandler(ctx context.Context, _ *mcp.CallToolRequest, args *ListDevicesParams) (
|
|
*mcp.CallToolResult, any, error,
|
|
) {
|
|
m.log.Debug().Str("serial", args.SerialNumber).Msg("list water heaters tool called")
|
|
|
|
devices, err := m.lookup(ctx, args.SerialNumber)
|
|
if err != nil {
|
|
return &mcp.CallToolResult{IsError: true, Meta: mcp.Meta{"error": err.Error()}}, nil, err
|
|
}
|
|
|
|
return &mcp.CallToolResult{
|
|
Content: []mcp.Content{&mcp.TextContent{Text: summarizeDevices(devices)}},
|
|
}, nil, nil
|
|
}
|
|
|
|
func (m *EconetMCPServer) lookup(ctx context.Context, serial string) ([]*pb.Device, error) {
|
|
if serial != "" {
|
|
resp, err := m.econetGRPC.GetDevice(ctx, &pb.GetDeviceRequest{SerialNumber: serial})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return []*pb.Device{resp.GetDevice()}, nil
|
|
}
|
|
|
|
resp, err := m.econetGRPC.ListDevices(ctx, &pb.ListDevicesRequest{})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return resp.GetDevices(), nil
|
|
}
|
|
|
|
func summarizeDevices(devices []*pb.Device) string {
|
|
if len(devices) == 0 {
|
|
return "No EcoNet devices found."
|
|
}
|
|
var b strings.Builder
|
|
for _, d := range devices {
|
|
fmt.Fprintf(&b, "%s (%s, serial %s): mode=%s setpoint=%d°F running=%t connected=%t hotWater=%d%% alerts=%d\n",
|
|
d.GetFriendlyName(), d.GetGenericType(), d.GetSerialNumber(),
|
|
d.GetMode(), d.GetSetpoint(), d.GetRunning(), d.GetConnected(),
|
|
d.GetHotWaterAvailability(), d.GetAlertCount())
|
|
}
|
|
return strings.TrimRight(b.String(), "\n")
|
|
}
|