Skip to content

Commit f4cfe22

Browse files
authored
support create serverless cluster (#7)
1 parent 3b1e81d commit f4cfe22

File tree

7 files changed

+580
-32
lines changed

7 files changed

+580
-32
lines changed

go.mod

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ require (
66
github.com/99designs/keyring v1.2.2
77
github.com/apache/pulsar-client-go v0.13.1
88
github.com/dgrijalva/jwt-go v3.2.0+incompatible
9-
github.com/mark3labs/mcp-go v0.25.0
9+
github.com/mark3labs/mcp-go v0.26.0
1010
github.com/mitchellh/go-homedir v1.1.0
1111
github.com/pkg/errors v0.9.1
1212
github.com/sirupsen/logrus v1.9.3
@@ -75,11 +75,10 @@ require (
7575
github.com/twmb/franz-go/pkg/kmsg v1.9.0 // indirect
7676
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
7777
go.uber.org/atomic v1.11.0 // indirect
78-
golang.org/x/crypto v0.36.0 // indirect
78+
golang.org/x/crypto v0.32.0 // indirect
7979
golang.org/x/mod v0.20.0 // indirect
80-
golang.org/x/net v0.38.0 // indirect
81-
golang.org/x/sys v0.31.0 // indirect
82-
golang.org/x/term v0.30.0 // indirect
80+
golang.org/x/sys v0.29.0 // indirect
81+
golang.org/x/term v0.28.0 // indirect
8382
google.golang.org/protobuf v1.35.1 // indirect
8483
)
8584

go.sum

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ
129129
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
130130
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
131131
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
132-
github.com/mark3labs/mcp-go v0.25.0 h1:UUpcMT3L5hIhuDy7aifj4Bphw4Pfx1Rf8mzMXDe8RQw=
133-
github.com/mark3labs/mcp-go v0.25.0/go.mod h1:rXqOudj/djTORU/ThxYx8fqEVj/5pvTuuebQ2RC7uk4=
132+
github.com/mark3labs/mcp-go v0.26.0 h1:xz/Kv1cHLYovF8txv6btBM39/88q3YOjnxqhi51jB0w=
133+
github.com/mark3labs/mcp-go v0.26.0/go.mod h1:rXqOudj/djTORU/ThxYx8fqEVj/5pvTuuebQ2RC7uk4=
134134
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
135135
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
136136
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
@@ -251,16 +251,16 @@ go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
251251
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
252252
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
253253
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
254-
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
255-
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
254+
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
255+
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
256256
golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
257257
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
258258
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
259259
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
260260
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
261261
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
262-
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
263-
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
262+
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
263+
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
264264
golang.org/x/oauth2 v0.25.0 h1:CY4y7XT9v0cRI9oupztF8AgiIu99L/ksR/Xp/6jrZ70=
265265
golang.org/x/oauth2 v0.25.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
266266
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -272,16 +272,16 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
272272
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
273273
golang.org/x/sys v0.0.0-20210819135213-f52c844e1c1c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
274274
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
275-
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
276-
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
275+
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
276+
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
277277
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
278-
golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y=
279-
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
278+
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
279+
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
280280
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
281281
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
282282
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
283-
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
284-
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
283+
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
284+
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
285285
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
286286
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
287287
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

pkg/cmd/mcp/stdio.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ func newStdioServer(configOpts *ServerOptions, logrusLogger *logrus.Logger) *ser
144144
mcp.RegisterPrompts(s)
145145
mcp.RegisterContextTools(s, configOpts.Features)
146146
mcp.StreamNativeAddLogTools(s, configOpts.ReadOnly, configOpts.Features)
147+
mcp.StreamNativeAddResourceTools(s, configOpts.ReadOnly, configOpts.Features)
147148
}
148149
case snConfig.ExternalKafka != nil:
149150
{

pkg/mcp/context_tools.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,15 @@ func RegisterContextTools(s *server.MCPServer, features []string) {
3434
return
3535
}
3636
// Add whoami tool
37-
whoamiTool := mcp.NewTool("streamnative_cloud_context_whoami",
37+
whoamiTool := mcp.NewTool("sncloud_context_whoami",
3838
mcp.WithDescription("Display the currently logged-in service account. "+
3939
"Returns the name of the authenticated service account and the organization."),
4040
)
4141
s.AddTool(whoamiTool, handleWhoami)
4242

4343
// Add set-context tool
44-
setContextTool := mcp.NewTool("streamnative_cloud_context_use_cluster",
45-
mcp.WithDescription("Set the current context to a specific StreamNative Cloud cluster, once you set the context, you can use pulsar and kafka tools to interact with the cluster. If you encounter ContextNotSetErr, please use `streamnative_cloud_context_available_clusters` to list the available clusters and set the context to a specific cluster."),
44+
setContextTool := mcp.NewTool("sncloud_context_use_cluster",
45+
mcp.WithDescription("Set the current context to a specific StreamNative Cloud cluster, once you set the context, you can use pulsar and kafka tools to interact with the cluster. If you encounter ContextNotSetErr, please use `sncloud_context_available_clusters` to list the available clusters and set the context to a specific cluster."),
4646
mcp.WithString("instanceName", mcp.Required(),
4747
mcp.Description("The name of the pulsar instance to use"),
4848
),
@@ -53,8 +53,8 @@ func RegisterContextTools(s *server.MCPServer, features []string) {
5353
s.AddTool(setContextTool, handleSetContext)
5454

5555
// Add available-contexts tool
56-
availableContextsTool := mcp.NewTool("streamnative_cloud_available_contexts",
57-
mcp.WithDescription("Display the available pulsar clusters for the current organization on StreamNative Cloud. You can use `streamnative_cloud_context_use_cluster` to change the context to a specific cluster. You will need to ask for the USER to confirm the target context cluster if there are multiple clusters."),
56+
availableContextsTool := mcp.NewTool("sncloud_context_available_clusters",
57+
mcp.WithDescription("Display the available pulsar clusters for the current organization on StreamNative Cloud. You can use `sncloud_context_use_cluster` to change the context to a specific cluster. You will need to ask for the USER to confirm the target context cluster if there are multiple clusters."),
5858
)
5959
s.AddTool(availableContextsTool, handleAvailableContexts)
6060
}

pkg/mcp/prompts.go

Lines changed: 194 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,21 +21,63 @@ import (
2121
"context"
2222
"encoding/json"
2323
"fmt"
24+
"slices"
2425

2526
"github.com/mark3labs/mcp-go/mcp"
2627
"github.com/mark3labs/mcp-go/server"
2728
"github.com/streamnative/streamnative-mcp-server/pkg/config"
2829
sncloud "github.com/streamnative/streamnative-mcp-server/sdk/sdk-apiserver"
30+
"k8s.io/utils/ptr"
31+
)
32+
33+
type ServerlessPoolMember struct {
34+
Provider string
35+
Namespace string
36+
Pool string
37+
Location string
38+
}
39+
40+
var (
41+
ServerlessPoolMemberList = []ServerlessPoolMember{
42+
{
43+
Provider: "azure",
44+
Namespace: "streamnative",
45+
Pool: "shared-azure",
46+
Location: "eastus",
47+
},
48+
{
49+
Provider: "aws",
50+
Namespace: "streamnative",
51+
Pool: "shared-aws",
52+
Location: "us-east-2",
53+
},
54+
// {
55+
// Provider: "gcloud",
56+
// Namespace: "streamnative",
57+
// Pool: "shared-gcp",
58+
// Location: "us-central1",
59+
// },
60+
}
61+
AvailableProviders = []string{"azure", "aws", "gcloud"}
2962
)
3063

3164
func RegisterPrompts(s *server.MCPServer) {
32-
s.AddPrompt(mcp.NewPrompt("list-streamnative-cloud-pulsar-clusters",
33-
mcp.WithPromptDescription("List all Pulsar clusters in the StreamNative Cloud"),
65+
s.AddPrompt(mcp.NewPrompt("list-sncloud-clusters",
66+
mcp.WithPromptDescription("List all clusters from the StreamNative Cloud"),
3467
), handleListPulsarClusters)
35-
s.AddPrompt(mcp.NewPrompt("read-streamnative-cloud-pulsar-cluster",
36-
mcp.WithPromptDescription("Read a Pulsar cluster in the StreamNative Cloud"),
37-
mcp.WithArgument("name", mcp.RequiredArgument(), mcp.ArgumentDescription("The name of the Pulsar cluster")),
68+
s.AddPrompt(mcp.NewPrompt("read-sncloud-cluster",
69+
mcp.WithPromptDescription("Read a cluster from the StreamNative Cloud"),
70+
mcp.WithArgument("name", mcp.RequiredArgument(), mcp.ArgumentDescription("The name of the cluster")),
3871
), handleReadPulsarCluster)
72+
s.AddPrompt(
73+
mcp.NewPrompt("build-sncloud-serverless-cluster",
74+
mcp.WithPromptDescription("Build a Serverless cluster in the StreamNative Cloud"),
75+
mcp.WithArgument("instance-name", mcp.RequiredArgument(), mcp.ArgumentDescription("The name of the Pulsar instance, cannot reuse the name of existing instance.")),
76+
mcp.WithArgument("cluster-name", mcp.RequiredArgument(), mcp.ArgumentDescription("The name of the Pulsar cluster, cannot reuse the name of existing cluster.")),
77+
mcp.WithArgument("provider", mcp.ArgumentDescription("The cloud provider, could be `aws`, `gcp`, `azure`. If the selected provider do not serve serverless cluster, the prompt will return an error. If not specified, the system will use a random provider depending on the availability.")),
78+
),
79+
handleBuildServerlessPulsarCluster,
80+
)
3981
}
4082

4183
func handleListPulsarClusters(ctx context.Context, _ mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
@@ -99,7 +141,7 @@ func handleListPulsarClusters(ctx context.Context, _ mcp.GetPromptRequest) (*mcp
99141
}
100142

101143
return &mcp.GetPromptResult{
102-
Description: fmt.Sprintf("Pulsar clusters from StreamNative Cloud organization %s, you can use `streamnative_cloud_context_use_cluster` tool to switch to selected cluster, and use pulsar and kafka tools to interact with the cluster.", options.Organization),
144+
Description: fmt.Sprintf("Pulsar clusters from StreamNative Cloud organization %s, you can use `sncloud_context_use_cluster` tool to switch to selected cluster, and use pulsar and kafka tools to interact with the cluster.", options.Organization),
103145
Messages: messages,
104146
}, nil
105147
}
@@ -156,7 +198,152 @@ func handleReadPulsarCluster(ctx context.Context, request mcp.GetPromptRequest)
156198
}
157199

158200
return &mcp.GetPromptResult{
159-
Description: fmt.Sprintf("Detailed information of Pulsar cluster %s, you can use `streamnative_cloud_context_use_cluster` tool to switch to this cluster, and use pulsar and kafka tools to interact with the cluster.", name),
201+
Description: fmt.Sprintf("Detailed information of Pulsar cluster %s, you can use `sncloud_context_use_cluster` tool to switch to this cluster, and use pulsar and kafka tools to interact with the cluster.", name),
202+
Messages: messages,
203+
}, nil
204+
}
205+
206+
func handleBuildServerlessPulsarCluster(ctx context.Context, request mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
207+
options := getOptions(ctx)
208+
apiClient, err := config.GetAPIClient()
209+
if err != nil {
210+
return nil, fmt.Errorf("failed to get API client: %v", err)
211+
}
212+
arguments := convertToMapInterface(request.Params.Arguments)
213+
214+
instanceName, err := requiredParam[string](arguments, "instance-name")
215+
if err != nil {
216+
return nil, fmt.Errorf("failed to get instance name: %v", err)
217+
}
218+
219+
clusterName, err := requiredParam[string](arguments, "cluster-name")
220+
if err != nil {
221+
return nil, fmt.Errorf("failed to get cluster name: %v", err)
222+
}
223+
224+
provider, hasProvider := optionalParam[string](arguments, "provider")
225+
if !hasProvider {
226+
provider = ""
227+
}
228+
if provider != "" {
229+
if !slices.Contains(AvailableProviders, provider) {
230+
return nil, fmt.Errorf("invalid provider: %s, available providers: %v", provider, AvailableProviders)
231+
}
232+
}
233+
234+
poolOptions, poolOptionsBody, err := apiClient.CloudStreamnativeIoV1alpha1Api.ListCloudStreamnativeIoV1alpha1NamespacedPoolOption(ctx, options.Organization).Execute()
235+
if err != nil {
236+
return nil, fmt.Errorf("failed to list pool options: %v", err)
237+
}
238+
defer poolOptionsBody.Body.Close()
239+
if poolOptions == nil {
240+
return nil, fmt.Errorf("no pool options found")
241+
}
242+
243+
var poolRef *sncloud.ComGithubStreamnativeCloudApiServerPkgApisCloudV1alpha1PoolRef
244+
var selectedLocation *string
245+
246+
for _, poolOpt := range poolOptions.Items {
247+
if pr, ok := poolOpt.Spec.GetPoolRefOk(); ok {
248+
for _, poolMember := range ServerlessPoolMemberList {
249+
if provider != "" && poolOpt.Spec.CloudType != provider {
250+
continue
251+
}
252+
if pr.Name == poolMember.Pool && pr.Namespace == poolMember.Namespace {
253+
for _, location := range poolOpt.Spec.Locations {
254+
if location.Location == poolMember.Location {
255+
poolRef = pr
256+
selectedLocation = &location.Location
257+
break
258+
}
259+
}
260+
}
261+
}
262+
}
263+
}
264+
265+
if poolRef == nil || selectedLocation == nil {
266+
return nil, fmt.Errorf("no available pool")
267+
}
268+
269+
inst := sncloud.ComGithubStreamnativeCloudApiServerPkgApisCloudV1alpha1PulsarInstance{}
270+
clus := sncloud.ComGithubStreamnativeCloudApiServerPkgApisCloudV1alpha1PulsarCluster{}
271+
272+
inst.ApiVersion = ptr.To("cloud.streamnative.io/v1alpha1")
273+
inst.Kind = ptr.To("PulsarInstance")
274+
inst.Metadata = &sncloud.V1ObjectMeta{
275+
Name: &instanceName,
276+
Namespace: &options.Organization,
277+
Labels: &map[string]string{
278+
"managed-by": "streamnative-mcp",
279+
},
280+
}
281+
282+
inst.Spec = &sncloud.ComGithubStreamnativeCloudApiServerPkgApisCloudV1alpha1PulsarInstanceSpec{
283+
AvailabilityMode: "zonal",
284+
PoolRef: poolRef,
285+
Type: ptr.To("serverless"),
286+
}
287+
288+
clus.ApiVersion = ptr.To("cloud.streamnative.io/v1alpha1")
289+
clus.Kind = ptr.To("PulsarCluster")
290+
clus.Metadata = &sncloud.V1ObjectMeta{
291+
Name: ptr.To(""),
292+
Namespace: &options.Organization,
293+
Labels: &map[string]string{
294+
"managed-by": "streamnative-mcp",
295+
},
296+
}
297+
298+
clus.Spec = &sncloud.ComGithubStreamnativeCloudApiServerPkgApisCloudV1alpha1PulsarClusterSpec{
299+
Broker: sncloud.ComGithubStreamnativeCloudApiServerPkgApisCloudV1alpha1Broker{
300+
Replicas: 2,
301+
Resources: &sncloud.ComGithubStreamnativeCloudApiServerPkgApisCloudV1alpha1DefaultNodeResource{
302+
Cpu: "1000m",
303+
Memory: "4294967296",
304+
},
305+
},
306+
DisplayName: ptr.To(clusterName),
307+
InstanceName: instanceName,
308+
Location: *selectedLocation,
309+
ReleaseChannel: ptr.To("rapid"),
310+
}
311+
312+
instJSON, err := json.Marshal(inst)
313+
if err != nil {
314+
return nil, fmt.Errorf("failed to marshal instance: %v", err)
315+
}
316+
clusJSON, err := json.Marshal(clus)
317+
if err != nil {
318+
return nil, fmt.Errorf("failed to marshal cluster: %v", err)
319+
}
320+
321+
messages := []mcp.PromptMessage{
322+
{
323+
Content: mcp.TextContent{
324+
Type: "text",
325+
Text: "The following is the Pulsar instance JSON definition and the Pulsar cluster JSON definition, you can use the `sncloud_resources_apply` tool to apply the resources to the StreamNative Cloud. Please directly use the JSON content and not modify the content. The PulsarCluster name is required to be empty. You will need to apply PulsarInstance first, then apply PulsarCluster.",
326+
},
327+
Role: mcp.RoleUser,
328+
},
329+
{
330+
Content: mcp.TextContent{
331+
Type: "text",
332+
Text: string(instJSON),
333+
},
334+
Role: mcp.RoleUser,
335+
},
336+
{
337+
Content: mcp.TextContent{
338+
Type: "text",
339+
Text: string(clusJSON),
340+
},
341+
Role: mcp.RoleUser,
342+
},
343+
}
344+
345+
return &mcp.GetPromptResult{
346+
Description: fmt.Sprintf("Create a new Serverless Pulsar cluster %s's related resources that can be applied to the StreamNative Cloud.", clusterName),
160347
Messages: messages,
161348
}, nil
162349
}

pkg/mcp/streamnative_resources_log_tools.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ func StreamNativeAddLogTools(s *server.MCPServer, _ bool, features []string) {
4242
return
4343
}
4444

45-
logTool := mcp.NewTool("streamnative_resources_log",
45+
logTool := mcp.NewTool("sncloud_logs",
4646
mcp.WithDescription("Display the logs of resources in StreamNative Cloud, including pulsar functions, pulsar source connectors, pulsar sink connectors, and kafka connect connectors logs running along with PulsarInstance and PulsarCluster."+
47-
"This tool is used to help you debug the issues of resources in StreamNative Cloud. You can use `streamnative_cloud_context_use_cluster` to change the context to a specific cluster first, then use this tool to get the logs of resources in the cluster. This tool is suggested to be used with 'pulsar_admin_functions', 'pulsar_admin_sinks', 'pulsar_admin_sources', and 'kafka_admin_connect'"),
47+
"This tool is used to help you debug the issues of resources in StreamNative Cloud. You can use `sncloud_context_use_cluster` to change the context to a specific cluster first, then use this tool to get the logs of resources in the cluster. This tool is suggested to be used with 'pulsar_admin_functions', 'pulsar_admin_sinks', 'pulsar_admin_sources', and 'kafka_admin_connect'"),
4848
mcp.WithString("component", mcp.Required(),
4949
mcp.Description("The component to get logs from, including "+strings.Join(FunctionConnectorList, ", ")),
5050
mcp.Enum(FunctionConnectorList...),
@@ -115,7 +115,7 @@ func handleStreamNativeResourcesLog(ctx context.Context, request mcp.CallToolReq
115115
snConfig := getOptions(ctx)
116116
instance, cluster, organization := GetMcpContext()
117117
if instance == "" || cluster == "" || organization == "" {
118-
return mcp.NewToolResultError("No context is set, please use `streamnative_cloud_context_use_cluster` to set the context first."), nil
118+
return mcp.NewToolResultError("No context is set, please use `sncloud_context_use_cluster` to set the context first."), nil
119119
}
120120

121121
// Extract required parameters with validation

0 commit comments

Comments
 (0)