浏览代码

feat(mcp): add MCP server structs and query types (#3375)

Signed-off-by: sneax <paladesh600@gmail.com>
Co-authored-by: Alex Meijer <ameijer@users.noreply.github.com>
segfault_bits 7 月之前
父节点
当前提交
353b9f2971
共有 1 个文件被更改,包括 292 次插入0 次删除
  1. 292 0
      pkg/mcp/server.go

+ 292 - 0
pkg/mcp/server.go

@@ -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
+}