Skip to content
Closed
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
70 changes: 70 additions & 0 deletions homebrew/Casks/mcpproxy.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# typed: false
# frozen_string_literal: true

# Homebrew cask for MCPProxy Tray App (macOS GUI application)
# To install from the tap:
# brew tap smart-mcp-proxy/mcpproxy
# brew install --cask mcpproxy
#
# The cask installs the tray app (GUI) which includes the core server.
# For the headless CLI only, use: brew install mcpproxy

cask "mcpproxy" do
version "0.20.2"

on_arm do
sha256 "ec7dafc012b5d7c08b582b5a70f8e7db2216758e5e27e0fbf1d385f212c26998"
url "https://github.com/smart-mcp-proxy/mcpproxy-go/releases/download/v#{version}/mcpproxy-#{version}-darwin-arm64-installer.dmg",
verified: "github.com/smart-mcp-proxy/mcpproxy-go/"
end

on_intel do
sha256 "912031a7dc739641016c9fa79d76d1292e415cd781f5a4766eebd2cbc0fc4b9a"
url "https://github.com/smart-mcp-proxy/mcpproxy-go/releases/download/v#{version}/mcpproxy-#{version}-darwin-amd64-installer.dmg",
verified: "github.com/smart-mcp-proxy/mcpproxy-go/"
end

name "MCPProxy"
desc "Smart MCP proxy with intelligent tool discovery for AI agents"
homepage "https://mcpproxy.app"

livecheck do
url :url
strategy :github_latest
end

depends_on macos: ">= :monterey"

on_arm do
pkg "mcpproxy-#{version}-darwin-arm64.pkg"
end

on_intel do
pkg "mcpproxy-#{version}-darwin-amd64.pkg"
end

uninstall pkgutil: "com.smartmcpproxy.mcpproxy",
launchctl: "com.smartmcpproxy.mcpproxy",
delete: [
"/usr/local/bin/mcpproxy",
]

zap trash: [
"~/.mcpproxy",
"~/Library/Logs/mcpproxy",
]

caveats <<~EOS
MCPProxy has been installed!

To start the tray app, open MCPProxy from your Applications folder.

To use the CLI directly:
mcpproxy serve # Start the server
mcpproxy doctor # Run health checks
mcpproxy upstream list # List upstream servers

Configuration: ~/.mcpproxy/mcp_config.json
Documentation: https://docs.mcpproxy.app
EOS
end
81 changes: 81 additions & 0 deletions homebrew/Formula/mcpproxy.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# typed: false
# frozen_string_literal: true

# Homebrew formula for MCPProxy CLI (headless server)
# To install from the tap:
# brew tap smart-mcp-proxy/mcpproxy
# brew install mcpproxy
#
# To submit to homebrew-core, see homebrew/README.md

class Mcpproxy < Formula
desc "Smart MCP proxy with intelligent tool discovery for AI agents"
homepage "https://mcpproxy.app"
url "https://github.com/smart-mcp-proxy/mcpproxy-go/archive/refs/tags/v0.20.2.tar.gz"
sha256 "aec23fff361d3bc9c874de0a37472301404bdeed18b4625dddcef492fb364914"
license "MIT"
head "https://github.com/smart-mcp-proxy/mcpproxy-go.git", branch: "main"

depends_on "go" => :build
depends_on "node" => :build

def install
# Generate TypeScript types from Go contracts (needed before frontend build)
system "go", "run", "./cmd/generate-types"

# Build frontend (embedded in the binary via go:embed)
cd "frontend" do
system "npm", "install"
system "npm", "run", "build"
end

# Copy frontend dist for embedding
mkdir_p "web/frontend"
cp_r "frontend/dist", "web/frontend/"

ldflags = %W[
-s -w
-X main.version=v#{version}
-X main.commit=brew
-X main.date=#{time.iso8601}
-X github.com/smart-mcp-proxy/mcpproxy-go/internal/httpapi.buildVersion=v#{version}
]
system "go", "build", *std_go_args(ldflags: ldflags), "./cmd/mcpproxy"
end

def post_install
(var/"log/mcpproxy").mkpath
end

service do
run [opt_bin/"mcpproxy", "serve"]
keep_alive true
log_path var/"log/mcpproxy/output.log"
error_log_path var/"log/mcpproxy/error.log"
end

test do
# Verify version output
assert_match "MCPProxy v#{version}", shell_output("#{bin}/mcpproxy version")

# Verify help output
assert_match "Smart MCP Proxy", shell_output("#{bin}/mcpproxy --help")

# Verify serve command exists
assert_match "serve", shell_output("#{bin}/mcpproxy --help")

# Try starting the server briefly to verify it can bind
port = free_port
pid = fork do
exec bin/"mcpproxy", "serve", "--listen", "127.0.0.1:#{port}"
end
sleep 2

# Check the status endpoint responds
output = shell_output("curl -sf http://127.0.0.1:#{port}/api/v1/status 2>/dev/null || true")
assert_match "edition", output if output.length > 0
ensure
Process.kill("TERM", pid) if pid
Process.wait(pid) if pid
end
end
131 changes: 131 additions & 0 deletions homebrew/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
# Homebrew Distribution for MCPProxy

MCPProxy is distributed via Homebrew in two ways:

| Package | Type | What it installs |
|---------|------|-----------------|
| `mcpproxy` (formula) | CLI | Headless server binary, built from source |
| `mcpproxy` (cask) | GUI | macOS tray app + CLI via signed PKG installer |

## Quick Start

### Install the CLI (formula, builds from source)

```bash
brew tap smart-mcp-proxy/mcpproxy
brew install mcpproxy
```

### Install the tray app (cask, prebuilt DMG)

```bash
brew tap smart-mcp-proxy/mcpproxy
brew install --cask mcpproxy
```

## Setting Up the Tap Repository

The tap repository must be created at `github.com/smart-mcp-proxy/homebrew-mcpproxy` with
this directory structure:

```
homebrew-mcpproxy/
Formula/
mcpproxy.rb # copy from homebrew/Formula/mcpproxy.rb
Casks/
mcpproxy.rb # copy from homebrew/Casks/mcpproxy.rb
```

### Steps

1. Create the repo:
```bash
gh repo create smart-mcp-proxy/homebrew-mcpproxy --public \
--description "Homebrew tap for MCPProxy"
```

2. Copy the formula and cask files:
```bash
git clone git@github.com:smart-mcp-proxy/homebrew-mcpproxy.git
cd homebrew-mcpproxy
mkdir -p Formula Casks
cp /path/to/mcpproxy-go/homebrew/Formula/mcpproxy.rb Formula/
cp /path/to/mcpproxy-go/homebrew/Casks/mcpproxy.rb Casks/
git add -A && git commit -m "Add mcpproxy formula and cask"
git push
```

3. Test:
```bash
brew tap smart-mcp-proxy/mcpproxy
brew install mcpproxy # formula (CLI)
brew install --cask mcpproxy # cask (tray app)
```

## Updating to a New Release

Run the update script from the mcpproxy-go repo:

```bash
./homebrew/update-formula.sh v0.21.0 # specific version
./homebrew/update-formula.sh # auto-detect latest
```

This downloads the source tarball and DMG assets, computes SHA256 hashes, and updates
both files in place. Then copy the updated files to the tap repo and push.

## Submitting to homebrew-core

The `mcpproxy` formula (CLI) can be submitted to homebrew-core once the project meets
the acceptance criteria:

### Requirements

- **75+ GitHub stars** (currently 155+, met)
- **30+ forks OR 30+ watchers** (check current count)
- **No vendored dependencies** (uses Go modules, OK)
- **MIT license** (met)
- **Stable versioning** (met, uses semver tags)
- **Working test block** (included)

### Submission Steps

1. Fork `Homebrew/homebrew-core`
2. Add `Formula/m/mcpproxy.rb` with the formula content
3. Run local checks:
```bash
brew audit --new --formula Formula/m/mcpproxy.rb
brew install --build-from-source Formula/m/mcpproxy.rb
brew test Formula/m/mcpproxy.rb
```
4. Open a PR to `Homebrew/homebrew-core`

### Notes for homebrew-core

- Remove the `head` stanza (not allowed in homebrew-core)
- Remove the `typed` and `frozen_string_literal` comments
- The `service` block is allowed in homebrew-core
- The `node` build dependency is acceptable (many Go projects embed web UIs)

## Submitting the Cask to homebrew-cask

Casks have a higher bar for acceptance:

### Requirements

- **225+ GitHub stars** (not yet met, currently ~155)
- Signed and notarized macOS binary (met)
- Stable download URLs (met, GitHub Releases)

### When ready

1. Fork `Homebrew/homebrew-cask`
2. Add `Casks/m/mcpproxy.rb` with the cask content
3. Run:
```bash
brew audit --new --cask Casks/m/mcpproxy.rb
brew install --cask Casks/m/mcpproxy.rb
```
4. Open a PR to `Homebrew/homebrew-cask`

Until then, the cask is available through the tap (`brew tap smart-mcp-proxy/mcpproxy`).
90 changes: 90 additions & 0 deletions homebrew/update-formula.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#!/bin/bash
set -euo pipefail

# Update Homebrew formula and cask with new version and SHA256 hashes.
# Usage:
# ./homebrew/update-formula.sh v0.21.0
# ./homebrew/update-formula.sh # auto-detect latest release

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
FORMULA="${SCRIPT_DIR}/Formula/mcpproxy.rb"
CASK="${SCRIPT_DIR}/Casks/mcpproxy.rb"
REPO="smart-mcp-proxy/mcpproxy-go"

# Determine version
if [ -n "${1:-}" ]; then
VERSION="${1#v}"
TAG="v${VERSION}"
else
echo "Auto-detecting latest release..."
TAG=$(gh release view --repo "${REPO}" --json tagName -q '.tagName')
VERSION="${TAG#v}"
fi

echo "Updating Homebrew files to version ${VERSION} (tag ${TAG})"

# --- Source tarball (formula) ---
SOURCE_URL="https://github.com/${REPO}/archive/refs/tags/${TAG}.tar.gz"
echo "Downloading source tarball..."
SOURCE_SHA256=$(curl -sL "${SOURCE_URL}" | shasum -a 256 | awk '{print $1}')
echo " Source SHA256: ${SOURCE_SHA256}"

# --- DMG assets (cask) ---
ARM64_DMG_URL="https://github.com/${REPO}/releases/download/${TAG}/mcpproxy-${VERSION}-darwin-arm64-installer.dmg"
AMD64_DMG_URL="https://github.com/${REPO}/releases/download/${TAG}/mcpproxy-${VERSION}-darwin-amd64-installer.dmg"

echo "Downloading arm64 DMG..."
ARM64_SHA256=$(curl -sL "${ARM64_DMG_URL}" | shasum -a 256 | awk '{print $1}')
echo " arm64 DMG SHA256: ${ARM64_SHA256}"

echo "Downloading amd64 DMG..."
AMD64_SHA256=$(curl -sL "${AMD64_DMG_URL}" | shasum -a 256 | awk '{print $1}')
echo " amd64 DMG SHA256: ${AMD64_SHA256}"

# --- Update formula ---
echo "Updating formula..."

# Update URL
sed -i '' "s|url \"https://github.com/${REPO}/archive/refs/tags/v[^\"]*\.tar\.gz\"|url \"https://github.com/${REPO}/archive/refs/tags/${TAG}.tar.gz\"|" "${FORMULA}"

# Update SHA256
sed -i '' "/^ url.*archive\/refs\/tags/{ n; s/sha256 \"[a-f0-9]*\"/sha256 \"${SOURCE_SHA256}\"/; }" "${FORMULA}"

echo " Formula updated."

# --- Update cask ---
echo "Updating cask..."

# Update version
sed -i '' "s/version \"[^\"]*\"/version \"${VERSION}\"/" "${CASK}"

# Update arm64 SHA256 (first sha256 in the file, inside on_arm block)
# Use awk for precise block-aware replacement
awk -v arm_sha="${ARM64_SHA256}" -v amd_sha="${AMD64_SHA256}" '
/on_arm do/ { in_arm=1 }
/on_intel do/ { in_arm=0; in_intel=1 }
/^ end$/ { in_arm=0; in_intel=0 }
in_arm && /sha256/ { sub(/sha256 "[a-f0-9]*"/, "sha256 \"" arm_sha "\"") }
in_intel && /sha256/ { sub(/sha256 "[a-f0-9]*"/, "sha256 \"" amd_sha "\"") }
{ print }
' "${CASK}" > "${CASK}.tmp" && mv "${CASK}.tmp" "${CASK}"

echo " Cask updated."

# --- Summary ---
echo ""
echo "=== Update Summary ==="
echo "Version: ${VERSION}"
echo "Source SHA256: ${SOURCE_SHA256}"
echo "arm64 DMG SHA256: ${ARM64_SHA256}"
echo "amd64 DMG SHA256: ${AMD64_SHA256}"
echo ""
echo "Files updated:"
echo " ${FORMULA}"
echo " ${CASK}"
echo ""
echo "Next steps:"
echo " 1. Review changes: git diff homebrew/"
echo " 2. Test formula: brew install --build-from-source homebrew/Formula/mcpproxy.rb"
echo " 3. Test cask: brew install --cask homebrew/Casks/mcpproxy.rb"
echo " 4. Commit: git add homebrew/ && git commit -m 'homebrew: update to ${VERSION}'"
Loading