Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
31 changes: 7 additions & 24 deletions .github/workflows/ci.yml → .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -1,39 +1,22 @@
name: CI
name: Build artifacts

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
workflow_call:

jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
permissions:
contents: read

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

- name: golangci-lint
uses: golangci/golangci-lint-action@v8
with:
version: latest
jobs:

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

- name: Set up Go
uses: actions/setup-go@v5
uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5
with:
go-version-file: 'go.mod'
cache: true
Expand Down
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
20 changes: 20 additions & 0 deletions .github/workflows/run-on-main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# These set of workflows run on every push to the main branch
name: Main build
permissions:
contents: read

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
16 changes: 16 additions & 0 deletions .github/workflows/run-on-pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# These set of workflows run on every push to the main branch
name: PR Checks
permissions:
contents: read

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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,5 @@ Thumbs.db

# Kubeconfig files
kubeconfig
.kubeconfig
.kubeconfig
**/.claude/settings.local.json
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
26 changes: 15 additions & 11 deletions cmd/server/main.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Package main provides the entry point for the mkp server application
package main

import (
Expand All @@ -17,9 +18,12 @@ func main() {
// 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")
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")
serveResources := flag.Bool("serve-resources", false,
"Whether to serve cluster resources as MCP resources. Setting to false reduces context size for LLMs with large clusters")
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()

// Create a context that can be cancelled
Expand All @@ -40,7 +44,7 @@ func main() {
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 +70,10 @@ func main() {

// 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 +82,19 @@ func main() {
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 +106,7 @@ func main() {
shutdownCh <- err
close(shutdownCh)
}()

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

log.Println("Server shutdown complete, exiting...")
// Ensure we exit the program
os.Exit(0)
Expand Down
Loading