Skip to content

Commit 4f6c1ad

Browse files
authored
Support start mcp server in SSE (#17)
1 parent 917be6a commit 4f6c1ad

File tree

9 files changed

+320
-86
lines changed

9 files changed

+320
-86
lines changed

README.md

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ If you want to access to your StreamNative Cloud, you will need to have followin
5656

5757
### Start the MCP Server
5858

59+
#### Using stdio Server
60+
5961
```bash
6062
# Start MCP server with StreamNative Cloud authentication
6163
bin/snmcp stdio --organization my-org --key-file /path/to/key-file.json
@@ -68,6 +70,19 @@ snmcp stdio --use-external-pulsar --pulsar-web-service-url http://pulsar.example
6870
bin/snmcp stdio --use-external-pulsar --pulsar-web-service-url http://pulsar.example.com:8080 --pulsar-token "xxx"
6971
```
7072

73+
#### Using SSE (Server-Sent Events) Server
74+
75+
```bash
76+
# Start MCP server with SSE and StreamNative Cloud authentication
77+
snmcp sse --http-addr :9090 --http-path /mcp --organization my-org --key-file /path/to/key-file.json
78+
79+
# Start MCP server with SSE and external Kafka
80+
snmcp sse --http-addr :9090 --http-path /mcp --use-external-kafka --kafka-bootstrap-servers localhost:9092
81+
82+
# Start MCP server with SSE and external Pulsar
83+
snmcp sse --http-addr :9090 --http-path /mcp --use-external-pulsar --pulsar-web-service-url http://pulsar.example.com:8080
84+
```
85+
7186
### Command-line Options
7287

7388
```
@@ -117,6 +132,8 @@ Flags:
117132
--server string The server to connect to (default "https://api.streamnative.cloud")
118133
--use-external-kafka Use external Kafka
119134
--use-external-pulsar Use external Pulsar
135+
--http-addr string HTTP server address (default ":9090")
136+
--http-path string HTTP server path for SSE endpoint (default "/mcp")
120137
-v, --version version for snmcp
121138
```
122139

@@ -190,6 +207,32 @@ You can combine these features as needed using the `--features` flag. For exampl
190207
bin/snmcp stdio --organization my-org --key-file /path/to/key-file.json --features pulsar-client
191208
```
192209

210+
## Inspecting the MCP Server
211+
212+
You can use the [@modelcontextprotocol/inspector](https://www.npmjs.com/package/@modelcontextprotocol/inspector) tool to inspect and test your MCP server. This is particularly useful for debugging and verifying your server's configuration.
213+
214+
### Installation
215+
216+
```bash
217+
npm install -g @modelcontextprotocol/inspector
218+
```
219+
220+
### Usage
221+
222+
```bash
223+
# Inspect a stdio server
224+
mcp-inspector stdio --command "snmcp stdio --organization my-org --key-file /path/to/key-file.json"
225+
226+
# Inspect an SSE server
227+
mcp-inspector sse --url "http://localhost:9090/mcp"
228+
```
229+
230+
The inspector provides a web interface where you can:
231+
- View available tools and their schemas
232+
- Test tool invocations
233+
- Monitor server responses
234+
- Debug connection issues
235+
193236
## Integration with MCP Clients
194237

195238
This server can be used with any MCP-compatible client, such as:
@@ -204,10 +247,12 @@ Without it, you may encounter the error: `message will exceed the length limit f
204247

205248
### Usage with Claude Desktop
206249

250+
#### Using stdio Server
251+
207252
```json
208253
{
209254
"mcpServers": {
210-
"snmcp": {
255+
"mcp-streamnative": {
211256
"command": "${PATH_TO_SNMCP}/bin/snmcp",
212257
"args": [
213258
"stdio",
@@ -223,6 +268,36 @@ Without it, you may encounter the error: `message will exceed the length limit f
223268

224269
Please remember to replace `${PATH_TO_SNMCP}` with the actual path to the `snmcp` binary and `${STREAMNATIVE_CLOUD_ORGANIZATION_ID}` and `${STREAMNATIVE_CLOUD_KEY_FILE}` with your StreamNative Cloud organization ID and key file path, respectively.
225270

271+
#### Using SSE Server
272+
273+
First, install the mcp-proxy tool:
274+
275+
```bash
276+
pip install mcp-proxy
277+
```
278+
279+
Then configure Claude Desktop to use the SSE server:
280+
281+
```json
282+
{
283+
"mcpServers": {
284+
"mcp-streamnative-proxy": {
285+
"command": "mcp-proxy",
286+
"args": [
287+
"http://localhost:9090/mcp/sse"
288+
]
289+
}
290+
}
291+
}
292+
```
293+
294+
Note: If mcp-proxy is not in your system PATH, you'll need to provide the full path to the executable. For example:
295+
- On macOS: `/Library/Frameworks/Python.framework/Versions/3.11/bin/mcp-proxy`
296+
- On Linux: `/usr/local/bin/mcp-proxy`
297+
- On Windows: `C:\Python311\Scripts\mcp-proxy.exe`
298+
299+
Please remember to replace `http://localhost:9090/mcp/sse` with the right URL.
300+
226301
## About Model Context Protocol (MCP)
227302

228303
The Model Context Protocol (MCP) is an open protocol that standardizes how applications provide context to LLMs. MCP helps build agents and complex workflows on top of LLMs by providing:

cmd/streamnative-mcp-server/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ to interact with StreamNative Cloud resources and services.`,
6666
o.AddFlags(rootCmd)
6767
// Add subcommands
6868
rootCmd.AddCommand(mcp.NewCmdMcpStdioServer(o))
69+
rootCmd.AddCommand(mcp.NewCmdMcpSseServer(o))
6970

7071
rootCmd.SetVersionTemplate("{{.Short}}\n{{.Version}}\n")
7172

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ require (
77
github.com/apache/pulsar-client-go v0.13.1
88
github.com/dgrijalva/jwt-go v3.2.0+incompatible
99
github.com/hamba/avro/v2 v2.28.0
10-
github.com/mark3labs/mcp-go v0.26.0
10+
github.com/mark3labs/mcp-go v0.27.0
1111
github.com/mitchellh/go-homedir v1.1.0
1212
github.com/pkg/errors v0.9.1
1313
github.com/sirupsen/logrus v1.9.3

go.sum

Lines changed: 2 additions & 2 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.26.0 h1:xz/Kv1cHLYovF8txv6btBM39/88q3YOjnxqhi51jB0w=
133-
github.com/mark3labs/mcp-go v0.26.0/go.mod h1:rXqOudj/djTORU/ThxYx8fqEVj/5pvTuuebQ2RC7uk4=
132+
github.com/mark3labs/mcp-go v0.27.0 h1:iok9kU4DUIU2/XVLgFS2Q9biIDqstC0jY4EQTK2Erzc=
133+
github.com/mark3labs/mcp-go v0.27.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=

pkg/cmd/mcp/mcp.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ type ServerOptions struct {
3636
LogFile string
3737
LogCommands bool
3838
Features []string
39+
HTTPAddr string
40+
HTTPPath string
3941
*config.Options
4042
}
4143

@@ -160,6 +162,8 @@ func (o *ServerOptions) AddFlags(cmd *cobra.Command) {
160162
cmd.PersistentFlags().StringVar(&o.LogFile, "log-file", "", "Path to log file")
161163
cmd.PersistentFlags().BoolVar(&o.LogCommands, "enable-command-logging", false, "When enabled, the server will log all command requests and responses to the log file")
162164
cmd.PersistentFlags().StringSliceVar(&o.Features, "features", []string{}, "Features to enable, defaults to `all`")
165+
cmd.PersistentFlags().StringVar(&o.HTTPAddr, "http-addr", "", "HTTP address")
166+
cmd.PersistentFlags().StringVar(&o.HTTPPath, "http-path", "", "HTTP path")
163167
}
164168

165169
func (o *ServerOptions) newClientCredentialsFlow(

pkg/cmd/mcp/server.go

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package mcp
19+
20+
import (
21+
stdlog "log"
22+
"os"
23+
24+
"github.com/mark3labs/mcp-go/server"
25+
"github.com/sirupsen/logrus"
26+
"github.com/streamnative/streamnative-mcp-server/pkg/mcp"
27+
)
28+
29+
func newMcpServer(configOpts *ServerOptions, logrusLogger *logrus.Logger) *server.MCPServer {
30+
snConfig := configOpts.Options.LoadConfigOrDie()
31+
var s *server.MCPServer
32+
switch {
33+
case snConfig.KeyFile != "":
34+
{
35+
issuer := snConfig.Auth.Issuer()
36+
userName, err := configOpts.Options.WhoAmI(issuer.Audience)
37+
if err != nil {
38+
stdlog.Fatalf("failed to get user name: %v", err)
39+
os.Exit(1)
40+
}
41+
// Create a new MCP server
42+
s = server.NewMCPServer(
43+
"streamnative-mcp-server",
44+
"0.0.1",
45+
server.WithResourceCapabilities(true, true),
46+
server.WithInstructions(mcp.GetStreamNativeCloudServerInstructions(userName, snConfig)),
47+
server.WithLogging())
48+
49+
mcp.RegisterPrompts(s)
50+
mcp.RegisterContextTools(s, configOpts.Features)
51+
mcp.StreamNativeAddLogTools(s, configOpts.ReadOnly, configOpts.Features)
52+
mcp.StreamNativeAddResourceTools(s, configOpts.ReadOnly, configOpts.Features)
53+
}
54+
case snConfig.ExternalKafka != nil:
55+
{
56+
s = server.NewMCPServer(
57+
"streamnative-mcp-server/kafka",
58+
"0.0.1",
59+
server.WithResourceCapabilities(true, true),
60+
server.WithInstructions(mcp.GetExternalKafkaServerInstructions(snConfig.ExternalKafka.BootstrapServers)),
61+
server.WithLogging())
62+
}
63+
case snConfig.ExternalPulsar != nil:
64+
{
65+
s = server.NewMCPServer(
66+
"streamnative-mcp-server/pulsar",
67+
"0.0.1",
68+
server.WithResourceCapabilities(true, true),
69+
server.WithInstructions(mcp.GetExternalPulsarServerInstructions(snConfig.ExternalPulsar.WebServiceURL)),
70+
server.WithLogging())
71+
}
72+
default:
73+
{
74+
stdlog.Fatalf("no valid configuration found")
75+
os.Exit(1)
76+
}
77+
}
78+
79+
mcp.PulsarAdminAddBrokersTools(s, configOpts.ReadOnly, configOpts.Features)
80+
mcp.PulsarAdminAddBrokerStatsTools(s, configOpts.ReadOnly, configOpts.Features)
81+
mcp.PulsarAdminAddClusterTools(s, configOpts.ReadOnly, configOpts.Features)
82+
mcp.PulsarAdminAddFunctionsWorkerTools(s, configOpts.ReadOnly, configOpts.Features)
83+
mcp.PulsarAdminAddNamespaceTools(s, configOpts.ReadOnly, configOpts.Features)
84+
mcp.PulsarAdminAddNamespacePolicyTools(s, configOpts.ReadOnly, configOpts.Features)
85+
mcp.PulsarAdminAddNsIsolationPolicyTools(s, configOpts.ReadOnly, configOpts.Features)
86+
mcp.PulsarAdminAddPackagesTools(s, configOpts.ReadOnly, configOpts.Features)
87+
mcp.PulsarAdminAddResourceQuotasTools(s, configOpts.ReadOnly, configOpts.Features)
88+
mcp.PulsarAdminAddSchemasTools(s, configOpts.ReadOnly, configOpts.Features)
89+
mcp.PulsarAdminAddSubscriptionTools(s, configOpts.ReadOnly, configOpts.Features)
90+
mcp.PulsarAdminAddTenantTools(s, configOpts.ReadOnly, configOpts.Features)
91+
mcp.PulsarAdminAddTopicTools(s, configOpts.ReadOnly, configOpts.Features)
92+
mcp.PulsarAdminAddSinksTools(s, configOpts.ReadOnly, configOpts.Features)
93+
mcp.PulsarAdminAddFunctionsTools(s, configOpts.ReadOnly, configOpts.Features)
94+
mcp.PulsarAdminAddSourcesTools(s, configOpts.ReadOnly, configOpts.Features)
95+
mcp.PulsarAdminAddTopicPolicyTools(s, configOpts.ReadOnly, configOpts.Features)
96+
mcp.PulsarClientAddConsumerTools(s, configOpts.ReadOnly, configOpts.Features)
97+
mcp.PulsarClientAddProducerTools(s, configOpts.ReadOnly, configOpts.Features)
98+
99+
mcp.KafkaAdminAddTopicTools(s, configOpts.ReadOnly, configOpts.Features)
100+
mcp.KafkaAdminAddPartitionsTools(s, configOpts.ReadOnly, configOpts.Features)
101+
mcp.KafkaAdminAddGroupsTools(s, configOpts.ReadOnly, configOpts.Features)
102+
mcp.KafkaAdminAddSchemaRegistryTools(s, configOpts.ReadOnly, configOpts.Features)
103+
mcp.KafkaAdminAddKafkaConnectTools(s, configOpts.ReadOnly, configOpts.Features)
104+
mcp.KafkaClientAddConsumeTools(s, configOpts.ReadOnly, logrusLogger, configOpts.Features)
105+
mcp.KafkaClientAddProduceTools(s, configOpts.ReadOnly, configOpts.Features)
106+
return s
107+
}

0 commit comments

Comments
 (0)