all the refactor
This commit is contained in:
@@ -1,11 +1,13 @@
|
||||
package mcp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"git.k6n.net/mats/go-cart-actor/pkg/promotions"
|
||||
pmcp "git.k6n.net/mats/platform/mcp"
|
||||
)
|
||||
|
||||
// NewPublic builds an MCP server exposing only the read-only promotion tools:
|
||||
@@ -17,23 +19,23 @@ func NewPublic(store *promotions.Store, eval *promotions.PromotionService) *Serv
|
||||
eval = promotions.NewPromotionService(nil)
|
||||
}
|
||||
s := &Server{store: store, eval: eval}
|
||||
s.tools = s.buildPublicTools()
|
||||
s.mcp = pmcp.NewServer(pmcp.Info{Name: serverName, Version: serverVersion}, s.buildPublicTools()...)
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *Server) buildPublicTools() []tool {
|
||||
return []tool{
|
||||
func (s *Server) buildPublicTools() []pmcp.Tool {
|
||||
return []pmcp.Tool{
|
||||
{
|
||||
Name: "list_promotions",
|
||||
Description: "List all promotion rules the cart engine evaluates, optionally filtered by status (active|inactive|scheduled|expired).",
|
||||
InputSchema: object(props{
|
||||
"status": str("optional status filter: active|inactive|scheduled|expired"),
|
||||
InputSchema: pmcp.Object(pmcp.Props{
|
||||
"status": pmcp.String("optional status filter: active|inactive|scheduled|expired"),
|
||||
}, nil),
|
||||
invoke: func(args json.RawMessage) (any, error) {
|
||||
Invoke: func(_ context.Context, args json.RawMessage) (any, error) {
|
||||
var a struct {
|
||||
Status string `json:"status"`
|
||||
}
|
||||
if err := decode(args, &a); err != nil {
|
||||
if err := pmcp.Decode(args, &a); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rules := s.store.List()
|
||||
@@ -52,12 +54,12 @@ func (s *Server) buildPublicTools() []tool {
|
||||
{
|
||||
Name: "get_promotion",
|
||||
Description: "Fetch a single promotion rule by id.",
|
||||
InputSchema: object(props{"id": str("the promotion id")}, []string{"id"}),
|
||||
invoke: func(args json.RawMessage) (any, error) {
|
||||
InputSchema: pmcp.Object(pmcp.Props{"id": pmcp.String("the promotion id")}, []string{"id"}),
|
||||
Invoke: func(_ context.Context, args json.RawMessage) (any, error) {
|
||||
var a struct {
|
||||
ID string `json:"id"`
|
||||
}
|
||||
if err := decode(args, &a); err != nil {
|
||||
if err := pmcp.Decode(args, &a); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r, ok := s.store.Get(a.ID)
|
||||
@@ -72,18 +74,18 @@ func (s *Server) buildPublicTools() []tool {
|
||||
Description: "Evaluate the current active promotions against a hypothetical cart total and report the " +
|
||||
"matched discount. cartTotalIncVat is in öre incl. VAT (e.g. 5 000 000 = 50 000 kr). Useful for " +
|
||||
"verifying Volymrabatt tiers without touching a real cart.",
|
||||
InputSchema: object(props{
|
||||
"cartTotalIncVat": integer("cart total incl. VAT, in öre"),
|
||||
"itemQuantity": integer("optional total item quantity"),
|
||||
"customerSegment": str("optional customer segment"),
|
||||
InputSchema: pmcp.Object(pmcp.Props{
|
||||
"cartTotalIncVat": pmcp.Integer("cart total incl. VAT, in öre"),
|
||||
"itemQuantity": pmcp.Integer("optional total item quantity"),
|
||||
"customerSegment": pmcp.String("optional customer segment"),
|
||||
}, []string{"cartTotalIncVat"}),
|
||||
invoke: func(args json.RawMessage) (any, error) {
|
||||
Invoke: func(_ context.Context, args json.RawMessage) (any, error) {
|
||||
var a struct {
|
||||
CartTotalIncVat int64 `json:"cartTotalIncVat"`
|
||||
ItemQuantity int `json:"itemQuantity"`
|
||||
CustomerSegment string `json:"customerSegment"`
|
||||
}
|
||||
if err := decode(args, &a); err != nil {
|
||||
if err := pmcp.Decode(args, &a); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
g := syntheticCart(a.CartTotalIncVat, a.ItemQuantity, s.defaultVatRate())
|
||||
@@ -109,20 +111,20 @@ func (s *Server) buildPublicTools() []tool {
|
||||
"which promotions match, what discount they apply, and any pending next-tier nudges (\"spend X more for Y%\"). " +
|
||||
"When promotionId is set, only that specific promotion is evaluated (useful for testing a new rule). " +
|
||||
"When omitted, all active promotions are evaluated. cartTotalIncVat is in öre incl. VAT.",
|
||||
InputSchema: object(props{
|
||||
"cartTotalIncVat": integer("cart total incl. VAT, in öre"),
|
||||
"promotionId": str("optional: evaluate only this promotion (by id)"),
|
||||
"itemQuantity": integer("optional total item quantity"),
|
||||
"customerSegment": str("optional customer segment"),
|
||||
InputSchema: pmcp.Object(pmcp.Props{
|
||||
"cartTotalIncVat": pmcp.Integer("cart total incl. VAT, in öre"),
|
||||
"promotionId": pmcp.String("optional: evaluate only this promotion (by id)"),
|
||||
"itemQuantity": pmcp.Integer("optional total item quantity"),
|
||||
"customerSegment": pmcp.String("optional customer segment"),
|
||||
}, []string{"cartTotalIncVat"}),
|
||||
invoke: func(args json.RawMessage) (any, error) {
|
||||
Invoke: func(_ context.Context, args json.RawMessage) (any, error) {
|
||||
var a struct {
|
||||
CartTotalIncVat int64 `json:"cartTotalIncVat"`
|
||||
PromotionId string `json:"promotionId"`
|
||||
ItemQuantity int `json:"itemQuantity"`
|
||||
CustomerSegment string `json:"customerSegment"`
|
||||
}
|
||||
if err := decode(args, &a); err != nil {
|
||||
if err := pmcp.Decode(args, &a); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -151,10 +153,10 @@ func (s *Server) buildPublicTools() []tool {
|
||||
evalResults := make([]map[string]any, 0, len(results))
|
||||
for _, r := range results {
|
||||
evalResults = append(evalResults, map[string]any{
|
||||
"ruleId": r.Rule.ID,
|
||||
"name": r.Rule.Name,
|
||||
"applicable": r.Applicable,
|
||||
"failedReason": r.FailedReason,
|
||||
"ruleId": r.Rule.ID,
|
||||
"name": r.Rule.Name,
|
||||
"applicable": r.Applicable,
|
||||
"failedReason": r.FailedReason,
|
||||
"matchedActions": r.MatchedActions,
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user