diff --git a/go.mod b/go.mod index 899189a..750bb8b 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/google/go-cmp v0.7.0 github.com/hamba/avro/v2 v2.28.0 - github.com/mark3labs/mcp-go v0.28.0 + github.com/mark3labs/mcp-go v0.31.0 github.com/mitchellh/go-homedir v1.1.0 github.com/pkg/errors v0.9.1 github.com/sirupsen/logrus v1.9.3 diff --git a/go.sum b/go.sum index 835b7fd..792a117 100644 --- a/go.sum +++ b/go.sum @@ -129,8 +129,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= -github.com/mark3labs/mcp-go v0.28.0 h1:7yl4y5D1KYU2f/9Uxp7xfLIggfunHoESCRbrjcytcLM= -github.com/mark3labs/mcp-go v0.28.0/go.mod h1:rXqOudj/djTORU/ThxYx8fqEVj/5pvTuuebQ2RC7uk4= +github.com/mark3labs/mcp-go v0.31.0 h1:4UxSV8aM770OPmTvaVe/b1rA2oZAjBMhGBfUgOGut+4= +github.com/mark3labs/mcp-go v0.31.0/go.mod h1:rXqOudj/djTORU/ThxYx8fqEVj/5pvTuuebQ2RC7uk4= github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE= diff --git a/go.work.sum b/go.work.sum index 22423cd..7123498 100644 --- a/go.work.sum +++ b/go.work.sum @@ -138,8 +138,8 @@ github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+ github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= github.com/mark3labs/mcp-go v0.23.1 h1:RzTzZ5kJ+HxwnutKA4rll8N/pKV6Wh5dhCmiJUu5S9I= github.com/mark3labs/mcp-go v0.23.1/go.mod h1:rXqOudj/djTORU/ThxYx8fqEVj/5pvTuuebQ2RC7uk4= -github.com/mark3labs/mcp-go v0.28.0 h1:7yl4y5D1KYU2f/9Uxp7xfLIggfunHoESCRbrjcytcLM= -github.com/mark3labs/mcp-go v0.28.0/go.mod h1:rXqOudj/djTORU/ThxYx8fqEVj/5pvTuuebQ2RC7uk4= +github.com/mark3labs/mcp-go v0.31.0 h1:4UxSV8aM770OPmTvaVe/b1rA2oZAjBMhGBfUgOGut+4= +github.com/mark3labs/mcp-go v0.31.0/go.mod h1:rXqOudj/djTORU/ThxYx8fqEVj/5pvTuuebQ2RC7uk4= github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= diff --git a/pkg/cmd/mcp/sse.go b/pkg/cmd/mcp/sse.go index 3222c61..86ce0fb 100644 --- a/pkg/cmd/mcp/sse.go +++ b/pkg/cmd/mcp/sse.go @@ -78,7 +78,7 @@ func runSseServer(configOpts *ServerOptions) error { sseServer := server.NewSSEServer( mcpServer, server.WithStaticBasePath(configOpts.HTTPPath), - server.WithHTTPContextFunc(func(ctx context.Context, _ *http.Request) context.Context { + server.WithSSEContextFunc(func(ctx context.Context, _ *http.Request) context.Context { return context.WithValue(ctx, common.OptionsKey, configOpts.Options) }), ) diff --git a/pkg/common/utils.go b/pkg/common/utils.go index e607701..2049fbf 100644 --- a/pkg/common/utils.go +++ b/pkg/common/utils.go @@ -180,6 +180,19 @@ func RequiredParamObject(arguments map[string]interface{}, name string) (map[str return nil, fmt.Errorf("%s parameter must be an object", name) } +func OptionalParamObject(arguments map[string]interface{}, name string) (map[string]interface{}, bool) { + paramValue, found := arguments[name] + if !found || paramValue == nil { + return nil, false + } + + if mapVal, ok := paramValue.(map[string]interface{}); ok { + return mapVal, true + } + + return nil, false +} + func GetOptions(ctx context.Context) *config.Options { return ctx.Value(OptionsKey).(*config.Options) } diff --git a/pkg/mcp/context_tools.go b/pkg/mcp/context_tools.go index fbf112b..469e217 100644 --- a/pkg/mcp/context_tools.go +++ b/pkg/mcp/context_tools.go @@ -93,12 +93,12 @@ func handleWhoami(ctx context.Context, _ mcp.CallToolRequest) (*mcp.CallToolResu func handleSetContext(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { options := ctx.Value(common.OptionsKey).(*config.Options) - instanceName, err := common.RequiredParam[string](request.Params.Arguments, "instanceName") + instanceName, err := request.RequireString("instanceName") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get instance name: %v", err)), nil } - clusterName, err := common.RequiredParam[string](request.Params.Arguments, "clusterName") + clusterName, err := request.RequireString("clusterName") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get cluster name: %v", err)), nil } diff --git a/pkg/mcp/kafka_admin_connect_tools.go b/pkg/mcp/kafka_admin_connect_tools.go index df5878d..a5ad24f 100644 --- a/pkg/mcp/kafka_admin_connect_tools.go +++ b/pkg/mcp/kafka_admin_connect_tools.go @@ -151,12 +151,12 @@ func KafkaAdminAddKafkaConnectTools(s *server.MCPServer, readOnly bool, features func handleKafkaConnectTool(readOnly bool) func(context.Context, mcp.CallToolRequest) (*mcp.CallToolResult, error) { return func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - resource, err := common.RequiredParam[string](request.Params.Arguments, "resource") + resource, err := request.RequireString("resource") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get resource: %v", err)), nil } - operation, err := common.RequiredParam[string](request.Params.Arguments, "operation") + operation, err := request.RequireString("operation") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get operation: %v", err)), nil } @@ -256,7 +256,7 @@ func handleKafkaConnectorsList(ctx context.Context, admin kafka.Connect, _ mcp.C func handleKafkaConnectorGet(ctx context.Context, admin kafka.Connect, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get a specific connector - name, err := common.RequiredParam[string](request.Params.Arguments, "name") + name, err := request.RequireString("name") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get connector name: %v", err)), nil } @@ -276,12 +276,12 @@ func handleKafkaConnectorGet(ctx context.Context, admin kafka.Connect, request m func handleKafkaConnectorCreate(ctx context.Context, admin kafka.Connect, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Create a new connector - name, err := common.RequiredParam[string](request.Params.Arguments, "name") + name, err := request.RequireString("name") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get connector name: %v", err)), nil } - configMap, err := common.RequiredParamObject(request.Params.Arguments, "config") + configMap, err := common.RequiredParamObject(request.GetArguments(), "config") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get config: %v", err)), nil } @@ -305,12 +305,12 @@ func handleKafkaConnectorCreate(ctx context.Context, admin kafka.Connect, reques func handleKafkaConnectorUpdate(ctx context.Context, admin kafka.Connect, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Update a connector - name, err := common.RequiredParam[string](request.Params.Arguments, "name") + name, err := request.RequireString("name") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get connector name: %v", err)), nil } - configMap, err := common.RequiredParamObject(request.Params.Arguments, "config") + configMap, err := common.RequiredParamObject(request.GetArguments(), "config") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get config: %v", err)), nil } @@ -334,7 +334,7 @@ func handleKafkaConnectorUpdate(ctx context.Context, admin kafka.Connect, reques func handleKafkaConnectorDelete(ctx context.Context, admin kafka.Connect, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Delete a connector - name, err := common.RequiredParam[string](request.Params.Arguments, "name") + name, err := request.RequireString("name") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get connector name: %v", err)), nil } @@ -349,7 +349,7 @@ func handleKafkaConnectorDelete(ctx context.Context, admin kafka.Connect, reques func handleKafkaConnectorRestart(ctx context.Context, admin kafka.Connect, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Restart a connector - name, err := common.RequiredParam[string](request.Params.Arguments, "name") + name, err := request.RequireString("name") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get connector name: %v", err)), nil } @@ -364,7 +364,7 @@ func handleKafkaConnectorRestart(ctx context.Context, admin kafka.Connect, reque func handleKafkaConnectorPause(ctx context.Context, admin kafka.Connect, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Pause a connector - name, err := common.RequiredParam[string](request.Params.Arguments, "name") + name, err := request.RequireString("name") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get connector name: %v", err)), nil } @@ -379,7 +379,7 @@ func handleKafkaConnectorPause(ctx context.Context, admin kafka.Connect, request func handleKafkaConnectorResume(ctx context.Context, admin kafka.Connect, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Resume a connector - name, err := common.RequiredParam[string](request.Params.Arguments, "name") + name, err := request.RequireString("name") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get connector name: %v", err)), nil } diff --git a/pkg/mcp/kafka_admin_groups_tools.go b/pkg/mcp/kafka_admin_groups_tools.go index 363f199..66a7c38 100644 --- a/pkg/mcp/kafka_admin_groups_tools.go +++ b/pkg/mcp/kafka_admin_groups_tools.go @@ -26,7 +26,6 @@ import ( "github.com/mark3labs/mcp-go/mcp" "github.com/mark3labs/mcp-go/server" - "github.com/streamnative/streamnative-mcp-server/pkg/common" "github.com/streamnative/streamnative-mcp-server/pkg/kafka" "github.com/twmb/franz-go/pkg/kadm" ) @@ -125,12 +124,12 @@ func KafkaAdminAddGroupsTools(s *server.MCPServer, readOnly bool, features []str func handleKafkaGroupsTool(readOnly bool) func(context.Context, mcp.CallToolRequest) (*mcp.CallToolResult, error) { return func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - resource, err := common.RequiredParam[string](request.Params.Arguments, "resource") + resource, err := request.RequireString("resource") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get resource: %v", err)), nil } - operation, err := common.RequiredParam[string](request.Params.Arguments, "operation") + operation, err := request.RequireString("operation") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get operation: %v", err)), nil } @@ -181,7 +180,7 @@ func handleKafkaGroupsTool(readOnly bool) func(context.Context, mcp.CallToolRequ } func handleKafkaGroupDescribe(ctx context.Context, admin *kadm.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { - groupName, err := common.RequiredParam[string](request.Params.Arguments, "group") + groupName, err := request.RequireString("group") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get group name: %v", err)), nil } @@ -210,12 +209,12 @@ func handleKafkaGroupDescribe(ctx context.Context, admin *kadm.Client, request m } func handleKafkaGroupRemoveMembers(ctx context.Context, admin *kadm.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { - groupName, err := common.RequiredParam[string](request.Params.Arguments, "group") + groupName, err := request.RequireString("group") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get group name: %v", err)), nil } - members, err := common.RequiredParam[string](request.Params.Arguments, "members") + members, err := request.RequireString("members") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get members: %v", err)), nil } @@ -248,7 +247,7 @@ func handleKafkaGroupsList(ctx context.Context, admin *kadm.Client, _ mcp.CallTo } func handleKafkaGroupOffsets(ctx context.Context, admin *kadm.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { - groupName, err := common.RequiredParam[string](request.Params.Arguments, "group") + groupName, err := request.RequireString("group") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get group name: %v", err)), nil } @@ -267,12 +266,12 @@ func handleKafkaGroupOffsets(ctx context.Context, admin *kadm.Client, request mc } func handleKafkaGroupDeleteOffset(ctx context.Context, admin *kadm.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { - groupName, err := common.RequiredParam[string](request.Params.Arguments, "group") + groupName, err := request.RequireString("group") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get group name: %v", err)), nil } - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic name: %v", err)), nil } @@ -303,23 +302,23 @@ func handleKafkaGroupDeleteOffset(ctx context.Context, admin *kadm.Client, reque func handleKafkaGroupSetOffset(ctx context.Context, admin *kadm.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - groupName, err := common.RequiredParam[string](request.Params.Arguments, "group") + groupName, err := request.RequireString("group") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get group name: %v", err)), nil } - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic name: %v", err)), nil } - partition, err := common.RequiredParam[float64](request.Params.Arguments, "partition") + partition, err := request.RequireFloat("partition") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get partition number: %v", err)), nil } partitionInt := int32(partition) - offset, err := common.RequiredParam[float64](request.Params.Arguments, "offset") + offset, err := request.RequireFloat("offset") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get offset value: %v", err)), nil } diff --git a/pkg/mcp/kafka_admin_partitions_tools.go b/pkg/mcp/kafka_admin_partitions_tools.go index 9448602..a1a3eb5 100644 --- a/pkg/mcp/kafka_admin_partitions_tools.go +++ b/pkg/mcp/kafka_admin_partitions_tools.go @@ -26,7 +26,6 @@ import ( "github.com/mark3labs/mcp-go/mcp" "github.com/mark3labs/mcp-go/server" - "github.com/streamnative/streamnative-mcp-server/pkg/common" "github.com/streamnative/streamnative-mcp-server/pkg/kafka" "github.com/twmb/franz-go/pkg/kadm" ) @@ -88,12 +87,12 @@ func KafkaAdminAddPartitionsTools(s *server.MCPServer, readOnly bool, features [ func handleKafkaPartitionsTool(readOnly bool) func(context.Context, mcp.CallToolRequest) (*mcp.CallToolResult, error) { return func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - resource, err := common.RequiredParam[string](request.Params.Arguments, "resource") + resource, err := request.RequireString("resource") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get resource: %v", err)), nil } - operation, err := common.RequiredParam[string](request.Params.Arguments, "operation") + operation, err := request.RequireString("operation") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get operation: %v", err)), nil } @@ -129,12 +128,12 @@ func handleKafkaPartitionsTool(readOnly bool) func(context.Context, mcp.CallTool } func handleKafkaPartitionUpdate(ctx context.Context, admin *kadm.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { - topicName, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topicName, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic name: %v", err)), nil } - newTotal, err := common.RequiredParam[int](request.Params.Arguments, "new-total") + newTotal, err := request.RequireInt("new-total") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get new total: %v", err)), nil } diff --git a/pkg/mcp/kafka_admin_sr_tools.go b/pkg/mcp/kafka_admin_sr_tools.go index eab524e..35093d3 100644 --- a/pkg/mcp/kafka_admin_sr_tools.go +++ b/pkg/mcp/kafka_admin_sr_tools.go @@ -26,7 +26,6 @@ import ( "github.com/mark3labs/mcp-go/mcp" "github.com/mark3labs/mcp-go/server" - "github.com/streamnative/streamnative-mcp-server/pkg/common" "github.com/streamnative/streamnative-mcp-server/pkg/kafka" "github.com/twmb/franz-go/pkg/sr" ) @@ -150,12 +149,12 @@ func KafkaAdminAddSchemaRegistryTools(s *server.MCPServer, readOnly bool, featur func handleKafkaSchemaRegistryTool(readOnly bool) func(context.Context, mcp.CallToolRequest) (*mcp.CallToolResult, error) { return func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - resource, err := common.RequiredParam[string](request.Params.Arguments, "resource") + resource, err := request.RequireString("resource") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get resource: %v", err)), nil } - operation, err := common.RequiredParam[string](request.Params.Arguments, "operation") + operation, err := request.RequireString("operation") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get operation: %v", err)), nil } @@ -246,7 +245,7 @@ func handleKafkaSubjectsList(ctx context.Context, admin *sr.Client, _ mcp.CallTo } func handleKafkaVersionsList(ctx context.Context, admin *sr.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { - subject, err := common.RequiredParam[string](request.Params.Arguments, "subject") + subject, err := request.RequireString("subject") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get subject: %v", err)), nil } @@ -279,7 +278,7 @@ func handleKafkaTypesList(ctx context.Context, admin *sr.Client, _ mcp.CallToolR } func handleKafkaSubjectGet(ctx context.Context, admin *sr.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { - subject, err := common.RequiredParam[string](request.Params.Arguments, "subject") + subject, err := request.RequireString("subject") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get subject: %v", err)), nil } @@ -298,17 +297,17 @@ func handleKafkaSubjectGet(ctx context.Context, admin *sr.Client, request mcp.Ca } func handleKafkaSubjectCreate(ctx context.Context, admin *sr.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { - subject, err := common.RequiredParam[string](request.Params.Arguments, "subject") + subject, err := request.RequireString("subject") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get subject: %v", err)), nil } - schema, err := common.RequiredParam[string](request.Params.Arguments, "schema") + schema, err := request.RequireString("schema") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get schema: %v", err)), nil } - typeString, err := common.RequiredParam[string](request.Params.Arguments, "type") + typeString, err := request.RequireString("type") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get schema type: %v", err)), nil } @@ -338,12 +337,12 @@ func handleKafkaSubjectCreate(ctx context.Context, admin *sr.Client, request mcp } func handleKafkaSubjectDelete(ctx context.Context, admin *sr.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { - subject, err := common.RequiredParam[string](request.Params.Arguments, "subject") + subject, err := request.RequireString("subject") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get subject: %v", err)), nil } - version, err := common.RequiredParam[int](request.Params.Arguments, "version") + version, err := request.RequireInt("version") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get version: %v", err)), nil } @@ -357,12 +356,12 @@ func handleKafkaSubjectDelete(ctx context.Context, admin *sr.Client, request mcp } func handleKafkaVersionGet(ctx context.Context, admin *sr.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { - subject, err := common.RequiredParam[string](request.Params.Arguments, "subject") + subject, err := request.RequireString("subject") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get subject: %v", err)), nil } - version, err := common.RequiredParam[int](request.Params.Arguments, "version") + version, err := request.RequireInt("version") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get version: %v", err)), nil } @@ -381,7 +380,7 @@ func handleKafkaVersionGet(ctx context.Context, admin *sr.Client, request mcp.Ca } func handleKafkaCompatibilityGet(ctx context.Context, admin *sr.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { - subject, err := common.RequiredParam[string](request.Params.Arguments, "subject") + subject, err := request.RequireString("subject") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get subject: %v", err)), nil } @@ -397,12 +396,12 @@ func handleKafkaCompatibilityGet(ctx context.Context, admin *sr.Client, request } func handleKafkaCompatibilitySet(ctx context.Context, admin *sr.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { - subject, err := common.RequiredParam[string](request.Params.Arguments, "subject") + subject, err := request.RequireString("subject") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get subject: %v", err)), nil } - compatibility, err := common.RequiredParam[string](request.Params.Arguments, "compatibility") + compatibility, err := request.RequireString("compatibility") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get compatibility: %v", err)), nil } diff --git a/pkg/mcp/kafka_admin_topics_tools.go b/pkg/mcp/kafka_admin_topics_tools.go index c83be6f..5ea1f75 100644 --- a/pkg/mcp/kafka_admin_topics_tools.go +++ b/pkg/mcp/kafka_admin_topics_tools.go @@ -128,12 +128,12 @@ func KafkaAdminAddTopicTools(s *server.MCPServer, readOnly bool, features []stri func handleKafkaTopicTool(readOnly bool) func(context.Context, mcp.CallToolRequest) (*mcp.CallToolResult, error) { return func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - resource, err := common.RequiredParam[string](request.Params.Arguments, "resource") + resource, err := request.RequireString("resource") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get resource: %v", err)), nil } - operation, err := common.RequiredParam[string](request.Params.Arguments, "operation") + operation, err := request.RequireString("operation") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get operation: %v", err)), nil } @@ -183,7 +183,7 @@ func handleKafkaTopicTool(readOnly bool) func(context.Context, mcp.CallToolReque func handleKafkaTopicGet(ctx context.Context, admin *kadm.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topicName, err := common.RequiredParam[string](request.Params.Arguments, "name") + topicName, err := request.RequireString("name") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic name: %v", err)), nil } @@ -205,26 +205,20 @@ func handleKafkaTopicGet(ctx context.Context, admin *kadm.Client, request mcp.Ca func handleKafkaTopicCreate(ctx context.Context, admin *kadm.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topicName, err := common.RequiredParam[string](request.Params.Arguments, "name") + topicName, err := request.RequireString("name") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic name: %v", err)), nil } // Get optional parameters - partitions, ok := common.OptionalParam[float64](request.Params.Arguments, "partitions") - if !ok { - partitions = 1 // Default to 1 partition - } + partitions := request.GetFloat("partitions", 1) - replicationFactor, ok := common.OptionalParam[float64](request.Params.Arguments, "replication-factor") - if !ok { - replicationFactor = 1 // Default to replication factor 1 - } + replicationFactor := request.GetFloat("replication-factor", 1) // Get configs if provided var configEntries map[string]*string - configsArray, ok := common.OptionalParamConfigs(request.Params.Arguments, "configs") - if ok { + configsArray := request.GetStringSlice("configs", []string{}) + if len(configsArray) > 0 { configEntries, err = common.ParseMessageConfigs(configsArray) if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to parse configs: %v", err)), nil @@ -242,7 +236,7 @@ func handleKafkaTopicCreate(ctx context.Context, admin *kadm.Client, request mcp func handleKafkaTopicDelete(ctx context.Context, admin *kadm.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topicName, err := common.RequiredParam[string](request.Params.Arguments, "name") + topicName, err := request.RequireString("name") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic name: %v", err)), nil } @@ -258,10 +252,7 @@ func handleKafkaTopicDelete(ctx context.Context, admin *kadm.Client, request mcp func handleKafkaTopicsList(ctx context.Context, admin *kadm.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - includeInternal, ok := common.OptionalParam[bool](request.Params.Arguments, "include-internal") - if !ok { - includeInternal = false - } + includeInternal := request.GetBool("include-internal", false) var topics kadm.TopicDetails var err error @@ -293,7 +284,7 @@ func handleKafkaTopicsList(ctx context.Context, admin *kadm.Client, request mcp. func handleKafkaTopicMetadata(ctx context.Context, admin *kadm.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topicName, err := common.RequiredParam[string](request.Params.Arguments, "name") + topicName, err := request.RequireString("name") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic name: %v", err)), nil } diff --git a/pkg/mcp/kafka_client_consume_tools.go b/pkg/mcp/kafka_client_consume_tools.go index 10d9c46..d8401d5 100644 --- a/pkg/mcp/kafka_client_consume_tools.go +++ b/pkg/mcp/kafka_client_consume_tools.go @@ -28,7 +28,6 @@ import ( "github.com/mark3labs/mcp-go/mcp" "github.com/mark3labs/mcp-go/server" "github.com/sirupsen/logrus" - "github.com/streamnative/streamnative-mcp-server/pkg/common" "github.com/streamnative/streamnative-mcp-server/pkg/kafka" "github.com/twmb/franz-go/pkg/kgo" "github.com/twmb/franz-go/pkg/sr" @@ -115,7 +114,7 @@ func KafkaClientAddConsumeTools(s *server.MCPServer, _ bool, logrusLogger *logru func handleKafkaConsume(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { opts := []kgo.Opt{} // Get required parameters - topicName, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topicName, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic name: %v", err)), nil } @@ -125,28 +124,16 @@ func handleKafkaConsume(ctx context.Context, request mcp.CallToolRequest) (*mcp. opts = append(opts, kgo.KeepRetryableFetchErrors()) w := logger.Writer() opts = append(opts, kgo.WithLogger(kgo.BasicLogger(w, kgo.LogLevelInfo, nil))) - maxMessages, hasMaxMessages := common.OptionalParam[float64](request.Params.Arguments, "max-messages") - if !hasMaxMessages { - maxMessages = 10 // Default to 10 messages - } + maxMessages := request.GetFloat("max-messages", 10) - timeoutSec, hasTimeout := common.OptionalParam[float64](request.Params.Arguments, "timeout") - if !hasTimeout { - timeoutSec = 10 // Default to 10 seconds - } + timeoutSec := request.GetFloat("timeout", 10) - group, hasGroup := common.OptionalParam[string](request.Params.Arguments, "group") - if !hasGroup { - group = "" - } + group := request.GetString("group", "") if group != "" { opts = append(opts, kgo.ConsumerGroup(group)) } - offsetStr, hasOffset := common.OptionalParam[string](request.Params.Arguments, "offset") - if !hasOffset { - offsetStr = "atstart" // Default to starting at the beginning - } + offsetStr := request.GetString("offset", "atstart") var offset kgo.Offset switch offsetStr { diff --git a/pkg/mcp/kafka_client_produce_tools.go b/pkg/mcp/kafka_client_produce_tools.go index 0b2b5c5..7ae1a6f 100644 --- a/pkg/mcp/kafka_client_produce_tools.go +++ b/pkg/mcp/kafka_client_produce_tools.go @@ -66,7 +66,7 @@ func KafkaClientAddProduceTools(s *server.MCPServer, readOnly bool, features []s "4. Message with headers - Include metadata with your message:\n" + " topic: \"my-topic\"\n" + " value: \"Message with headers\"\n" + - " headers: [{\"key\": \"source\", \"value\": \"mcp-tool\"}, {\"key\": \"timestamp\", \"value\": \"2023-06-01\"}]\n\n" + + " headers: [\"source=mcp-tool\", \"timestamp=2023-06-01\"]\n\n" + "5. Specific partition - Send to a particular partition:\n" + " topic: \"my-topic\"\n" + " value: \"Targeted message\"\n" + @@ -91,15 +91,13 @@ func KafkaClientAddProduceTools(s *server.MCPServer, readOnly bool, features []s "This is the actual payload that will be delivered to consumers. It can be a JSON string, and the system will automatically serialize it to the appropriate format based on the schema registry if it is available."), ), mcp.WithArray("headers", - mcp.Description("Message headers in the format of [{\"key\": \"value\"}]. "+ + mcp.Description("Message headers in the format of [\"key=value\"]. "+ "Optional. Headers allow you to attach metadata to messages without modifying the payload. "+ "They are passed along with the message to consumers."), - mcp.Items( - map[string]interface{}{ - "type": "string", - "description": "header entry", - }, - ), + mcp.Items(map[string]interface{}{ + "type": "string", + "description": "key value pair in the format of \"key=value\"", + }), ), mcp.WithBoolean("sync", mcp.Description("Whether to wait for server acknowledgment before returning. "+ @@ -113,25 +111,22 @@ func KafkaClientAddProduceTools(s *server.MCPServer, readOnly bool, features []s // handleKafkaProduce handles producing messages to a Kafka topic func handleKafkaProduce(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topicName, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topicName, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic name: %v", err)), nil } // Handle single message case // Get value from parameter or file - value, err := common.RequiredParam[string](request.Params.Arguments, "value") + value, err := request.RequireString("value") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get value: %v", err)), nil } // Get optional parameters - key, hasKey := common.OptionalParam[string](request.Params.Arguments, "key") - headers, hasHeaders := common.OptionalParam[[]interface{}](request.Params.Arguments, "headers") - sync := true - if syncVal, hasSync := common.OptionalParam[bool](request.Params.Arguments, "sync"); hasSync { - sync = syncVal - } + key := request.GetString("key", "") + headers := request.GetStringSlice("headers", []string{}) + sync := request.GetBool("sync", true) // Create Kafka client kafkaClient, err := kafka.GetKafkaClient() @@ -194,13 +189,17 @@ func handleKafkaProduce(ctx context.Context, request mcp.CallToolRequest) (*mcp. } // Add key if provided - if hasKey { + if key != "" { record.Key = []byte(key) } // Add headers if provided - if hasHeaders { - record.Headers = parseHeaders(headers) + if len(headers) > 0 { + headerEntries, err := common.ParseMessageConfigs(headers) + if err != nil { + return mcp.NewToolResultError(fmt.Sprintf("Failed to parse headers: %v", err)), nil + } + record.Headers = parseHeaders(headerEntries) } if schemaReady { @@ -225,19 +224,19 @@ func handleKafkaProduce(ctx context.Context, request mcp.CallToolRequest) (*mcp. } // parseHeaders converts the headers array to kgo.RecordHeader format -func parseHeaders(headers []interface{}) []kgo.RecordHeader { +func parseHeaders(headers map[string]*string) []kgo.RecordHeader { var recordHeaders []kgo.RecordHeader - for _, header := range headers { - headerMap, ok := header.(map[string]interface{}) - if !ok { - continue - } - - for key, value := range headerMap { + for key, value := range headers { + if value == nil { + recordHeaders = append(recordHeaders, kgo.RecordHeader{ + Key: key, + Value: []byte{}, + }) + } else { recordHeaders = append(recordHeaders, kgo.RecordHeader{ Key: key, - Value: []byte(value.(string)), + Value: []byte(*value), }) } } diff --git a/pkg/mcp/pulsar_admin_brokers_stats_tools.go b/pkg/mcp/pulsar_admin_brokers_stats_tools.go index 830b0ef..7e4f811 100644 --- a/pkg/mcp/pulsar_admin_brokers_stats_tools.go +++ b/pkg/mcp/pulsar_admin_brokers_stats_tools.go @@ -26,7 +26,6 @@ import ( "github.com/mark3labs/mcp-go/mcp" "github.com/mark3labs/mcp-go/server" "github.com/streamnative/pulsarctl/pkg/cmdutils" - "github.com/streamnative/streamnative-mcp-server/pkg/common" "github.com/streamnative/streamnative-mcp-server/pkg/pulsar" ) @@ -71,7 +70,7 @@ func handleBrokerStats(_ bool) func(context.Context, mcp.CallToolRequest) (*mcp. } // Get required resource parameter - resource, err := common.RequiredParam[string](request.Params.Arguments, "resource") + resource, err := request.RequireString("resource") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'resource'. " + "Please specify one of: monitoring_metrics, mbeans, topics, allocator_stats, load_report.")), nil @@ -86,7 +85,7 @@ func handleBrokerStats(_ bool) func(context.Context, mcp.CallToolRequest) (*mcp. case "topics": return handleTopics(client) case "allocator_stats": - allocatorName, err := common.RequiredParam[string](request.Params.Arguments, "allocator_name") + allocatorName, err := request.RequireString("allocator_name") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'allocator_name' for allocator_stats resource. " + "Please provide the name of the allocator to get statistics for.")), nil diff --git a/pkg/mcp/pulsar_admin_brokers_tools.go b/pkg/mcp/pulsar_admin_brokers_tools.go index 388233c..70d404c 100644 --- a/pkg/mcp/pulsar_admin_brokers_tools.go +++ b/pkg/mcp/pulsar_admin_brokers_tools.go @@ -26,7 +26,6 @@ import ( "github.com/mark3labs/mcp-go/mcp" "github.com/mark3labs/mcp-go/server" "github.com/streamnative/pulsarctl/pkg/cmdutils" - "github.com/streamnative/streamnative-mcp-server/pkg/common" "github.com/streamnative/streamnative-mcp-server/pkg/pulsar" ) @@ -97,13 +96,13 @@ func handleBrokerTool(readOnly bool) func(context.Context, mcp.CallToolRequest) } // Get required parameters - resource, err := common.RequiredParam[string](request.Params.Arguments, "resource") + resource, err := request.RequireString("resource") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required resource parameter. " + "Please specify one of: brokers, health, config, namespaces.")), nil } - operation, err := common.RequiredParam[string](request.Params.Arguments, "operation") + operation, err := request.RequireString("operation") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required operation parameter. " + "Please specify one of: list, get, update, delete based on the resource type.")), nil @@ -163,7 +162,7 @@ func validateResourceOperation(resource, operation string) (bool, string) { func handleBrokersResource(client cmdutils.Client, operation string, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { switch operation { case "list": - clusterName, err := common.RequiredParam[string](request.Params.Arguments, "clusterName") + clusterName, err := request.RequireString("clusterName") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'clusterName'. " + "Please provide the name of the Pulsar cluster to list brokers for.")), nil @@ -208,7 +207,7 @@ func handleHealthResource(client cmdutils.Client, operation string, _ mcp.CallTo func handleConfigResource(client cmdutils.Client, operation string, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { switch operation { case "get": - configType, err := common.RequiredParam[string](request.Params.Arguments, "configType") + configType, err := request.RequireString("configType") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'configType'. " + "Please specify one of: dynamic, runtime, internal, all_dynamic.")), nil @@ -243,13 +242,13 @@ func handleConfigResource(client cmdutils.Client, operation string, request mcp. return mcp.NewToolResultText(string(resultJSON)), nil case "update": - configName, err := common.RequiredParam[string](request.Params.Arguments, "configName") + configName, err := request.RequireString("configName") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'configName'. " + "Please provide the name of the configuration parameter to update.")), nil } - configValue, err := common.RequiredParam[string](request.Params.Arguments, "configValue") + configValue, err := request.RequireString("configValue") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'configValue'. " + "Please provide the new value for the configuration parameter.")), nil @@ -265,7 +264,7 @@ func handleConfigResource(client cmdutils.Client, operation string, request mcp. configName, configValue)), nil case "delete": - configName, err := common.RequiredParam[string](request.Params.Arguments, "configName") + configName, err := request.RequireString("configName") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'configName'. " + "Please provide the name of the configuration parameter to delete.")), nil @@ -289,13 +288,13 @@ func handleConfigResource(client cmdutils.Client, operation string, request mcp. func handleNamespacesResource(client cmdutils.Client, operation string, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { switch operation { case "get": - clusterName, err := common.RequiredParam[string](request.Params.Arguments, "clusterName") + clusterName, err := request.RequireString("clusterName") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'clusterName'. " + "Please provide the name of the Pulsar cluster.")), nil } - brokerURL, err := common.RequiredParam[string](request.Params.Arguments, "brokerUrl") + brokerURL, err := request.RequireString("brokerUrl") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'brokerUrl'. " + "Please provide the URL of the broker (e.g., '127.0.0.1:8080').")), nil diff --git a/pkg/mcp/pulsar_admin_cluster_tools.go b/pkg/mcp/pulsar_admin_cluster_tools.go index cc89fb6..7f526a4 100644 --- a/pkg/mcp/pulsar_admin_cluster_tools.go +++ b/pkg/mcp/pulsar_admin_cluster_tools.go @@ -27,7 +27,6 @@ import ( "github.com/mark3labs/mcp-go/mcp" "github.com/mark3labs/mcp-go/server" "github.com/streamnative/pulsarctl/pkg/cmdutils" - "github.com/streamnative/streamnative-mcp-server/pkg/common" "github.com/streamnative/streamnative-mcp-server/pkg/pulsar" ) @@ -114,13 +113,13 @@ func handleClusterTool(readOnly bool) func(context.Context, mcp.CallToolRequest) } // Get required parameters - resource, err := common.RequiredParam[string](request.Params.Arguments, "resource") + resource, err := request.RequireString("resource") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required resource parameter. " + "Please specify one of: cluster, peer_clusters, failure_domain.")), nil } - operation, err := common.RequiredParam[string](request.Params.Arguments, "operation") + operation, err := request.RequireString("operation") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required operation parameter. " + "Please specify one of: list, get, create, update, delete based on the resource type.")), nil @@ -180,7 +179,7 @@ func handleClusterResource(client cmdutils.Client, operation string, request mcp case "list": return handleClusterList(client) case "get": - clusterName, err := common.RequiredParam[string](request.Params.Arguments, "cluster_name") + clusterName, err := request.RequireString("cluster_name") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'cluster_name'. " + "Please provide the name of the cluster to get information for.")), nil @@ -191,7 +190,7 @@ func handleClusterResource(client cmdutils.Client, operation string, request mcp case "update": return updateCluster(client, request) case "delete": - clusterName, err := common.RequiredParam[string](request.Params.Arguments, "cluster_name") + clusterName, err := request.RequireString("cluster_name") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'cluster_name'. " + "Please provide the name of the cluster to delete.")), nil @@ -205,7 +204,7 @@ func handleClusterResource(client cmdutils.Client, operation string, request mcp // Handle peer_clusters resource operations func handlePeerClustersResource(client cmdutils.Client, operation string, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { - clusterName, err := common.RequiredParam[string](request.Params.Arguments, "cluster_name") + clusterName, err := request.RequireString("cluster_name") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'cluster_name'. " + "Please provide the name of the cluster to operate on.")), nil @@ -215,7 +214,7 @@ func handlePeerClustersResource(client cmdutils.Client, operation string, reques case "get": return getPeerClusters(client, clusterName) case "update": - peerClusters, err := common.RequiredParamArray[string](request.Params.Arguments, "peer_cluster_names") + peerClusters, err := request.RequireStringSlice("peer_cluster_names") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'peer_cluster_names'. " + "Please provide an array of peer cluster names to set.")), nil @@ -229,7 +228,7 @@ func handlePeerClustersResource(client cmdutils.Client, operation string, reques // Handle failure_domain resource operations func handleFailureDomainResource(client cmdutils.Client, operation string, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { - clusterName, err := common.RequiredParam[string](request.Params.Arguments, "cluster_name") + clusterName, err := request.RequireString("cluster_name") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'cluster_name'. " + "Please provide the name of the cluster to operate on.")), nil @@ -239,7 +238,7 @@ func handleFailureDomainResource(client cmdutils.Client, operation string, reque case "list": return listFailureDomains(client, clusterName) case "get": - domainName, err := common.RequiredParam[string](request.Params.Arguments, "domain_name") + domainName, err := request.RequireString("domain_name") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'domain_name'. " + "Please provide the name of the failure domain to get.")), nil @@ -250,7 +249,7 @@ func handleFailureDomainResource(client cmdutils.Client, operation string, reque case "update": return updateFailureDomain(client, request) case "delete": - domainName, err := common.RequiredParam[string](request.Params.Arguments, "domain_name") + domainName, err := request.RequireString("domain_name") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'domain_name'. " + "Please provide the name of the failure domain to delete.")), nil @@ -297,7 +296,7 @@ func getClusterData(client cmdutils.Client, clusterName string) (*mcp.CallToolRe // createCluster creates a new Pulsar cluster func createCluster(client cmdutils.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { - clusterName, err := common.RequiredParam[string](request.Params.Arguments, "cluster_name") + clusterName, err := request.RequireString("cluster_name") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'cluster_name'. " + "Please provide the name of the cluster to create.")), nil @@ -308,19 +307,19 @@ func createCluster(client cmdutils.Client, request mcp.CallToolRequest) (*mcp.Ca } // Set optional parameters if provided - if serviceURL, ok := common.OptionalParam[string](request.Params.Arguments, "service_url"); ok { + if serviceURL := request.GetString("service_url", ""); serviceURL != "" { clusterData.ServiceURL = serviceURL } - if serviceURLTls, ok := common.OptionalParam[string](request.Params.Arguments, "service_url_tls"); ok { + if serviceURLTls := request.GetString("service_url_tls", ""); serviceURLTls != "" { clusterData.ServiceURLTls = serviceURLTls } - if brokerServiceURL, ok := common.OptionalParam[string](request.Params.Arguments, "broker_service_url"); ok { + if brokerServiceURL := request.GetString("broker_service_url", ""); brokerServiceURL != "" { clusterData.BrokerServiceURL = brokerServiceURL } - if brokerServiceURLTls, ok := common.OptionalParam[string](request.Params.Arguments, "broker_service_url_tls"); ok { + if brokerServiceURLTls := request.GetString("broker_service_url_tls", ""); brokerServiceURLTls != "" { clusterData.BrokerServiceURLTls = brokerServiceURLTls } - if peerClusters, ok := common.OptionalParamArray[string](request.Params.Arguments, "peer_cluster_names"); ok { + if peerClusters := request.GetStringSlice("peer_cluster_names", []string{}); len(peerClusters) > 0 { clusterData.PeerClusterNames = peerClusters } @@ -334,7 +333,7 @@ func createCluster(client cmdutils.Client, request mcp.CallToolRequest) (*mcp.Ca // updateCluster updates an existing Pulsar cluster func updateCluster(client cmdutils.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { - clusterName, err := common.RequiredParam[string](request.Params.Arguments, "cluster_name") + clusterName, err := request.RequireString("cluster_name") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'cluster_name'. " + "Please provide the name of the cluster to update.")), nil @@ -345,19 +344,19 @@ func updateCluster(client cmdutils.Client, request mcp.CallToolRequest) (*mcp.Ca } // Set optional parameters if provided - if serviceURL, ok := common.OptionalParam[string](request.Params.Arguments, "service_url"); ok { + if serviceURL := request.GetString("service_url", ""); serviceURL != "" { clusterData.ServiceURL = serviceURL } - if serviceURLTls, ok := common.OptionalParam[string](request.Params.Arguments, "service_url_tls"); ok { + if serviceURLTls := request.GetString("service_url_tls", ""); serviceURLTls != "" { clusterData.ServiceURLTls = serviceURLTls } - if brokerServiceURL, ok := common.OptionalParam[string](request.Params.Arguments, "broker_service_url"); ok { + if brokerServiceURL := request.GetString("broker_service_url", ""); brokerServiceURL != "" { clusterData.BrokerServiceURL = brokerServiceURL } - if brokerServiceURLTls, ok := common.OptionalParam[string](request.Params.Arguments, "broker_service_url_tls"); ok { + if brokerServiceURLTls := request.GetString("broker_service_url_tls", ""); brokerServiceURLTls != "" { clusterData.BrokerServiceURLTls = brokerServiceURLTls } - if peerClusters, ok := common.OptionalParamArray[string](request.Params.Arguments, "peer_cluster_names"); ok { + if peerClusters := request.GetStringSlice("peer_cluster_names", []string{}); len(peerClusters) > 0 { clusterData.PeerClusterNames = peerClusters } @@ -439,19 +438,19 @@ func listFailureDomains(client cmdutils.Client, clusterName string) (*mcp.CallTo // createFailureDomain creates a new failure domain in the specified cluster func createFailureDomain(client cmdutils.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { - clusterName, err := common.RequiredParam[string](request.Params.Arguments, "cluster_name") + clusterName, err := request.RequireString("cluster_name") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'cluster_name'. " + "Please provide the name of the cluster.")), nil } - domainName, err := common.RequiredParam[string](request.Params.Arguments, "domain_name") + domainName, err := request.RequireString("domain_name") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'domain_name'. " + "Please provide the name of the failure domain to create.")), nil } - brokers, err := common.RequiredParamArray[string](request.Params.Arguments, "brokers") + brokers, err := request.RequireStringSlice("brokers") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'brokers'. " + "Please provide an array of broker names to include in this failure domain.")), nil @@ -473,19 +472,19 @@ func createFailureDomain(client cmdutils.Client, request mcp.CallToolRequest) (* // updateFailureDomain updates an existing failure domain in the specified cluster func updateFailureDomain(client cmdutils.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { - clusterName, err := common.RequiredParam[string](request.Params.Arguments, "cluster_name") + clusterName, err := request.RequireString("cluster_name") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'cluster_name'. " + "Please provide the name of the cluster.")), nil } - domainName, err := common.RequiredParam[string](request.Params.Arguments, "domain_name") + domainName, err := request.RequireString("domain_name") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'domain_name'. " + "Please provide the name of the failure domain to update.")), nil } - brokers, err := common.RequiredParamArray[string](request.Params.Arguments, "brokers") + brokers, err := request.RequireStringSlice("brokers") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'brokers'. " + "Please provide an array of broker names to include in this failure domain.")), nil diff --git a/pkg/mcp/pulsar_admin_functions_tools.go b/pkg/mcp/pulsar_admin_functions_tools.go index cd7bdab..0a3c798 100644 --- a/pkg/mcp/pulsar_admin_functions_tools.go +++ b/pkg/mcp/pulsar_admin_functions_tools.go @@ -28,7 +28,6 @@ import ( "github.com/mark3labs/mcp-go/mcp" "github.com/mark3labs/mcp-go/server" "github.com/streamnative/pulsarctl/pkg/cmdutils" - "github.com/streamnative/streamnative-mcp-server/pkg/common" ) // PulsarAdminAddFunctionsTools adds a unified function-related tool to the MCP server @@ -167,7 +166,7 @@ func handleFunctionsTool(readOnly bool) func(ctx context.Context, request mcp.Ca client := cmdutils.NewPulsarClientWithAPIVersion(config.V3) // Extract and validate operation parameter - operation, err := common.RequiredParam[string](request.Params.Arguments, "operation") + operation, err := request.RequireString("operation") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'operation': %v", err)), nil } @@ -194,12 +193,12 @@ func handleFunctionsTool(readOnly bool) func(ctx context.Context, request mcp.Ca } // Extract common parameters - tenant, err := common.RequiredParam[string](request.Params.Arguments, "tenant") + tenant, err := request.RequireString("tenant") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'tenant': %v. A tenant is required for all Pulsar Functions operations.", err)), nil } - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'namespace': %v. A namespace is required for all Pulsar Functions operations.", err)), nil } @@ -207,7 +206,7 @@ func handleFunctionsTool(readOnly bool) func(ctx context.Context, request mcp.Ca // For all operations except 'list', name is required var name string if operation != "list" { - name, err = common.RequiredParam[string](request.Params.Arguments, "name") + name, err = request.RequireString("name") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'name' for operation '%s': %v. The function name must be specified for this operation.", operation, err)), nil } @@ -224,15 +223,15 @@ func handleFunctionsTool(readOnly bool) func(ctx context.Context, request mcp.Ca case "stats": return handleFunctionStats(ctx, client, tenant, namespace, name) case "querystate": - key, err := common.RequiredParam[string](request.Params.Arguments, "key") + key, err := request.RequireString("key") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'key' for operation 'querystate': %v. A key is required to look up state in the function's state store.", err)), nil } return handleFunctionQuerystate(ctx, client, tenant, namespace, name, key) case "create": - return handleFunctionCreate(ctx, client, tenant, namespace, name, request.Params.Arguments) + return handleFunctionCreate(ctx, client, tenant, namespace, name, request) case "update": - return handleFunctionUpdate(ctx, client, tenant, namespace, name, request.Params.Arguments) + return handleFunctionUpdate(ctx, client, tenant, namespace, name, request) case "delete": return handleFunctionDelete(ctx, client, tenant, namespace, name) case "start": @@ -242,18 +241,18 @@ func handleFunctionsTool(readOnly bool) func(ctx context.Context, request mcp.Ca case "restart": return handleFunctionRestart(ctx, client, tenant, namespace, name) case "putstate": - key, err := common.RequiredParam[string](request.Params.Arguments, "key") + key, err := request.RequireString("key") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'key' for operation 'putstate': %v. A key is required to store state in the function's state store.", err)), nil } - value, err := common.RequiredParam[string](request.Params.Arguments, "value") + value, err := request.RequireString("value") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'value' for operation 'putstate': %v. A value is required to store state in the function's state store.", err)), nil } return handleFunctionPutstate(ctx, client, tenant, namespace, name, key, value) case "trigger": - topic, _ := common.OptionalParam[string](request.Params.Arguments, "topic") - triggerValue, _ := common.OptionalParam[string](request.Params.Arguments, "triggerValue") + topic := request.GetString("topic", "") + triggerValue := request.GetString("triggerValue", "") return handleFunctionTrigger(ctx, client, tenant, namespace, name, topic, triggerValue) default: // This should never happen due to the valid operations check above @@ -353,25 +352,25 @@ func handleFunctionQuerystate(_ context.Context, client cmdutils.Client, tenant, } // handleFunctionCreate handles creating a new function -func handleFunctionCreate(_ context.Context, client cmdutils.Client, tenant, namespace, name string, arguments map[string]interface{}) (*mcp.CallToolResult, error) { +func handleFunctionCreate(_ context.Context, client cmdutils.Client, tenant, namespace, name string, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Extract required parameters - classname, err := common.RequiredParam[string](arguments, "classname") + classname, err := request.RequireString("classname") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get classname (required for function creation): %v. The classname must specify the fully qualified class implementing the function.", err)), nil } // Extract optional parameters - inputTopics, _ := common.OptionalParamArray[string](arguments, "inputs") - output, _ := common.OptionalParam[string](arguments, "output") - jar, _ := common.OptionalParam[string](arguments, "jar") - py, _ := common.OptionalParam[string](arguments, "py") - goPath, _ := common.OptionalParam[string](arguments, "go") - parallelismFloat, _ := common.OptionalParam[float64](arguments, "parallelism") + inputTopics := request.GetStringSlice("inputs", []string{}) + output := request.GetString("output", "") + jar := request.GetString("jar", "") + py := request.GetString("py", "") + goPath := request.GetString("go", "") + parallelismFloat := request.GetFloat("parallelism", 1) parallelism := int(parallelismFloat) // Get user config if available var userConfigMap map[string]interface{} - userConfigObj, ok := arguments["userConfig"] + userConfigObj, ok := request.GetArguments()["userConfig"] if ok && userConfigObj != nil { if configMap, isMap := userConfigObj.(map[string]interface{}); isMap { userConfigMap = configMap @@ -439,20 +438,20 @@ func handleFunctionCreate(_ context.Context, client cmdutils.Client, tenant, nam } // handleFunctionUpdate handles updating an existing function -func handleFunctionUpdate(_ context.Context, client cmdutils.Client, tenant, namespace, name string, arguments map[string]interface{}) (*mcp.CallToolResult, error) { +func handleFunctionUpdate(_ context.Context, client cmdutils.Client, tenant, namespace, name string, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Extract optional parameters - classname, _ := common.OptionalParam[string](arguments, "classname") - inputTopics, _ := common.OptionalParamArray[string](arguments, "inputs") - output, _ := common.OptionalParam[string](arguments, "output") - jar, _ := common.OptionalParam[string](arguments, "jar") - py, _ := common.OptionalParam[string](arguments, "py") - goPath, _ := common.OptionalParam[string](arguments, "go") - parallelismFloat, _ := common.OptionalParam[float64](arguments, "parallelism") + classname := request.GetString("classname", "") + inputTopics := request.GetStringSlice("inputs", []string{}) + output := request.GetString("output", "") + jar := request.GetString("jar", "") + py := request.GetString("py", "") + goPath := request.GetString("go", "") + parallelismFloat := request.GetFloat("parallelism", 1) parallelism := int(parallelismFloat) // Get user config if available var userConfigMap map[string]interface{} - userConfigObj, ok := arguments["userConfig"] + userConfigObj, ok := request.GetArguments()["userConfig"] if ok && userConfigObj != nil { if configMap, isMap := userConfigObj.(map[string]interface{}); isMap { userConfigMap = configMap diff --git a/pkg/mcp/pulsar_admin_functions_worker_tools.go b/pkg/mcp/pulsar_admin_functions_worker_tools.go index bf84f49..fa7a0fd 100644 --- a/pkg/mcp/pulsar_admin_functions_worker_tools.go +++ b/pkg/mcp/pulsar_admin_functions_worker_tools.go @@ -26,7 +26,6 @@ import ( "github.com/mark3labs/mcp-go/mcp" "github.com/mark3labs/mcp-go/server" "github.com/streamnative/pulsarctl/pkg/cmdutils" - "github.com/streamnative/streamnative-mcp-server/pkg/common" "github.com/streamnative/streamnative-mcp-server/pkg/pulsar" ) @@ -67,7 +66,7 @@ func handleFunctionsWorkerTool(_ bool) func(context.Context, mcp.CallToolRequest admin := pulsar.AdminClient // Get required resource parameter - resource, err := common.RequiredParam[string](request.Params.Arguments, "resource") + resource, err := request.RequireString("resource") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'resource'. " + "Please specify one of: function_stats, monitoring_metrics, cluster, cluster_leader, function_assignments.")), nil diff --git a/pkg/mcp/pulsar_admin_namespace_policy_tools.go b/pkg/mcp/pulsar_admin_namespace_policy_tools.go index 1372533..13a018e 100644 --- a/pkg/mcp/pulsar_admin_namespace_policy_tools.go +++ b/pkg/mcp/pulsar_admin_namespace_policy_tools.go @@ -30,7 +30,6 @@ import ( "github.com/mark3labs/mcp-go/mcp" "github.com/mark3labs/mcp-go/server" pulsarctlutils "github.com/streamnative/pulsarctl/pkg/ctl/utils" - "github.com/streamnative/streamnative-mcp-server/pkg/common" "github.com/streamnative/streamnative-mcp-server/pkg/pulsar" ) @@ -332,7 +331,7 @@ func handleNamespaceGetPolicies(_ context.Context, request mcp.CallToolRequest) return mcp.NewToolResultError(fmt.Sprintf("Failed to get admin client: %v", err)), nil } - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace name: %v", err)), nil } @@ -360,12 +359,12 @@ func handleSetMessageTTL(_ context.Context, request mcp.CallToolRequest) (*mcp.C return mcp.NewToolResultError(fmt.Sprintf("Failed to get admin client: %v", err)), nil } - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace name: %v", err)), nil } - ttlStr, err := common.RequiredParam[string](request.Params.Arguments, "ttl") + ttlStr, err := request.RequireString("ttl") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get TTL: %v", err)), nil } @@ -392,21 +391,21 @@ func handleSetRetention(_ context.Context, request mcp.CallToolRequest) (*mcp.Ca return mcp.NewToolResultError(fmt.Sprintf("Failed to get admin client: %v", err)), nil } - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace name: %v", err)), nil } - timeStr, hasTime := common.OptionalParam[string](request.Params.Arguments, "time") - sizeStr, hasSize := common.OptionalParam[string](request.Params.Arguments, "size") + timeStr := request.GetString("time", "") + sizeStr := request.GetString("size", "") - if !hasTime && !hasSize { + if timeStr == "" && sizeStr == "" { return mcp.NewToolResultError("At least one of 'time' or 'size' must be specified"), nil } // Parse retention time var retentionTimeInMin int - if hasTime { + if timeStr != "" { // Parse relative time in seconds from the input string retentionTime, err := pulsarctlutils.ParseRelativeTimeInSeconds(timeStr) if err != nil { @@ -425,7 +424,7 @@ func handleSetRetention(_ context.Context, request mcp.CallToolRequest) (*mcp.Ca // Parse retention size var retentionSizeInMB int - if hasSize { + if sizeStr != "" { if sizeStr == "-1" { retentionSizeInMB = -1 // Infinite size retention } else { @@ -471,17 +470,17 @@ func handleGrantPermission(_ context.Context, request mcp.CallToolRequest) (*mcp return mcp.NewToolResultError(fmt.Sprintf("Failed to get admin client: %v", err)), nil } - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace name: %v", err)), nil } - role, err := common.RequiredParam[string](request.Params.Arguments, "role") + role, err := request.RequireString("role") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get role: %v", err)), nil } - actions, err := common.RequiredParamArray[string](request.Params.Arguments, "actions") + actions, err := request.RequireStringSlice("actions") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get actions: %v", err)), nil } @@ -525,12 +524,12 @@ func handleRevokePermission(_ context.Context, request mcp.CallToolRequest) (*mc return mcp.NewToolResultError(fmt.Sprintf("Failed to get admin client: %v", err)), nil } - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace name: %v", err)), nil } - role, err := common.RequiredParam[string](request.Params.Arguments, "role") + role, err := request.RequireString("role") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get role: %v", err)), nil } @@ -557,12 +556,12 @@ func handleSetReplicationClusters(_ context.Context, request mcp.CallToolRequest return mcp.NewToolResultError(fmt.Sprintf("Failed to get admin client: %v", err)), nil } - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace name: %v", err)), nil } - clusters, err := common.RequiredParamArray[string](request.Params.Arguments, "clusters") + clusters, err := request.RequireStringSlice("clusters") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get clusters: %v", err)), nil } @@ -590,17 +589,17 @@ func handleSetBacklogQuota(_ context.Context, request mcp.CallToolRequest) (*mcp return mcp.NewToolResultError(fmt.Sprintf("Failed to get admin client: %v", err)), nil } - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace name: %v", err)), nil } - limitSizeStr, err := common.RequiredParam[string](request.Params.Arguments, "limit-size") + limitSizeStr, err := request.RequireString("limit-size") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get limit size: %v", err)), nil } - policyStr, err := common.RequiredParam[string](request.Params.Arguments, "policy") + policyStr, err := request.RequireString("policy") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get policy: %v", err)), nil } @@ -612,9 +611,9 @@ func handleSetBacklogQuota(_ context.Context, request mcp.CallToolRequest) (*mcp } // Parse time limit (optional) - limitTimeStr, hasLimitTime := common.OptionalParam[string](request.Params.Arguments, "limit-time") + limitTimeStr := request.GetString("limit-time", "") var limitTime int64 = -1 // Default to -1 (infinite) - if hasLimitTime && limitTimeStr != "" { + if limitTimeStr != "" { limitTimeVal, err := strconv.ParseInt(limitTimeStr, 10, 64) if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Invalid time limit format: %v", err)), nil @@ -636,9 +635,9 @@ func handleSetBacklogQuota(_ context.Context, request mcp.CallToolRequest) (*mcp } // Parse quota type (optional) - quotaTypeStr, hasQuotaType := common.OptionalParam[string](request.Params.Arguments, "type") + quotaTypeStr := request.GetString("type", "") quotaType := utils.DestinationStorage // Default - if hasQuotaType && quotaTypeStr != "" { + if quotaTypeStr != "" { parsedType, err := utils.ParseBacklogQuotaType(quotaTypeStr) if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Invalid backlog quota type: %v", err)), nil @@ -664,7 +663,7 @@ func handleRemoveBacklogQuota(_ context.Context, request mcp.CallToolRequest) (* return mcp.NewToolResultError(fmt.Sprintf("Failed to get admin client: %v", err)), nil } - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace name: %v", err)), nil } @@ -686,7 +685,7 @@ func handleSetTopicAutoCreation(_ context.Context, request mcp.CallToolRequest) return mcp.NewToolResultError(fmt.Sprintf("Failed to get admin client: %v", err)), nil } - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace name: %v", err)), nil } @@ -698,9 +697,9 @@ func handleSetTopicAutoCreation(_ context.Context, request mcp.CallToolRequest) } // Check if disabled - disableStr, hasDisable := common.OptionalParam[string](request.Params.Arguments, "disable") + disableStr := request.GetString("disable", "") disable := false - if hasDisable && disableStr == "true" { + if disableStr == "true" { disable = true } @@ -712,8 +711,8 @@ func handleSetTopicAutoCreation(_ context.Context, request mcp.CallToolRequest) // Only set topic type and partitions if not disabled if !disable { // Get topic type (optional) - topicTypeStr, hasType := common.OptionalParam[string](request.Params.Arguments, "type") - if hasType && topicTypeStr != "" { + topicTypeStr := request.GetString("type", "") + if topicTypeStr != "" { parsedType, err := utils.ParseTopicType(topicTypeStr) if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Invalid topic type: %v", err)), nil @@ -722,8 +721,8 @@ func handleSetTopicAutoCreation(_ context.Context, request mcp.CallToolRequest) } // Get partitions (optional) - partitionsStr, hasPartitions := common.OptionalParam[string](request.Params.Arguments, "partitions") - if hasPartitions && partitionsStr != "" { + partitionsStr := request.GetString("partitions", "") + if partitionsStr != "" { partitions, err := strconv.Atoi(partitionsStr) if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Invalid partitions value: %v", err)), nil @@ -749,7 +748,7 @@ func handleRemoveTopicAutoCreation(_ context.Context, request mcp.CallToolReques return mcp.NewToolResultError(fmt.Sprintf("Failed to get admin client: %v", err)), nil } - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace name: %v", err)), nil } @@ -777,7 +776,7 @@ func handleSetSchemaValidationEnforced(_ context.Context, request mcp.CallToolRe return mcp.NewToolResultError(fmt.Sprintf("Failed to get admin client: %v", err)), nil } - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace name: %v", err)), nil } @@ -789,9 +788,9 @@ func handleSetSchemaValidationEnforced(_ context.Context, request mcp.CallToolRe } // Check if disabled - disableStr, hasDisable := common.OptionalParam[string](request.Params.Arguments, "disable") + disableStr := request.GetString("disable", "") disable := false - if hasDisable && disableStr == "true" { + if disableStr == "true" { disable = true } @@ -816,12 +815,12 @@ func handleSetSchemaAutoUpdateStrategy(_ context.Context, request mcp.CallToolRe return mcp.NewToolResultError(fmt.Sprintf("Failed to get admin client: %v", err)), nil } - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace name: %v", err)), nil } - strategyStr, err := common.RequiredParam[string](request.Params.Arguments, "compatibility") + strategyStr, err := request.RequireString("compatibility") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get compatibility strategy: %v", err)), nil } @@ -857,7 +856,7 @@ func handleSetIsAllowAutoUpdateSchema(_ context.Context, request mcp.CallToolReq return mcp.NewToolResultError(fmt.Sprintf("Failed to get admin client: %v", err)), nil } - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace name: %v", err)), nil } @@ -869,20 +868,20 @@ func handleSetIsAllowAutoUpdateSchema(_ context.Context, request mcp.CallToolReq } // Check if enabled or disabled - enableStr, hasEnable := common.OptionalParam[string](request.Params.Arguments, "enable") - disableStr, hasDisable := common.OptionalParam[string](request.Params.Arguments, "disable") + enableStr := request.GetString("enable", "") + disableStr := request.GetString("disable", "") - if (hasEnable && enableStr == "true") && (hasDisable && disableStr == "true") { + if (enableStr == "true") && (disableStr == "true") { return mcp.NewToolResultError("Specify only one of 'enable' or 'disable'"), nil } var isAllowUpdateSchema bool //nolint:gocritic - if hasEnable && enableStr == "true" { + if enableStr == "true" { isAllowUpdateSchema = true - } else if hasDisable && disableStr == "true" { + } else if disableStr == "true" { isAllowUpdateSchema = false - } else if !hasEnable && !hasDisable { + } else if enableStr == "" && disableStr == "" { return mcp.NewToolResultError("You must specify either 'enable=true' or 'disable=true'"), nil } @@ -907,12 +906,12 @@ func handleSetOffloadThreshold(_ context.Context, request mcp.CallToolRequest) ( return mcp.NewToolResultError(fmt.Sprintf("Failed to get admin client: %v", err)), nil } - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace name: %v", err)), nil } - thresholdStr, err := common.RequiredParam[string](request.Params.Arguments, "threshold") + thresholdStr, err := request.RequireString("threshold") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get threshold: %v", err)), nil } @@ -948,12 +947,12 @@ func handleSetOffloadDeletionLag(_ context.Context, request mcp.CallToolRequest) return mcp.NewToolResultError(fmt.Sprintf("Failed to get admin client: %v", err)), nil } - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace name: %v", err)), nil } - lagStr, err := common.RequiredParam[string](request.Params.Arguments, "lag") + lagStr, err := request.RequireString("lag") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get lag: %v", err)), nil } @@ -992,7 +991,7 @@ func handleClearOffloadDeletionLag(_ context.Context, request mcp.CallToolReques return mcp.NewToolResultError(fmt.Sprintf("Failed to get admin client: %v", err)), nil } - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace name: %v", err)), nil } @@ -1022,12 +1021,12 @@ func handleSetCompactionThreshold(_ context.Context, request mcp.CallToolRequest return mcp.NewToolResultError(fmt.Sprintf("Failed to get admin client: %v", err)), nil } - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace name: %v", err)), nil } - thresholdStr, err := common.RequiredParam[string](request.Params.Arguments, "threshold") + thresholdStr, err := request.RequireString("threshold") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get threshold: %v", err)), nil } @@ -1063,12 +1062,12 @@ func handleSetMaxProducersPerTopic(_ context.Context, request mcp.CallToolReques return mcp.NewToolResultError(fmt.Sprintf("Failed to get admin client: %v", err)), nil } - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace name: %v", err)), nil } - maxStr, err := common.RequiredParam[string](request.Params.Arguments, "max") + maxStr, err := request.RequireString("max") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get max value: %v", err)), nil } @@ -1108,12 +1107,12 @@ func handleSetMaxConsumersPerTopic(_ context.Context, request mcp.CallToolReques return mcp.NewToolResultError(fmt.Sprintf("Failed to get admin client: %v", err)), nil } - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace name: %v", err)), nil } - maxStr, err := common.RequiredParam[string](request.Params.Arguments, "max") + maxStr, err := request.RequireString("max") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get max value: %v", err)), nil } @@ -1153,12 +1152,12 @@ func handleSetMaxConsumersPerSubscription(_ context.Context, request mcp.CallToo return mcp.NewToolResultError(fmt.Sprintf("Failed to get admin client: %v", err)), nil } - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace name: %v", err)), nil } - maxStr, err := common.RequiredParam[string](request.Params.Arguments, "max") + maxStr, err := request.RequireString("max") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get max value: %v", err)), nil } @@ -1198,12 +1197,12 @@ func handleSetAntiAffinityGroup(_ context.Context, request mcp.CallToolRequest) return mcp.NewToolResultError(fmt.Sprintf("Failed to get admin client: %v", err)), nil } - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace name: %v", err)), nil } - group, err := common.RequiredParam[string](request.Params.Arguments, "group") + group, err := request.RequireString("group") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get anti-affinity group: %v", err)), nil } @@ -1227,7 +1226,7 @@ func handleDeleteAntiAffinityGroup(_ context.Context, request mcp.CallToolReques return mcp.NewToolResultError(fmt.Sprintf("Failed to get admin client: %v", err)), nil } - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace name: %v", err)), nil } @@ -1251,22 +1250,22 @@ func handleSetPersistence(_ context.Context, request mcp.CallToolRequest) (*mcp. return mcp.NewToolResultError(fmt.Sprintf("Failed to get admin client: %v", err)), nil } - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace name: %v", err)), nil } - ensembleSizeStr, err := common.RequiredParam[string](request.Params.Arguments, "ensemble-size") + ensembleSizeStr, err := request.RequireString("ensemble-size") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get ensemble size: %v", err)), nil } - writeQuorumSizeStr, err := common.RequiredParam[string](request.Params.Arguments, "write-quorum-size") + writeQuorumSizeStr, err := request.RequireString("write-quorum-size") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get write quorum size: %v", err)), nil } - ackQuorumSizeStr, err := common.RequiredParam[string](request.Params.Arguments, "ack-quorum-size") + ackQuorumSizeStr, err := request.RequireString("ack-quorum-size") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get ack quorum size: %v", err)), nil } @@ -1294,8 +1293,8 @@ func handleSetPersistence(_ context.Context, request mcp.CallToolRequest) (*mcp. // Parse optional rate parameter markDeleteMaxRate := 0.0 - markDeleteMaxRateStr, hasRate := common.OptionalParam[string](request.Params.Arguments, "ml-mark-delete-max-rate") - if hasRate && markDeleteMaxRateStr != "" { + markDeleteMaxRateStr := request.GetString("ml-mark-delete-max-rate", "") + if markDeleteMaxRateStr != "" { rate, err := strconv.ParseFloat(markDeleteMaxRateStr, 64) if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Invalid mark delete max rate, must be a number: %v", err)), nil @@ -1325,13 +1324,13 @@ func handleSetDeduplication(_ context.Context, request mcp.CallToolRequest) (*mc return mcp.NewToolResultError(fmt.Sprintf("Failed to get admin client: %v", err)), nil } - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace name: %v", err)), nil } // Get enable flag, default to false if not specified - enable, _ := common.OptionalParam[string](request.Params.Arguments, "enable") + enable := request.GetString("enable", "") enableBool := false if enable == "true" { enableBool = true @@ -1356,13 +1355,13 @@ func handleSetEncryptionRequired(_ context.Context, request mcp.CallToolRequest) return mcp.NewToolResultError(fmt.Sprintf("Failed to get admin client: %v", err)), nil } - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace name: %v", err)), nil } // Get disable flag, default to false if not specified - disable, _ := common.OptionalParam[string](request.Params.Arguments, "disable") + disable := request.GetString("disable", "") disableFlag := disable == "true" // Get namespace name @@ -1395,12 +1394,12 @@ func handleSetSubscriptionAuthMode(_ context.Context, request mcp.CallToolReques return mcp.NewToolResultError(fmt.Sprintf("Failed to get admin client: %v", err)), nil } - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace name: %v", err)), nil } - mode, err := common.RequiredParam[string](request.Params.Arguments, "mode") + mode, err := request.RequireString("mode") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get subscription auth mode: %v", err)), nil } @@ -1437,17 +1436,17 @@ func handleGrantSubscriptionPermission(_ context.Context, request mcp.CallToolRe return mcp.NewToolResultError(fmt.Sprintf("Failed to get admin client: %v", err)), nil } - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace name: %v", err)), nil } - subscription, err := common.RequiredParam[string](request.Params.Arguments, "subscription") + subscription, err := request.RequireString("subscription") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get subscription name: %v", err)), nil } - roles, err := common.RequiredParamArray[string](request.Params.Arguments, "roles") + roles, err := request.RequireStringSlice("roles") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get roles: %v", err)), nil } @@ -1482,17 +1481,17 @@ func handleRevokeSubscriptionPermission(_ context.Context, request mcp.CallToolR return mcp.NewToolResultError(fmt.Sprintf("Failed to get admin client: %v", err)), nil } - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace name: %v", err)), nil } - subscription, err := common.RequiredParam[string](request.Params.Arguments, "subscription") + subscription, err := request.RequireString("subscription") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get subscription name: %v", err)), nil } - role, err := common.RequiredParam[string](request.Params.Arguments, "role") + role, err := request.RequireString("role") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get role: %v", err)), nil } @@ -1523,13 +1522,13 @@ func handleSetDispatchRate(_ context.Context, request mcp.CallToolRequest) (*mcp return mcp.NewToolResultError(fmt.Sprintf("Failed to get admin client: %v", err)), nil } - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace name: %v", err)), nil } // Get rate parameters - msgRateStr, _ := common.OptionalParam[string](request.Params.Arguments, "dispatchThrottlingRateInMsg") + msgRateStr := request.GetString("dispatchThrottlingRateInMsg", "") msgRate := -1 // Default value if msgRateStr != "" { parsedMsgRate, err := strconv.Atoi(msgRateStr) @@ -1539,7 +1538,7 @@ func handleSetDispatchRate(_ context.Context, request mcp.CallToolRequest) (*mcp msgRate = parsedMsgRate } - byteRateStr, _ := common.OptionalParam[string](request.Params.Arguments, "dispatchThrottlingRateInByte") + byteRateStr := request.GetString("dispatchThrottlingRateInByte", "") byteRate := int64(-1) // Default value if byteRateStr != "" { parsedByteRate, err := strconv.ParseInt(byteRateStr, 10, 64) @@ -1549,7 +1548,7 @@ func handleSetDispatchRate(_ context.Context, request mcp.CallToolRequest) (*mcp byteRate = parsedByteRate } - ratePeriodStr, _ := common.OptionalParam[string](request.Params.Arguments, "ratePeriodInSecond") + ratePeriodStr := request.GetString("ratePeriodInSecond", "") ratePeriod := 1 // Default value if ratePeriodStr != "" { parsedRatePeriod, err := strconv.Atoi(ratePeriodStr) @@ -1591,13 +1590,13 @@ func handleSetReplicatorDispatchRate(_ context.Context, request mcp.CallToolRequ return mcp.NewToolResultError(fmt.Sprintf("Failed to get admin client: %v", err)), nil } - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace name: %v", err)), nil } // Get rate parameters - msgRateStr, _ := common.OptionalParam[string](request.Params.Arguments, "dispatchThrottlingRateInMsg") + msgRateStr := request.GetString("dispatchThrottlingRateInMsg", "") msgRate := -1 // Default value if msgRateStr != "" { parsedMsgRate, err := strconv.Atoi(msgRateStr) @@ -1607,7 +1606,7 @@ func handleSetReplicatorDispatchRate(_ context.Context, request mcp.CallToolRequ msgRate = parsedMsgRate } - byteRateStr, _ := common.OptionalParam[string](request.Params.Arguments, "dispatchThrottlingRateInByte") + byteRateStr := request.GetString("dispatchThrottlingRateInByte", "") byteRate := int64(-1) // Default value if byteRateStr != "" { parsedByteRate, err := strconv.ParseInt(byteRateStr, 10, 64) @@ -1617,7 +1616,7 @@ func handleSetReplicatorDispatchRate(_ context.Context, request mcp.CallToolRequ byteRate = parsedByteRate } - ratePeriodStr, _ := common.OptionalParam[string](request.Params.Arguments, "ratePeriodInSecond") + ratePeriodStr := request.GetString("ratePeriodInSecond", "") ratePeriod := 1 // Default value if ratePeriodStr != "" { parsedRatePeriod, err := strconv.Atoi(ratePeriodStr) @@ -1659,13 +1658,13 @@ func handleSetSubscribeRate(_ context.Context, request mcp.CallToolRequest) (*mc return mcp.NewToolResultError(fmt.Sprintf("Failed to get admin client: %v", err)), nil } - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace name: %v", err)), nil } // Get rate parameters - subRateStr, _ := common.OptionalParam[string](request.Params.Arguments, "subscribeThrottlingRatePerConsumer") + subRateStr := request.GetString("subscribeThrottlingRatePerConsumer", "") subRate := -1 // Default value if subRateStr != "" { parsedSubRate, err := strconv.Atoi(subRateStr) @@ -1675,7 +1674,7 @@ func handleSetSubscribeRate(_ context.Context, request mcp.CallToolRequest) (*mc subRate = parsedSubRate } - periodStr, _ := common.OptionalParam[string](request.Params.Arguments, "ratePeriodInSecond") + periodStr := request.GetString("ratePeriodInSecond", "") period := 30 // Default value if periodStr != "" { parsedPeriod, err := strconv.Atoi(periodStr) @@ -1714,13 +1713,13 @@ func handleSetSubscriptionDispatchRate(_ context.Context, request mcp.CallToolRe return mcp.NewToolResultError(fmt.Sprintf("Failed to get admin client: %v", err)), nil } - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace name: %v", err)), nil } // Get rate parameters - msgRateStr, _ := common.OptionalParam[string](request.Params.Arguments, "dispatchThrottlingRateInMsg") + msgRateStr := request.GetString("dispatchThrottlingRateInMsg", "") msgRate := -1 // Default value if msgRateStr != "" { parsedMsgRate, err := strconv.Atoi(msgRateStr) @@ -1730,7 +1729,7 @@ func handleSetSubscriptionDispatchRate(_ context.Context, request mcp.CallToolRe msgRate = parsedMsgRate } - byteRateStr, _ := common.OptionalParam[string](request.Params.Arguments, "dispatchThrottlingRateInByte") + byteRateStr := request.GetString("dispatchThrottlingRateInByte", "") byteRate := int64(-1) // Default value if byteRateStr != "" { parsedByteRate, err := strconv.ParseInt(byteRateStr, 10, 64) @@ -1740,7 +1739,7 @@ func handleSetSubscriptionDispatchRate(_ context.Context, request mcp.CallToolRe byteRate = parsedByteRate } - periodStr, _ := common.OptionalParam[string](request.Params.Arguments, "ratePeriodInSecond") + periodStr := request.GetString("ratePeriodInSecond", "") period := 1 // Default value if periodStr != "" { parsedPeriod, err := strconv.Atoi(periodStr) @@ -1782,7 +1781,7 @@ func handleSetPublishRate(_ context.Context, request mcp.CallToolRequest) (*mcp. return mcp.NewToolResultError(fmt.Sprintf("Failed to get admin client: %v", err)), nil } - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace name: %v", err)), nil } @@ -1800,8 +1799,8 @@ func handleSetPublishRate(_ context.Context, request mcp.CallToolRequest) (*mcp. } // Get message rate if provided - msgRateStr, hasMsgRate := common.OptionalParam[string](request.Params.Arguments, "publishThrottlingRateInMsg") - if hasMsgRate && msgRateStr != "" { + msgRateStr := request.GetString("publishThrottlingRateInMsg", "") + if msgRateStr != "" { msgRate, err := strconv.Atoi(msgRateStr) if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Invalid message rate: %v", err)), nil @@ -1810,8 +1809,8 @@ func handleSetPublishRate(_ context.Context, request mcp.CallToolRequest) (*mcp. } // Get byte rate if provided - byteRateStr, hasByteRate := common.OptionalParam[string](request.Params.Arguments, "publishThrottlingRateInByte") - if hasByteRate && byteRateStr != "" { + byteRateStr := request.GetString("publishThrottlingRateInByte", "") + if byteRateStr != "" { byteRate, err := strconv.ParseInt(byteRateStr, 10, 64) if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Invalid byte rate: %v", err)), nil @@ -1832,12 +1831,12 @@ func handleSetPublishRate(_ context.Context, request mcp.CallToolRequest) (*mcp. // handleNamespaceSetPolicy handles setting policies for a namespace using the unified tool func handleNamespaceSetPolicy(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { - _, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + _, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace name: %v", err)), nil } - policyType, err := common.RequiredParam[string](request.Params.Arguments, "policy") + policyType, err := request.RequireString("policy") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get policy type: %v", err)), nil } @@ -1903,12 +1902,12 @@ func handleNamespaceSetPolicy(ctx context.Context, request mcp.CallToolRequest) // handleNamespaceRemovePolicy handles removing policies from a namespace using the unified tool func handleNamespaceRemovePolicy(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { - _, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + _, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace name: %v", err)), nil } - policyType, err := common.RequiredParam[string](request.Params.Arguments, "policy") + policyType, err := request.RequireString("policy") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get policy type: %v", err)), nil } diff --git a/pkg/mcp/pulsar_admin_namespace_tools.go b/pkg/mcp/pulsar_admin_namespace_tools.go index 4e35c9d..5f7bb2d 100644 --- a/pkg/mcp/pulsar_admin_namespace_tools.go +++ b/pkg/mcp/pulsar_admin_namespace_tools.go @@ -28,7 +28,6 @@ import ( "github.com/mark3labs/mcp-go/mcp" "github.com/mark3labs/mcp-go/server" "github.com/streamnative/pulsarctl/pkg/cmdutils" - "github.com/streamnative/streamnative-mcp-server/pkg/common" "github.com/streamnative/streamnative-mcp-server/pkg/pulsar" ) @@ -94,7 +93,7 @@ func PulsarAdminAddNamespaceTools(s *server.MCPServer, readOnly bool, features [ func handleNamespace(readOnly bool) func(context.Context, mcp.CallToolRequest) (*mcp.CallToolResult, error) { return func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get operation parameter - operation, err := common.RequiredParam[string](request.Params.Arguments, "operation") + operation, err := request.RequireString("operation") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get operation: %v", err)), nil } @@ -143,7 +142,7 @@ func handleNamespace(readOnly bool) func(context.Context, mcp.CallToolRequest) ( // handleNamespaceList handles listing namespaces for a tenant func handleNamespaceList(_ context.Context, client cmdutils.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { - tenant, err := common.RequiredParam[string](request.Params.Arguments, "tenant") + tenant, err := request.RequireString("tenant") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get tenant name: %v", err)), nil } @@ -165,7 +164,7 @@ func handleNamespaceList(_ context.Context, client cmdutils.Client, request mcp. // handleNamespaceGetTopics handles getting topics for a namespace func handleNamespaceGetTopics(_ context.Context, client cmdutils.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace name: %v", err)), nil } @@ -187,15 +186,15 @@ func handleNamespaceGetTopics(_ context.Context, client cmdutils.Client, request // handleNamespaceCreate handles creating a new namespace func handleNamespaceCreate(_ context.Context, client cmdutils.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace name: %v", err)), nil } // Get optional parameters - bundlesStr, hasBundles := common.OptionalParam[string](request.Params.Arguments, "bundles") + bundlesStr := request.GetString("bundles", "") bundles := 0 - if hasBundles && bundlesStr != "" { + if bundlesStr != "" { bundlesInt, err := strconv.Atoi(bundlesStr) if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Invalid bundles value, must be an integer: %v", err)), nil @@ -203,13 +202,13 @@ func handleNamespaceCreate(_ context.Context, client cmdutils.Client, request mc bundles = bundlesInt } - clusters, _ := common.OptionalParamArray[string](request.Params.Arguments, "clusters") + clusters := request.GetStringSlice("clusters", []string{}) // Prepare policies policies := utils.NewDefaultPolicies() // Set bundles if provided - if hasBundles && bundles > 0 { + if bundles > 0 { if bundles < 0 || bundles > int(^uint32(0)) { // MaxInt32 return mcp.NewToolResultError( fmt.Sprintf("Invalid number of bundles. Number of bundles has to be in the range of (0, %d].", int(^uint32(0))), @@ -239,7 +238,7 @@ func handleNamespaceCreate(_ context.Context, client cmdutils.Client, request mc // handleNamespaceDelete handles deleting a namespace func handleNamespaceDelete(_ context.Context, client cmdutils.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace name: %v", err)), nil } @@ -255,15 +254,15 @@ func handleNamespaceDelete(_ context.Context, client cmdutils.Client, request mc // handleClearBacklog handles clearing the backlog for all topics in a namespace func handleClearBacklog(_ context.Context, client cmdutils.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace name: %v", err)), nil } // Get optional parameters - subscription, _ := common.OptionalParam[string](request.Params.Arguments, "subscription") - bundle, _ := common.OptionalParam[string](request.Params.Arguments, "bundle") - force, _ := common.OptionalParam[string](request.Params.Arguments, "force") + subscription := request.GetString("subscription", "") + bundle := request.GetString("bundle", "") + force := request.GetString("force", "") forceFlag := force == "true" // If not forced, return an error requiring explicit force flag @@ -305,18 +304,18 @@ func handleClearBacklog(_ context.Context, client cmdutils.Client, request mcp.C // handleUnsubscribe handles unsubscribing the specified subscription for all topics of a namespace func handleUnsubscribe(_ context.Context, client cmdutils.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace name: %v", err)), nil } - subscription, err := common.RequiredParam[string](request.Params.Arguments, "subscription") + subscription, err := request.RequireString("subscription") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get subscription name: %v", err)), nil } // Get optional bundle - bundle, _ := common.OptionalParam[string](request.Params.Arguments, "bundle") + bundle := request.GetString("bundle", "") // Get namespace name ns, err := utils.GetNamespaceName(namespace) @@ -351,13 +350,13 @@ func handleUnsubscribe(_ context.Context, client cmdutils.Client, request mcp.Ca // handleUnload handles unloading a namespace from the current serving broker func handleUnload(_ context.Context, client cmdutils.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace name: %v", err)), nil } // Get optional bundle - bundle, _ := common.OptionalParam[string](request.Params.Arguments, "bundle") + bundle := request.GetString("bundle", "") // Unload namespace var unloadErr error @@ -384,19 +383,18 @@ func handleUnload(_ context.Context, client cmdutils.Client, request mcp.CallToo // handleSplitBundle handles splitting a namespace bundle func handleSplitBundle(_ context.Context, client cmdutils.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace name: %v", err)), nil } - bundle, err := common.RequiredParam[string](request.Params.Arguments, "bundle") + bundle, err := request.RequireString("bundle") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get bundle: %v", err)), nil } // Get optional unload flag - unloadStr, _ := common.OptionalParam[string](request.Params.Arguments, "unload") - unload := unloadStr == "true" + unload := request.GetString("unload", "") == "true" // Split namespace bundle err = client.Namespaces().SplitNamespaceBundle(namespace, bundle, unload) diff --git a/pkg/mcp/pulsar_admin_nsisolationpolicy_tools.go b/pkg/mcp/pulsar_admin_nsisolationpolicy_tools.go index 3da9cff..68bc744 100644 --- a/pkg/mcp/pulsar_admin_nsisolationpolicy_tools.go +++ b/pkg/mcp/pulsar_admin_nsisolationpolicy_tools.go @@ -116,17 +116,17 @@ func handleNsIsolationPolicy(readOnly bool) func(context.Context, mcp.CallToolRe } // Get required parameters - resource, err := common.RequiredParam[string](request.Params.Arguments, "resource") + resource, err := request.RequireString("resource") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get resource: %v", err)), nil } - operation, err := common.RequiredParam[string](request.Params.Arguments, "operation") + operation, err := request.RequireString("operation") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get operation: %v", err)), nil } - cluster, err := common.RequiredParam[string](request.Params.Arguments, "cluster") + cluster, err := request.RequireString("cluster") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get cluster name: %v", err)), nil } @@ -158,7 +158,7 @@ func handleNsIsolationPolicy(readOnly bool) func(context.Context, mcp.CallToolRe func handlePolicyResource(client cmdutils.Client, operation, cluster string, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { switch operation { case "get": - name, err := common.RequiredParam[string](request.Params.Arguments, "name") + name, err := request.RequireString("name") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'name' for policy.get: %v", err)), nil } @@ -193,7 +193,7 @@ func handlePolicyResource(client cmdutils.Client, operation, cluster string, req return mcp.NewToolResultText(string(policiesJSON)), nil case "delete": - name, err := common.RequiredParam[string](request.Params.Arguments, "name") + name, err := request.RequireString("name") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'name' for policy.delete: %v", err)), nil } @@ -207,26 +207,30 @@ func handlePolicyResource(client cmdutils.Client, operation, cluster string, req return mcp.NewToolResultText(fmt.Sprintf("Delete namespace isolation policy %s successfully", name)), nil case "set": - name, err := common.RequiredParam[string](request.Params.Arguments, "name") + name, err := request.RequireString("name") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'name' for policy.set: %v", err)), nil } - namespaces, err := getRequiredParamArray[string](request.Params.Arguments, "namespaces") + namespaces, err := request.RequireStringSlice("namespaces") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'namespaces' for policy.set: %v", err)), nil } - primary, err := getRequiredParamArray[string](request.Params.Arguments, "primary") + primary, err := request.RequireStringSlice("primary") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'primary' for policy.set: %v", err)), nil } - secondary, _ := common.OptionalParamArray[string](request.Params.Arguments, "secondary") - autoFailoverPolicyType, _ := common.OptionalParam[string](request.Params.Arguments, "autoFailoverPolicyType") + secondary := request.GetStringSlice("secondary", []string{}) + autoFailoverPolicyType := request.GetString("autoFailoverPolicyType", "") // Parse autoFailoverPolicyParams as a map - autoFailoverPolicyParamsRaw, _ := common.OptionalParam[map[string]interface{}](request.Params.Arguments, "autoFailoverPolicyParams") + autoFailoverPolicyParamsRaw, ok := common.OptionalParamObject(request.GetArguments(), "autoFailoverPolicyParams") + if !ok { + return mcp.NewToolResultError("Failed to extract autoFailoverPolicyParams"), nil + } + autoFailoverPolicyParams := make(map[string]string) for k, v := range autoFailoverPolicyParamsRaw { if strVal, ok := v.(string); ok { @@ -258,7 +262,7 @@ func handlePolicyResource(client cmdutils.Client, operation, cluster string, req func handleBrokerResource(client cmdutils.Client, operation, cluster string, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { switch operation { case "get": - name, err := common.RequiredParam[string](request.Params.Arguments, "name") + name, err := request.RequireString("name") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'name' for broker.get: %v", err)), nil } @@ -304,27 +308,3 @@ func handleNsIsolationBrokersResource(client cmdutils.Client, operation, cluster return mcp.NewToolResultError(fmt.Sprintf("Invalid operation for resource 'brokers': %s. Available operations: list", operation)), nil } } - -// getRequiredParamArray is a helper function to get a required array parameter with a specific type -func getRequiredParamArray[T any](args map[string]interface{}, paramName string) ([]T, error) { - value, ok := args[paramName] - if !ok { - return nil, fmt.Errorf("missing required parameter: %s", paramName) - } - - arrayValue, ok := value.([]interface{}) - if !ok { - return nil, fmt.Errorf("parameter %s is not an array", paramName) - } - - result := make([]T, 0, len(arrayValue)) - for _, v := range arrayValue { - typedValue, ok := v.(T) - if !ok { - return nil, fmt.Errorf("array element in %s has incorrect type", paramName) - } - result = append(result, typedValue) - } - - return result, nil -} diff --git a/pkg/mcp/pulsar_admin_packages_tools.go b/pkg/mcp/pulsar_admin_packages_tools.go index 0ded0df..dea0ba7 100644 --- a/pkg/mcp/pulsar_admin_packages_tools.go +++ b/pkg/mcp/pulsar_admin_packages_tools.go @@ -27,7 +27,6 @@ import ( "github.com/mark3labs/mcp-go/mcp" "github.com/mark3labs/mcp-go/server" "github.com/streamnative/pulsarctl/pkg/cmdutils" - "github.com/streamnative/streamnative-mcp-server/pkg/common" "github.com/streamnative/streamnative-mcp-server/pkg/pulsar" ) @@ -113,12 +112,12 @@ func PulsarAdminAddPackagesTools(s *server.MCPServer, readOnly bool, features [] func handlePackageTool(readOnly bool) func(context.Context, mcp.CallToolRequest) (*mcp.CallToolResult, error) { return func(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - resource, err := common.RequiredParam[string](request.Params.Arguments, "resource") + resource, err := request.RequireString("resource") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get resource: %v", err)), nil } - operation, err := common.RequiredParam[string](request.Params.Arguments, "operation") + operation, err := request.RequireString("operation") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get operation: %v", err)), nil } @@ -152,7 +151,7 @@ func handlePackageTool(readOnly bool) func(context.Context, mcp.CallToolRequest) // handlePackageResource handles operations on a specific package func handlePackageResource(client cmdutils.Client, operation string, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { - packageName, err := common.RequiredParam[string](request.Params.Arguments, "packageName") + packageName, err := request.RequireString("packageName") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'packageName' for package operations: %v", err)), nil } @@ -189,13 +188,13 @@ func handlePackageResource(client cmdutils.Client, operation string, request mcp return mcp.NewToolResultText(string(metadataJSON)), nil case "update": - description, err := common.RequiredParam[string](request.Params.Arguments, "description") + description, err := request.RequireString("description") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'description' for package.update: %v", err)), nil } - contact, _ := common.OptionalParam[string](request.Params.Arguments, "contact") - properties := extractProperties(request.Params.Arguments) + contact := request.GetString("contact", "") + properties := extractProperties(request.GetArguments()) // Update package metadata err = client.Packages().UpdateMetadata(packageName, description, contact, properties) @@ -215,7 +214,7 @@ func handlePackageResource(client cmdutils.Client, operation string, request mcp return mcp.NewToolResultText(fmt.Sprintf("The package '%s' deleted successfully", packageName)), nil case "download": - path, err := common.RequiredParam[string](request.Params.Arguments, "path") + path, err := request.RequireString("path") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'path' for package.download: %v", err)), nil } @@ -231,18 +230,18 @@ func handlePackageResource(client cmdutils.Client, operation string, request mcp ), nil case "upload": - path, err := common.RequiredParam[string](request.Params.Arguments, "path") + path, err := request.RequireString("path") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'path' for package.upload: %v", err)), nil } - description, err := common.RequiredParam[string](request.Params.Arguments, "description") + description, err := request.RequireString("description") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'description' for package.upload: %v", err)), nil } - contact, _ := common.OptionalParam[string](request.Params.Arguments, "contact") - properties := extractProperties(request.Params.Arguments) + contact := request.GetString("contact", "") + properties := extractProperties(request.GetArguments()) // Upload package err = client.Packages().Upload(packageName, path, description, contact, properties) @@ -263,12 +262,12 @@ func handlePackageResource(client cmdutils.Client, operation string, request mcp func handlePackagesResource(client cmdutils.Client, operation string, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { switch operation { case "list": - packageType, err := common.RequiredParam[string](request.Params.Arguments, "type") + packageType, err := request.RequireString("type") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'type' for packages.list: %v", err)), nil } - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'namespace' for packages.list: %v", err)), nil } diff --git a/pkg/mcp/pulsar_admin_resourcequotas_tools.go b/pkg/mcp/pulsar_admin_resourcequotas_tools.go index 059f63c..65eac50 100644 --- a/pkg/mcp/pulsar_admin_resourcequotas_tools.go +++ b/pkg/mcp/pulsar_admin_resourcequotas_tools.go @@ -28,7 +28,6 @@ import ( "github.com/mark3labs/mcp-go/mcp" "github.com/mark3labs/mcp-go/server" "github.com/streamnative/pulsarctl/pkg/cmdutils" - "github.com/streamnative/streamnative-mcp-server/pkg/common" "github.com/streamnative/streamnative-mcp-server/pkg/pulsar" ) @@ -101,12 +100,12 @@ func PulsarAdminAddResourceQuotasTools(s *server.MCPServer, readOnly bool, featu func handleResourceQuotaTool(readOnly bool) func(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { return func(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - resource, err := common.RequiredParam[string](request.Params.Arguments, "resource") + resource, err := request.RequireString("resource") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get resource: %v", err)), nil } - operation, err := common.RequiredParam[string](request.Params.Arguments, "operation") + operation, err := request.RequireString("operation") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get operation: %v", err)), nil } @@ -148,11 +147,11 @@ func handleResourceQuotaTool(readOnly bool) func(_ context.Context, request mcp. // handleQuotaGet handles getting a resource quota func handleQuotaGet(admin cmdutils.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get optional parameters - namespace, hasNamespace := common.OptionalParam[string](request.Params.Arguments, "namespace") - bundle, hasBundle := common.OptionalParam[string](request.Params.Arguments, "bundle") + namespace := request.GetString("namespace", "") + bundle := request.GetString("bundle", "") // Check if both namespace and bundle are provided or neither is provided - if (hasNamespace && !hasBundle) || (!hasNamespace && hasBundle) { + if (namespace != "" && bundle == "") || (namespace == "" && bundle != "") { return mcp.NewToolResultError("When specifying a namespace, you must also specify a bundle and vice versa."), nil } @@ -161,7 +160,7 @@ func handleQuotaGet(admin cmdutils.Client, request mcp.CallToolRequest) (*mcp.Ca getErr error ) - if !hasNamespace && !hasBundle { + if namespace == "" && bundle == "" { // Get default resource quota resourceQuotaData, getErr = admin.ResourceQuotas().GetDefaultResourceQuota() if getErr != nil { @@ -192,42 +191,38 @@ func handleQuotaGet(admin cmdutils.Client, request mcp.CallToolRequest) (*mcp.Ca // handleQuotaSet handles setting a resource quota func handleQuotaSet(admin cmdutils.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters for set operation - msgRateIn, err := common.RequiredParam[float64](request.Params.Arguments, "msgRateIn") + msgRateIn, err := request.RequireFloat("msgRateIn") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'msgRateIn' for quota.set: %v", err)), nil } - msgRateOut, err := common.RequiredParam[float64](request.Params.Arguments, "msgRateOut") + msgRateOut, err := request.RequireFloat("msgRateOut") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'msgRateOut' for quota.set: %v", err)), nil } - bandwidthIn, err := common.RequiredParam[float64](request.Params.Arguments, "bandwidthIn") + bandwidthIn, err := request.RequireFloat("bandwidthIn") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'bandwidthIn' for quota.set: %v", err)), nil } - bandwidthOut, err := common.RequiredParam[float64](request.Params.Arguments, "bandwidthOut") + bandwidthOut, err := request.RequireFloat("bandwidthOut") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'bandwidthOut' for quota.set: %v", err)), nil } - memory, err := common.RequiredParam[float64](request.Params.Arguments, "memory") + memory, err := request.RequireFloat("memory") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'memory' for quota.set: %v", err)), nil } // Get optional parameters - namespace, hasNamespace := common.OptionalParam[string](request.Params.Arguments, "namespace") - bundle, hasBundle := common.OptionalParam[string](request.Params.Arguments, "bundle") - dynamic, hasDynamic := common.OptionalParam[bool](request.Params.Arguments, "dynamic") - - if !hasDynamic { - dynamic = false - } + namespace := request.GetString("namespace", "") + bundle := request.GetString("bundle", "") + dynamic := request.GetBool("dynamic", false) // Check if both namespace and bundle are provided or neither is provided - if (hasNamespace && !hasBundle) || (!hasNamespace && hasBundle) { + if (namespace != "" && bundle == "") || (namespace == "" && bundle != "") { return mcp.NewToolResultError("When specifying a namespace, you must also specify a bundle and vice versa."), nil } @@ -241,7 +236,7 @@ func handleQuotaSet(admin cmdutils.Client, request mcp.CallToolRequest) (*mcp.Ca quota.Dynamic = dynamic var resultMsg string - if !hasNamespace && !hasBundle { + if namespace == "" && bundle == "" { // Set default resource quota err = admin.ResourceQuotas().SetDefaultResourceQuota(*quota) if err != nil { @@ -264,12 +259,12 @@ func handleQuotaSet(admin cmdutils.Client, request mcp.CallToolRequest) (*mcp.Ca // handleQuotaReset handles resetting a resource quota func handleQuotaReset(admin cmdutils.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters for reset operation - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'namespace' for quota.reset: %v", err)), nil } - bundle, err := common.RequiredParam[string](request.Params.Arguments, "bundle") + bundle, err := request.RequireString("bundle") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'bundle' for quota.reset: %v", err)), nil } diff --git a/pkg/mcp/pulsar_admin_schemas_tools.go b/pkg/mcp/pulsar_admin_schemas_tools.go index eece294..d159f2a 100644 --- a/pkg/mcp/pulsar_admin_schemas_tools.go +++ b/pkg/mcp/pulsar_admin_schemas_tools.go @@ -30,7 +30,6 @@ import ( "github.com/mark3labs/mcp-go/mcp" "github.com/mark3labs/mcp-go/server" "github.com/streamnative/pulsarctl/pkg/cmdutils" - "github.com/streamnative/streamnative-mcp-server/pkg/common" "github.com/streamnative/streamnative-mcp-server/pkg/pulsar" ) @@ -87,17 +86,17 @@ func PulsarAdminAddSchemasTools(s *server.MCPServer, readOnly bool, features []s func handleSchemaTool(readOnly bool) func(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { return func(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - resource, err := common.RequiredParam[string](request.Params.Arguments, "resource") + resource, err := request.RequireString("resource") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get resource: %v", err)), nil } - operation, err := common.RequiredParam[string](request.Params.Arguments, "operation") + operation, err := request.RequireString("operation") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get operation: %v", err)), nil } - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'topic'. Please provide the fully qualified topic name: %v", err)), nil } @@ -139,10 +138,10 @@ func handleSchemaTool(readOnly bool) func(_ context.Context, request mcp.CallToo // handleSchemaGet handles getting a schema func handleSchemaGet(admin cmdutils.Client, topic string, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get optional version parameter - version, hasVersion := common.OptionalParam[float64](request.Params.Arguments, "version") + version := request.GetFloat("version", 0) // Get schema info - if hasVersion { + if version != 0 { // Get schema by version info, err := admin.Schemas().GetSchemaInfoByVersion(topic, int64(version)) if err != nil { @@ -195,7 +194,7 @@ func handleSchemaGet(admin cmdutils.Client, topic string, request mcp.CallToolRe // handleSchemaUpload handles uploading a schema func handleSchemaUpload(admin cmdutils.Client, topic string, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { - filename, err := common.RequiredParam[string](request.Params.Arguments, "filename") + filename, err := request.RequireString("filename") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'filename' for schema.upload. Please provide the path to the schema definition file: %v", err)), nil } diff --git a/pkg/mcp/pulsar_admin_sinks_tools.go b/pkg/mcp/pulsar_admin_sinks_tools.go index a098716..a780678 100644 --- a/pkg/mcp/pulsar_admin_sinks_tools.go +++ b/pkg/mcp/pulsar_admin_sinks_tools.go @@ -29,7 +29,6 @@ import ( "github.com/mark3labs/mcp-go/mcp" "github.com/mark3labs/mcp-go/server" "github.com/streamnative/pulsarctl/pkg/cmdutils" - "github.com/streamnative/streamnative-mcp-server/pkg/common" ) // PulsarAdminAddSinksTools adds a unified sink-related tool to the MCP server @@ -136,7 +135,7 @@ func PulsarAdminAddSinksTools(s *server.MCPServer, readOnly bool, features []str func handleSinksTool(readOnly bool) func(context.Context, mcp.CallToolRequest) (*mcp.CallToolResult, error) { return func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Extract and validate operation parameter - operation, err := common.RequiredParam[string](request.Params.Arguments, "operation") + operation, err := request.RequireString("operation") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'operation': %v", err)), nil } @@ -170,12 +169,12 @@ func handleSinksTool(readOnly bool) func(context.Context, mcp.CallToolRequest) ( } // Extract common parameters (all operations except list-built-in require tenant and namespace) - tenant, err := common.RequiredParam[string](request.Params.Arguments, "tenant") + tenant, err := request.RequireString("tenant") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'tenant': %v. A tenant is required for operation '%s'.", err, operation)), nil } - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'namespace': %v. A namespace is required for operation '%s'.", err, operation)), nil } @@ -183,7 +182,7 @@ func handleSinksTool(readOnly bool) func(context.Context, mcp.CallToolRequest) ( // For all operations except 'list', name is required var name string if operation != "list" { - name, err = common.RequiredParam[string](request.Params.Arguments, "name") + name, err = request.RequireString("name") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'name' for operation '%s': %v. The sink name must be specified for this operation.", operation, err)), nil } @@ -198,9 +197,9 @@ func handleSinksTool(readOnly bool) func(context.Context, mcp.CallToolRequest) ( case "status": return handleSinkStatus(ctx, admin, tenant, namespace, name) case "create": - return handleSinkCreate(ctx, admin, request.Params.Arguments) + return handleSinkCreate(ctx, admin, request) case "update": - return handleSinkUpdate(ctx, admin, request.Params.Arguments) + return handleSinkUpdate(ctx, admin, request) case "delete": return handleSinkDelete(ctx, admin, tenant, namespace, name) case "start": @@ -268,18 +267,18 @@ func handleSinkStatus(_ context.Context, admin cmdutils.Client, tenant, namespac } // handleSinkCreate handles creating a new sink -func handleSinkCreate(_ context.Context, admin cmdutils.Client, arguments map[string]interface{}) (*mcp.CallToolResult, error) { - tenant, err := common.RequiredParam[string](arguments, "tenant") +func handleSinkCreate(_ context.Context, admin cmdutils.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { + tenant, err := request.RequireString("tenant") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get tenant: %v", err)), nil } - namespace, err := common.RequiredParam[string](arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace: %v", err)), nil } - name, err := common.RequiredParam[string](arguments, "name") + name, err := request.RequireString("name") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get name: %v", err)), nil } @@ -293,39 +292,39 @@ func handleSinkCreate(_ context.Context, admin cmdutils.Client, arguments map[st } // Get optional parameters - archive, hasArchive := common.OptionalParam[string](arguments, "archive") - if hasArchive && archive != "" { + archive := request.GetString("archive", "") + if archive != "" { sinkData.Archive = archive } - sinkType, hasSinkType := common.OptionalParam[string](arguments, "sink-type") - if hasSinkType && sinkType != "" { + sinkType := request.GetString("sink-type", "") + if sinkType != "" { sinkData.SinkType = sinkType } - inputsArray, hasInputs := common.OptionalParamArray[string](arguments, "inputs") - if hasInputs && len(inputsArray) > 0 { + inputsArray := request.GetStringSlice("inputs", []string{}) + if len(inputsArray) > 0 { sinkData.Inputs = strings.Join(inputsArray, ",") } - topicsPattern, hasTopicsPattern := common.OptionalParam[string](arguments, "topics-pattern") - if hasTopicsPattern && topicsPattern != "" { + topicsPattern := request.GetString("topics-pattern", "") + if topicsPattern != "" { sinkData.TopicsPattern = topicsPattern } - subsName, hasSubsName := common.OptionalParam[string](arguments, "subs-name") - if hasSubsName && subsName != "" { + subsName := request.GetString("subs-name", "") + if subsName != "" { sinkData.SubsName = subsName } - parallelismFloat, hasParallelism := common.OptionalParam[float64](arguments, "parallelism") - if hasParallelism { + parallelismFloat := request.GetFloat("parallelism", 1) + if parallelismFloat >= 0 { sinkData.Parallelism = int(parallelismFloat) } // Get sink config if available var sinkConfigMap map[string]interface{} - sinkConfigObj, ok := arguments["sink-config"] + sinkConfigObj, ok := request.GetArguments()["sink-config"] if ok && sinkConfigObj != nil { if configMap, isMap := sinkConfigObj.(map[string]interface{}); isMap { sinkConfigMap = configMap @@ -374,18 +373,18 @@ func handleSinkCreate(_ context.Context, admin cmdutils.Client, arguments map[st } // handleSinkUpdate handles updating an existing sink -func handleSinkUpdate(_ context.Context, admin cmdutils.Client, arguments map[string]interface{}) (*mcp.CallToolResult, error) { - tenant, err := common.RequiredParam[string](arguments, "tenant") +func handleSinkUpdate(_ context.Context, admin cmdutils.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { + tenant, err := request.RequireString("tenant") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get tenant: %v", err)), nil } - namespace, err := common.RequiredParam[string](arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace: %v", err)), nil } - name, err := common.RequiredParam[string](arguments, "name") + name, err := request.RequireString("name") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get name: %v", err)), nil } @@ -399,39 +398,39 @@ func handleSinkUpdate(_ context.Context, admin cmdutils.Client, arguments map[st } // Get optional parameters - archive, hasArchive := common.OptionalParam[string](arguments, "archive") - if hasArchive && archive != "" { + archive := request.GetString("archive", "") + if archive != "" { sinkData.Archive = archive } - sinkType, hasSinkType := common.OptionalParam[string](arguments, "sink-type") - if hasSinkType && sinkType != "" { + sinkType := request.GetString("sink-type", "") + if sinkType != "" { sinkData.SinkType = sinkType } - inputsArray, hasInputs := common.OptionalParamArray[string](arguments, "inputs") - if hasInputs && len(inputsArray) > 0 { + inputsArray := request.GetStringSlice("inputs", []string{}) + if len(inputsArray) > 0 { sinkData.Inputs = strings.Join(inputsArray, ",") } - topicsPattern, hasTopicsPattern := common.OptionalParam[string](arguments, "topics-pattern") - if hasTopicsPattern && topicsPattern != "" { + topicsPattern := request.GetString("topics-pattern", "") + if topicsPattern != "" { sinkData.TopicsPattern = topicsPattern } - subsName, hasSubsName := common.OptionalParam[string](arguments, "subs-name") - if hasSubsName && subsName != "" { + subsName := request.GetString("subs-name", "") + if subsName != "" { sinkData.SubsName = subsName } - parallelismFloat, hasParallelism := common.OptionalParam[float64](arguments, "parallelism") - if hasParallelism { + parallelismFloat := request.GetFloat("parallelism", 1) + if parallelismFloat >= 0 { sinkData.Parallelism = int(parallelismFloat) } // Get sink config if available var sinkConfigMap map[string]interface{} - sinkConfigObj, ok := arguments["sink-config"] + sinkConfigObj, ok := request.GetArguments()["sink-config"] if ok && sinkConfigObj != nil { if configMap, isMap := sinkConfigObj.(map[string]interface{}); isMap { sinkConfigMap = configMap diff --git a/pkg/mcp/pulsar_admin_sources_tools.go b/pkg/mcp/pulsar_admin_sources_tools.go index 664a9da..48b0615 100644 --- a/pkg/mcp/pulsar_admin_sources_tools.go +++ b/pkg/mcp/pulsar_admin_sources_tools.go @@ -28,7 +28,6 @@ import ( "github.com/mark3labs/mcp-go/mcp" "github.com/mark3labs/mcp-go/server" "github.com/streamnative/pulsarctl/pkg/cmdutils" - "github.com/streamnative/streamnative-mcp-server/pkg/common" ) // PulsarAdminAddSourcesTools adds a unified source-related tool to the MCP server @@ -136,7 +135,7 @@ func PulsarAdminAddSourcesTools(s *server.MCPServer, readOnly bool, features []s func handleSourcesTool(readOnly bool) func(context.Context, mcp.CallToolRequest) (*mcp.CallToolResult, error) { return func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Extract and validate operation parameter - operation, err := common.RequiredParam[string](request.Params.Arguments, "operation") + operation, err := request.RequireString("operation") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'operation': %v", err)), nil } @@ -170,12 +169,12 @@ func handleSourcesTool(readOnly bool) func(context.Context, mcp.CallToolRequest) } // Extract common parameters (all operations except list-built-in require tenant and namespace) - tenant, err := common.RequiredParam[string](request.Params.Arguments, "tenant") + tenant, err := request.RequireString("tenant") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'tenant': %v. A tenant is required for operation '%s'.", err, operation)), nil } - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'namespace': %v. A namespace is required for operation '%s'.", err, operation)), nil } @@ -183,7 +182,7 @@ func handleSourcesTool(readOnly bool) func(context.Context, mcp.CallToolRequest) // For all operations except 'list', name is required var name string if operation != "list" { - name, err = common.RequiredParam[string](request.Params.Arguments, "name") + name, err = request.RequireString("name") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'name' for operation '%s': %v. The source name must be specified for this operation.", operation, err)), nil } @@ -198,9 +197,9 @@ func handleSourcesTool(readOnly bool) func(context.Context, mcp.CallToolRequest) case "status": return handleSourceStatus(ctx, admin, tenant, namespace, name) case "create": - return handleSourceCreate(ctx, admin, request.Params.Arguments) + return handleSourceCreate(ctx, admin, request) case "update": - return handleSourceUpdate(ctx, admin, request.Params.Arguments) + return handleSourceUpdate(ctx, admin, request) case "delete": return handleSourceDelete(ctx, admin, tenant, namespace, name) case "start": @@ -268,18 +267,18 @@ func handleSourceStatus(_ context.Context, admin cmdutils.Client, tenant, namesp } // handleSourceCreate handles creating a new source -func handleSourceCreate(_ context.Context, admin cmdutils.Client, arguments map[string]interface{}) (*mcp.CallToolResult, error) { - tenant, err := common.RequiredParam[string](arguments, "tenant") +func handleSourceCreate(_ context.Context, admin cmdutils.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { + tenant, err := request.RequireString("tenant") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get tenant: %v", err)), nil } - namespace, err := common.RequiredParam[string](arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace: %v", err)), nil } - name, err := common.RequiredParam[string](arguments, "name") + name, err := request.RequireString("name") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get name: %v", err)), nil } @@ -293,49 +292,49 @@ func handleSourceCreate(_ context.Context, admin cmdutils.Client, arguments map[ } // Get optional parameters - archive, hasArchive := common.OptionalParam[string](arguments, "archive") - if hasArchive && archive != "" { + archive := request.GetString("archive", "") + if archive != "" { sourceData.Archive = archive } - sourceType, hasSourceType := common.OptionalParam[string](arguments, "source-type") - if hasSourceType && sourceType != "" { + sourceType := request.GetString("source-type", "") + if sourceType != "" { sourceData.SourceType = sourceType } - destTopic, hasDestTopic := common.OptionalParam[string](arguments, "destination-topic-name") - if hasDestTopic && destTopic != "" { + destTopic := request.GetString("destination-topic-name", "") + if destTopic != "" { sourceData.DestinationTopicName = destTopic } - deserializationClassName, hasDeserialization := common.OptionalParam[string](arguments, "deserialization-classname") - if hasDeserialization && deserializationClassName != "" { + deserializationClassName := request.GetString("deserialization-classname", "") + if deserializationClassName != "" { sourceData.DeserializationClassName = deserializationClassName } - schemaType, hasSchemaType := common.OptionalParam[string](arguments, "schema-type") - if hasSchemaType && schemaType != "" { + schemaType := request.GetString("schema-type", "") + if schemaType != "" { sourceData.SchemaType = schemaType } - className, hasClassName := common.OptionalParam[string](arguments, "classname") - if hasClassName && className != "" { + className := request.GetString("classname", "") + if className != "" { sourceData.ClassName = className } - processingGuarantees, hasProcessingGuarantees := common.OptionalParam[string](arguments, "processing-guarantees") - if hasProcessingGuarantees && processingGuarantees != "" { + processingGuarantees := request.GetString("processing-guarantees", "") + if processingGuarantees != "" { sourceData.ProcessingGuarantees = processingGuarantees } - parallelismFloat, hasParallelism := common.OptionalParam[float64](arguments, "parallelism") - if hasParallelism { + parallelismFloat := request.GetFloat("parallelism", 1) + if parallelismFloat >= 0 { sourceData.Parallelism = int(parallelismFloat) } // Get source config if available var sourceConfigMap map[string]interface{} - sourceConfigObj, ok := arguments["source-config"] + sourceConfigObj, ok := request.GetArguments()["source-config"] if ok && sourceConfigObj != nil { if configMap, isMap := sourceConfigObj.(map[string]interface{}); isMap { sourceConfigMap = configMap @@ -384,18 +383,18 @@ func handleSourceCreate(_ context.Context, admin cmdutils.Client, arguments map[ } // handleSourceUpdate handles updating an existing source -func handleSourceUpdate(_ context.Context, admin cmdutils.Client, arguments map[string]interface{}) (*mcp.CallToolResult, error) { - tenant, err := common.RequiredParam[string](arguments, "tenant") +func handleSourceUpdate(_ context.Context, admin cmdutils.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { + tenant, err := request.RequireString("tenant") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get tenant: %v", err)), nil } - namespace, err := common.RequiredParam[string](arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get namespace: %v", err)), nil } - name, err := common.RequiredParam[string](arguments, "name") + name, err := request.RequireString("name") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get name: %v", err)), nil } @@ -409,49 +408,49 @@ func handleSourceUpdate(_ context.Context, admin cmdutils.Client, arguments map[ } // Get optional parameters - archive, hasArchive := common.OptionalParam[string](arguments, "archive") - if hasArchive && archive != "" { + archive := request.GetString("archive", "") + if archive != "" { sourceData.Archive = archive } - sourceType, hasSourceType := common.OptionalParam[string](arguments, "source-type") - if hasSourceType && sourceType != "" { + sourceType := request.GetString("source-type", "") + if sourceType != "" { sourceData.SourceType = sourceType } - destTopic, hasDestTopic := common.OptionalParam[string](arguments, "destination-topic-name") - if hasDestTopic && destTopic != "" { + destTopic := request.GetString("destination-topic-name", "") + if destTopic != "" { sourceData.DestinationTopicName = destTopic } - deserializationClassName, hasDeserialization := common.OptionalParam[string](arguments, "deserialization-classname") - if hasDeserialization && deserializationClassName != "" { + deserializationClassName := request.GetString("deserialization-classname", "") + if deserializationClassName != "" { sourceData.DeserializationClassName = deserializationClassName } - schemaType, hasSchemaType := common.OptionalParam[string](arguments, "schema-type") - if hasSchemaType && schemaType != "" { + schemaType := request.GetString("schema-type", "") + if schemaType != "" { sourceData.SchemaType = schemaType } - className, hasClassName := common.OptionalParam[string](arguments, "classname") - if hasClassName && className != "" { + className := request.GetString("classname", "") + if className != "" { sourceData.ClassName = className } - processingGuarantees, hasProcessingGuarantees := common.OptionalParam[string](arguments, "processing-guarantees") - if hasProcessingGuarantees && processingGuarantees != "" { + processingGuarantees := request.GetString("processing-guarantees", "") + if processingGuarantees != "" { sourceData.ProcessingGuarantees = processingGuarantees } - parallelismFloat, hasParallelism := common.OptionalParam[float64](arguments, "parallelism") - if hasParallelism { + parallelismFloat := request.GetFloat("parallelism", 1) + if parallelismFloat >= 0 { sourceData.Parallelism = int(parallelismFloat) } // Get source config if available var sourceConfigMap map[string]interface{} - sourceConfigObj, ok := arguments["source-config"] + sourceConfigObj, ok := request.GetArguments()["source-config"] if ok && sourceConfigObj != nil { if configMap, isMap := sourceConfigObj.(map[string]interface{}); isMap { sourceConfigMap = configMap diff --git a/pkg/mcp/pulsar_admin_subscription_tools.go b/pkg/mcp/pulsar_admin_subscription_tools.go index 604765c..10fc26f 100644 --- a/pkg/mcp/pulsar_admin_subscription_tools.go +++ b/pkg/mcp/pulsar_admin_subscription_tools.go @@ -28,7 +28,6 @@ import ( "github.com/mark3labs/mcp-go/mcp" "github.com/mark3labs/mcp-go/server" "github.com/streamnative/pulsarctl/pkg/cmdutils" - "github.com/streamnative/streamnative-mcp-server/pkg/common" "github.com/streamnative/streamnative-mcp-server/pkg/pulsar" ) @@ -104,17 +103,17 @@ func PulsarAdminAddSubscriptionTools(s *server.MCPServer, readOnly bool, feature func handleSubscriptionTool(readOnly bool) func(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { return func(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - resource, err := common.RequiredParam[string](request.Params.Arguments, "resource") + resource, err := request.RequireString("resource") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get resource: %v", err)), nil } - operation, err := common.RequiredParam[string](request.Params.Arguments, "operation") + operation, err := request.RequireString("operation") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get operation: %v", err)), nil } - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'topic'. Please provide the fully qualified topic name: %v", err)), nil } @@ -186,16 +185,13 @@ func handleSubsList(admin cmdutils.Client, topicName *utils.TopicName) (*mcp.Cal // handleSubsCreate handles creating a new subscription func handleSubsCreate(admin cmdutils.Client, topicName *utils.TopicName, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameter - subscription, err := common.RequiredParam[string](request.Params.Arguments, "subscription") + subscription, err := request.RequireString("subscription") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'subscription' for subscription.create: %v", err)), nil } // Get optional messageID parameter (default is "latest") - messageID, hasMessageID := common.OptionalParam[string](request.Params.Arguments, "messageId") - if !hasMessageID { - messageID = "latest" - } + messageID := request.GetString("messageId", "latest") // Parse messageId var messageIDObj utils.MessageID @@ -231,16 +227,13 @@ func handleSubsCreate(admin cmdutils.Client, topicName *utils.TopicName, request // handleSubsDelete handles deleting a subscription func handleSubsDelete(admin cmdutils.Client, topicName *utils.TopicName, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameter - subscription, err := common.RequiredParam[string](request.Params.Arguments, "subscription") + subscription, err := request.RequireString("subscription") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'subscription' for subscription.delete: %v", err)), nil } // Get optional force parameter (default is false) - force, hasForce := common.OptionalParam[bool](request.Params.Arguments, "force") - if !hasForce { - force = false - } + force := request.GetBool("force", false) // Delete subscription if force { @@ -268,12 +261,12 @@ func handleSubsDelete(admin cmdutils.Client, topicName *utils.TopicName, request // handleSubsSkip handles skipping messages for a subscription func handleSubsSkip(admin cmdutils.Client, topicName *utils.TopicName, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - subscription, err := common.RequiredParam[string](request.Params.Arguments, "subscription") + subscription, err := request.RequireString("subscription") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'subscription' for subscription.skip: %v", err)), nil } - count, err := common.RequiredParam[float64](request.Params.Arguments, "count") + count, err := request.RequireFloat("count") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'count' for subscription.skip: %v", err)), nil } @@ -292,12 +285,12 @@ func handleSubsSkip(admin cmdutils.Client, topicName *utils.TopicName, request m // handleSubsExpire handles expiring messages for a subscription func handleSubsExpire(admin cmdutils.Client, topicName *utils.TopicName, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - subscription, err := common.RequiredParam[string](request.Params.Arguments, "subscription") + subscription, err := request.RequireString("subscription") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'subscription' for subscription.expire: %v", err)), nil } - expireTime, err := common.RequiredParam[float64](request.Params.Arguments, "expireTimeInSeconds") + expireTime, err := request.RequireFloat("expireTimeInSeconds") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'expireTimeInSeconds' for subscription.expire: %v", err)), nil } @@ -318,12 +311,12 @@ func handleSubsExpire(admin cmdutils.Client, topicName *utils.TopicName, request // handleSubsResetCursor handles resetting a subscription cursor func handleSubsResetCursor(admin cmdutils.Client, topicName *utils.TopicName, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - subscription, err := common.RequiredParam[string](request.Params.Arguments, "subscription") + subscription, err := request.RequireString("subscription") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'subscription' for subscription.reset-cursor: %v", err)), nil } - messageID, err := common.RequiredParam[string](request.Params.Arguments, "messageId") + messageID, err := request.RequireString("messageId") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'messageId' for subscription.reset-cursor: %v", err)), nil } diff --git a/pkg/mcp/pulsar_admin_tenant_tools.go b/pkg/mcp/pulsar_admin_tenant_tools.go index f55c964..75097c6 100644 --- a/pkg/mcp/pulsar_admin_tenant_tools.go +++ b/pkg/mcp/pulsar_admin_tenant_tools.go @@ -28,7 +28,6 @@ import ( "github.com/mark3labs/mcp-go/mcp" "github.com/mark3labs/mcp-go/server" "github.com/streamnative/pulsarctl/pkg/cmdutils" - "github.com/streamnative/streamnative-mcp-server/pkg/common" "github.com/streamnative/streamnative-mcp-server/pkg/pulsar" ) @@ -105,12 +104,12 @@ func PulsarAdminAddTenantTools(s *server.MCPServer, readOnly bool, features []st func handleTenantTool(readOnly bool) func(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { return func(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - resource, err := common.RequiredParam[string](request.Params.Arguments, "resource") + resource, err := request.RequireString("resource") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get resource: %v", err)), nil } - operation, err := common.RequiredParam[string](request.Params.Arguments, "operation") + operation, err := request.RequireString("operation") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get operation: %v", err)), nil } @@ -172,7 +171,7 @@ func handleTenantsList(admin cmdutils.Client) (*mcp.CallToolResult, error) { // handleTenantGet handles getting a tenant's configuration func handleTenantGet(admin cmdutils.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { - tenant, err := common.RequiredParam[string](request.Params.Arguments, "tenant") + tenant, err := request.RequireString("tenant") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'tenant' for tenant.get: %v", err)), nil } @@ -194,20 +193,14 @@ func handleTenantGet(admin cmdutils.Client, request mcp.CallToolRequest) (*mcp.C // handleTenantCreate handles creating a new tenant func handleTenantCreate(admin cmdutils.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { - tenant, err := common.RequiredParam[string](request.Params.Arguments, "tenant") + tenant, err := request.RequireString("tenant") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'tenant' for tenant.create: %v", err)), nil } - adminRoles, hasAdminRoles := common.OptionalParamArray[string](request.Params.Arguments, "adminRoles") - if !hasAdminRoles { - adminRoles = []string{} - } + adminRoles := request.GetStringSlice("adminRoles", []string{}) - allowedClusters, hasAllowedClusters := common.OptionalParamArray[string](request.Params.Arguments, "allowedClusters") - if !hasAllowedClusters { - allowedClusters = []string{""} - } + allowedClusters := request.GetStringSlice("allowedClusters", []string{}) // Create tenant data struct tenantData := utils.TenantData{ @@ -239,7 +232,7 @@ func handleTenantCreate(admin cmdutils.Client, request mcp.CallToolRequest) (*mc // handleTenantUpdate handles updating an existing tenant func handleTenantUpdate(admin cmdutils.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { - tenant, err := common.RequiredParam[string](request.Params.Arguments, "tenant") + tenant, err := request.RequireString("tenant") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'tenant' for tenant.update: %v", err)), nil } @@ -251,15 +244,15 @@ func handleTenantUpdate(admin cmdutils.Client, request mcp.CallToolRequest) (*mc } // Get update parameters - adminRoles, hasAdminRoles := common.OptionalParamArray[string](request.Params.Arguments, "adminRoles") - allowedClusters, hasAllowedClusters := common.OptionalParamArray[string](request.Params.Arguments, "allowedClusters") + adminRoles := request.GetStringSlice("adminRoles", []string{}) + allowedClusters := request.GetStringSlice("allowedClusters", []string{}) // If parameters not provided, keep existing values - if !hasAdminRoles { + if len(adminRoles) == 0 { adminRoles = currentTenantInfo.AdminRoles } - if !hasAllowedClusters { + if len(allowedClusters) == 0 { allowedClusters = currentTenantInfo.AllowedClusters } @@ -293,7 +286,7 @@ func handleTenantUpdate(admin cmdutils.Client, request mcp.CallToolRequest) (*mc // handleTenantDelete handles deleting an existing tenant func handleTenantDelete(admin cmdutils.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { - tenant, err := common.RequiredParam[string](request.Params.Arguments, "tenant") + tenant, err := request.RequireString("tenant") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'tenant' for tenant.delete: %v", err)), nil } diff --git a/pkg/mcp/pulsar_admin_topic_policy_tools.go b/pkg/mcp/pulsar_admin_topic_policy_tools.go index fbc492a..a67aec8 100644 --- a/pkg/mcp/pulsar_admin_topic_policy_tools.go +++ b/pkg/mcp/pulsar_admin_topic_policy_tools.go @@ -27,7 +27,6 @@ import ( "github.com/apache/pulsar-client-go/pulsaradmin/pkg/utils" "github.com/mark3labs/mcp-go/mcp" "github.com/mark3labs/mcp-go/server" - "github.com/streamnative/streamnative-mcp-server/pkg/common" "github.com/streamnative/streamnative-mcp-server/pkg/pulsar" ) @@ -337,7 +336,7 @@ func PulsarAdminAddTopicPolicyTools(s *server.MCPServer, readOnly bool, features // handleTopicsGetPublishRate gets the publish rate for a topic func handleTopicsGetPublishRate(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } @@ -377,7 +376,7 @@ func handleTopicsGetPublishRate(_ context.Context, request mcp.CallToolRequest) // handleTopicsSetPublishRate sets the publish rate for a topic func handleTopicsSetPublishRate(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } @@ -399,14 +398,14 @@ func handleTopicsSetPublishRate(_ context.Context, request mcp.CallToolRequest) publishRateInByte := int64(-1) // unlimited // Get publish rate in messages if provided - msgRateParam, hasMsgRate := common.OptionalParam[float64](request.Params.Arguments, "publishThrottlingRateInMsg") - if hasMsgRate { + msgRateParam := request.GetFloat("publishThrottlingRateInMsg", -1) + if msgRateParam != -1 { publishRateInMsg = int64(msgRateParam) } // Get publish rate in bytes if provided - byteRateParam, hasByteRate := common.OptionalParam[float64](request.Params.Arguments, "publishThrottlingRateInByte") - if hasByteRate { + byteRateParam := request.GetFloat("publishThrottlingRateInByte", -1) + if byteRateParam != -1 { publishRateInByte = int64(byteRateParam) } @@ -448,7 +447,7 @@ func handleTopicsSetPublishRate(_ context.Context, request mcp.CallToolRequest) // handleTopicsRemovePublishRate removes the publish rate for a topic func handleTopicsRemovePublishRate(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } @@ -477,7 +476,7 @@ func handleTopicsRemovePublishRate(_ context.Context, request mcp.CallToolReques // handleTopicsGetPermissions gets the permissions on a topic func handleTopicsGetPermissions(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } @@ -512,17 +511,17 @@ func handleTopicsGetPermissions(_ context.Context, request mcp.CallToolRequest) // handleTopicsGrantPermissions grants a new permission to a role on a topic func handleTopicsGrantPermissions(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } - role, err := common.RequiredParam[string](request.Params.Arguments, "role") + role, err := request.RequireString("role") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get role: %v", err)), nil } - actions, err := common.RequiredParamArray[string](request.Params.Arguments, "actions") + actions, err := request.RequireStringSlice("actions") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get actions: %v", err)), nil } @@ -567,12 +566,12 @@ func handleTopicsGrantPermissions(_ context.Context, request mcp.CallToolRequest // handleTopicsRevokePermissions revokes all permissions for a role on a topic func handleTopicsRevokePermissions(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } - role, err := common.RequiredParam[string](request.Params.Arguments, "role") + role, err := request.RequireString("role") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get role: %v", err)), nil } @@ -621,7 +620,7 @@ func grantTopicPermission(admin interface{}, topicName utils.TopicName, role str // handleTopicsGetMessageTTL gets the message TTL for a topic func handleTopicsGetMessageTTL(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } @@ -655,12 +654,12 @@ func handleTopicsGetMessageTTL(_ context.Context, request mcp.CallToolRequest) ( // handleTopicsSetMessageTTL sets the message TTL for a topic func handleTopicsSetMessageTTL(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } - ttl, err := common.RequiredParam[float64](request.Params.Arguments, "ttl") + ttl, err := request.RequireFloat("ttl") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get TTL: %v", err)), nil } @@ -701,7 +700,7 @@ func handleTopicsSetMessageTTL(_ context.Context, request mcp.CallToolRequest) ( // handleTopicsRemoveMessageTTL removes the message TTL for a topic func handleTopicsRemoveMessageTTL(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } @@ -730,7 +729,7 @@ func handleTopicsRemoveMessageTTL(_ context.Context, request mcp.CallToolRequest // handleTopicsGetMaxProducers gets the maximum number of producers allowed for a topic func handleTopicsGetMaxProducers(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } @@ -765,12 +764,12 @@ func handleTopicsGetMaxProducers(_ context.Context, request mcp.CallToolRequest) // handleTopicsSetMaxProducers sets the maximum number of producers allowed for a topic func handleTopicsSetMaxProducers(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } - maxProducers, err := common.RequiredParam[float64](request.Params.Arguments, "maxProducers") + maxProducers, err := request.RequireFloat("maxProducers") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get maxProducers: %v", err)), nil } @@ -811,7 +810,7 @@ func handleTopicsSetMaxProducers(_ context.Context, request mcp.CallToolRequest) // handleTopicsRemoveMaxProducers removes the maximum producers limit for a topic func handleTopicsRemoveMaxProducers(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } @@ -840,7 +839,7 @@ func handleTopicsRemoveMaxProducers(_ context.Context, request mcp.CallToolReque // handleTopicsGetMaxConsumers gets the maximum number of consumers allowed for a topic func handleTopicsGetMaxConsumers(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } @@ -875,12 +874,12 @@ func handleTopicsGetMaxConsumers(_ context.Context, request mcp.CallToolRequest) // handleTopicsSetMaxConsumers sets the maximum number of consumers allowed for a topic func handleTopicsSetMaxConsumers(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } - maxConsumers, err := common.RequiredParam[float64](request.Params.Arguments, "maxConsumers") + maxConsumers, err := request.RequireFloat("maxConsumers") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get maxConsumers: %v", err)), nil } @@ -921,7 +920,7 @@ func handleTopicsSetMaxConsumers(_ context.Context, request mcp.CallToolRequest) // handleTopicsRemoveMaxConsumers removes the maximum consumers limit for a topic func handleTopicsRemoveMaxConsumers(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } @@ -951,7 +950,7 @@ func handleTopicsRemoveMaxConsumers(_ context.Context, request mcp.CallToolReque // gets the maximum number of unacknowledged messages allowed for a consumer on a topic func handleTopicsGetMaxUnackMessagesPerConsumer(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } @@ -989,12 +988,12 @@ func handleTopicsGetMaxUnackMessagesPerConsumer(_ context.Context, request mcp.C // sets the maximum number of unacknowledged messages allowed for a consumer on a topic func handleTopicsSetMaxUnackMessagesPerConsumer(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } - maxUnack, err := common.RequiredParam[float64](request.Params.Arguments, "maxUnackMessagesPerConsumer") + maxUnack, err := request.RequireFloat("maxUnackMessagesPerConsumer") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get maxUnackMessagesPerConsumer: %v", err)), nil } @@ -1036,7 +1035,7 @@ func handleTopicsSetMaxUnackMessagesPerConsumer(_ context.Context, request mcp.C // removes the maximum unacknowledged messages per consumer limit for a topic func handleTopicsRemoveMaxUnackMessagesPerConsumer(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } @@ -1071,7 +1070,7 @@ func handleTopicsRemoveMaxUnackMessagesPerConsumer(_ context.Context, request mc // gets the maximum number of unacknowledged messages allowed for a subscription on a topic func handleTopicsGetMaxUnackMessagesPerSubscription(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } @@ -1111,12 +1110,12 @@ func handleTopicsGetMaxUnackMessagesPerSubscription(_ context.Context, request m // sets the maximum number of unacknowledged messages allowed for a subscription on a topic func handleTopicsSetMaxUnackMessagesPerSubscription(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } - maxUnack, err := common.RequiredParam[float64](request.Params.Arguments, "maxUnackMessagesPerSubscription") + maxUnack, err := request.RequireFloat("maxUnackMessagesPerSubscription") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get maxUnackMessagesPerSubscription: %v", err)), nil } @@ -1162,7 +1161,7 @@ func handleTopicsSetMaxUnackMessagesPerSubscription(_ context.Context, request m // removes the maximum unacknowledged messages per subscription limit for a topic func handleTopicsRemoveMaxUnackMessagesPerSubscription(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } @@ -1196,7 +1195,7 @@ func handleTopicsRemoveMaxUnackMessagesPerSubscription(_ context.Context, reques // handleTopicsGetPersistence gets the persistence policy for a topic func handleTopicsGetPersistence(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } @@ -1231,22 +1230,22 @@ func handleTopicsGetPersistence(_ context.Context, request mcp.CallToolRequest) // handleTopicsSetPersistence sets the persistence policy for a topic func handleTopicsSetPersistence(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } - ensembleSize, err := common.RequiredParam[float64](request.Params.Arguments, "ensembleSize") + ensembleSize, err := request.RequireFloat("ensembleSize") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get ensembleSize: %v", err)), nil } - writeQuorum, err := common.RequiredParam[float64](request.Params.Arguments, "writeQuorum") + writeQuorum, err := request.RequireFloat("writeQuorum") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get writeQuorum: %v", err)), nil } - ackQuorum, err := common.RequiredParam[float64](request.Params.Arguments, "ackQuorum") + ackQuorum, err := request.RequireFloat("ackQuorum") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get ackQuorum: %v", err)), nil } @@ -1299,7 +1298,7 @@ func handleTopicsSetPersistence(_ context.Context, request mcp.CallToolRequest) // handleTopicsRemovePersistence removes the persistence policy for a topic func handleTopicsRemovePersistence(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } @@ -1328,7 +1327,7 @@ func handleTopicsRemovePersistence(_ context.Context, request mcp.CallToolReques // handleTopicsGetDelayedDelivery gets the delayed delivery policy for a topic func handleTopicsGetDelayedDelivery(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } @@ -1363,12 +1362,12 @@ func handleTopicsGetDelayedDelivery(_ context.Context, request mcp.CallToolReque // handleTopicsSetDelayedDelivery sets the delayed delivery policy for a topic func handleTopicsSetDelayedDelivery(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } - delayInMillis, err := common.RequiredParam[float64](request.Params.Arguments, "delayInMillis") + delayInMillis, err := request.RequireFloat("delayInMillis") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get delayInMillis: %v", err)), nil } @@ -1380,8 +1379,8 @@ func handleTopicsSetDelayedDelivery(_ context.Context, request mcp.CallToolReque // Default tick time is 1 second (1000ms) tickTime := 1000.0 - tickTimeParam, hasTickTime := common.OptionalParam[float64](request.Params.Arguments, "tickTime") - if hasTickTime && tickTimeParam > 0 { + tickTimeParam := request.GetFloat("tickTime", 0) + if tickTimeParam > 0 { tickTime = tickTimeParam } @@ -1421,7 +1420,7 @@ func handleTopicsSetDelayedDelivery(_ context.Context, request mcp.CallToolReque // handleTopicsRemoveDelayedDelivery removes the delayed delivery policy for a topic func handleTopicsRemoveDelayedDelivery(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } @@ -1450,7 +1449,7 @@ func handleTopicsRemoveDelayedDelivery(_ context.Context, request mcp.CallToolRe // handleTopicsGetDispatchRate gets the message dispatch rate for a topic func handleTopicsGetDispatchRate(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } @@ -1490,7 +1489,7 @@ func handleTopicsGetDispatchRate(_ context.Context, request mcp.CallToolRequest) // handleTopicsSetDispatchRate sets the message dispatch rate for a topic func handleTopicsSetDispatchRate(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } @@ -1513,22 +1512,22 @@ func handleTopicsSetDispatchRate(_ context.Context, request mcp.CallToolRequest) ratePeriodInSecond := int64(1) // default 1 second // Get dispatch rate in messages if provided - msgRateParam, hasMsgRate := common.OptionalParam[float64](request.Params.Arguments, "dispatchThrottlingRateInMsg") - if hasMsgRate { + msgRateParam := request.GetFloat("dispatchThrottlingRateInMsg", -1) + if msgRateParam != -1 { dispatchRateInMsg = int64(msgRateParam) } // Get dispatch rate in bytes if provided - byteRateParam, hasByteRate := common.OptionalParam[float64](request.Params.Arguments, "dispatchThrottlingRateInByte") - if hasByteRate { + byteRateParam := request.GetFloat("dispatchThrottlingRateInByte", -1) + if byteRateParam != -1 { dispatchRateInByte = int64(byteRateParam) } // Get rate period if provided - ratePeriodParam, hasRatePeriod := common.OptionalParam[float64](request.Params.Arguments, "ratePeriodInSecond") - if hasRatePeriod && ratePeriodParam > 0 { + ratePeriodParam := request.GetFloat("ratePeriodInSecond", 0) + if ratePeriodParam > 0 { ratePeriodInSecond = int64(ratePeriodParam) - } else if hasRatePeriod && ratePeriodParam <= 0 { + } else if ratePeriodParam <= 0 { return mcp.NewToolResultError("Rate period must be positive"), nil } @@ -1572,7 +1571,7 @@ func handleTopicsSetDispatchRate(_ context.Context, request mcp.CallToolRequest) // handleTopicsRemoveDispatchRate removes the message dispatch rate for a topic func handleTopicsRemoveDispatchRate(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } @@ -1601,7 +1600,7 @@ func handleTopicsRemoveDispatchRate(_ context.Context, request mcp.CallToolReque // handleTopicsGetDeduplicationStatus gets the deduplication status for a topic func handleTopicsGetDeduplicationStatus(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } @@ -1635,12 +1634,12 @@ func handleTopicsGetDeduplicationStatus(_ context.Context, request mcp.CallToolR // handleTopicsSetDeduplicationStatus sets the deduplication status for a topic func handleTopicsSetDeduplicationStatus(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } - enabled, err := common.RequiredParam[bool](request.Params.Arguments, "enabled") + enabled, err := request.RequireBool("enabled") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get enabled parameter: %v", err)), nil } @@ -1674,7 +1673,7 @@ func handleTopicsSetDeduplicationStatus(_ context.Context, request mcp.CallToolR // handleTopicsRemoveDeduplicationStatus removes the deduplication status for a topic func handleTopicsRemoveDeduplicationStatus(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } @@ -1703,7 +1702,7 @@ func handleTopicsRemoveDeduplicationStatus(_ context.Context, request mcp.CallTo // handleTopicsGetRetention gets the retention policy for a topic func handleTopicsGetRetention(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } @@ -1716,8 +1715,8 @@ func handleTopicsGetRetention(_ context.Context, request mcp.CallToolRequest) (* // Check if applied policies should be included applied := false - appliedParam, hasApplied := common.OptionalParam[bool](request.Params.Arguments, "applied") - if hasApplied { + appliedParam := request.GetBool("applied", false) + if appliedParam { applied = appliedParam } @@ -1769,17 +1768,17 @@ func handleTopicsGetRetention(_ context.Context, request mcp.CallToolRequest) (* // handleTopicsSetRetention sets the retention policy for a topic func handleTopicsSetRetention(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } - retentionTimeInMinutes, err := common.RequiredParam[float64](request.Params.Arguments, "retentionTimeInMinutes") + retentionTimeInMinutes, err := request.RequireFloat("retentionTimeInMinutes") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get retentionTimeInMinutes: %v", err)), nil } - retentionSizeInMB, err := common.RequiredParam[float64](request.Params.Arguments, "retentionSizeInMB") + retentionSizeInMB, err := request.RequireFloat("retentionSizeInMB") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get retentionSizeInMB: %v", err)), nil } @@ -1836,7 +1835,7 @@ func handleTopicsSetRetention(_ context.Context, request mcp.CallToolRequest) (* // handleTopicsRemoveRetention removes the retention policy for a topic func handleTopicsRemoveRetention(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } @@ -1865,7 +1864,7 @@ func handleTopicsRemoveRetention(_ context.Context, request mcp.CallToolRequest) // handleTopicsGetBacklogQuota gets the backlog quota policy for a topic func handleTopicsGetBacklogQuota(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } @@ -1878,8 +1877,8 @@ func handleTopicsGetBacklogQuota(_ context.Context, request mcp.CallToolRequest) // Check if applied policies should be included applied := false - appliedParam, hasApplied := common.OptionalParam[bool](request.Params.Arguments, "applied") - if hasApplied { + appliedParam := request.GetBool("applied", false) + if appliedParam { applied = appliedParam } @@ -1911,17 +1910,17 @@ func handleTopicsGetBacklogQuota(_ context.Context, request mcp.CallToolRequest) // handleTopicsSetBacklogQuota sets the backlog quota policy for a topic func handleTopicsSetBacklogQuota(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } - limitSize, err := common.RequiredParam[float64](request.Params.Arguments, "limitSize") + limitSize, err := request.RequireFloat("limitSize") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get limitSize: %v", err)), nil } - policy, err := common.RequiredParam[string](request.Params.Arguments, "policy") + policy, err := request.RequireString("policy") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get policy: %v", err)), nil } @@ -1942,8 +1941,8 @@ func handleTopicsSetBacklogQuota(_ context.Context, request mcp.CallToolRequest) limitTime := int64(-1) // unlimited by default // Get limit time if provided - limitTimeParam, hasLimitTime := common.OptionalParam[float64](request.Params.Arguments, "limitTime") - if hasLimitTime { + limitTimeParam := request.GetFloat("limitTime", -1) + if limitTimeParam != -1 { limitTime = int64(limitTimeParam) } @@ -1957,8 +1956,8 @@ func handleTopicsSetBacklogQuota(_ context.Context, request mcp.CallToolRequest) backlogQuotaType := utils.DestinationStorage // Get quota type if provided - quotaTypeStr, hasQuotaType := common.OptionalParam[string](request.Params.Arguments, "type") - if hasQuotaType { + quotaTypeStr := request.GetString("type", "") + if quotaTypeStr != "" { parsedType, err := utils.ParseBacklogQuotaType(quotaTypeStr) if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to parse quota type: %v", err)), nil @@ -1982,7 +1981,7 @@ func handleTopicsSetBacklogQuota(_ context.Context, request mcp.CallToolRequest) // handleTopicsRemoveBacklogQuota removes the backlog quota policy from a topic func handleTopicsRemoveBacklogQuota(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } @@ -2003,8 +2002,8 @@ func handleTopicsRemoveBacklogQuota(_ context.Context, request mcp.CallToolReque backlogQuotaType := utils.DestinationStorage // Get quota type if provided - quotaTypeStr, hasQuotaType := common.OptionalParam[string](request.Params.Arguments, "type") - if hasQuotaType { + quotaTypeStr := request.GetString("type", "") + if quotaTypeStr != "" { parsedType, err := utils.ParseBacklogQuotaType(quotaTypeStr) if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to parse quota type: %v", err)), nil @@ -2024,7 +2023,7 @@ func handleTopicsRemoveBacklogQuota(_ context.Context, request mcp.CallToolReque // handleTopicsGetCompactionThreshold gets the compaction threshold for a topic func handleTopicsGetCompactionThreshold(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } @@ -2037,8 +2036,8 @@ func handleTopicsGetCompactionThreshold(_ context.Context, request mcp.CallToolR // Check if applied policies should be included applied := false - appliedParam, hasApplied := common.OptionalParam[bool](request.Params.Arguments, "applied") - if hasApplied { + appliedParam := request.GetBool("applied", false) + if appliedParam { applied = appliedParam } @@ -2066,12 +2065,12 @@ func handleTopicsGetCompactionThreshold(_ context.Context, request mcp.CallToolR // handleTopicsSetCompactionThreshold sets the compaction threshold for a topic func handleTopicsSetCompactionThreshold(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } - threshold, err := common.RequiredParam[float64](request.Params.Arguments, "threshold") + threshold, err := request.RequireFloat("threshold") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get threshold: %v", err)), nil } @@ -2112,7 +2111,7 @@ func handleTopicsSetCompactionThreshold(_ context.Context, request mcp.CallToolR // handleTopicsRemoveCompactionThreshold removes the compaction threshold for a topic func handleTopicsRemoveCompactionThreshold(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } @@ -2142,7 +2141,7 @@ func handleTopicsRemoveCompactionThreshold(_ context.Context, request mcp.CallTo // handleTopicsGetInactiveTopic gets the inactive topic policies for a topic func handleTopicsGetInactiveTopic(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } @@ -2155,8 +2154,8 @@ func handleTopicsGetInactiveTopic(_ context.Context, request mcp.CallToolRequest // Check if applied policies should be included applied := false - appliedParam, hasApplied := common.OptionalParam[bool](request.Params.Arguments, "applied") - if hasApplied { + appliedParam := request.GetBool("applied", false) + if appliedParam { applied = appliedParam } @@ -2184,22 +2183,22 @@ func handleTopicsGetInactiveTopic(_ context.Context, request mcp.CallToolRequest // handleTopicsSetInactiveTopic sets the inactive topic policies for a topic func handleTopicsSetInactiveTopic(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } - enableDelete, err := common.RequiredParam[bool](request.Params.Arguments, "enableDeleteWhileInactive") + enableDelete, err := request.RequireBool("enableDeleteWhileInactive") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get enableDeleteWhileInactive: %v", err)), nil } - maxInactiveDuration, err := common.RequiredParam[float64](request.Params.Arguments, "maxInactiveDurationSeconds") + maxInactiveDuration, err := request.RequireFloat("maxInactiveDurationSeconds") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get maxInactiveDurationSeconds: %v", err)), nil } - deleteModeStr, err := common.RequiredParam[string](request.Params.Arguments, "deleteMode") + deleteModeStr, err := request.RequireString("deleteMode") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get deleteMode: %v", err)), nil } @@ -2247,7 +2246,7 @@ func handleTopicsSetInactiveTopic(_ context.Context, request mcp.CallToolRequest // handleTopicsRemoveInactiveTopic removes the inactive topic policies from a topic func handleTopicsRemoveInactiveTopic(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } @@ -2277,12 +2276,12 @@ func handleTopicsRemoveInactiveTopic(_ context.Context, request mcp.CallToolRequ // handleTopicGetPolicy handles getting policies for a topic using the unified tool func handleTopicGetPolicy(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - _, err := common.RequiredParam[string](request.Params.Arguments, "topic") + _, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic name: %v", err)), nil } - policyType, err := common.RequiredParam[string](request.Params.Arguments, "policy") + policyType, err := request.RequireString("policy") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get policy type: %v", err)), nil } @@ -2327,12 +2326,12 @@ func handleTopicGetPolicy(ctx context.Context, request mcp.CallToolRequest) (*mc // handleTopicSetPolicy handles setting policies for a topic using the unified tool func handleTopicSetPolicy(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - _, err := common.RequiredParam[string](request.Params.Arguments, "topic") + _, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic name: %v", err)), nil } - policyType, err := common.RequiredParam[string](request.Params.Arguments, "policy") + policyType, err := request.RequireString("policy") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get policy type: %v", err)), nil } @@ -2377,12 +2376,12 @@ func handleTopicSetPolicy(ctx context.Context, request mcp.CallToolRequest) (*mc // handleTopicRemovePolicy handles removing policies for a topic using the unified tool func handleTopicRemovePolicy(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - _, err := common.RequiredParam[string](request.Params.Arguments, "topic") + _, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic name: %v", err)), nil } - policyType, err := common.RequiredParam[string](request.Params.Arguments, "policy") + policyType, err := request.RequireString("policy") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get policy type: %v", err)), nil } diff --git a/pkg/mcp/pulsar_admin_topic_tools.go b/pkg/mcp/pulsar_admin_topic_tools.go index 50be189..9bf561b 100644 --- a/pkg/mcp/pulsar_admin_topic_tools.go +++ b/pkg/mcp/pulsar_admin_topic_tools.go @@ -28,7 +28,6 @@ import ( "github.com/mark3labs/mcp-go/mcp" "github.com/mark3labs/mcp-go/server" "github.com/streamnative/pulsarctl/pkg/cmdutils" - "github.com/streamnative/streamnative-mcp-server/pkg/common" "github.com/streamnative/streamnative-mcp-server/pkg/pulsar" ) @@ -136,12 +135,12 @@ func PulsarAdminAddTopicTools(s *server.MCPServer, readOnly bool, features []str func handleTopicTool(readOnly bool) func(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { return func(_ context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - resource, err := common.RequiredParam[string](request.Params.Arguments, "resource") + resource, err := request.RequireString("resource") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get resource: %v", err)), nil } - operation, err := common.RequiredParam[string](request.Params.Arguments, "operation") + operation, err := request.RequireString("operation") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get operation: %v", err)), nil } @@ -217,7 +216,7 @@ func handleTopicTool(readOnly bool) func(_ context.Context, request mcp.CallTool // handleTopicsList lists all existing topics under the specified namespace func handleTopicsList(admin cmdutils.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - namespace, err := common.RequiredParam[string](request.Params.Arguments, "namespace") + namespace, err := request.RequireString("namespace") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'namespace' for topics.list: %v", err)), nil } @@ -255,7 +254,7 @@ func handleTopicsList(admin cmdutils.Client, request mcp.CallToolRequest) (*mcp. // handleTopicGet gets the metadata of an existing topic func handleTopicGet(admin cmdutils.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'topic' for topic.get: %v", err)), nil } @@ -285,20 +284,20 @@ func handleTopicGet(admin cmdutils.Client, request mcp.CallToolRequest) (*mcp.Ca // handleTopicStats gets the stats for an existing topic func handleTopicStats(admin cmdutils.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'topic' for topic.stats: %v", err)), nil } // Get optional parameters - partitioned, hasPartitioned := common.OptionalParam[bool](request.Params.Arguments, "partitioned") - perPartition, hasPerPartition := common.OptionalParam[bool](request.Params.Arguments, "per-partition") + partitioned := request.GetBool("partitioned", false) + perPartition := request.GetBool("per-partition", false) - if !hasPartitioned { + if !partitioned { partitioned = false } - if !hasPerPartition { + if !perPartition { perPartition = false } @@ -362,7 +361,7 @@ func handleTopicStats(admin cmdutils.Client, request mcp.CallToolRequest) (*mcp. // handleTopicLookup looks up the owner broker of a topic func handleTopicLookup(admin cmdutils.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'topic' for topic.lookup: %v", err)), nil } @@ -392,12 +391,12 @@ func handleTopicLookup(admin cmdutils.Client, request mcp.CallToolRequest) (*mcp // handleTopicCreate creates a topic with the specified number of partitions func handleTopicCreate(admin cmdutils.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'topic' for topic.create: %v", err)), nil } - partitions, err := common.RequiredParam[float64](request.Params.Arguments, "partitions") + partitions, err := request.RequireFloat("partitions") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'partitions' for topic.create: %v", err)), nil } @@ -431,20 +430,20 @@ func handleTopicCreate(admin cmdutils.Client, request mcp.CallToolRequest) (*mcp // handleTopicDelete deletes a topic func handleTopicDelete(admin cmdutils.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'topic' for topic.delete: %v", err)), nil } // Get optional parameters - force, hasForce := common.OptionalParam[bool](request.Params.Arguments, "force") - nonPartitioned, hasNonPartitioned := common.OptionalParam[bool](request.Params.Arguments, "non-partitioned") + force := request.GetBool("force", false) + nonPartitioned := request.GetBool("non-partitioned", false) - if !hasForce { + if !force { force = false } - if !hasNonPartitioned { + if !nonPartitioned { nonPartitioned = false } @@ -477,7 +476,7 @@ func handleTopicDelete(admin cmdutils.Client, request mcp.CallToolRequest) (*mcp // handleTopicUnload unloads a topic func handleTopicUnload(admin cmdutils.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'topic' for topic.unload: %v", err)), nil } @@ -500,7 +499,7 @@ func handleTopicUnload(admin cmdutils.Client, request mcp.CallToolRequest) (*mcp // handleTopicTerminate terminates a topic func handleTopicTerminate(admin cmdutils.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'topic' for topic.terminate: %v", err)), nil } @@ -528,7 +527,7 @@ func handleTopicTerminate(admin cmdutils.Client, request mcp.CallToolRequest) (* // handleTopicCompact triggers compaction on a topic func handleTopicCompact(admin cmdutils.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'topic' for topic.compact: %v", err)), nil } @@ -552,7 +551,7 @@ func handleTopicCompact(admin cmdutils.Client, request mcp.CallToolRequest) (*mc // handleTopicInternalStats gets the internal stats for a topic func handleTopicInternalStats(admin cmdutils.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'topic' for topic.internal-stats: %v", err)), nil } @@ -581,7 +580,7 @@ func handleTopicInternalStats(admin cmdutils.Client, request mcp.CallToolRequest // handleTopicInternalInfo gets the internal info for a topic func handleTopicInternalInfo(admin cmdutils.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'topic' for topic.internal-info: %v", err)), nil } @@ -610,7 +609,7 @@ func handleTopicInternalInfo(admin cmdutils.Client, request mcp.CallToolRequest) // handleTopicBundleRange gets the bundle range of a topic func handleTopicBundleRange(admin cmdutils.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'topic' for topic.bundle-range: %v", err)), nil } @@ -633,7 +632,7 @@ func handleTopicBundleRange(admin cmdutils.Client, request mcp.CallToolRequest) // handleTopicLastMessageID gets the last message ID of a topic func handleTopicLastMessageID(admin cmdutils.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'topic' for topic.last-message-id: %v", err)), nil } @@ -662,7 +661,7 @@ func handleTopicLastMessageID(admin cmdutils.Client, request mcp.CallToolRequest // handleTopicStatus gets the status of a topic func handleTopicStatus(admin cmdutils.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'topic' for topic.status: %v", err)), nil } @@ -700,12 +699,12 @@ func handleTopicStatus(admin cmdutils.Client, request mcp.CallToolRequest) (*mcp // handleTopicUpdate updates a topic configuration func handleTopicUpdate(admin cmdutils.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'topic' for topic.update: %v", err)), nil } - partitions, err := common.RequiredParam[float64](request.Params.Arguments, "partitions") + partitions, err := request.RequireFloat("partitions") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'partitions' for topic.update: %v", err)), nil } @@ -728,12 +727,12 @@ func handleTopicUpdate(admin cmdutils.Client, request mcp.CallToolRequest) (*mcp // handleTopicOffload offloads data from a topic to long-term storage func handleTopicOffload(admin cmdutils.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'topic' for topic.offload: %v", err)), nil } - messageIDStr, err := common.RequiredParam[string](request.Params.Arguments, "messageId") + messageIDStr, err := request.RequireString("messageId") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'messageId' for topic.offload: %v", err)), nil } @@ -771,7 +770,7 @@ func handleTopicOffload(admin cmdutils.Client, request mcp.CallToolRequest) (*mc // handleTopicOffloadStatus checks the status of data offloading for a topic func handleTopicOffloadStatus(admin cmdutils.Client, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Get required parameters - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Missing required parameter 'topic' for topic.offload-status: %v", err)), nil } diff --git a/pkg/mcp/pulsar_client_consume_tools.go b/pkg/mcp/pulsar_client_consume_tools.go index b247034..3c9edb3 100644 --- a/pkg/mcp/pulsar_client_consume_tools.go +++ b/pkg/mcp/pulsar_client_consume_tools.go @@ -28,7 +28,6 @@ import ( "github.com/apache/pulsar-client-go/pulsar" "github.com/mark3labs/mcp-go/mcp" "github.com/mark3labs/mcp-go/server" - "github.com/streamnative/streamnative-mcp-server/pkg/common" mcppulsar "github.com/streamnative/streamnative-mcp-server/pkg/pulsar" ) @@ -77,49 +76,49 @@ func PulsarClientAddConsumerTools(s *server.MCPServer, _ bool, features []string func handleClientConsume(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Extract required parameters with validation - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } - subscriptionName, err := common.RequiredParam[string](request.Params.Arguments, "subscription-name") + subscriptionName, err := request.RequireString("subscription-name") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get subscription name: %v", err)), nil } // Set default values and extract optional parameters subscriptionType := "exclusive" - if val, exists := common.OptionalParam[string](request.Params.Arguments, "subscription-type"); exists && val != "" { + if val := request.GetString("subscription-type", ""); val != "" { subscriptionType = val } subscriptionMode := "durable" - if val, exists := common.OptionalParam[string](request.Params.Arguments, "subscription-mode"); exists && val != "" { + if val := request.GetString("subscription-mode", ""); val != "" { subscriptionMode = val } initialPosition := "latest" - if val, exists := common.OptionalParam[string](request.Params.Arguments, "initial-position"); exists && val != "" { + if val := request.GetString("initial-position", ""); val != "" { initialPosition = val } numMessages := 10 - if val, exists := common.OptionalParam[float64](request.Params.Arguments, "num-messages"); exists { + if val := request.GetFloat("num-messages", 10); val != 0 { numMessages = int(val) } timeout := 30 - if val, exists := common.OptionalParam[float64](request.Params.Arguments, "timeout"); exists { + if val := request.GetFloat("timeout", 30); val != 0 { timeout = int(val) } showProperties := false - if val, exists := common.OptionalParam[bool](request.Params.Arguments, "show-properties"); exists { + if val := request.GetBool("show-properties", false); val { showProperties = val } hidePayload := false - if val, exists := common.OptionalParam[bool](request.Params.Arguments, "hide-payload"); exists { + if val := request.GetBool("hide-payload", false); val { hidePayload = val } diff --git a/pkg/mcp/pulsar_client_produce_tools.go b/pkg/mcp/pulsar_client_produce_tools.go index c064cae..b7ccae1 100644 --- a/pkg/mcp/pulsar_client_produce_tools.go +++ b/pkg/mcp/pulsar_client_produce_tools.go @@ -28,7 +28,6 @@ import ( "github.com/apache/pulsar-client-go/pulsar" "github.com/mark3labs/mcp-go/mcp" "github.com/mark3labs/mcp-go/server" - "github.com/streamnative/streamnative-mcp-server/pkg/common" mcppulsar "github.com/streamnative/streamnative-mcp-server/pkg/pulsar" ) @@ -88,19 +87,15 @@ func PulsarClientAddProducerTools(s *server.MCPServer, _ bool, features []string func handleClientProduce(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) { // Extract required parameters with validation - topic, err := common.RequiredParam[string](request.Params.Arguments, "topic") + topic, err := request.RequireString("topic") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get topic: %v", err)), nil } // Set default values and extract optional parameters messages := []string{} - if val, exists := common.OptionalParam[[]interface{}](request.Params.Arguments, "messages"); exists && len(val) > 0 { - for _, m := range val { - if strMsg, ok := m.(string); ok { - messages = append(messages, strMsg) - } - } + if val := request.GetStringSlice("messages", []string{}); len(val) > 0 { + messages = val } if len(messages) == 0 { @@ -108,41 +103,37 @@ func handleClientProduce(ctx context.Context, request mcp.CallToolRequest) (*mcp } numProduce := 1 - if val, exists := common.OptionalParam[float64](request.Params.Arguments, "num-produce"); exists { + if val := request.GetFloat("num-produce", 1); val != 0 { numProduce = int(val) } rate := 0.0 - if val, exists := common.OptionalParam[float64](request.Params.Arguments, "rate"); exists { + if val := request.GetFloat("rate", 0); val != 0 { rate = val } disableBatching := false - if val, exists := common.OptionalParam[bool](request.Params.Arguments, "disable-batching"); exists { + if val := request.GetBool("disable-batching", false); val { disableBatching = val } chunkingAllowed := false - if val, exists := common.OptionalParam[bool](request.Params.Arguments, "chunking"); exists { + if val := request.GetBool("chunking", false); val { chunkingAllowed = val } separator := "" - if val, exists := common.OptionalParam[string](request.Params.Arguments, "separator"); exists && val != "" { + if val := request.GetString("separator", ""); val != "" { separator = val } properties := []string{} - if val, exists := common.OptionalParam[[]interface{}](request.Params.Arguments, "properties"); exists && len(val) > 0 { - for _, p := range val { - if strProp, ok := p.(string); ok { - properties = append(properties, strProp) - } - } + if val := request.GetStringSlice("properties", []string{}); len(val) > 0 { + properties = val } key := "" - if val, exists := common.OptionalParam[string](request.Params.Arguments, "key"); exists { + if val := request.GetString("key", ""); val != "" { key = val } diff --git a/pkg/mcp/streamnative_resources_log_tools.go b/pkg/mcp/streamnative_resources_log_tools.go index 1611748..ebc1706 100644 --- a/pkg/mcp/streamnative_resources_log_tools.go +++ b/pkg/mcp/streamnative_resources_log_tools.go @@ -120,50 +120,31 @@ func handleStreamNativeResourcesLog(ctx context.Context, request mcp.CallToolReq } // Extract required parameters with validation - component, err := common.RequiredParam[string](request.Params.Arguments, "component") + component, err := request.RequireString("component") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get component: %v", err)), nil } - name, err := common.RequiredParam[string](request.Params.Arguments, "name") + name, err := request.RequireString("name") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get name: %v", err)), nil } - tenant, hasTenant := common.OptionalParam[string](request.Params.Arguments, "tenant") - if !hasTenant { - tenant = "public" - } + tenant := request.GetString("tenant", "public") - namespace, hasNamespace := common.OptionalParam[string](request.Params.Arguments, "namespace") - if !hasNamespace { - namespace = "default" - } + namespace := request.GetString("namespace", "default") - size, hasSize := common.OptionalParam[string](request.Params.Arguments, "size") - if !hasSize { - size = "20" - } + size := request.GetString("size", "20") - replicaID, hasreplicaID := common.OptionalParam[int](request.Params.Arguments, "replica_id") - if !hasreplicaID { + replicaID := request.GetInt("replica_id", -1) + if replicaID == 0 { replicaID = -1 } - timestampStr, hasTimestamp := common.OptionalParam[string](request.Params.Arguments, "timestamp") - if !hasTimestamp { - timestampStr = "" - } + timestampStr := request.GetString("timestamp", "") + sinceStr := request.GetString("since", "") - sinceStr, hasSince := common.OptionalParam[string](request.Params.Arguments, "since") - if !hasSince { - sinceStr = "" - } - - previousContainer, hasPreviousContainer := common.OptionalParam[bool](request.Params.Arguments, "previous_container") - if !hasPreviousContainer { - previousContainer = false - } + previousContainer := request.GetBool("previous_container", false) if sinceStr != "" { sinceStr = "-" + sinceStr diff --git a/pkg/mcp/streamnative_resources_tools.go b/pkg/mcp/streamnative_resources_tools.go index 7d09842..69007ab 100644 --- a/pkg/mcp/streamnative_resources_tools.go +++ b/pkg/mcp/streamnative_resources_tools.go @@ -81,16 +81,13 @@ func handleStreamNativeResourcesApply(ctx context.Context, request mcp.CallToolR } // Get YAML content - jsonContent, err := common.RequiredParam[string](request.Params.Arguments, "json_content") + jsonContent, err := request.RequireString("json_content") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get json_content: %v", err)), nil } // Get dry_run flag - dryRun, hasDryRun := common.OptionalParam[bool](request.Params.Arguments, "dry_run") - if !hasDryRun { - dryRun = false - } + dryRun := request.GetBool("dry_run", false) // Get API client apiClient, err := config.GetAPIClient() @@ -327,12 +324,12 @@ func handleStreamNativeResourcesDelete(ctx context.Context, request mcp.CallTool snConfig := common.GetOptions(ctx) organization := snConfig.Organization - name, err := common.RequiredParam[string](request.Params.Arguments, "name") + name, err := request.RequireString("name") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get name: %v", err)), nil } - resourceType, err := common.RequiredParam[string](request.Params.Arguments, "type") + resourceType, err := request.RequireString("type") if err != nil { return mcp.NewToolResultError(fmt.Sprintf("Failed to get type: %v", err)), nil } diff --git a/pkg/pftools/manager.go b/pkg/pftools/manager.go index d69470b..91fb014 100644 --- a/pkg/pftools/manager.go +++ b/pkg/pftools/manager.go @@ -435,7 +435,7 @@ func (m *PulsarFunctionManager) handleToolCall(fnTool *FunctionTool) func(ctx co }() // Invoke function and wait for result - result, err := invoker.InvokeFunctionAndWait(timeoutCtx, fnTool, request.Params.Arguments) + result, err := invoker.InvokeFunctionAndWait(timeoutCtx, fnTool, request.GetArguments()) // Record success or failure if err != nil {