tools

package
v0.0.0-...-6ded401 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 28, 2026 License: OSL-3.0 Imports: 17 Imported by: 0

Documentation

Overview

Package tools implements the individual MCP tool handlers exposed by the CUDly MCP server (mcp/server.go), plus the shared validation and purchase harness they all build on.

Index

Constants

View Source
const EnvEnableRealPurchases = "CUDLY_MCP_ENABLE_REAL_PURCHASES"

EnvEnableRealPurchases is the operator-side authorization control gating every real (non-preview) purchase this server executes. The model-supplied confirm flag (decidePurchaseMode) only proves the model asked to spend money; it says nothing about whether the operator running this MCP server process wants it able to. mcp/README.md previously documented confirm as "a guardrail against an accidental call, not an authorization control", which left a prompt-injected or simply hallucinating model, given ambient production credentials, able to execute a real purchase from a single tool call. This env var closes that gap: it must be explicitly set before ExecutePurchase will call into a provider for a real purchase, regardless of confirm. See realPurchasesEnabled for the fail-closed matching rule.

Variables

This section is empty.

Functions

func BuildInputSchema

func BuildInputSchema[T any](overrides map[string]FieldOverride) (*jsonschema.Schema, error)

BuildInputSchema infers the JSON Schema for T via jsonschema.For, then applies the given per-field overrides by JSON field name. It returns an error -- rather than silently skipping -- when an override names a field that does not exist on T, so a typo in the override map is caught at server-startup / test time instead of quietly shipping an unconstrained schema for a money-affecting field.

func CredentialScope

func CredentialScope(explicit string, envVars ...string) string

CredentialScope resolves the account/subscription/project identifier that bounds where a purchase lands: the caller-supplied override when present, otherwise the first non-empty value among the ambient environment variables the matching provider factory itself consults (e.g. AZURE_SUBSCRIPTION_ID, providers/azure/provider.go's resolveDefaultSubscription).

It returns "" when neither is set, which is correct rather than an error: a provider that resolves its account purely from ambient credentials (single visible Azure subscription, AWS STS identity, ambient GCP project) is unambiguous for the life of the server process, so there is no second scope for a token to collide with.

Normalization here is limited to trimming, because it is the only rule that is safe for all three providers. Case is deliberately NOT folded: AWS named profiles are case-sensitive section names in ~/.aws/config, so lower-casing one could name a profile that does not exist or a different one that does. Azure subscription IDs ARE case-insensitive and do need folding -- see azureCredentialScope in azure_compute_ri.go, which wraps this.

func ResolveDryRunConfirm

func ResolveDryRunConfirm(dryRun, confirm *bool) (effectiveDryRun, effectiveConfirm bool)

ResolveDryRunConfirm applies the dry_run=true / confirm=false defaults to a tool's optional flags. Go's zero value for bool cannot distinguish "caller omitted the field" from "caller explicitly set it false", which is why both arrive as *bool; this is the single place that resolves them to concrete booleans.

Shared by every purchase tool rather than reimplemented per tool. This is the gate that decides whether real money moves, so seven hand-copied versions of it were seven chances for one to drift: a copy that defaulted dryRun to false would turn an unconfirmed preview into a live purchase, and nothing but review would catch it.

func ValidatePlatform

func ValidatePlatform(s string) (ec2types.RIProductDescription, error)

ValidatePlatform returns the AWS SDK's own ec2types.RIProductDescription enum member for s, or an explicit error when s does not match one of the four values that DescribeReservedInstancesOfferings accepts as ProductDescription (providers/aws/services/ec2/client.go:419). Reusing the SDK's own enum constants -- rather than inventing a "linux"/"windows" vocabulary -- means an outbound offering lookup can never carry a bare string literal that drifts from what the SDK actually recognizes (feedback_sdk_enum_string_literals).

Types

type AZConfig

type AZConfig string

AZConfig is the RDS deployment topology (single-AZ vs multi-AZ), which carries a different price and offering catalog per providers/aws/services/rds/client.go:314-322.

const (
	AZConfigSingleAZ AZConfig = "single-az"
	AZConfigMultiAZ  AZConfig = "multi-az"
)

func ValidateAZConfig

func ValidateAZConfig(s string) (AZConfig, error)

ValidateAZConfig returns the typed AZConfig for s, or an explicit error when s is not single-az or multi-az. RDS's own client refuses to guess this value (see the comment at providers/aws/services/rds/client.go:306-322), so the MCP boundary must not default it either.

type ActionEntry

type ActionEntry struct {
	Name                string   `json:"name"`
	Provider            string   `json:"provider,omitempty"`
	Product             string   `json:"product,omitempty"`
	Action              string   `json:"action,omitempty"`
	Description         string   `json:"description"`
	RealPurchaseEnabled bool     `json:"real_purchase_enabled"`
	ExamplePrompts      []string `json:"example_prompts,omitempty"`
}

ActionEntry is one catalog entry returned by cudly_list_commitment_actions, reshaping a Descriptor for JSON output.

type ArcheraOffer

type ArcheraOffer struct {
	// Pitch is what the coverage does and why it is relevant right now.
	Pitch string `json:"pitch"`
	// SignupURL is the Archera signup link carrying CUDly attribution.
	SignupURL string `json:"signup_url"`
	// EnrollmentWindowDays is how long from THIS purchase the buyer has to
	// enroll it. Surfaced as a number so a client can compute the deadline
	// from effective_date rather than parsing it out of prose.
	EnrollmentWindowDays int `json:"enrollment_window_days"`
	// NonGatingDisclosure states the offer is optional and CUDly works
	// without it.
	NonGatingDisclosure string `json:"non_gating_disclosure"`
	// SponsorshipDisclosure states the financial relationship behind the
	// recommendation.
	SponsorshipDisclosure string `json:"sponsorship_disclosure"`
}

ArcheraOffer is the post-purchase Archera underutilization-insurance offer.

Both disclosure fields are non-optional parts of the payload, not decoration: CUDly commits to surfacing the sponsorship AND the fact that it works fully without Archera everywhere the signup link appears (the CLI's printArcheraPitch does the same after a real purchase). An MCP client renders this JSON through a model, so shipping the link without the disclosures alongside it would let the model present a sponsored recommendation as a neutral one.

type CacheEngine

type CacheEngine string

CacheEngine is the ElastiCache engine dimension (common.CacheDetails.Engine).

const (
	CacheEngineRedis     CacheEngine = "redis"
	CacheEngineMemcached CacheEngine = "memcached"
)

func ValidateCacheEngine

func ValidateCacheEngine(s string) (CacheEngine, error)

ValidateCacheEngine returns the typed CacheEngine for s, or an explicit error when s is neither redis nor memcached.

type Descriptor

type Descriptor struct {
	// Name is the MCP tool name, e.g. "cudly_aws_ec2_ri_purchase".
	Name string
	// Provider is "aws", "azure", "gcp", or "" for provider-agnostic
	// meta-tools (cudly_list_commitment_actions, cudly_search_recommendations).
	Provider string
	// Product is the service the tool acts on, e.g. "ec2", "rds", "compute".
	Product string
	// Action is what the tool does, e.g. "ri_purchase", "cud_purchase", "search".
	Action string
	// Description is the tool's full MCP description, shared verbatim with
	// the live mcp.Tool registration so the two can never disagree.
	Description string
	// RealPurchaseEnabled reports whether this tool can execute a real,
	// money-spending purchase today (dry_run=false, confirm=true). false for
	// read-only tools and for tools shipped dry-run-only pending a
	// prerequisite fix (see the Azure/GCP tool comments).
	RealPurchaseEnabled bool
	// ExamplePrompts are 2-3 natural-language prompts that would plausibly
	// invoke this tool, surfaced by cudly_list_commitment_actions so a
	// session that doesn't know the tool name yet can find it.
	ExamplePrompts []string
}

Descriptor is the source-of-truth metadata for one MCP tool. Every tool file builds one and both mcp/server.go (to know what to register) and cudly_list_commitment_actions (to know what to advertise) read it, so the live tool set and the discoverability catalog can never drift apart -- there is exactly one place each tool's name/description/example prompts are written.

func ListCommitmentActionsDescriptor

func ListCommitmentActionsDescriptor() Descriptor

ListCommitmentActionsDescriptor returns the static Descriptor for cudly_list_commitment_actions itself. It is exported so mcp/server.go can include this tool in its own catalog: the descriptors slice passed to NewListCommitmentActions must be assembled (and thus known) before the tool exists, so its own entry can't come from calling Descriptor() on an already-constructed instance the way every other tool's entry does.

type FieldOverride

type FieldOverride struct {
	// Enum, when non-empty, restricts the property to these exact values.
	Enum []any
	// Default, when non-nil, is recorded on the schema as the property's
	// documented default so a caller inspecting the tool (or an MCP client
	// that surfaces schema defaults in its UI) can see it without reading
	// the tool description prose. It does NOT, by itself, cause the value to
	// be applied when the caller omits the field -- each tool's handler
	// applies its own default explicitly (see the dry_run/confirm pattern in
	// purchase.go) so "omitted" is never silently confused with "false".
	Default any
}

FieldOverride declares JSON Schema refinements -- an explicit enum membership and/or a documented default -- for one property of an otherwise auto-inferred schema. Centralizing this in one helper (BuildInputSchema) means every tool declares its enum/default once, next to its Go struct, instead of re-implementing schema post-processing per tool.

type LookbackPeriod

type LookbackPeriod string

LookbackPeriod is the cost/usage lookback window backing a cudly_search_recommendations call. Values match the enum search_recommendations.go's Register advertises in the tool's JSON schema (BuildInputSchema's "lookback_period" FieldOverride); re-validated here so a caller invoking the tool directly -- bypassing MCP schema enforcement -- cannot pass an unsupported window through to the provider.

const (
	LookbackPeriod7Days  LookbackPeriod = "7d"
	LookbackPeriod30Days LookbackPeriod = "30d"
	LookbackPeriod60Days LookbackPeriod = "60d"
)

func ValidateLookbackPeriod

func ValidateLookbackPeriod(s string) (LookbackPeriod, error)

ValidateLookbackPeriod returns the typed LookbackPeriod for s, or an explicit error when s is non-empty and not one of the three supported windows. An empty s is valid: lookback_period is optional (json:"...,omitempty"), meaning "let the provider apply its own default".

type PaymentOption

type PaymentOption string

PaymentOption is the AWS/Azure/GCP-agnostic reserved-capacity payment schedule. It is validated at the MCP tool boundary before being copied onto common.Recommendation.PaymentOption (which stays a bare string there for backward compatibility with existing CSV/DB rows -- see pkg/common/types.go) so a caller can never smuggle an unrecognized payment term into a purchase.

const (
	PaymentOptionAllUpfront     PaymentOption = "all-upfront"
	PaymentOptionPartialUpfront PaymentOption = "partial-upfront"
	PaymentOptionNoUpfront      PaymentOption = "no-upfront"
)

func ValidatePaymentOption

func ValidatePaymentOption(s string) (PaymentOption, error)

ValidatePaymentOption returns the typed PaymentOption for s, or an explicit error when s is not one of the three allowed values. There is no default: an empty or unknown payment option is always an error, never silently coerced to a fallback term (feedback_no_silent_fallbacks).

type PurchaseRequest

type PurchaseRequest struct {
	Region         string
	Recommendation common.Recommendation
	DryRun         bool
	Confirm        bool
	ResolveClient  ResolveClientFunc

	// Nonce is optional. When non-empty, this call is treated as a
	// DISTINCT purchase from an otherwise-identical one (authorizes a
	// deliberate repeat, e.g. "buy 3 more RIs" on top of an earlier "buy 3
	// RIs" with the same parameters). When empty (the default), identical
	// purchases dedupe so retries never double-buy. See idempotencyKeyFor.
	Nonce string

	// CredentialScope identifies WHERE the purchase lands: the AWS profile,
	// Azure subscription, or GCP project the call is billed to. It is folded
	// into the idempotency key so two purchases that are identical in every
	// product dimension but target different accounts derive DIFFERENT
	// tokens. Populated by each tool via CredentialScope(). See
	// idempotencyKeyFor for why omitting it is a double-spend/skipped-spend
	// hazard on Azure specifically.
	CredentialScope string
}

PurchaseRequest is the provider-agnostic input to ExecutePurchase. Each per-service tool handler builds one after validating its own typed parameters and constructing the common.Recommendation.

type PurchaseResponse

type PurchaseResponse struct {
	Success           bool     `json:"success"`
	DryRun            bool     `json:"dry_run"`
	CommitmentID      string   `json:"commitment_id,omitempty"`
	Cost              *float64 `json:"cost,omitempty"`
	OnDemandCost      *float64 `json:"on_demand_cost,omitempty"`
	EstimatedSavings  *float64 `json:"estimated_savings,omitempty"`
	SavingsPercentage *float64 `json:"savings_percentage,omitempty"`
	EffectiveDate     *string  `json:"effective_date,omitempty"`
	TermYears         int      `json:"term_years,omitempty"`
	Error             string   `json:"error,omitempty"`

	// Archera is the optional underutilization-insurance offer, populated
	// ONLY after a real purchase actually succeeds. See archeraOffer.
	Archera *ArcheraOffer `json:"archera,omitempty"`
}

PurchaseResponse is the structured result returned to the MCP caller for both preview and real-purchase outcomes. Error is a string (not the Go error) because it crosses the MCP JSON-RPC boundary as tool output, not a protocol-level error -- ExecutePurchase itself still returns a Go error for gate refusals and provider-call failures.

Cost/OnDemandCost/EstimatedSavings/SavingsPercentage are pointers with omitempty: none of the *FromArgs constructors in this package populate Recommendation's cost fields (they build a fresh Recommendation from the caller's typed args, not from a priced search result), and some provider clients (e.g. AWS EC2 RIs, Savings Plans) never populate PurchaseResult.Cost either. A plain float64 could not distinguish "not known" from "genuinely $0", so every response reported 0 for money fields it never actually priced. A pointer that's nil (and omitted from the JSON payload entirely) when no real value exists lets a caller tell "unknown" apart from "confirmed zero" (feedback_nullable_not_zero).

EffectiveDate is a pointer for the same reason, and it is not a hypothetical concern: `omitempty` on a string only drops "", so a PurchaseResult whose Timestamp was never populated formatted its zero time.Time to the literal "0001-01-01T00:00:00Z" and shipped that as the commitment's start date. That is a fabricated date presented as real, on a field a caller may key billing or renewal reminders off. Nil (and omitted) when the provider reported no timestamp.

func ExecutePurchase

func ExecutePurchase(ctx context.Context, req PurchaseRequest) (*PurchaseResponse, error)

ExecutePurchase runs the shared dry_run/confirm safety gate, then every gate in authorizeRealPurchase (operator opt-in via EnvEnableRealPurchases, and a determinable target account), and for a real purchase that clears them all, resolves the service client and calls PurchaseCommitment with PurchaseSourceMCP and a derived idempotency token. It never calls ResolveClient in preview mode, so a preview makes zero provider/SDK calls; it also never calls ResolveClient when any authorizeRealPurchase gate refuses, so a disabled server -- or one that cannot tell which account a purchase would land in -- makes zero provider/SDK calls either.

type Registration

type Registration interface {
	Descriptor() Descriptor
	Register(s *mcp.Server) error
}

Registration is implemented by every tool file. Descriptor feeds the catalog; Register performs the live mcp.AddTool (or mcp.Server.AddTool) call that wires the tool's schema and handler onto the server.

func NewAWSEC2RIPurchaseTool

func NewAWSEC2RIPurchaseTool() Registration

NewAWSEC2RIPurchaseTool builds the cudly_aws_ec2_ri_purchase tool.

func NewAWSElastiCacheRIPurchaseTool

func NewAWSElastiCacheRIPurchaseTool() Registration

NewAWSElastiCacheRIPurchaseTool builds the cudly_aws_elasticache_ri_purchase tool.

func NewAWSMemoryDBRIPurchaseTool

func NewAWSMemoryDBRIPurchaseTool() Registration

NewAWSMemoryDBRIPurchaseTool builds cudly_aws_memorydb_ri_purchase.

func NewAWSOpenSearchRIPurchaseTool

func NewAWSOpenSearchRIPurchaseTool() Registration

NewAWSOpenSearchRIPurchaseTool builds cudly_aws_opensearch_ri_purchase.

func NewAWSRDSRIPurchaseTool

func NewAWSRDSRIPurchaseTool() Registration

NewAWSRDSRIPurchaseTool builds the cudly_aws_rds_ri_purchase tool.

func NewAWSRedshiftRIPurchaseTool

func NewAWSRedshiftRIPurchaseTool() Registration

NewAWSRedshiftRIPurchaseTool builds cudly_aws_redshift_ri_purchase.

func NewAWSSavingsPlansPurchaseTool

func NewAWSSavingsPlansPurchaseTool() Registration

NewAWSSavingsPlansPurchaseTool builds the cudly_aws_savingsplans_purchase tool.

func NewAzureComputeRIPurchaseTool

func NewAzureComputeRIPurchaseTool() Registration

NewAzureComputeRIPurchaseTool builds the cudly_azure_compute_ri_purchase tool.

func NewGCPComputeEngineCUDPurchaseTool

func NewGCPComputeEngineCUDPurchaseTool() Registration

NewGCPComputeEngineCUDPurchaseTool builds the cudly_gcp_computeengine_cud_purchase tool.

func NewListCommitmentActions

func NewListCommitmentActions(descriptors []Descriptor) Registration

NewListCommitmentActions builds the cudly_list_commitment_actions tool from descriptors -- the same slice of Descriptor values mcp/server.go collects from every other tool's Descriptor() method, so this catalog is generated from the live registry rather than hand-duplicated in code or docs.

func NewSearchRecommendationsTool

func NewSearchRecommendationsTool() Registration

NewSearchRecommendationsTool builds the cudly_search_recommendations tool.

type ResolveClientFunc

type ResolveClientFunc func(ctx context.Context) (provider.ServiceClient, error)

ResolveClientFunc lazily resolves the provider.ServiceClient that will receive the real PurchaseCommitment call. It is a func, not an already-resolved client, so ExecutePurchase can prove (and tests can assert) that a preview never triggers provider/credential resolution -- only modeExecute invokes it.

type SPType

type SPType string

SPType is the AWS Savings Plans product family (--include-sp-types in the CLI, cmd/main.go:112).

const (
	SPTypeCompute     SPType = "Compute"
	SPTypeEC2Instance SPType = "EC2Instance"
	SPTypeSageMaker   SPType = "SageMaker"
	SPTypeDatabase    SPType = "Database"
)

func ValidateSPType

func ValidateSPType(s string) (SPType, error)

ValidateSPType returns the typed SPType for s, or an explicit error when s is not one of the four AWS Savings Plans product families.

type Scope

type Scope string

Scope is the EC2 RI applicability dimension. Values are the lowercase, hyphenated form that providers/aws/services/ec2/client.go:330-339 (canonicalizeEC2Scope) recognizes and normalizes to the SDK's ec2types.Scope casing ("Region" / "Availability Zone").

const (
	ScopeRegion           Scope = "region"
	ScopeAvailabilityZone Scope = "availability-zone"
)

func ValidateScope

func ValidateScope(s string) (Scope, error)

ValidateScope returns the typed Scope for s, or an explicit error when s is neither region nor availability-zone.

type Tenancy

type Tenancy string

Tenancy is the EC2 RI tenancy dimension. Values match ec2types.Tenancy (providers/aws/services/ec2/client.go:309-318 canonicalizes them further, but "default"/"dedicated" already pass through unchanged).

const (
	TenancyDefault   Tenancy = Tenancy(ec2types.TenancyDefault)
	TenancyDedicated Tenancy = Tenancy(ec2types.TenancyDedicated)
)

func ValidateTenancy

func ValidateTenancy(s string) (Tenancy, error)

ValidateTenancy returns the typed Tenancy for s, or an explicit error when s is neither default nor dedicated.

type TermYears

type TermYears int

TermYears is the reserved-capacity commitment length, in years.

const (
	TermOneYear   TermYears = 1
	TermThreeYear TermYears = 3
)

func ValidateTermYears

func ValidateTermYears(n int) (TermYears, error)

ValidateTermYears returns the typed TermYears for n, or an explicit error when n is not 1 or 3 (the only terms AWS/Azure/GCP reserved-capacity products offer).

func (TermYears) RecommendationTerm

func (t TermYears) RecommendationTerm() string

RecommendationTerm renders t in the "1yr"/"3yr" vocabulary that common.Recommendation.Term and the provider clients expect.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL