|
|
@@ -0,0 +1,292 @@
|
|
|
+package mcp
|
|
|
+
|
|
|
+import (
|
|
|
+ "time"
|
|
|
+ models "github.com/opencost/opencost/pkg/cloud/models"
|
|
|
+ "github.com/opencost/opencost/pkg/cloudcost"
|
|
|
+ "github.com/opencost/opencost/pkg/costmodel"
|
|
|
+)
|
|
|
+
|
|
|
+// QueryType defines the type of query to be executed.
|
|
|
+type QueryType string
|
|
|
+
|
|
|
+const (
|
|
|
+ AllocationQueryType QueryType = "allocation"
|
|
|
+ AssetQueryType QueryType = "asset"
|
|
|
+ CloudCostQueryType QueryType = "cloudcost"
|
|
|
+)
|
|
|
+
|
|
|
+// MCPRequest represents a single turn in a conversation with the OpenCost MCP server.
|
|
|
+type MCPRequest struct {
|
|
|
+ SessionID string `json:"sessionId"`
|
|
|
+ Query *OpenCostQueryRequest `json:"query"`
|
|
|
+}
|
|
|
+
|
|
|
+// MCPResponse is the response from the OpenCost MCP server for a single turn.
|
|
|
+type MCPResponse struct {
|
|
|
+ Data interface{} `json:"data"`
|
|
|
+ QueryInfo QueryMetadata `json:"queryInfo"`
|
|
|
+ Summary *DataSummary `json:"summary,omitempty"`
|
|
|
+}
|
|
|
+
|
|
|
+// QueryMetadata contains metadata about the query execution.
|
|
|
+type QueryMetadata struct {
|
|
|
+ QueryID string `json:"queryId"`
|
|
|
+ Timestamp time.Time `json:"timestamp"`
|
|
|
+ ProcessingTime time.Duration `json:"processingTime"`
|
|
|
+}
|
|
|
+
|
|
|
+// DataSummary provides a summary of the data.
|
|
|
+type DataSummary struct {
|
|
|
+ Title string `json:"title"`
|
|
|
+ Content string `json:"content"`
|
|
|
+}
|
|
|
+
|
|
|
+// OpenCostQueryRequest provides a unified interface for all OpenCost query types.
|
|
|
+type OpenCostQueryRequest struct {
|
|
|
+ QueryType QueryType `json:"queryType" validate:"required,oneof=allocation asset cloudcost"`
|
|
|
+
|
|
|
+ Window string `json:"window" validate:"required"`
|
|
|
+
|
|
|
+ AllocationParams *AllocationQuery `json:"allocationParams,omitempty"`
|
|
|
+ AssetParams *AssetQuery `json:"assetParams,omitempty"`
|
|
|
+ CloudCostParams *CloudCostQuery `json:"cloudCostParams,omitempty"`
|
|
|
+}
|
|
|
+
|
|
|
+// AllocationQuery contains the parameters for an allocation query.
|
|
|
+type AllocationQuery struct {
|
|
|
+ Step time.Duration `json:"step,omitempty"`
|
|
|
+ Accumulate bool `json:"accumulate,omitempty"`
|
|
|
+ ShareIdle bool `json:"shareIdle,omitempty"`
|
|
|
+ Aggregate string `json:"aggregate,omitempty"`
|
|
|
+ IncludeIdle bool `json:"includeIdle,omitempty"`
|
|
|
+ IdleByNode bool `json:"idleByNode,omitempty"`
|
|
|
+ IncludeProportionalAssetResourceCosts bool `json:"includeProportionalAssetResourceCosts,omitempty"`
|
|
|
+ IncludeAggregatedMetadata bool `json:"includeAggregatedMetadata,omitempty"`
|
|
|
+ ShareLB bool `json:"sharelb,omitempty"`
|
|
|
+}
|
|
|
+
|
|
|
+// AssetQuery contains the parameters for an asset query.
|
|
|
+type AssetQuery struct {
|
|
|
+ // Currently no specific parameters needed for asset queries as it only takes window as parameter
|
|
|
+}
|
|
|
+
|
|
|
+// CloudCostQuery contains the parameters for a cloud cost query.
|
|
|
+type CloudCostQuery struct {
|
|
|
+ Aggregate string `json:"aggregate,omitempty"` // Comma-separated list of aggregation properties
|
|
|
+ Accumulate string `json:"accumulate,omitempty"` // e.g., "week", "day", "month"
|
|
|
+ Filter string `json:"filter,omitempty"` // Filter expression for cloud costs
|
|
|
+ Provider string `json:"provider,omitempty"` // Cloud provider filter (aws, gcp, azure, etc.)
|
|
|
+ Service string `json:"service,omitempty"` // Service filter (ec2, s3, compute, etc.)
|
|
|
+ Category string `json:"category,omitempty"` // Category filter (compute, storage, network, etc.)
|
|
|
+ Region string `json:"region,omitempty"` // Region filter
|
|
|
+ Account string `json:"account,omitempty"` // Account filter
|
|
|
+}
|
|
|
+
|
|
|
+// AllocationResponse represents the allocation data returned to the AI agent.
|
|
|
+type AllocationResponse struct {
|
|
|
+ // The allocation data, as a map of allocation sets.
|
|
|
+ Allocations map[string]*AllocationSet `json:"allocations"`
|
|
|
+}
|
|
|
+
|
|
|
+// AllocationSet represents a set of allocation data.
|
|
|
+type AllocationSet struct {
|
|
|
+ // The name of the allocation set.
|
|
|
+ Name string `json:"name"`
|
|
|
+ Properties map[string]string `json:"properties"`
|
|
|
+ Allocations []*Allocation `json:"allocations"`
|
|
|
+}
|
|
|
+
|
|
|
+// TotalCost calculates the total cost of all allocations in the set.
|
|
|
+func (as *AllocationSet) TotalCost() float64 {
|
|
|
+ var total float64
|
|
|
+ for _, alloc := range as.Allocations {
|
|
|
+ total += alloc.TotalCost
|
|
|
+ }
|
|
|
+ return total
|
|
|
+}
|
|
|
+
|
|
|
+// Allocation represents a single allocation data point.
|
|
|
+
|
|
|
+type Allocation struct {
|
|
|
+ Name string `json:"name"` // Allocation key (namespace, cluster, etc.)
|
|
|
+
|
|
|
+ CPUCost float64 `json:"cpuCost"` // Cost of CPU usage
|
|
|
+ GPUCost float64 `json:"gpuCost"` // Cost of GPU usage
|
|
|
+ RAMCost float64 `json:"ramCost"` // Cost of memory usage
|
|
|
+ PVCost float64 `json:"pvCost"` // Cost of persistent volumes
|
|
|
+ NetworkCost float64 `json:"networkCost"` // Cost of network usage
|
|
|
+ SharedCost float64 `json:"sharedCost"` // Shared/unallocated costs assigned here
|
|
|
+ ExternalCost float64 `json:"externalCost"` // External costs (cloud services, etc.)
|
|
|
+ TotalCost float64 `json:"totalCost"` // Sum of all costs above
|
|
|
+
|
|
|
+ CPUCoreHours float64 `json:"cpuCoreHours"` // Usage metrics: CPU core-hours
|
|
|
+ RAMByteHours float64 `json:"ramByteHours"` // Usage metrics: RAM byte-hours
|
|
|
+ GPUHours float64 `json:"gpuHours"` // Usage metrics: GPU-hours
|
|
|
+ PVByteHours float64 `json:"pvByteHours"` // Usage metrics: PV byte-hours
|
|
|
+
|
|
|
+ Start time.Time `json:"start"` // Start timestamp for this allocation
|
|
|
+ End time.Time `json:"end"` // End timestamp for this allocation
|
|
|
+}
|
|
|
+
|
|
|
+// AssetResponse represents the asset data returned to the AI agent.
|
|
|
+type AssetResponse struct {
|
|
|
+ // The asset data, as a map of asset sets.
|
|
|
+ Assets map[string]*AssetSet `json:"assets"`
|
|
|
+}
|
|
|
+
|
|
|
+// AssetSet represents a set of asset data.
|
|
|
+type AssetSet struct {
|
|
|
+ // The name of the asset set.
|
|
|
+ Name string `json:"name"`
|
|
|
+
|
|
|
+ // The asset data for the set.
|
|
|
+ Assets []*Asset `json:"assets"`
|
|
|
+}
|
|
|
+
|
|
|
+// Asset represents a single asset data point.
|
|
|
+type Asset struct {
|
|
|
+ Type string `json:"type"`
|
|
|
+ Properties AssetProperties `json:"properties"`
|
|
|
+ Labels map[string]string `json:"labels,omitempty"`
|
|
|
+
|
|
|
+ Start time.Time `json:"start"`
|
|
|
+ End time.Time `json:"end"`
|
|
|
+
|
|
|
+ Minutes float64 `json:"minutes"`
|
|
|
+ Adjustment float64 `json:"adjustment"`
|
|
|
+ TotalCost float64 `json:"totalCost"`
|
|
|
+
|
|
|
+ // Disk-specific fields
|
|
|
+ ByteHours float64 `json:"byteHours,omitempty"`
|
|
|
+ ByteHoursUsed *float64 `json:"byteHoursUsed,omitempty"`
|
|
|
+ ByteUsageMax *float64 `json:"byteUsageMax,omitempty"`
|
|
|
+ StorageClass string `json:"storageClass,omitempty"`
|
|
|
+ VolumeName string `json:"volumeName,omitempty"`
|
|
|
+ ClaimName string `json:"claimName,omitempty"`
|
|
|
+ ClaimNamespace string `json:"claimNamespace,omitempty"`
|
|
|
+ Local float64 `json:"local,omitempty"`
|
|
|
+
|
|
|
+ // Node-specific fields
|
|
|
+ NodeType string `json:"nodeType,omitempty"`
|
|
|
+ CPUCoreHours float64 `json:"cpuCoreHours,omitempty"`
|
|
|
+ RAMByteHours float64 `json:"ramByteHours,omitempty"`
|
|
|
+ GPUHours float64 `json:"gpuHours,omitempty"`
|
|
|
+ GPUCount float64 `json:"gpuCount,omitempty"`
|
|
|
+ CPUCost float64 `json:"cpuCost,omitempty"`
|
|
|
+ GPUCost float64 `json:"gpuCost,omitempty"`
|
|
|
+ RAMCost float64 `json:"ramCost,omitempty"`
|
|
|
+ Discount float64 `json:"discount,omitempty"`
|
|
|
+ Preemptible float64 `json:"preemptible,omitempty"`
|
|
|
+
|
|
|
+ // Breakdown fields (can be used for different types)
|
|
|
+ Breakdown *AssetBreakdown `json:"breakdown,omitempty"`
|
|
|
+ CPUBreakdown *AssetBreakdown `json:"cpuBreakdown,omitempty"`
|
|
|
+ RAMBreakdown *AssetBreakdown `json:"ramBreakdown,omitempty"`
|
|
|
+
|
|
|
+ // Overhead (Node-specific)
|
|
|
+ Overhead *NodeOverhead `json:"overhead,omitempty"`
|
|
|
+}
|
|
|
+
|
|
|
+// NodeOverhead represents node overhead information
|
|
|
+type NodeOverhead struct {
|
|
|
+ RamOverheadFraction float64 `json:"ramOverheadFraction"`
|
|
|
+ CpuOverheadFraction float64 `json:"cpuOverheadFraction"`
|
|
|
+ OverheadCostFraction float64 `json:"overheadCostFraction"`
|
|
|
+}
|
|
|
+type AssetProperties struct {
|
|
|
+ Category string `json:"category,omitempty"`
|
|
|
+ Provider string `json:"provider,omitempty"`
|
|
|
+ Account string `json:"account,omitempty"`
|
|
|
+ Project string `json:"project,omitempty"`
|
|
|
+ Service string `json:"service,omitempty"`
|
|
|
+ Cluster string `json:"cluster,omitempty"`
|
|
|
+ Name string `json:"name,omitempty"`
|
|
|
+ ProviderID string `json:"providerID,omitempty"`
|
|
|
+}
|
|
|
+
|
|
|
+type AssetBreakdown struct {
|
|
|
+ Idle float64 `json:"idle"`
|
|
|
+ Other float64 `json:"other"`
|
|
|
+ System float64 `json:"system"`
|
|
|
+ User float64 `json:"user"`
|
|
|
+}
|
|
|
+
|
|
|
+// CloudCostResponse represents the cloud cost data returned to the AI agent.
|
|
|
+type CloudCostResponse struct {
|
|
|
+ // The cloud cost data, as a map of cloud cost sets.
|
|
|
+ CloudCosts map[string]*CloudCostSet `json:"cloudCosts"`
|
|
|
+ // Summary information
|
|
|
+ Summary *CloudCostSummary `json:"summary,omitempty"`
|
|
|
+}
|
|
|
+
|
|
|
+// CloudCostSummary provides summary information about cloud costs
|
|
|
+type CloudCostSummary struct {
|
|
|
+ TotalNetCost float64 `json:"totalNetCost"`
|
|
|
+ TotalAmortizedCost float64 `json:"totalAmortizedCost"`
|
|
|
+ TotalInvoicedCost float64 `json:"totalInvoicedCost"`
|
|
|
+ KubernetesPercent float64 `json:"kubernetesPercent"`
|
|
|
+ ProviderBreakdown map[string]float64 `json:"providerBreakdown,omitempty"`
|
|
|
+ ServiceBreakdown map[string]float64 `json:"serviceBreakdown,omitempty"`
|
|
|
+ RegionBreakdown map[string]float64 `json:"regionBreakdown,omitempty"`
|
|
|
+}
|
|
|
+
|
|
|
+// CloudCostSet represents a set of cloud cost data.
|
|
|
+type CloudCostSet struct {
|
|
|
+ // The name of the cloud cost set.
|
|
|
+ Name string `json:"name"`
|
|
|
+
|
|
|
+ // The cloud cost data for the set.
|
|
|
+ CloudCosts []*CloudCost `json:"cloudCosts"`
|
|
|
+
|
|
|
+ // Aggregation information
|
|
|
+ AggregationProperties []string `json:"aggregationProperties,omitempty"`
|
|
|
+
|
|
|
+ // Time window
|
|
|
+ Window *TimeWindow `json:"window,omitempty"`
|
|
|
+}
|
|
|
+
|
|
|
+// TimeWindow represents a time range
|
|
|
+type TimeWindow struct {
|
|
|
+ Start time.Time `json:"start"`
|
|
|
+ End time.Time `json:"end"`
|
|
|
+}
|
|
|
+
|
|
|
+// CloudCostProperties defines the properties of a cloud cost item.
|
|
|
+type CloudCostProperties struct {
|
|
|
+ ProviderID string `json:"providerID,omitempty"`
|
|
|
+ Provider string `json:"provider,omitempty"`
|
|
|
+ AccountID string `json:"accountID,omitempty"`
|
|
|
+ AccountName string `json:"accountName,omitempty"`
|
|
|
+ InvoiceEntityID string `json:"invoiceEntityID,omitempty"`
|
|
|
+ InvoiceEntityName string `json:"invoiceEntityName,omitempty"`
|
|
|
+ RegionID string `json:"regionID,omitempty"`
|
|
|
+ AvailabilityZone string `json:"availabilityZone,omitempty"`
|
|
|
+ Service string `json:"service,omitempty"`
|
|
|
+ Category string `json:"category,omitempty"`
|
|
|
+ Labels map[string]string `json:"labels,omitempty"`
|
|
|
+}
|
|
|
+
|
|
|
+// CloudCost represents a single cloud cost data point.
|
|
|
+type CloudCost struct {
|
|
|
+ Properties CloudCostProperties `json:"properties"`
|
|
|
+ Window TimeWindow `json:"window"`
|
|
|
+ ListCost CostMetric `json:"listCost"`
|
|
|
+ NetCost CostMetric `json:"netCost"`
|
|
|
+ AmortizedNetCost CostMetric `json:"amortizedNetCost"`
|
|
|
+ InvoicedCost CostMetric `json:"invoicedCost"`
|
|
|
+ AmortizedCost CostMetric `json:"amortizedCost"`
|
|
|
+}
|
|
|
+
|
|
|
+// CostMetric represents a cost value with Kubernetes percentage
|
|
|
+type CostMetric struct {
|
|
|
+ Cost float64 `json:"cost"`
|
|
|
+ KubernetesPercent float64 `json:"kubernetesPercent"`
|
|
|
+}
|
|
|
+
|
|
|
+// MCPServer holds the dependencies for the MCP API server.
|
|
|
+type MCPServer struct {
|
|
|
+ costModel *costmodel.CostModel
|
|
|
+ provider models.Provider
|
|
|
+ integration cloudcost.CloudCostIntegration
|
|
|
+}
|