generated from rmcguire/go-server-with-otel
move to generated mcp for econet
This commit is contained in:
@@ -24,8 +24,14 @@ Exporter for Rheem EcoNet / Rheemcloud water heaters, built on the
|
|||||||
**No MQTT**, so `WiFiSignal` and `Running`/`RunningState` stay zero.
|
**No MQTT**, so `WiFiSignal` and `Running`/`RunningState` stay zero.
|
||||||
- `pkg/econet/econetgrpc/` — `EconetService` gRPC impl (`ListDevices`,
|
- `pkg/econet/econetgrpc/` — `EconetService` gRPC impl (`ListDevices`,
|
||||||
`GetDevice`) + `deviceToProto`. Does **not** own a client; it's injected.
|
`GetDevice`) + `deviceToProto`. Does **not** own a client; it's injected.
|
||||||
- `pkg/econet/econetmcp/` — MCP server at `/api/mcp`; the `list_water_heaters`
|
- `pkg/econet/econetmcpgen/` — **active** MCP server at `/api/mcp`. Registers
|
||||||
tool delegates to the gRPC server.
|
the tools generated by protoc-gen-go-mcp (`api/econet/v1alpha1/v1alpha1mcp/`)
|
||||||
|
against our go-sdk `*mcp.Server` via the `runtime/gosdk` adapter, forwarding
|
||||||
|
in-process to the gRPC server. Exposes the same package API as `econetmcp`.
|
||||||
|
- `pkg/econet/econetmcp/` — the older hand-written MCP server; a single
|
||||||
|
`list_water_heaters` tool delegating to the gRPC server. Kept in place as a
|
||||||
|
fallback. **Switch between the two** with the aliased `econetmcp` import in
|
||||||
|
`pkg/econet/econet.go` (one line — both packages export identical symbols).
|
||||||
- `pkg/econet/econetmetrics/` — OTEL observable gauges (read the client
|
- `pkg/econet/econetmetrics/` — OTEL observable gauges (read the client
|
||||||
snapshot at scrape time; no poller of its own).
|
snapshot at scrape time; no poller of its own).
|
||||||
|
|
||||||
@@ -68,6 +74,8 @@ that's all it takes — no extra wiring.
|
|||||||
## Workflow
|
## Workflow
|
||||||
|
|
||||||
- Regenerate proto: `make proto` (buf; `PROTO_DIRS=proto/econet/v1alpha1/*`).
|
- Regenerate proto: `make proto` (buf; `PROTO_DIRS=proto/econet/v1alpha1/*`).
|
||||||
|
This also runs the `protoc-gen-go-mcp` plugin (see `buf.gen.yaml`), emitting
|
||||||
|
the MCP registrars under `api/econet/v1alpha1/v1alpha1mcp/`.
|
||||||
- Regenerate config schema after config changes: `make schema`.
|
- Regenerate config schema after config changes: `make schema`.
|
||||||
- Build/test: `go build ./... && go test ./...`.
|
- Build/test: `go build ./... && go test ./...`.
|
||||||
- `econetclient.Device` is a plain struct, so `deviceToProto` and the datapoint
|
- `econetclient.Device` is a plain struct, so `deviceToProto` and the datapoint
|
||||||
|
|||||||
@@ -0,0 +1,316 @@
|
|||||||
|
// Code generated by protoc-gen-mcp-go. DO NOT EDIT.
|
||||||
|
// source: econet/v1alpha1/econet.proto
|
||||||
|
|
||||||
|
package v1alpha1mcp
|
||||||
|
|
||||||
|
import (
|
||||||
|
v1alpha1 "gitea.libretechconsulting.com/rmcguire/econet-exporter/api/econet/v1alpha1"
|
||||||
|
)
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"google.golang.org/protobuf/encoding/protojson"
|
||||||
|
"connectrpc.com/connect"
|
||||||
|
grpc "google.golang.org/grpc"
|
||||||
|
"github.com/redpanda-data/protoc-gen-go-mcp/pkg/runtime"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
EconetService_GetDeviceTool = runtime.Tool{Name: "econet_v1alpha1_EconetService_GetDevice", Description: "", RawInputSchema: json.RawMessage{0x7b, 0x22, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0x3a, 0x7b, 0x22, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x3a, 0x7b, 0x22, 0x6d, 0x69, 0x6e, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x22, 0x3a, 0x31, 0x2c, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x7d, 0x7d, 0x2c, 0x22, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x22, 0x3a, 0x5b, 0x5d, 0x2c, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x7d}, RawOutputSchema: json.RawMessage{0x7b, 0x22, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0x3a, 0x7b, 0x22, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x22, 0x3a, 0x7b, 0x22, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0x3a, 0x7b, 0x22, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x3a, 0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x7d, 0x2c, 0x22, 0x61, 0x77, 0x61, 0x79, 0x22, 0x3a, 0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x62, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x22, 0x7d, 0x2c, 0x22, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x22, 0x3a, 0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x62, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x22, 0x7d, 0x2c, 0x22, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x22, 0x3a, 0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x7d, 0x2c, 0x22, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0x3a, 0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x62, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x22, 0x7d, 0x2c, 0x22, 0x66, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x6c, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x3a, 0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x7d, 0x2c, 0x22, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x7d, 0x2c, 0x22, 0x68, 0x6f, 0x74, 0x5f, 0x77, 0x61, 0x74, 0x65, 0x72, 0x5f, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x22, 0x3a, 0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x7d, 0x2c, 0x22, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x22, 0x3a, 0x7b, 0x22, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x22, 0x3a, 0x22, 0x64, 0x61, 0x74, 0x65, 0x2d, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x2c, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x5b, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x2c, 0x22, 0x6e, 0x75, 0x6c, 0x6c, 0x22, 0x5d, 0x7d, 0x2c, 0x22, 0x6d, 0x6f, 0x64, 0x65, 0x22, 0x3a, 0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x7d, 0x2c, 0x22, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x22, 0x3a, 0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x62, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x22, 0x7d, 0x2c, 0x22, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0x3a, 0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x7d, 0x2c, 0x22, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x3a, 0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x7d, 0x2c, 0x22, 0x73, 0x65, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x22, 0x3a, 0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x7d, 0x2c, 0x22, 0x73, 0x65, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x5f, 0x6d, 0x61, 0x78, 0x22, 0x3a, 0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x7d, 0x2c, 0x22, 0x73, 0x65, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x22, 0x3a, 0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x7d, 0x2c, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x7d, 0x2c, 0x22, 0x77, 0x69, 0x66, 0x69, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x22, 0x3a, 0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x7d, 0x7d, 0x2c, 0x22, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x22, 0x3a, 0x5b, 0x5d, 0x2c, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x7d, 0x7d, 0x2c, 0x22, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x22, 0x3a, 0x5b, 0x5d, 0x2c, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x7d}}
|
||||||
|
EconetService_ListDevicesTool = runtime.Tool{Name: "econet_v1alpha1_EconetService_ListDevices", Description: "", RawInputSchema: json.RawMessage{0x7b, 0x22, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0x3a, 0x7b, 0x7d, 0x2c, 0x22, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x22, 0x3a, 0x5b, 0x5d, 0x2c, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x7d}, RawOutputSchema: json.RawMessage{0x7b, 0x22, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0x3a, 0x7b, 0x22, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x22, 0x3a, 0x7b, 0x22, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x22, 0x3a, 0x7b, 0x22, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x69, 0x65, 0x73, 0x22, 0x3a, 0x7b, 0x22, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x3a, 0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x7d, 0x2c, 0x22, 0x61, 0x77, 0x61, 0x79, 0x22, 0x3a, 0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x62, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x22, 0x7d, 0x2c, 0x22, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x22, 0x3a, 0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x62, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x22, 0x7d, 0x2c, 0x22, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x22, 0x3a, 0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x7d, 0x2c, 0x22, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0x3a, 0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x62, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x22, 0x7d, 0x2c, 0x22, 0x66, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x6c, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x3a, 0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x7d, 0x2c, 0x22, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x69, 0x63, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x7d, 0x2c, 0x22, 0x68, 0x6f, 0x74, 0x5f, 0x77, 0x61, 0x74, 0x65, 0x72, 0x5f, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x22, 0x3a, 0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x7d, 0x2c, 0x22, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x22, 0x3a, 0x7b, 0x22, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x22, 0x3a, 0x22, 0x64, 0x61, 0x74, 0x65, 0x2d, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x2c, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x5b, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x2c, 0x22, 0x6e, 0x75, 0x6c, 0x6c, 0x22, 0x5d, 0x7d, 0x2c, 0x22, 0x6d, 0x6f, 0x64, 0x65, 0x22, 0x3a, 0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x7d, 0x2c, 0x22, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x22, 0x3a, 0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x62, 0x6f, 0x6f, 0x6c, 0x65, 0x61, 0x6e, 0x22, 0x7d, 0x2c, 0x22, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0x3a, 0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x7d, 0x2c, 0x22, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x22, 0x3a, 0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x7d, 0x2c, 0x22, 0x73, 0x65, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x22, 0x3a, 0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x7d, 0x2c, 0x22, 0x73, 0x65, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x5f, 0x6d, 0x61, 0x78, 0x22, 0x3a, 0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x7d, 0x2c, 0x22, 0x73, 0x65, 0x74, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x22, 0x3a, 0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x7d, 0x2c, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x7d, 0x2c, 0x22, 0x77, 0x69, 0x66, 0x69, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x22, 0x3a, 0x7b, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x22, 0x7d, 0x7d, 0x2c, 0x22, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x22, 0x3a, 0x5b, 0x5d, 0x2c, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x7d, 0x2c, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x61, 0x72, 0x72, 0x61, 0x79, 0x22, 0x7d, 0x7d, 0x2c, 0x22, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x22, 0x3a, 0x5b, 0x5d, 0x2c, 0x22, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x22, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x7d}}
|
||||||
|
)
|
||||||
|
|
||||||
|
// EconetServiceServer is compatible with the grpc-go server interface.
|
||||||
|
type EconetServiceServer interface {
|
||||||
|
GetDevice(ctx context.Context, req *v1alpha1.GetDeviceRequest) (*v1alpha1.GetDeviceResponse, error)
|
||||||
|
ListDevices(ctx context.Context, req *v1alpha1.ListDevicesRequest) (*v1alpha1.ListDevicesResponse, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterEconetServiceHandler registers standard MCP handlers for EconetService
|
||||||
|
func RegisterEconetServiceHandler(s runtime.MCPServer, srv EconetServiceServer, opts ...runtime.Option) {
|
||||||
|
config := runtime.NewConfig()
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(config)
|
||||||
|
}
|
||||||
|
GetDeviceTool := EconetService_GetDeviceTool
|
||||||
|
GetDeviceTool = runtime.ApplyConfig(GetDeviceTool, config)
|
||||||
|
|
||||||
|
if config.ShouldRegister(GetDeviceTool.Name) {
|
||||||
|
s.AddTool(GetDeviceTool, func(ctx context.Context, request *runtime.CallToolRequest) (*runtime.CallToolResult, error) {
|
||||||
|
var req v1alpha1.GetDeviceRequest
|
||||||
|
|
||||||
|
message := request.Arguments
|
||||||
|
|
||||||
|
// Extract extra properties if configured
|
||||||
|
for _, prop := range config.ExtraProperties {
|
||||||
|
if propVal, ok := message[prop.Name]; ok {
|
||||||
|
ctx = context.WithValue(ctx, prop.ContextKey, propVal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rewrite oneof discriminated wrappers and recursion placeholders into the
|
||||||
|
// protojson-native shape. Errors are model-readable for self-correction.
|
||||||
|
if err := runtime.DecodeArguments(req.ProtoReflect().Descriptor(), message); err != nil {
|
||||||
|
return runtime.NewToolResultError(err.Error()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
marshaled, err := json.Marshal(message)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := (protojson.UnmarshalOptions{DiscardUnknown: true}).Unmarshal(marshaled, &req); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := srv.GetDevice(ctx, &req)
|
||||||
|
if err != nil {
|
||||||
|
return runtime.HandleError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
structured, err := runtime.EncodeMessage(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return runtime.NewToolResultJSON(structured), nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
ListDevicesTool := EconetService_ListDevicesTool
|
||||||
|
ListDevicesTool = runtime.ApplyConfig(ListDevicesTool, config)
|
||||||
|
|
||||||
|
if config.ShouldRegister(ListDevicesTool.Name) {
|
||||||
|
s.AddTool(ListDevicesTool, func(ctx context.Context, request *runtime.CallToolRequest) (*runtime.CallToolResult, error) {
|
||||||
|
var req v1alpha1.ListDevicesRequest
|
||||||
|
|
||||||
|
message := request.Arguments
|
||||||
|
|
||||||
|
// Extract extra properties if configured
|
||||||
|
for _, prop := range config.ExtraProperties {
|
||||||
|
if propVal, ok := message[prop.Name]; ok {
|
||||||
|
ctx = context.WithValue(ctx, prop.ContextKey, propVal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rewrite oneof discriminated wrappers and recursion placeholders into the
|
||||||
|
// protojson-native shape. Errors are model-readable for self-correction.
|
||||||
|
if err := runtime.DecodeArguments(req.ProtoReflect().Descriptor(), message); err != nil {
|
||||||
|
return runtime.NewToolResultError(err.Error()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
marshaled, err := json.Marshal(message)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := (protojson.UnmarshalOptions{DiscardUnknown: true}).Unmarshal(marshaled, &req); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := srv.ListDevices(ctx, &req)
|
||||||
|
if err != nil {
|
||||||
|
return runtime.HandleError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
structured, err := runtime.EncodeMessage(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return runtime.NewToolResultJSON(structured), nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// EconetServiceClient is compatible with the grpc-go client interface.
|
||||||
|
type EconetServiceClient interface {
|
||||||
|
GetDevice(ctx context.Context, req *v1alpha1.GetDeviceRequest, opts ...grpc.CallOption) (*v1alpha1.GetDeviceResponse, error)
|
||||||
|
ListDevices(ctx context.Context, req *v1alpha1.ListDevicesRequest, opts ...grpc.CallOption) (*v1alpha1.ListDevicesResponse, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ConnectEconetServiceClient is compatible with the connectrpc-go client interface.
|
||||||
|
type ConnectEconetServiceClient interface {
|
||||||
|
GetDevice(ctx context.Context, req *connect.Request[v1alpha1.GetDeviceRequest]) (*connect.Response[v1alpha1.GetDeviceResponse], error)
|
||||||
|
ListDevices(ctx context.Context, req *connect.Request[v1alpha1.ListDevicesRequest]) (*connect.Response[v1alpha1.ListDevicesResponse], error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ForwardToConnectEconetServiceClient registers a connectrpc client, to forward MCP calls to it.
|
||||||
|
func ForwardToConnectEconetServiceClient(s runtime.MCPServer, client ConnectEconetServiceClient, opts ...runtime.Option) {
|
||||||
|
config := runtime.NewConfig()
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(config)
|
||||||
|
}
|
||||||
|
GetDeviceTool := EconetService_GetDeviceTool
|
||||||
|
GetDeviceTool = runtime.ApplyConfig(GetDeviceTool, config)
|
||||||
|
|
||||||
|
if config.ShouldRegister(GetDeviceTool.Name) {
|
||||||
|
s.AddTool(GetDeviceTool, func(ctx context.Context, request *runtime.CallToolRequest) (*runtime.CallToolResult, error) {
|
||||||
|
var req v1alpha1.GetDeviceRequest
|
||||||
|
|
||||||
|
message := request.Arguments
|
||||||
|
|
||||||
|
// Extract extra properties if configured
|
||||||
|
for _, prop := range config.ExtraProperties {
|
||||||
|
if propVal, ok := message[prop.Name]; ok {
|
||||||
|
ctx = context.WithValue(ctx, prop.ContextKey, propVal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := runtime.DecodeArguments(req.ProtoReflect().Descriptor(), message); err != nil {
|
||||||
|
return runtime.NewToolResultError(err.Error()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
marshaled, err := json.Marshal(message)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := (protojson.UnmarshalOptions{DiscardUnknown: true}).Unmarshal(marshaled, &req); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := client.GetDevice(ctx, connect.NewRequest(&req))
|
||||||
|
if err != nil {
|
||||||
|
return runtime.HandleError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
structured, err := runtime.EncodeMessage(resp.Msg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return runtime.NewToolResultJSON(structured), nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
ListDevicesTool := EconetService_ListDevicesTool
|
||||||
|
ListDevicesTool = runtime.ApplyConfig(ListDevicesTool, config)
|
||||||
|
|
||||||
|
if config.ShouldRegister(ListDevicesTool.Name) {
|
||||||
|
s.AddTool(ListDevicesTool, func(ctx context.Context, request *runtime.CallToolRequest) (*runtime.CallToolResult, error) {
|
||||||
|
var req v1alpha1.ListDevicesRequest
|
||||||
|
|
||||||
|
message := request.Arguments
|
||||||
|
|
||||||
|
// Extract extra properties if configured
|
||||||
|
for _, prop := range config.ExtraProperties {
|
||||||
|
if propVal, ok := message[prop.Name]; ok {
|
||||||
|
ctx = context.WithValue(ctx, prop.ContextKey, propVal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := runtime.DecodeArguments(req.ProtoReflect().Descriptor(), message); err != nil {
|
||||||
|
return runtime.NewToolResultError(err.Error()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
marshaled, err := json.Marshal(message)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := (protojson.UnmarshalOptions{DiscardUnknown: true}).Unmarshal(marshaled, &req); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := client.ListDevices(ctx, connect.NewRequest(&req))
|
||||||
|
if err != nil {
|
||||||
|
return runtime.HandleError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
structured, err := runtime.EncodeMessage(resp.Msg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return runtime.NewToolResultJSON(structured), nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ForwardToEconetServiceClient registers a gRPC client, to forward MCP calls to it.
|
||||||
|
func ForwardToEconetServiceClient(s runtime.MCPServer, client EconetServiceClient, opts ...runtime.Option) {
|
||||||
|
config := runtime.NewConfig()
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(config)
|
||||||
|
}
|
||||||
|
GetDeviceTool := EconetService_GetDeviceTool
|
||||||
|
GetDeviceTool = runtime.ApplyConfig(GetDeviceTool, config)
|
||||||
|
|
||||||
|
if config.ShouldRegister(GetDeviceTool.Name) {
|
||||||
|
s.AddTool(GetDeviceTool, func(ctx context.Context, request *runtime.CallToolRequest) (*runtime.CallToolResult, error) {
|
||||||
|
var req v1alpha1.GetDeviceRequest
|
||||||
|
|
||||||
|
message := request.Arguments
|
||||||
|
|
||||||
|
// Extract extra properties if configured
|
||||||
|
for _, prop := range config.ExtraProperties {
|
||||||
|
if propVal, ok := message[prop.Name]; ok {
|
||||||
|
ctx = context.WithValue(ctx, prop.ContextKey, propVal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := runtime.DecodeArguments(req.ProtoReflect().Descriptor(), message); err != nil {
|
||||||
|
return runtime.NewToolResultError(err.Error()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
marshaled, err := json.Marshal(message)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := (protojson.UnmarshalOptions{DiscardUnknown: true}).Unmarshal(marshaled, &req); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := client.GetDevice(ctx, &req)
|
||||||
|
if err != nil {
|
||||||
|
return runtime.HandleError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
structured, err := runtime.EncodeMessage(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return runtime.NewToolResultJSON(structured), nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
ListDevicesTool := EconetService_ListDevicesTool
|
||||||
|
ListDevicesTool = runtime.ApplyConfig(ListDevicesTool, config)
|
||||||
|
|
||||||
|
if config.ShouldRegister(ListDevicesTool.Name) {
|
||||||
|
s.AddTool(ListDevicesTool, func(ctx context.Context, request *runtime.CallToolRequest) (*runtime.CallToolResult, error) {
|
||||||
|
var req v1alpha1.ListDevicesRequest
|
||||||
|
|
||||||
|
message := request.Arguments
|
||||||
|
|
||||||
|
// Extract extra properties if configured
|
||||||
|
for _, prop := range config.ExtraProperties {
|
||||||
|
if propVal, ok := message[prop.Name]; ok {
|
||||||
|
ctx = context.WithValue(ctx, prop.ContextKey, propVal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := runtime.DecodeArguments(req.ProtoReflect().Descriptor(), message); err != nil {
|
||||||
|
return runtime.NewToolResultError(err.Error()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
marshaled, err := json.Marshal(message)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := (protojson.UnmarshalOptions{DiscardUnknown: true}).Unmarshal(marshaled, &req); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := client.ListDevices(ctx, &req)
|
||||||
|
if err != nil {
|
||||||
|
return runtime.HandleError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
structured, err := runtime.EncodeMessage(resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return runtime.NewToolResultJSON(structured), nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,5 +24,9 @@ plugins:
|
|||||||
opt:
|
opt:
|
||||||
- merge_file_name=econet-exporter
|
- merge_file_name=econet-exporter
|
||||||
- allow_merge=true
|
- allow_merge=true
|
||||||
|
- local: ["go", "run", "github.com/redpanda-data/protoc-gen-go-mcp/cmd/protoc-gen-go-mcp@latest"]
|
||||||
|
out: api
|
||||||
|
opt:
|
||||||
|
- paths=source_relative
|
||||||
inputs:
|
inputs:
|
||||||
- directory: proto
|
- directory: proto
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
version: v2
|
version: v2
|
||||||
deps:
|
deps:
|
||||||
- name: buf.build/bufbuild/protovalidate
|
- name: buf.build/bufbuild/protovalidate
|
||||||
commit: 50325440f8f24053b047484a6bf60b76
|
commit: 435963d1631043e694e56e6bcc3c79c3
|
||||||
digest: b5:74cb6f5c0853c3c10aafc701614194bbd63326bdb8ef4068214454b8894b03ba4113e04b3a33a8321cdf05336e37db4dc14a5e2495db8462566914f36086ba31
|
digest: b5:f4ea07ad2dd94bd7243562f9908b9fb104feef8076040c89d9f7c1dedc074de4d4ce2b997686ef4400f3eccb765a7cfc20ed4acdd70b9a3699351245c61dba97
|
||||||
- name: buf.build/googleapis/googleapis
|
- name: buf.build/googleapis/googleapis
|
||||||
commit: c17df5b2beca46928cc87d5656bd5343
|
commit: c17df5b2beca46928cc87d5656bd5343
|
||||||
digest: b5:648a01e0170d4512dea7d564016165decd1ed6e34bef79fe54753e51ad7e27545709ad9157d7551270147d551155c595a2fb0bf5bb33b1c83040ddbce915c604
|
digest: b5:648a01e0170d4512dea7d564016165decd1ed6e34bef79fe54753e51ad7e27545709ad9157d7551270147d551155c595a2fb0bf5bb33b1c83040ddbce915c604
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
module gitea.libretechconsulting.com/rmcguire/econet-exporter
|
module gitea.libretechconsulting.com/rmcguire/econet-exporter
|
||||||
|
|
||||||
go 1.26
|
go 1.26.1
|
||||||
|
|
||||||
require (
|
require (
|
||||||
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260415201107-50325440f8f2.1
|
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260415201107-50325440f8f2.1
|
||||||
|
connectrpc.com/connect v1.20.0
|
||||||
gitea.libretechconsulting.com/rmcguire/go-app v0.17.1
|
gitea.libretechconsulting.com/rmcguire/go-app v0.17.1
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0
|
||||||
github.com/modelcontextprotocol/go-sdk v1.6.1
|
github.com/modelcontextprotocol/go-sdk v1.6.1
|
||||||
|
github.com/redpanda-data/protoc-gen-go-mcp v0.0.0-20260709214304-372b2d56e470
|
||||||
github.com/rs/zerolog v1.35.1
|
github.com/rs/zerolog v1.35.1
|
||||||
go.opentelemetry.io/otel/metric v1.44.0
|
go.opentelemetry.io/otel/metric v1.44.0
|
||||||
go.opentelemetry.io/otel/trace v1.44.0
|
go.opentelemetry.io/otel/trace v1.44.0
|
||||||
@@ -36,6 +38,7 @@ require (
|
|||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
buf.build/gen/go/redpandadata/common/protocolbuffers/go v1.34.2-20240917150400-3f349e63f44a.2 // indirect
|
||||||
buf.build/go/protovalidate v1.2.0 // indirect
|
buf.build/go/protovalidate v1.2.0 // indirect
|
||||||
cel.dev/expr v0.25.2 // indirect
|
cel.dev/expr v0.25.2 // indirect
|
||||||
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
|
github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
|
||||||
@@ -55,6 +58,7 @@ require (
|
|||||||
github.com/prometheus/common v0.69.0 // indirect
|
github.com/prometheus/common v0.69.0 // indirect
|
||||||
github.com/prometheus/otlptranslator v1.0.0 // indirect
|
github.com/prometheus/otlptranslator v1.0.0 // indirect
|
||||||
github.com/prometheus/procfs v0.21.1 // indirect
|
github.com/prometheus/procfs v0.21.1 // indirect
|
||||||
|
github.com/redpanda-data/common-go/api v0.0.0-20250801174835-9eea07f1ea06 // indirect
|
||||||
github.com/rs/cors v1.11.1 // indirect
|
github.com/rs/cors v1.11.1 // indirect
|
||||||
github.com/segmentio/asm v1.2.1 // indirect
|
github.com/segmentio/asm v1.2.1 // indirect
|
||||||
github.com/segmentio/encoding v0.5.4 // indirect
|
github.com/segmentio/encoding v0.5.4 // indirect
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260415201107-50325440f8f2.1 h1:s6hzCXtND/ICdGPTMGk7C+/BFlr2Jg5GyH0NKf4XGXg=
|
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260415201107-50325440f8f2.1 h1:s6hzCXtND/ICdGPTMGk7C+/BFlr2Jg5GyH0NKf4XGXg=
|
||||||
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260415201107-50325440f8f2.1/go.mod h1:tvtbpgaVXZX4g6Pn+AnzFycuRK3MOz5HJfEGeEllXYM=
|
buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260415201107-50325440f8f2.1/go.mod h1:tvtbpgaVXZX4g6Pn+AnzFycuRK3MOz5HJfEGeEllXYM=
|
||||||
|
buf.build/gen/go/redpandadata/common/protocolbuffers/go v1.34.2-20240917150400-3f349e63f44a.2 h1:JyGBchZNUPlQ7/qjieeKq/Cy+/i1vc0H+cIniGZNSFg=
|
||||||
|
buf.build/gen/go/redpandadata/common/protocolbuffers/go v1.34.2-20240917150400-3f349e63f44a.2/go.mod h1:wThyg02xJx4K/DA5fg0QlKts8XVPyTT86JC8hPfEzno=
|
||||||
buf.build/go/protovalidate v1.2.0 h1:DQVrUWkmGTBij+kOYv/x2LLxwcLaGKMdzShj1/6/3H0=
|
buf.build/go/protovalidate v1.2.0 h1:DQVrUWkmGTBij+kOYv/x2LLxwcLaGKMdzShj1/6/3H0=
|
||||||
buf.build/go/protovalidate v1.2.0/go.mod h1:7rYiQEhqvAipoazpVNBBH2S2f8bjG4huMVy1V2Yofn4=
|
buf.build/go/protovalidate v1.2.0/go.mod h1:7rYiQEhqvAipoazpVNBBH2S2f8bjG4huMVy1V2Yofn4=
|
||||||
cel.dev/expr v0.25.2 h1:K6j46C81hXtZQfuX60cVWQFBJahKSE2gfRbNuvr5bFs=
|
cel.dev/expr v0.25.2 h1:K6j46C81hXtZQfuX60cVWQFBJahKSE2gfRbNuvr5bFs=
|
||||||
cel.dev/expr v0.25.2/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4=
|
cel.dev/expr v0.25.2/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4=
|
||||||
|
connectrpc.com/connect v1.20.0 h1:6TNDAB+WeNd2uolWNlYczB5E0KNNaVMNUEx8JEUsPmQ=
|
||||||
|
connectrpc.com/connect v1.20.0/go.mod h1:A2ygJrukXwWy32vkCAAHNVguZrqZ+jeZ9rGRnGR4dN4=
|
||||||
gitea.libretechconsulting.com/rmcguire/go-app v0.17.1 h1:OdUNAXRoDpB5sC3KdaJC7Rav8MmxiRZC0fRx9YNH1Ks=
|
gitea.libretechconsulting.com/rmcguire/go-app v0.17.1 h1:OdUNAXRoDpB5sC3KdaJC7Rav8MmxiRZC0fRx9YNH1Ks=
|
||||||
gitea.libretechconsulting.com/rmcguire/go-app v0.17.1/go.mod h1:YBygVa9JBYAP+ibF8FevN1KUe3h5GHWxAdFyU6I8QgA=
|
gitea.libretechconsulting.com/rmcguire/go-app v0.17.1/go.mod h1:YBygVa9JBYAP+ibF8FevN1KUe3h5GHWxAdFyU6I8QgA=
|
||||||
github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ=
|
github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ=
|
||||||
@@ -65,6 +69,8 @@ github.com/modelcontextprotocol/go-sdk v1.6.1 h1:0zOSupjKUxPKSocPT1Wtago+mUHU2/u
|
|||||||
github.com/modelcontextprotocol/go-sdk v1.6.1/go.mod h1:kzm3kzFL1/+AziGOE0nUs3gvPoNxMCvkxokMkuFapXQ=
|
github.com/modelcontextprotocol/go-sdk v1.6.1/go.mod h1:kzm3kzFL1/+AziGOE0nUs3gvPoNxMCvkxokMkuFapXQ=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
|
github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y=
|
||||||
|
github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
|
github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o=
|
||||||
@@ -77,6 +83,10 @@ github.com/prometheus/otlptranslator v1.0.0 h1:s0LJW/iN9dkIH+EnhiD3BlkkP5QVIUVEo
|
|||||||
github.com/prometheus/otlptranslator v1.0.0/go.mod h1:vRYWnXvI6aWGpsdY/mOT/cbeVRBlPWtBNDb7kGR3uKM=
|
github.com/prometheus/otlptranslator v1.0.0/go.mod h1:vRYWnXvI6aWGpsdY/mOT/cbeVRBlPWtBNDb7kGR3uKM=
|
||||||
github.com/prometheus/procfs v0.21.1 h1:GljZCt+zSTS+NZq88cyQ1LjZ+RCHp3uVuabBWA5+OJI=
|
github.com/prometheus/procfs v0.21.1 h1:GljZCt+zSTS+NZq88cyQ1LjZ+RCHp3uVuabBWA5+OJI=
|
||||||
github.com/prometheus/procfs v0.21.1/go.mod h1:aB55Cww9pdSJVHk0hUf0inxWyyjPogFIjmHKYgMKmtY=
|
github.com/prometheus/procfs v0.21.1/go.mod h1:aB55Cww9pdSJVHk0hUf0inxWyyjPogFIjmHKYgMKmtY=
|
||||||
|
github.com/redpanda-data/common-go/api v0.0.0-20250801174835-9eea07f1ea06 h1:9Ecc+Cg1EyqSTIQ6wQKoKk8BqDlBQmR74bJui4qIqsM=
|
||||||
|
github.com/redpanda-data/common-go/api v0.0.0-20250801174835-9eea07f1ea06/go.mod h1:klAmWfc8Q3hEZk8geFTMu6f2sk3VUKRS7cv/LvB05ig=
|
||||||
|
github.com/redpanda-data/protoc-gen-go-mcp v0.0.0-20260709214304-372b2d56e470 h1:gBvQBXc+MtBa8aGjXTOFLPu+1a+7I0UMu6Np9ofY1Ow=
|
||||||
|
github.com/redpanda-data/protoc-gen-go-mcp v0.0.0-20260709214304-372b2d56e470/go.mod h1:1Ulz0OS7NpChjyMu6NWZucui6SEbIsOzAshGfpqWCV8=
|
||||||
github.com/rodaine/protogofakeit v0.1.1 h1:ZKouljuRM3A+TArppfBqnH8tGZHOwM/pjvtXe9DaXH8=
|
github.com/rodaine/protogofakeit v0.1.1 h1:ZKouljuRM3A+TArppfBqnH8tGZHOwM/pjvtXe9DaXH8=
|
||||||
github.com/rodaine/protogofakeit v0.1.1/go.mod h1:pXn/AstBYMaSfc1/RqH3N82pBuxtWgejz1AlYpY1mI0=
|
github.com/rodaine/protogofakeit v0.1.1/go.mod h1:pXn/AstBYMaSfc1/RqH3N82pBuxtWgejz1AlYpY1mI0=
|
||||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||||
|
|||||||
@@ -16,7 +16,11 @@ import (
|
|||||||
"gitea.libretechconsulting.com/rmcguire/econet-exporter/pkg/config"
|
"gitea.libretechconsulting.com/rmcguire/econet-exporter/pkg/config"
|
||||||
"gitea.libretechconsulting.com/rmcguire/econet-exporter/pkg/econet/econetclient"
|
"gitea.libretechconsulting.com/rmcguire/econet-exporter/pkg/econet/econetclient"
|
||||||
"gitea.libretechconsulting.com/rmcguire/econet-exporter/pkg/econet/econetgrpc"
|
"gitea.libretechconsulting.com/rmcguire/econet-exporter/pkg/econet/econetgrpc"
|
||||||
"gitea.libretechconsulting.com/rmcguire/econet-exporter/pkg/econet/econetmcp"
|
// MCP server. Aliased so switching implementations is a one-line change.
|
||||||
|
// Generated (protoc-gen-go-mcp) tools:
|
||||||
|
econetmcp "gitea.libretechconsulting.com/rmcguire/econet-exporter/pkg/econet/econetmcpgen"
|
||||||
|
// Hand-written tools (switch back by using this import instead):
|
||||||
|
// econetmcp "gitea.libretechconsulting.com/rmcguire/econet-exporter/pkg/econet/econetmcp"
|
||||||
"gitea.libretechconsulting.com/rmcguire/econet-exporter/pkg/econet/econetmetrics"
|
"gitea.libretechconsulting.com/rmcguire/econet-exporter/pkg/econet/econetmetrics"
|
||||||
"gitea.libretechconsulting.com/rmcguire/econet-exporter/pkg/service"
|
"gitea.libretechconsulting.com/rmcguire/econet-exporter/pkg/service"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
Package econetmcpgen exposes an MCP server, mounted as an HTTP handler at
|
||||||
|
/api/mcp, whose tools are generated from the EconetService proto by
|
||||||
|
protoc-gen-go-mcp and forwarded to the in-process gRPC server.
|
||||||
|
|
||||||
|
It is the generated-code counterpart to econetmcp (which hand-writes a single
|
||||||
|
list_water_heaters tool). Both expose an identical package API, so switching
|
||||||
|
between them is a one-line import change in pkg/econet/econet.go.
|
||||||
|
*/
|
||||||
|
package econetmcpgen
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"gitea.libretechconsulting.com/rmcguire/go-app/pkg/srv/http/opts"
|
||||||
|
"github.com/modelcontextprotocol/go-sdk/mcp"
|
||||||
|
"github.com/redpanda-data/protoc-gen-go-mcp/pkg/runtime/gosdk"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
|
||||||
|
v1alpha1mcp "gitea.libretechconsulting.com/rmcguire/econet-exporter/api/econet/v1alpha1/v1alpha1mcp"
|
||||||
|
"gitea.libretechconsulting.com/rmcguire/econet-exporter/pkg/config"
|
||||||
|
"gitea.libretechconsulting.com/rmcguire/econet-exporter/pkg/econet/econetgrpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
var EconetMCPImpl = &mcp.Implementation{
|
||||||
|
Name: "Econet MCP Server",
|
||||||
|
Title: "Econet Exporter MCP",
|
||||||
|
}
|
||||||
|
|
||||||
|
type EconetMCPServer struct {
|
||||||
|
ctx context.Context
|
||||||
|
cfg *config.ServiceConfig
|
||||||
|
log *zerolog.Logger
|
||||||
|
server *mcp.Server
|
||||||
|
econetGRPC *econetgrpc.EconetGRPCServer
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEconetMCPServer(ctx context.Context, cfg *config.ServiceConfig,
|
||||||
|
grpc *econetgrpc.EconetGRPCServer,
|
||||||
|
) *EconetMCPServer {
|
||||||
|
return &EconetMCPServer{
|
||||||
|
ctx: ctx,
|
||||||
|
cfg: cfg,
|
||||||
|
log: zerolog.Ctx(ctx),
|
||||||
|
econetGRPC: grpc,
|
||||||
|
server: mcp.NewServer(EconetMCPImpl, &mcp.ServerOptions{
|
||||||
|
Instructions: "Use these tools to inspect Rheem EcoNet water heaters: " +
|
||||||
|
"current mode, setpoint, hot water availability, connectivity, and alerts.",
|
||||||
|
HasTools: true,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *EconetMCPServer) GetHandlers() []opts.HTTPHandler {
|
||||||
|
// Register the generated tools against the in-process gRPC server via the
|
||||||
|
// go-sdk adapter, so the generated code shares our configured *mcp.Server.
|
||||||
|
v1alpha1mcp.RegisterEconetServiceHandler(gosdk.Wrap(m.server), m.econetGRPC)
|
||||||
|
|
||||||
|
handler := mcp.NewStreamableHTTPHandler(func(*http.Request) *mcp.Server {
|
||||||
|
return m.server
|
||||||
|
}, &mcp.StreamableHTTPOptions{})
|
||||||
|
|
||||||
|
m.log.Debug().Msg("Econet MCP tools ready (generated)")
|
||||||
|
|
||||||
|
return []opts.HTTPHandler{
|
||||||
|
{
|
||||||
|
Prefix: "/api/mcp",
|
||||||
|
Handler: handler,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user