blob: 27d897327f645874c2f812b082a992c5df8cdf2b [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package model
import (
"regexp"
"time"
)
// McpServerConfig MCP Server Filter configuration
type McpServerConfig struct {
ServerInfo ServerInfo `yaml:"server_info" json:"server_info"`
Endpoint string `yaml:"endpoint" json:"endpoint" default:"/mcp"`
Tools []ToolConfig `yaml:"tools,omitempty" json:"tools,omitempty"`
Resources []ResourceConfig `yaml:"resources,omitempty" json:"resources,omitempty"`
ResourceTemplates []ResourceTemplateConfig `yaml:"resource_templates,omitempty" json:"resource_templates,omitempty"`
Prompts []PromptConfig `yaml:"prompts,omitempty" json:"prompts,omitempty"`
}
// ServerInfo server information
type ServerInfo struct {
Name string `yaml:"name" json:"name" default:"Pixiu MCP Server"`
Version string `yaml:"version" json:"version" default:"1.0.0"`
Description string `yaml:"description,omitempty" json:"description,omitempty" default:"MCP Server powered by Apache Dubbo-go-pixiu"`
Instructions string `yaml:"instructions,omitempty" json:"instructions,omitempty" default:"Use the provided tools to interact with backend services."`
}
// ToolConfig tool configuration
type ToolConfig struct {
Name string `yaml:"name" json:"name"`
Description string `yaml:"description" json:"description"`
Cluster string `yaml:"cluster" json:"cluster"`
BackendURL string `yaml:"backend_url,omitempty" json:"backend_url,omitempty"`
Request RequestConfig `yaml:"request" json:"request"`
Args []ArgConfig `yaml:"args,omitempty" json:"args,omitempty"`
}
// RequestConfig request configuration
type RequestConfig struct {
Method string `yaml:"method" json:"method" default:"GET"`
Path string `yaml:"path" json:"path"`
Headers map[string]string `yaml:"headers,omitempty" json:"headers,omitempty"`
Timeout string `yaml:"timeout,omitempty" json:"timeout,omitempty" default:"30s"`
}
// ArgConfig parameter configuration (simplified)
type ArgConfig struct {
Name string `yaml:"name" json:"name"`
Type string `yaml:"type" json:"type" default:"string"`
In string `yaml:"in" json:"in"`
Description string `yaml:"description,omitempty" json:"description,omitempty"`
Required bool `yaml:"required,omitempty" json:"required,omitempty"`
Default any `yaml:"default,omitempty" json:"default,omitempty"`
Enum []string `yaml:"enum,omitempty" json:"enum,omitempty"`
}
// ResourceConfig resource configuration
type ResourceConfig struct {
Name string `yaml:"name" json:"name"`
URI string `yaml:"uri" json:"uri"`
Description string `yaml:"description,omitempty" json:"description,omitempty"`
MIMEType string `yaml:"mime_type,omitempty" json:"mime_type,omitempty"`
Source ResourceSource `yaml:"source" json:"source"`
}
// ResourceSource resource source configuration (simplified)
type ResourceSource struct {
Type string `yaml:"type" json:"type"`
Path string `yaml:"path,omitempty" json:"path,omitempty"` // for file type
URL string `yaml:"url,omitempty" json:"url,omitempty"` // for url type
Content string `yaml:"content,omitempty" json:"content,omitempty"` // for inline type
Template string `yaml:"template,omitempty" json:"template,omitempty"` // for template type
}
// ResourceTemplateConfig resource template configuration
type ResourceTemplateConfig struct {
Name string `yaml:"name" json:"name"`
URITemplate string `yaml:"uri_template" json:"uri_template"`
Title string `yaml:"title,omitempty" json:"title,omitempty"`
Description string `yaml:"description,omitempty" json:"description,omitempty"`
MIMEType string `yaml:"mime_type,omitempty" json:"mime_type,omitempty"`
Parameters []ResourceTemplateParameter `yaml:"parameters,omitempty" json:"parameters,omitempty"`
Annotations *ResourceTemplateAnnotations `yaml:"annotations,omitempty" json:"annotations,omitempty"`
}
// ResourceTemplateParameter resource template parameter
type ResourceTemplateParameter struct {
Name string `yaml:"name" json:"name"`
Type string `yaml:"type" json:"type" default:"string"`
Description string `yaml:"description,omitempty" json:"description,omitempty"`
Required bool `yaml:"required,omitempty" json:"required,omitempty" default:"false"`
Enum []string `yaml:"enum,omitempty" json:"enum,omitempty"`
Default any `yaml:"default,omitempty" json:"default,omitempty"`
}
// ResourceTemplateAnnotations resource template annotations
type ResourceTemplateAnnotations struct {
Audience []string `yaml:"audience,omitempty" json:"audience,omitempty"`
Priority *float64 `yaml:"priority,omitempty" json:"priority,omitempty"`
LastModified string `yaml:"last_modified,omitempty" json:"last_modified,omitempty"`
}
// ComputedParameter computed parameter (for internal processing, simplified)
type ComputedParameter struct {
Name string
Type string
In string
Description string
Required bool
Enum []string
Default any
}
// PromptConfig prompt configuration
type PromptConfig struct {
Name string `yaml:"name" json:"name"`
Title string `yaml:"title,omitempty" json:"title,omitempty"`
Description string `yaml:"description,omitempty" json:"description,omitempty"`
Arguments []PromptArgumentConfig `yaml:"arguments,omitempty" json:"arguments,omitempty"`
Messages []PromptMessageConfig `yaml:"messages" json:"messages"`
}
// PromptArgumentConfig prompt argument configuration
type PromptArgumentConfig struct {
Name string `yaml:"name" json:"name"`
Description string `yaml:"description,omitempty" json:"description,omitempty"`
Required bool `yaml:"required,omitempty" json:"required,omitempty"`
}
// PromptMessageConfig prompt message configuration
type PromptMessageConfig struct {
Role string `yaml:"role" json:"role"` // "user" or "assistant"
Content string `yaml:"content" json:"content"`
}
// RegistryConfig registry configuration
type RegistryConfig struct {
ToolConfigs map[string]ToolConfig `yaml:"toolConfigs"`
ResourceConfigs map[string]ResourceConfig `yaml:"resourceConfigs"`
PromptConfigs map[string]PromptConfig `yaml:"promptConfigs"`
LastUpdated time.Time `yaml:"lastUpdated"`
}
// GetAllParameters gets all parameters of the tool
func (tc *ToolConfig) GetAllParameters() ([]ComputedParameter, error) {
var allParams []ComputedParameter
// 1. Automatically extract path parameters
pathParams := GetPathParameterNames(tc.Request.Path)
for _, paramName := range pathParams {
// Find corresponding arg configuration
var argConfig *ArgConfig
for _, arg := range tc.Args {
if arg.Name == paramName && arg.In == "path" {
argConfig = &arg
break
}
}
// Create computed parameter
computed := ComputedParameter{
Name: paramName,
Type: "string", // Default type
In: "path",
Required: true, // Path parameters are always required
}
// Apply arg configuration
if argConfig != nil {
computed.Type = argConfig.Type
computed.Description = argConfig.Description
}
allParams = append(allParams, computed)
}
// 2. Add non-path parameters
for _, arg := range tc.Args {
if arg.In != "path" {
computed := ComputedParameter{
Name: arg.Name,
Type: arg.Type,
In: arg.In,
Description: arg.Description,
Required: arg.Required,
Enum: arg.Enum,
Default: arg.Default,
// Simplified: removed complex validation fields
}
allParams = append(allParams, computed)
}
}
return allParams, nil
}
// GetPathParameterNames gets all parameter names in the path template
func GetPathParameterNames(pathTemplate string) []string {
re := regexp.MustCompile(`\{([^}]+)}`)
matches := re.FindAllStringSubmatch(pathTemplate, -1)
// Initialize as empty slice instead of nil
names := []string{}
for _, match := range matches {
names = append(names, match[1])
}
return names
}
// DeepCopy returns a new independent copy of Config
// Deep copy slices/maps to avoid sharing pointers with the factory
func (config *McpServerConfig) DeepCopy() *McpServerConfig {
if config == nil {
return nil
}
cpConfig := *config
// Deep copy Tools
if config.Tools != nil {
cpConfig.Tools = make([]ToolConfig, len(config.Tools))
for i := range config.Tools {
cpConfig.Tools[i] = *config.Tools[i].DeepCopy()
}
}
// Deep copy Resources
if config.Resources != nil {
cpConfig.Resources = make([]ResourceConfig, len(config.Resources))
copy(cpConfig.Resources, config.Resources)
}
// Deep copy ResourceTemplates
if config.ResourceTemplates != nil {
cpConfig.ResourceTemplates = make([]ResourceTemplateConfig, len(config.ResourceTemplates))
for i := range config.ResourceTemplates {
cpConfig.ResourceTemplates[i] = *config.ResourceTemplates[i].DeepCopy()
}
}
// Deep copy Prompts
if config.Prompts != nil {
cpConfig.Prompts = make([]PromptConfig, len(config.Prompts))
for i := range config.Prompts {
cpConfig.Prompts[i] = *config.Prompts[i].DeepCopy()
}
}
return &cpConfig
}
// DeepCopy returns a new independent copy of Config
// Deep copy slices/maps to avoid sharing pointers with the factory
func (toolConfig *ToolConfig) DeepCopy() *ToolConfig {
if toolConfig == nil {
return nil
}
cpConfig := *toolConfig
cpConfig.Request = *toolConfig.Request.DeepCopy()
if toolConfig.Args != nil {
cpConfig.Args = make([]ArgConfig, len(toolConfig.Args))
for index := range toolConfig.Args {
argPtr := &toolConfig.Args[index]
cpConfig.Args[index] = *argPtr.DeepCopy()
}
}
return &cpConfig
}
// DeepCopy returns a new independent copy of Config
// Deep copy slices/maps to avoid sharing pointers with the factory
func (config *RequestConfig) DeepCopy() *RequestConfig {
if config == nil {
return nil
}
cpConfig := *config
if config.Headers != nil {
cpConfig.Headers = make(map[string]string, len(config.Headers))
for k, v := range config.Headers {
cpConfig.Headers[k] = v
}
}
return &cpConfig
}
// DeepCopy returns a new independent copy of Config
// Deep copy slices/maps to avoid sharing pointers with the factory
func (config *ArgConfig) DeepCopy() *ArgConfig {
if config == nil {
return nil
}
cpConfig := *config
if config.Enum != nil {
cpConfig.Enum = make([]string, len(config.Enum))
copy(cpConfig.Enum, config.Enum)
}
return &cpConfig
}
// DeepCopy returns a new independent copy of Config
// Deep copy slices/maps to avoid sharing pointers with the factory
func (param *ResourceTemplateParameter) DeepCopy() *ResourceTemplateParameter {
if param == nil {
return nil
}
cpParam := *param
if param.Enum != nil {
cpParam.Enum = make([]string, len(param.Enum))
copy(cpParam.Enum, param.Enum)
}
return &cpParam
}
// DeepCopy returns a new independent copy of Config
// Deep copy slices/maps to avoid sharing pointers with the factory
func (ann *ResourceTemplateAnnotations) DeepCopy() *ResourceTemplateAnnotations {
if ann == nil {
return nil
}
cpAnn := *ann
// Deep copy Audience slice
if ann.Audience != nil {
cpAnn.Audience = make([]string, len(ann.Audience))
copy(cpAnn.Audience, ann.Audience)
}
// Deep copy Priority pointer
if ann.Priority != nil {
p := *ann.Priority
cpAnn.Priority = &p
}
return &cpAnn
}
// DeepCopy returns a new independent copy of Config
// Deep copy slices/maps to avoid sharing pointers with the factory
func (config *ResourceTemplateConfig) DeepCopy() *ResourceTemplateConfig {
if config == nil {
return nil
}
cpConfig := *config
// Deep copy Parameters slice
if config.Parameters != nil {
cpConfig.Parameters = make([]ResourceTemplateParameter, len(config.Parameters))
for i := range config.Parameters {
paramPtr := &config.Parameters[i]
cpConfig.Parameters[i] = *paramPtr.DeepCopy()
}
}
// Deep copy Annotations pointer
if config.Annotations != nil {
cpConfig.Annotations = config.Annotations.DeepCopy()
}
return &cpConfig
}
// DeepCopy returns a new independent copy of Config
// Deep copy slices/maps to avoid sharing pointers with the factory
func (config *PromptConfig) DeepCopy() *PromptConfig {
if config == nil {
return nil
}
cp := *config
// Deep copy Arguments slice
if config.Arguments != nil {
cp.Arguments = make([]PromptArgumentConfig, len(config.Arguments))
copy(cp.Arguments, config.Arguments)
}
// Deep copy Messages slice
if config.Messages != nil {
cp.Messages = make([]PromptMessageConfig, len(config.Messages))
copy(cp.Messages, config.Messages)
}
return &cp
}