Skip to content

Commit 8bfbe22

Browse files
committed
lint
1 parent c9dd4b8 commit 8bfbe22

26 files changed

+355
-305
lines changed

.github/workflows/lint.yaml

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
name: Lint
2+
on:
3+
push:
4+
pull_request:
5+
6+
permissions:
7+
contents: read
8+
9+
jobs:
10+
lint:
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- name: Check out code
15+
uses: actions/checkout@v4
16+
17+
- name: Set up Go
18+
uses: actions/setup-go@v5
19+
with:
20+
go-version-file: 'go.mod'
21+
22+
- name: Verify dependencies
23+
run: |
24+
go mod verify
25+
go mod download
26+
27+
LINT_VERSION=1.64.8
28+
curl -fsSL https://github.com/golangci/golangci-lint/releases/download/v${LINT_VERSION}/golangci-lint-${LINT_VERSION}-linux-amd64.tar.gz | \
29+
tar xz --strip-components 1 --wildcards \*/golangci-lint
30+
mkdir -p bin && mv golangci-lint bin/
31+
32+
- name: Run checks
33+
run: |
34+
STATUS=0
35+
assert-nothing-changed() {
36+
local diff
37+
"$@" >/dev/null || return 1
38+
if ! diff="$(git diff -U1 --color --exit-code)"; then
39+
printf '\e[31mError: running `\e[1m%s\e[22m` results in modifications that you must check into version control:\e[0m\n%s\n\n' "$*" "$diff" >&2
40+
git checkout -- .
41+
STATUS=1
42+
fi
43+
}
44+
45+
assert-nothing-changed go fmt ./...
46+
assert-nothing-changed go mod tidy
47+
48+
bin/golangci-lint run --out-format=colored-line-number --timeout=3m || STATUS=$?
49+
50+
exit $STATUS

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,6 @@ dist/
55
.DS_Store
66
tmp/
77
*.log
8+
9+
# Go
10+
vendor

.golangci.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
run:
2+
timeout: 5m
3+
tests: true
4+
concurrency: 4
5+
6+
linters:
7+
enable:
8+
- govet
9+
- errcheck
10+
- staticcheck
11+
- gofmt
12+
- goimports
13+
- revive
14+
- ineffassign
15+
- typecheck
16+
- unused
17+
- gosimple
18+
- misspell
19+
- nakedret
20+
- bodyclose
21+
- gocritic
22+
- makezero
23+
- gosec
24+
25+
output:
26+
formats: colored-line-number
27+
print-issued-lines: true
28+
print-linter-name: true

.goreleaser.yaml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
version: 2
2+
project_name: streamnative-mcp-server
3+
before:
4+
hooks:
5+
- go mod tidy
6+
- go generate ./...
7+
8+
builds:
9+
- env:
10+
- CGO_ENABLED=0
11+
ldflags:
12+
- -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}
13+
goos:
14+
- linux
15+
- windows
16+
- darwin
17+
main: ./cmd/streamnative-mcp-server
18+
19+
archives:
20+
- formats: tar.gz
21+
# this name template makes the OS and Arch compatible with the results of `uname`.
22+
name_template: >-
23+
{{ .ProjectName }}_
24+
{{- title .Os }}_
25+
{{- if eq .Arch "amd64" }}x86_64
26+
{{- else if eq .Arch "386" }}i386
27+
{{- else }}{{ .Arch }}{{ end }}
28+
{{- if .Arm }}v{{ .Arm }}{{ end }}
29+
# use zip for windows archives
30+
format_overrides:
31+
- goos: windows
32+
formats: zip
33+
34+
changelog:
35+
sort: asc
36+
filters:
37+
exclude:
38+
- "^docs:"
39+
- "^test:"
40+
41+
release:
42+
draft: true
43+
prerelease: auto
44+
name_template: "StreamNative MCP Server {{.Version}}"

Makefile

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
BASE_PATH=github.com/streamnative/streamnative-mcp-server
22
VERSION_PATH=main
3-
# GIT_VERSION=$(shell git describe --tags --abbrev=0)-SNAPSHOT-$(shell git rev-parse --short HEAD)
4-
# GIT_COMMIT=$(shell git rev-parse HEAD)
5-
GIT_VERSION=snapshot
6-
GIT_COMMIT=snapshot
3+
GIT_VERSION=$(shell git describe --tags --abbrev=0)-SNAPSHOT-$(shell git rev-parse --short HEAD)
4+
GIT_COMMIT=$(shell git rev-parse HEAD)
75
BUILD_DATE=$(shell date -u +"%Y-%m-%dT%H:%M:%SZ")
86
MKDIR_P = mkdir -p
97

cmd/streamnative-mcp-server/main.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ func newRootCommand(configOpts *config.Options) *cobra.Command {
3838
Short: "StreamNative Cloud MCP Server for AI agent integration",
3939
Long: `StreamNative Cloud MCP Server provides resources and tools for AI agents
4040
to interact with StreamNative Cloud resources and services.`,
41-
Run: func(cmd *cobra.Command, args []string) {
42-
cmd.Help()
41+
Run: func(cmd *cobra.Command, _ []string) {
42+
_ = cmd.Help()
4343
},
4444
Version: fmt.Sprintf("Version: %s\nCommit: %s\nBuild Date: %s", version, commit, date),
4545
}

pkg/auth/store/keyring.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
package store
44

55
import (
6-
"crypto/sha1"
6+
"crypto/sha1" //nolint:gosec
77
"encoding/json"
88
"fmt"
99
"sync"
@@ -180,7 +180,7 @@ func (f *KeyringStore) setItem(item storedItem) error {
180180

181181
// hashKeyringKey creates a safe key based on the given string
182182
func hashKeyringKey(s string) string {
183-
h := sha1.New()
183+
h := sha1.New() //nolint:gosec
184184
h.Write([]byte(s))
185185
bs := h.Sum(nil)
186186
return fmt.Sprintf("%x", bs)

pkg/cmd/mcp/mcp.go

Lines changed: 83 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -38,94 +38,103 @@ func (o *ServerOptions) Complete() error {
3838
snConfig := o.Options.LoadConfigOrDie()
3939

4040
// If the key file is provided, use it to authenticate to StreamNative Cloud
41-
if snConfig.KeyFile != "" {
42-
issuer := snConfig.Auth.Issuer()
41+
switch {
42+
case snConfig.KeyFile != "":
43+
{
44+
issuer := snConfig.Auth.Issuer()
4345

44-
// authorize
45-
flow, err := o.newClientCredentialsFlow(issuer, o.KeyFile)
46-
if err != nil {
47-
return errors.Wrap(err, "configuration error: unable to use client credential flow")
48-
}
49-
grant, err := flow.Authorize()
50-
if err != nil {
51-
return errors.Wrap(err, "activation failed")
52-
}
53-
54-
// persist the authorization data
55-
if err = o.Options.SaveGrant(issuer.Audience, *grant); err != nil {
56-
return errors.Wrap(err, "Unable to store the authorization data")
57-
}
46+
// authorize
47+
flow, err := o.newClientCredentialsFlow(issuer, o.KeyFile)
48+
if err != nil {
49+
return errors.Wrap(err, "configuration error: unable to use client credential flow")
50+
}
51+
grant, err := flow.Authorize()
52+
if err != nil {
53+
return errors.Wrap(err, "activation failed")
54+
}
5855

59-
err = config.InitSNCloudClient(
60-
issuer.IssuerEndpoint, issuer.Audience, o.KeyFile, o.Options.Server, 30*time.Second, o.Options.Store)
61-
if err != nil {
62-
return errors.Wrap(err, "failed to initialize StreamNative Cloud client")
63-
}
56+
// persist the authorization data
57+
if err = o.Options.SaveGrant(issuer.Audience, *grant); err != nil {
58+
return errors.Wrap(err, "Unable to store the authorization data")
59+
}
6460

65-
if o.Options.PulsarInstance != "" && o.Options.PulsarCluster != "" {
66-
err = mcp.SetContext(o.Options, o.Options.PulsarInstance, o.Options.PulsarCluster)
61+
err = config.InitSNCloudClient(
62+
issuer.IssuerEndpoint, issuer.Audience, o.KeyFile, o.Options.Server, 30*time.Second, o.Options.Store)
6763
if err != nil {
68-
return errors.Wrap(err, "failed to set StreamNative Cloud context")
64+
return errors.Wrap(err, "failed to initialize StreamNative Cloud client")
6965
}
70-
}
7166

72-
if len(o.Features) != 0 {
73-
requiredFeatures := []mcp.McpFeature{
74-
mcp.FeatureStreamNativeCloud,
67+
if o.Options.PulsarInstance != "" && o.Options.PulsarCluster != "" {
68+
err = mcp.SetContext(o.Options, o.Options.PulsarInstance, o.Options.PulsarCluster)
69+
if err != nil {
70+
return errors.Wrap(err, "failed to set StreamNative Cloud context")
71+
}
7572
}
76-
for _, feature := range requiredFeatures {
77-
if !slices.Contains(o.Features, string(feature)) {
78-
o.Features = append(o.Features, string(feature))
73+
74+
if len(o.Features) != 0 {
75+
requiredFeatures := []mcp.Feature{
76+
mcp.FeatureStreamNativeCloud,
77+
}
78+
for _, feature := range requiredFeatures {
79+
if !slices.Contains(o.Features, string(feature)) {
80+
o.Features = append(o.Features, string(feature))
81+
}
7982
}
83+
} else {
84+
o.Features = []string{string(mcp.FeatureAll)}
8085
}
81-
} else {
82-
o.Features = []string{string(mcp.FeatureAll)}
8386
}
84-
} else if snConfig.ExternalKafka != nil {
85-
if len(o.Features) != 0 {
86-
return errors.New("kafka-only mode does not support additional features")
87-
}
88-
o.Features = []string{string(mcp.FeatureKafkaClient), string(mcp.FeatureKafkaAdmin), string(mcp.FeatureKafkaAdminSchemaRegistry)}
89-
err := kafka.NewCurrentKafkaContext(kafka.KafkaContext{
90-
BootstrapServers: snConfig.ExternalKafka.BootstrapServers,
91-
AuthType: snConfig.ExternalKafka.AuthType,
92-
AuthMechanism: snConfig.ExternalKafka.AuthMechanism,
93-
AuthUser: snConfig.ExternalKafka.AuthUser,
94-
AuthPass: snConfig.ExternalKafka.AuthPass,
95-
UseTLS: snConfig.ExternalKafka.UseTLS,
96-
ClientKeyFile: snConfig.ExternalKafka.ClientKeyFile,
97-
ClientCertFile: snConfig.ExternalKafka.ClientCertFile,
98-
CaFile: snConfig.ExternalKafka.CaFile,
99-
SchemaRegistryURL: snConfig.ExternalKafka.SchemaRegistryURL,
100-
SchemaRegistryAuthUser: snConfig.ExternalKafka.SchemaRegistryAuthUser,
101-
SchemaRegistryAuthPass: snConfig.ExternalKafka.SchemaRegistryAuthPass,
102-
SchemaRegistryBearerToken: snConfig.ExternalKafka.SchemaRegistryBearerToken,
103-
})
104-
if err != nil {
105-
return errors.Wrap(err, "failed to set external Kafka context")
87+
case snConfig.ExternalKafka != nil:
88+
{
89+
if len(o.Features) != 0 {
90+
return errors.New("kafka-only mode does not support additional features")
91+
}
92+
o.Features = []string{string(mcp.FeatureKafkaClient), string(mcp.FeatureKafkaAdmin), string(mcp.FeatureKafkaAdminSchemaRegistry)}
93+
err := kafka.NewCurrentKafkaContext(kafka.KafkaContext{
94+
BootstrapServers: snConfig.ExternalKafka.BootstrapServers,
95+
AuthType: snConfig.ExternalKafka.AuthType,
96+
AuthMechanism: snConfig.ExternalKafka.AuthMechanism,
97+
AuthUser: snConfig.ExternalKafka.AuthUser,
98+
AuthPass: snConfig.ExternalKafka.AuthPass,
99+
UseTLS: snConfig.ExternalKafka.UseTLS,
100+
ClientKeyFile: snConfig.ExternalKafka.ClientKeyFile,
101+
ClientCertFile: snConfig.ExternalKafka.ClientCertFile,
102+
CaFile: snConfig.ExternalKafka.CaFile,
103+
SchemaRegistryURL: snConfig.ExternalKafka.SchemaRegistryURL,
104+
SchemaRegistryAuthUser: snConfig.ExternalKafka.SchemaRegistryAuthUser,
105+
SchemaRegistryAuthPass: snConfig.ExternalKafka.SchemaRegistryAuthPass,
106+
SchemaRegistryBearerToken: snConfig.ExternalKafka.SchemaRegistryBearerToken,
107+
})
108+
if err != nil {
109+
return errors.Wrap(err, "failed to set external Kafka context")
110+
}
106111
}
107-
} else if snConfig.ExternalPulsar != nil {
108-
if len(o.Features) != 0 {
109-
return errors.New("pulsar-only mode does not support additional features")
112+
case snConfig.ExternalPulsar != nil:
113+
{
114+
if len(o.Features) != 0 {
115+
return errors.New("pulsar-only mode does not support additional features")
116+
}
117+
o.Features = []string{string(mcp.FeatureAllPulsar)}
118+
err := pulsar.NewCurrentPulsarContext(pulsar.PulsarContext{
119+
WebServiceURL: snConfig.ExternalPulsar.WebServiceURL,
120+
AuthPlugin: snConfig.ExternalPulsar.AuthPlugin,
121+
AuthParams: snConfig.ExternalPulsar.AuthParams,
122+
Token: snConfig.ExternalPulsar.Token,
123+
TLSAllowInsecureConnection: snConfig.ExternalPulsar.TLSAllowInsecureConnection,
124+
TLSEnableHostnameVerification: snConfig.ExternalPulsar.TLSEnableHostnameVerification,
125+
TLSTrustCertsFilePath: snConfig.ExternalPulsar.TLSTrustCertsFilePath,
126+
TLSCertFile: snConfig.ExternalPulsar.TLSCertFile,
127+
TLSKeyFile: snConfig.ExternalPulsar.TLSKeyFile,
128+
})
129+
if err != nil {
130+
return errors.Wrap(err, "failed to set external Pulsar context")
131+
}
110132
}
111-
o.Features = []string{string(mcp.FeatureAllPulsar)}
112-
err := pulsar.NewCurrentPulsarContext(pulsar.PulsarContext{
113-
WebServiceURL: snConfig.ExternalPulsar.WebServiceURL,
114-
AuthPlugin: snConfig.ExternalPulsar.AuthPlugin,
115-
AuthParams: snConfig.ExternalPulsar.AuthParams,
116-
Token: snConfig.ExternalPulsar.Token,
117-
TLSAllowInsecureConnection: snConfig.ExternalPulsar.TLSAllowInsecureConnection,
118-
TLSEnableHostnameVerification: snConfig.ExternalPulsar.TLSEnableHostnameVerification,
119-
TLSTrustCertsFilePath: snConfig.ExternalPulsar.TLSTrustCertsFilePath,
120-
TLSCertFile: snConfig.ExternalPulsar.TLSCertFile,
121-
TLSKeyFile: snConfig.ExternalPulsar.TLSKeyFile,
122-
})
123-
if err != nil {
124-
return errors.Wrap(err, "failed to set external Pulsar context")
133+
default:
134+
{
135+
return errors.New("no valid configuration found")
125136
}
126137
}
127-
128-
return nil
129138
}
130139

131140
func (o *ServerOptions) AddFlags(cmd *cobra.Command) {

0 commit comments

Comments
 (0)