Skip to content

Commit b0b8189

Browse files
authored
Merge pull request #333 from txn2/fix/improvements
MCP improvements for stability and distribution
2 parents f2c248a + 684f61a commit b0b8189

File tree

25 files changed

+3332
-71
lines changed

25 files changed

+3332
-71
lines changed

.github/workflows/release.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,22 @@ jobs:
6060
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
6161
HOMEBREW_TAP_GITHUB_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
6262

63+
- name: Build MCPB bundles
64+
run: |
65+
# Extract version from tag (remove 'v' prefix)
66+
VERSION="${GITHUB_REF_NAME#v}"
67+
./mcpb/build.sh "$VERSION" --use-dist
68+
69+
- name: Upload MCPB bundles to release
70+
env:
71+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
72+
run: |
73+
# Upload each .mcpb file to the release
74+
for mcpb in dist/mcpb/*.mcpb; do
75+
echo "Uploading $mcpb..."
76+
gh release upload "$GITHUB_REF_NAME" "$mcpb" --clobber
77+
done
78+
6379
- name: Generate artifact hashes
6480
id: hash
6581
run: |

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
[![Docker Pulls](https://img.shields.io/docker/pulls/txn2/kubefwd)](https://hub.docker.com/r/txn2/kubefwd)
1111
[![GitHub Downloads](https://img.shields.io/github/downloads/txn2/kubefwd/total)](https://github.com/txn2/kubefwd/releases)
1212

13-
**[Documentation](https://kubefwd.com)** | **[Getting Started](https://kubefwd.com/getting-started/)** | **[TUI Guide](https://kubefwd.com/tui-guide/)**
13+
**[Documentation](https://kubefwd.com)** | **[Getting Started](https://kubefwd.com/getting-started/)** | **[TUI Guide](https://kubefwd.com/tui-guide/)** | **[API Reference](https://kubefwd.com/api-reference/)** | **[MCP (AI Integration)](https://kubefwd.com/mcp-integration/)**
1414

1515
## Develop Locally, Connect to Kubernetes
1616

cmd/kubefwd/kubefwd.go

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ func init() {
8484
}
8585

8686
log.SetOutput(&LogOutputSplitter{})
87-
if len(args) > 0 && (args[0] == "completion" || args[0] == "__complete") {
87+
if len(args) > 0 && (args[0] == "completion" || args[0] == "__complete" || args[0] == "mcp") {
8888
log.SetOutput(io.Discard)
8989
}
9090
}
@@ -146,6 +146,20 @@ func isTUIMode() bool {
146146
return false
147147
}
148148

149+
// isMCPMode checks if running the mcp subcommand
150+
func isMCPMode() bool {
151+
for _, arg := range os.Args[1:] {
152+
if arg == "mcp" {
153+
return true
154+
}
155+
// Stop at first non-flag argument
156+
if !strings.HasPrefix(arg, "-") {
157+
break
158+
}
159+
}
160+
return false
161+
}
162+
149163
// isKnownSubcommand checks if arg is a known subcommand
150164
func isKnownSubcommand(arg string) bool {
151165
knownCommands := map[string]bool{
@@ -171,8 +185,8 @@ func main() {
171185
os.Args = append([]string{os.Args[0], "svc"}, args...)
172186
}
173187

174-
// Only print banner in non-TUI mode
175-
if !isTUIMode() {
188+
// Only print banner in non-TUI, non-MCP mode
189+
if !isTUIMode() && !isMCPMode() {
176190
log.Print(` _ _ __ _`)
177191
log.Print(`| | ___ _| |__ ___ / _|_ ____| |`)
178192
log.Print(`| |/ / | | | '_ \ / _ \ |_\ \ /\ / / _ |`)

docs/api-reference.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@ sudo -E kubefwd svc -n default --api
1515
curl http://kubefwd.internal/api/health
1616
```
1717

18-
The API is available at `http://kubefwd.internal/api`. Interactive documentation is at `http://kubefwd.internal/docs`.
18+
The API is available at `http://kubefwd.internal/api`.
19+
20+
Interactive documentation is at `http://kubefwd.internal/docs`.
21+
22+
![API Documentation](images/API-docs.png)
1923

2024
## Overview
2125

docs/images/API-docs.png

392 KB
Loading

docs/mcp-integration.md

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,16 @@ sudo -E kubefwd # Idle mode, API enabled
107107
108108
### 2. Configure Your AI
109109

110+
=== "Claude Desktop (One-Click)"
111+
112+
Download the `.mcpb` bundle for your platform from [GitHub Releases](https://github.com/txn2/kubefwd/releases):
113+
114+
- **macOS (Apple Silicon):** `kubefwd-VERSION-darwin-arm64.mcpb`
115+
- **macOS (Intel):** `kubefwd-VERSION-darwin-amd64.mcpb`
116+
- **Windows:** `kubefwd-VERSION-windows-amd64.mcpb`
117+
118+
Double-click the downloaded file to install kubefwd as a Claude Desktop extension.
119+
110120
=== "Claude Code (Easy)"
111121

112122
One command to add kubefwd:
@@ -207,23 +217,34 @@ That's it. Start talking to your AI about your work.
207217

208218
## What Your AI Can Do
209219

210-
### Access Dependencies
211-
- Connect to any cluster service by name
212-
- Set up your local dev environment
213-
- Discover available services and databases
214-
- Switch between clusters and namespaces
215-
216-
### Test Your Deployments
217-
- Forward and test newly deployed services
218-
- Make HTTP requests and report results
219-
- Monitor traffic and bandwidth
220-
- Stream pod logs
221-
222-
### Troubleshoot
223-
- Diagnose connection failures
224-
- Auto-reconnect stale forwards
225-
- Analyze HTTP traffic patterns
226-
- Identify misconfigured services
220+
### Service Forwarding
221+
222+
- **Forward entire namespaces** - Forward all services in a namespace to localhost with automatic `/etc/hosts` entries
223+
- **Forward individual services** - Forward specific services with custom port mappings
224+
- **Remove forwards** - Stop forwarding namespaces or individual services
225+
226+
### Discovery & Connection
227+
228+
- **List Kubernetes contexts** - See available clusters from your kubeconfig
229+
- **List namespaces** - Discover what namespaces are available and which are forwarded
230+
- **List services** - See services in a namespace with their types, ports, and selectors
231+
- **Get connection info** - Get ready-to-use connection strings, IPs, hostnames, and environment variables
232+
- **Find services** - Search forwarded services by name pattern, port, or namespace
233+
234+
### Monitoring & Debugging
235+
236+
- **Quick status** - Fast health check of kubefwd (healthy/degraded/unhealthy)
237+
- **View logs** - Filter by level (debug, info, warn, error) or search terms
238+
- **Get metrics** - Bandwidth stats, bytes in/out, transfer rates, per-service breakdown
239+
- **HTTP traffic** - View requests flowing through forwards (method, path, status code, response time)
240+
- **Event history** - Track events, errors, and reconnections over time
241+
242+
### Troubleshooting
243+
244+
- **Diagnose errors** - Root cause analysis with specific fix suggestions
245+
- **Get analysis** - Full issue classification with priorities and recommended actions
246+
- **Reconnect services** - Force reconnection for errored or stale services
247+
- **Sync services** - Re-discover pods after deployments or pod restarts
227248

228249
---
229250

mcpb/build.sh

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
#!/bin/bash
2+
# Build MCPB bundles for Claude Desktop
3+
# Usage: ./mcpb/build.sh [version] [--use-dist]
4+
#
5+
# This script creates platform-specific .mcpb bundles for:
6+
# - macOS (darwin) amd64 and arm64
7+
# - Windows amd64
8+
#
9+
# Options:
10+
# --use-dist Use binaries from goreleaser's dist/ folder instead of building
11+
#
12+
# Prerequisites:
13+
# - Go toolchain (if building from source)
14+
# - goreleaser dist/ output (if using --use-dist)
15+
16+
set -e
17+
18+
VERSION="${1:-dev}"
19+
USE_DIST=false
20+
21+
# Check for --use-dist flag
22+
for arg in "$@"; do
23+
if [ "$arg" = "--use-dist" ]; then
24+
USE_DIST=true
25+
fi
26+
done
27+
28+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
29+
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
30+
BUILD_DIR="$PROJECT_ROOT/dist/mcpb"
31+
MANIFEST_TEMPLATE="$SCRIPT_DIR/manifest.json"
32+
33+
echo "Building MCPB bundles for kubefwd v${VERSION}"
34+
if [ "$USE_DIST" = true ]; then
35+
echo "Using pre-built binaries from dist/"
36+
fi
37+
38+
# Clean and create build directory
39+
rm -rf "$BUILD_DIR"
40+
mkdir -p "$BUILD_DIR"
41+
42+
# Platforms to build for (Claude Desktop supports macOS and Windows)
43+
# Format: GOOS:GOARCH:goreleaser_dir_suffix
44+
PLATFORMS=(
45+
"darwin:amd64:darwin_amd64_v1"
46+
"darwin:arm64:darwin_arm64"
47+
"windows:amd64:windows_amd64_v1"
48+
)
49+
50+
for platform in "${PLATFORMS[@]}"; do
51+
IFS=':' read -r GOOS GOARCH DIST_SUFFIX <<< "$platform"
52+
53+
PLATFORM_NAME="${GOOS}-${GOARCH}"
54+
BUNDLE_DIR="$BUILD_DIR/kubefwd-${PLATFORM_NAME}"
55+
56+
echo ""
57+
echo "=== Building for ${PLATFORM_NAME} ==="
58+
59+
# Create bundle directory
60+
mkdir -p "$BUNDLE_DIR"
61+
62+
# Determine binary name
63+
BINARY_NAME="kubefwd"
64+
if [ "$GOOS" = "windows" ]; then
65+
BINARY_NAME="kubefwd.exe"
66+
fi
67+
68+
if [ "$USE_DIST" = true ]; then
69+
# Use goreleaser's pre-built binary
70+
DIST_BINARY="$PROJECT_ROOT/dist/kubefwd_${DIST_SUFFIX}/${BINARY_NAME}"
71+
if [ ! -f "$DIST_BINARY" ]; then
72+
echo "ERROR: Binary not found at $DIST_BINARY"
73+
echo "Make sure goreleaser has run first, or omit --use-dist to build from source"
74+
exit 1
75+
fi
76+
echo "Copying ${BINARY_NAME} from dist/..."
77+
cp "$DIST_BINARY" "$BUNDLE_DIR/$BINARY_NAME"
78+
else
79+
# Build from source
80+
echo "Compiling ${BINARY_NAME}..."
81+
CGO_ENABLED=0 GOOS="$GOOS" GOARCH="$GOARCH" go build \
82+
-trimpath \
83+
-tags=netgo \
84+
-ldflags="-s -w -X main.Version=${VERSION}" \
85+
-o "$BUNDLE_DIR/$BINARY_NAME" \
86+
"$PROJECT_ROOT/cmd/kubefwd/kubefwd.go"
87+
fi
88+
89+
# Copy and update manifest
90+
echo "Creating manifest.json..."
91+
sed "s/\"version\": \"0.0.0\"/\"version\": \"${VERSION}\"/" "$MANIFEST_TEMPLATE" > "$BUNDLE_DIR/manifest.json"
92+
93+
# Create .mcpb bundle
94+
MCPB_FILE="$BUILD_DIR/kubefwd-${VERSION}-${PLATFORM_NAME}.mcpb"
95+
96+
echo "Packaging ${MCPB_FILE}..."
97+
if command -v mcpb &> /dev/null; then
98+
# Use official mcpb CLI if available
99+
mcpb pack "$BUNDLE_DIR" "$MCPB_FILE"
100+
else
101+
# Fallback to zip (mcpb files are just zip archives)
102+
echo "Note: mcpb CLI not found, using zip fallback"
103+
(cd "$BUNDLE_DIR" && zip -r "$MCPB_FILE" .)
104+
fi
105+
106+
echo "Created: $MCPB_FILE"
107+
done
108+
109+
echo ""
110+
echo "=== Build complete ==="
111+
echo "MCPB bundles created in: $BUILD_DIR"
112+
ls -la "$BUILD_DIR"/*.mcpb 2>/dev/null || echo "No .mcpb files found"

mcpb/manifest.json

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
{
2+
"manifest_version": "0.3",
3+
"name": "kubefwd",
4+
"display_name": "kubefwd",
5+
"version": "0.0.0",
6+
"description": "Kubernetes port forwarding for local development. Forward services from any namespace to localhost with automatic /etc/hosts entries.",
7+
"long_description": "kubefwd is a command line utility for bulk forwarding Kubernetes services to your local machine. It creates local loopback IP addresses for each service, adds entries to /etc/hosts, and lets you access cluster services by name - just like you're running inside the cluster. Perfect for local development against microservices.",
8+
"author": {
9+
"name": "Craig Johnston",
10+
"email": "cj@imti.co",
11+
"url": "https://imti.co"
12+
},
13+
"repository": {
14+
"type": "git",
15+
"url": "https://github.com/txn2/kubefwd"
16+
},
17+
"homepage": "https://kubefwd.com",
18+
"documentation": "https://kubefwd.com/mcp-integration/",
19+
"license": "Apache-2.0",
20+
"keywords": [
21+
"kubernetes",
22+
"k8s",
23+
"port-forward",
24+
"development",
25+
"microservices",
26+
"local-development",
27+
"devops"
28+
],
29+
"server": {
30+
"type": "binary",
31+
"entry_point": "kubefwd",
32+
"mcp_config": {
33+
"command": "${__dirname}/kubefwd",
34+
"args": ["mcp"],
35+
"env": {}
36+
},
37+
"platform_overrides": {
38+
"win32": {
39+
"command": "${__dirname}/kubefwd.exe",
40+
"args": ["mcp"]
41+
}
42+
}
43+
},
44+
"compatibility": {
45+
"claude_desktop": ">=1.0.0",
46+
"platforms": ["darwin", "win32"],
47+
"runtimes": {}
48+
},
49+
"tools": [
50+
{
51+
"name": "add_namespace",
52+
"description": "Forward all services in a namespace to localhost"
53+
},
54+
{
55+
"name": "remove_namespace",
56+
"description": "Stop forwarding a namespace"
57+
},
58+
{
59+
"name": "add_service",
60+
"description": "Forward a single service"
61+
},
62+
{
63+
"name": "remove_service",
64+
"description": "Stop forwarding a service"
65+
},
66+
{
67+
"name": "get_connection_info",
68+
"description": "Get connection details for a forwarded service"
69+
},
70+
{
71+
"name": "list_services",
72+
"description": "List all forwarded services"
73+
},
74+
{
75+
"name": "find_services",
76+
"description": "Search forwarded services"
77+
},
78+
{
79+
"name": "get_quick_status",
80+
"description": "Fast health check"
81+
},
82+
{
83+
"name": "diagnose_errors",
84+
"description": "Diagnose connection issues"
85+
},
86+
{
87+
"name": "reconnect_service",
88+
"description": "Reconnect a failed service"
89+
}
90+
],
91+
"user_config": {
92+
"kubeconfig": {
93+
"type": "file",
94+
"title": "Kubeconfig",
95+
"description": "Path to kubeconfig file (optional, uses default if not set)",
96+
"required": false
97+
}
98+
},
99+
"_meta": {
100+
"claude_desktop": {
101+
"category": "Development Tools",
102+
"featured": false
103+
}
104+
}
105+
}

0 commit comments

Comments
 (0)