Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: Build artifacts

on:
workflow_call:

permissions:
contents: read

jobs:

build:
name: Build and Test
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4

- name: Set up Go
uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5
with:
go-version-file: 'go.mod'
cache: true

- name: Install Task
uses: arduino/setup-task@v2
with:
version: '3.x'
repo-token: ${{ secrets.GITHUB_TOKEN }}

- name: Install dependencies
run: task install

- name: Build
run: task build

- name: Test
run: task test

- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: mkp-server
path: build/mkp-server
retention-days: 7
25 changes: 25 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: Linting

on:
workflow_call:

permissions:
contents: read

jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4

- name: Set up Go
uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5
with:
go-version-file: 'go.mod'
cache: true

- name: Run golangci-lint
uses: golangci/golangci-lint-action@4afd733a84b1f43292c63897423277bb7f4313a9 # v8.0.0
with:
args: --timeout=5m
18 changes: 18 additions & 0 deletions .github/workflows/run-on-main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# These set of workflows run on every push to the main branch
name: Main build

on:
workflow_dispatch:
push:
branches: [ main ]

jobs:
linting:
name: Linting
uses: ./.github/workflows/lint.yml
tests:
name: Tests
uses: ./.github/workflows/test.yml
build:
name: Build
uses: ./.github/workflows/build.yml
14 changes: 14 additions & 0 deletions .github/workflows/run-on-pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# These set of workflows run on every push to the main branch
name: PR Checks

on:
workflow_dispatch:
pull_request:

jobs:
linting:
name: Linting
uses: ./.github/workflows/lint.yml
tests:
name: Tests
uses: ./.github/workflows/test.yml
29 changes: 29 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: Tests

on:
workflow_call:

permissions:
contents: read

jobs:
test:
name: Test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4

- name: Set up Go
uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5
with:
go-version-file: 'go.mod'
cache: true

- name: Install Task
uses: arduino/setup-task@v2
with:
version: '3.x'
repo-token: ${{ secrets.GITHUB_TOKEN }}

- name: Test
run: task test
106 changes: 106 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
version: "2"
run:
issues-exit-code: 1
output:
formats:
text:
path: stdout
print-linter-name: true
print-issued-lines: true
linters:
default: none
enable:
- depguard
- exhaustive
- goconst
- gocyclo
- gosec
- govet
- ineffassign
- lll
- paralleltest
- promlinter
- revive
- staticcheck
- thelper
- tparallel
- unparam
- unused
settings:
depguard:
rules:
prevent_unmaintained_packages:
list-mode: lax
files:
- $all
- '!$test'
deny:
- pkg: io/ioutil
desc: this is deprecated
gocyclo:
min-complexity: 15
gosec:
excludes:
- G601
lll:
line-length: 130
revive:
severity: warning
rules:
- name: blank-imports
severity: warning
- name: context-as-argument
- name: context-keys-type
- name: duplicated-imports
- name: error-naming
- name: error-return
- name: exported
severity: error
- name: if-return
- name: identical-branches
- name: indent-error-flow
- name: import-shadowing
- name: package-comments
- name: redefines-builtin-id
- name: struct-tag
- name: unconditional-recursion
- name: unnecessary-stmt
- name: unreachable-code
- name: unused-parameter
- name: unused-receiver
- name: unhandled-error
disabled: true
exclusions:
generated: lax
rules:
- linters:
- lll
- gocyclo
- errcheck
- dupl
- gosec
- paralleltest
path: (.+)_test\.go
- linters:
- lll
path: .golangci.yml
paths:
- third_party$
- builtin$
- examples$
formatters:
enable:
- gci
- gofmt
settings:
gci:
sections:
- standard
- default
- prefix(github.com/StacklokLabs/mkp)
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$
11 changes: 11 additions & 0 deletions Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,17 @@ tasks:
cmds:
- ./{{.BUILD_DIR}}/{{.BINARY_NAME}}

lint:
desc: Run linting tools
cmds:
- golangci-lint run ./...
- go vet ./...

lint-fix:
desc: Run linting tools, and apply fixes.
cmds:
- golangci-lint run --fix ./...

test:
desc: Run tests
cmds:
Expand Down
16 changes: 8 additions & 8 deletions cmd/server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
// Parse command line flags
kubeconfig := flag.String("kubeconfig", "", "Path to kubeconfig file. If not provided, in-cluster config will be used")
addr := flag.String("addr", ":8080", "Address to listen on")
serveResources := flag.Bool("serve-resources", false, "Whether to serve cluster resources as MCP resources. Setting to false can reduce context size for LLMs when working with large clusters")

Check failure on line 20 in cmd/server/main.go

View workflow job for this annotation

GitHub Actions / Lint

The line is 193 characters long, which exceeds the maximum of 130 characters. (lll)

Check failure on line 20 in cmd/server/main.go

View workflow job for this annotation

GitHub Actions / Linting / Lint

The line is 193 characters long, which exceeds the maximum of 130 characters. (lll)
readWrite := flag.Bool("read-write", false, "Whether to allow write operations on the cluster. When false, the server operates in read-only mode")
kubeconfigRefreshInterval := flag.Duration("kubeconfig-refresh-interval", 0, "Interval to periodically re-read the kubeconfig (e.g., 5m for 5 minutes). If 0, no refresh will be performed")
flag.Parse()
Expand All @@ -40,7 +40,7 @@
if err != nil {
log.Fatalf("Failed to create Kubernetes client: %v", err)
}

// Start periodic refresh if interval is set
if *kubeconfigRefreshInterval > 0 {
log.Printf("Starting periodic kubeconfig refresh every %v", *kubeconfigRefreshInterval)
Expand All @@ -66,10 +66,10 @@

// Create SSE server
sseServer := mcp.CreateSSEServer(mcpServer)

// Channel to receive server errors
serverErrCh := make(chan error, 1)

// Start the server in a goroutine
go func() {
log.Printf("Starting MCP server on %s", *addr)
Expand All @@ -78,19 +78,19 @@
serverErrCh <- err
}
}()

// Wait for either a server error or a shutdown signal
select {
case err := <-serverErrCh:
log.Fatalf("Server failed to start: %v", err)
case <-ctx.Done():
log.Println("Shutting down server...")
}

// Create a context with timeout for shutdown
shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 5*time.Second)
defer shutdownCancel()

// Attempt to shut down the server gracefully
shutdownCh := make(chan error, 1)
go func() {
Expand All @@ -102,7 +102,7 @@
shutdownCh <- err
close(shutdownCh)
}()

// Wait for shutdown to complete or timeout
select {
case err, ok := <-shutdownCh:
Expand All @@ -118,7 +118,7 @@
// Force exit after timeout
os.Exit(1)
}

log.Println("Server shutdown complete, exiting...")
// Ensure we exit the program
os.Exit(0)
Expand Down
2 changes: 1 addition & 1 deletion pkg/k8s/refresh_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,4 +186,4 @@ func TestRefreshClientWithRealClients(t *testing.T) {
ctx := context.Background()
_, err = client.ListAPIResources(ctx)
assert.NoError(t, err, "ListAPIResources should not return an error after refresh")
}
}
Loading
Loading