Skip to content

feat(mcp): advertise native args object on call_tool_* variants #1175

feat(mcp): advertise native args object on call_tool_* variants

feat(mcp): advertise native args object on call_tool_* variants #1175

Workflow file for this run

name: E2E Tests
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
jobs:
# Build frontend once and share across all jobs
build-frontend:
name: Build Frontend
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
cache-dependency-path: frontend/package-lock.json
- name: Install frontend dependencies
run: cd frontend && npm ci
- name: Build frontend
run: cd frontend && npm run build
- name: Upload frontend artifact
uses: actions/upload-artifact@v4
with:
name: frontend-dist-e2e
path: frontend/dist/
retention-days: 1
e2e-tests:
name: End-to-End Tests
needs: build-frontend
runs-on: ${{ matrix.os }}
env:
GO111MODULE: "on"
strategy:
matrix:
# On PRs: test only latest Go on ubuntu-latest
# On main/push: test full matrix
os: ${{ github.event_name == 'pull_request' && fromJSON('["ubuntu-latest"]') || fromJSON('["ubuntu-latest", "macos-latest", "windows-latest"]') }}
go-version: ${{ github.event_name == 'pull_request' && fromJSON('["1.25"]') || fromJSON('["1.23.10", "1.24.5", "1.25"]') }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go-version }}
cache: true
- name: Download dependencies
run: go mod download
- name: Verify dependencies
run: go mod verify
- name: Download frontend artifact
uses: actions/download-artifact@v4
with:
name: frontend-dist-e2e
path: frontend/dist
- name: Copy frontend dist for embedding
shell: bash
run: |
mkdir -p web/frontend
cp -r frontend/dist web/frontend/
- name: Build mcpproxy binary for tests (Windows)
if: matrix.os == 'windows-latest'
env:
CGO_ENABLED: "0"
run: go build -tags nogui -o mcpproxy.exe ./cmd/mcpproxy
- name: Build mcpproxy binary for tests (Unix)
if: matrix.os != 'windows-latest'
env:
CGO_ENABLED: "0"
run: go build -tags nogui -o mcpproxy ./cmd/mcpproxy
- name: Run unit tests
run: go test -v -race -timeout 2m -skip "Binary|MCP|E2E|TestInfoEndpoint|TestGracefulShutdownNoPanic|TestSocketInfoEndpoint" ./internal/...
# Binary tests are too flaky in CI due to server startup timing issues
# All Binary tests consistently timeout waiting for server to be ready
# The binary compilation is verified by the build step, and functionality
# is tested via unit tests and mock-based E2E tests
# - name: Run Binary tests (Windows)
# if: matrix.os == 'windows-latest'
# env:
# MCPPROXY_BINARY_PATH: ${{ github.workspace }}/mcpproxy.exe
# run: go test -v -race -timeout 3m ./internal/server -run 'TestBinary'
#
# - name: Run Binary tests (Unix)
# if: matrix.os != 'windows-latest'
# env:
# MCPPROXY_BINARY_PATH: ${{ github.workspace }}/mcpproxy
# run: go test -v -race -timeout 3m ./internal/server -run 'TestBinary'
- name: Run MCP Protocol tests
run: go test -v -race -timeout 5m ./internal/server -run TestMCP -skip 'TestMCPProtocolWithBinary|TestMCPProtocolComplexWorkflows|TestMCPProtocolToolCalling|TestMCPProtocolEdgeCases'
env:
GO_TEST_TIMEOUT: 300s
- name: Run E2E tests
run: go test -v -race -timeout 5m ./internal/server -run TestE2E -skip 'TestE2E_ToolDiscovery|TestE2E_ServerDeleteReaddDifferentTools'
env:
GO_TEST_TIMEOUT: 300s
- name: Check for skipped security tests
shell: bash
run: |
echo "Verifying that security-critical authentication tests were not skipped..."
# Run the security test explicitly and capture output
go test -v -timeout 2m ./internal/server -run TestE2E_TrayToCore_UnixSocket 2>&1 | tee security_test_output.log
# Check for skipped API key security tests
if grep -q "SKIP.*TCP_NoAPIKey_Fail" security_test_output.log; then
echo "::error::CRITICAL SECURITY: TCP_NoAPIKey_Fail test was skipped!"
echo "::error::This test verifies TCP connections require API key authentication."
echo "::error::Skipping this test could allow authentication bypass vulnerabilities."
echo "::error::See issue #159 for details."
exit 1
fi
if grep -q "SKIP.*TCP_WithAPIKey_Success" security_test_output.log; then
echo "::error::CRITICAL SECURITY: TCP_WithAPIKey_Success test was skipped!"
echo "::error::This test verifies TCP connections with valid API keys are accepted."
echo "::error::Skipping this test could allow authentication bypass vulnerabilities."
echo "::error::See issue #159 for details."
exit 1
fi
echo "✅ All security tests executed successfully (no skips detected)"
- name: Run Logging E2E tests
run: go test -v -race -timeout 5m ./internal/logs -run TestE2E
env:
GO_TEST_TIMEOUT: 300s
- name: Run E2E tests with race detector
if: matrix.os == 'ubuntu-latest' && matrix.go-version == '1.23.10'
run: go test -v -race -timeout 10m ./internal/server -run TestE2E
env:
GO_TEST_TIMEOUT: 600s
- name: Run Logging E2E tests with race detector
if: matrix.os == 'ubuntu-latest' && matrix.go-version == '1.23.10'
run: go test -v -race -timeout 10m ./internal/logs -run TestE2E
env:
GO_TEST_TIMEOUT: 600s
integration-tests:
name: Integration Tests
runs-on: ubuntu-latest
needs: [build-frontend, e2e-tests]
env:
GO111MODULE: "on"
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: "1.25"
cache: true
- name: Download frontend artifact
uses: actions/download-artifact@v4
with:
name: frontend-dist-e2e
path: frontend/dist
- name: Copy frontend dist for embedding
run: |
mkdir -p web/frontend
cp -r frontend/dist web/frontend/
- name: Build mcpproxy
env:
CGO_ENABLED: "0"
run: go build -tags nogui -o mcpproxy ./cmd/mcpproxy
- name: Test mcpproxy binary
run: |
# Test version command
./mcpproxy --version
# Test help command
./mcpproxy --help
# Test logging functionality
timeout 10s ./mcpproxy serve --log-to-file --log-level debug --listen :0 || true
# Verify log file was created in standard OS location
if [ "$(uname)" = "Linux" ]; then
if [ -f "$HOME/.local/state/mcpproxy/logs/main.log" ]; then
echo "✓ Log file created in Linux standard location"
head -5 "$HOME/.local/state/mcpproxy/logs/main.log"
else
echo "⚠ Log file not found in expected location"
fi
fi
- name: Run tests with coverage (Windows)
if: matrix.os == 'windows-latest'
shell: pwsh
run: |
go test -v -race '-coverprofile=coverage.out' -covermode=atomic ./internal/server -run TestE2E -skip 'TestE2E_ToolDiscovery|TestE2E_ServerDeleteReaddDifferentTools'
go test -v -race '-coverprofile=coverage-logs.out' -covermode=atomic ./internal/logs -run TestE2E
go tool cover '-html=coverage.out' -o coverage.html
go tool cover '-html=coverage-logs.out' -o coverage-logs.html
- name: Run tests with coverage (Unix)
if: matrix.os != 'windows-latest'
run: |
go test -v -race -coverprofile=coverage.out -covermode=atomic ./internal/server -run TestE2E -skip 'TestE2E_ToolDiscovery|TestE2E_ServerDeleteReaddDifferentTools'
go test -v -race -coverprofile=coverage-logs.out -covermode=atomic ./internal/logs -run TestE2E
go tool cover -html=coverage.out -o coverage.html
go tool cover -html=coverage-logs.out -o coverage-logs.html
- name: Upload coverage reports
uses: codecov/codecov-action@v3
with:
file: ./coverage.out
flags: e2e-tests
name: e2e-coverage
fail_ci_if_error: false
logging-tests:
name: Cross-Platform Logging Tests
needs: build-frontend
runs-on: ${{ matrix.os }}
env:
GO111MODULE: "on"
strategy:
matrix:
# On PRs: test only on ubuntu-latest
# On main/push: test on all platforms
os: ${{ github.event_name == 'pull_request' && fromJSON('["ubuntu-latest"]') || fromJSON('["ubuntu-latest", "macos-latest", "windows-latest"]') }}
include:
- os: ubuntu-latest
log_path_check: "$HOME/.local/state/mcpproxy/logs"
log_standard: "XDG Base Directory Specification"
- os: macos-latest
log_path_check: "$HOME/Library/Logs/mcpproxy"
log_standard: "macOS File System Programming Guide"
- os: windows-latest
log_path_check: "$env:LOCALAPPDATA\\mcpproxy\\logs"
log_standard: "Windows Application Data Guidelines"
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: "1.25"
cache: true
- name: Download frontend artifact
uses: actions/download-artifact@v4
with:
name: frontend-dist-e2e
path: frontend/dist
- name: Copy frontend dist for embedding
shell: bash
run: |
mkdir -p web/frontend
cp -r frontend/dist web/frontend/
- name: Run logging unit tests
run: go test -v -race -timeout 2m ./internal/logs
- name: Run logging E2E tests
run: go test -v -race -timeout 5m ./internal/logs -run TestE2E
- name: Build mcpproxy for logging test (Windows)
if: matrix.os == 'windows-latest'
env:
CGO_ENABLED: "0"
run: go build -tags nogui -o mcpproxy.exe ./cmd/mcpproxy
- name: Build mcpproxy for logging test (Unix)
if: matrix.os != 'windows-latest'
env:
CGO_ENABLED: "0"
run: go build -tags nogui -o mcpproxy ./cmd/mcpproxy
- name: Test OS-specific log directory creation (Unix)
if: matrix.os != 'windows-latest'
run: |
echo "Testing logging on ${{ matrix.os }}"
echo "Expected log path: ${{ matrix.log_path_check }}"
echo "OS Standard: ${{ matrix.log_standard }}"
# Run mcpproxy briefly to create log files
./mcpproxy serve --log-to-file --log-level info --listen :0 &
MCPPROXY_PID=$!
sleep 5
kill $MCPPROXY_PID 2>/dev/null || true
wait $MCPPROXY_PID 2>/dev/null || true
# Check if log directory was created
if [ -d "${{ matrix.log_path_check }}" ]; then
echo "✓ Log directory created successfully"
ls -la "${{ matrix.log_path_check }}"
# Check if log file exists and has content
if [ -f "${{ matrix.log_path_check }}/main.log" ]; then
echo "✓ Log file created successfully"
echo "Log file size: $(wc -c < "${{ matrix.log_path_check }}/main.log") bytes"
echo "First few lines:"
head -3 "${{ matrix.log_path_check }}/main.log"
# Verify log contains expected content
if grep -q "Log directory configured" "${{ matrix.log_path_check }}/main.log"; then
echo "✓ Log contains expected startup messages"
else
echo "⚠ Log missing expected startup messages"
fi
if grep -q "${{ matrix.log_standard }}" "${{ matrix.log_path_check }}/main.log"; then
echo "✓ Log contains OS standard compliance information"
else
echo "⚠ Log missing OS standard compliance information"
fi
else
echo "✗ Log file not created"
exit 1
fi
else
echo "✗ Log directory not created"
exit 1
fi
- name: Test OS-specific log directory creation (Windows)
if: matrix.os == 'windows-latest'
shell: pwsh
run: |
Write-Host "Testing logging on Windows"
Write-Host "Expected log path: $env:LOCALAPPDATA\mcpproxy\logs"
Write-Host "OS Standard: Windows Application Data Guidelines"
# Run mcpproxy briefly to create log files
try {
$process = Start-Process -FilePath "./mcpproxy.exe" -ArgumentList "serve", "--log-to-file", "--log-level", "info", "--listen", ":0" -NoNewWindow -PassThru
Start-Sleep -Seconds 5
$process | Stop-Process -Force -ErrorAction SilentlyContinue
} catch {
Write-Host "Error starting/stopping mcpproxy: $_"
}
# Check if log directory was created
$logPath = "$env:LOCALAPPDATA\mcpproxy\logs"
if (-not (Test-Path $logPath)) {
Write-Host "✗ Log directory not created"
exit 1
}
Write-Host "✓ Log directory created successfully"
Get-ChildItem $logPath
# Check if log file exists and has content
$logFile = Join-Path $logPath "main.log"
if (-not (Test-Path $logFile)) {
Write-Host "✗ Log file not created"
exit 1
}
Write-Host "✓ Log file created successfully"
$fileSize = (Get-Item $logFile).Length
Write-Host "Log file size: $fileSize bytes"
Write-Host "First few lines:"
Get-Content $logFile -Head 3
# Verify log contains expected content
$content = Get-Content $logFile -Raw
if ($content -match "Log directory configured") {
Write-Host "✓ Log contains expected startup messages"
} else {
Write-Host "⚠ Log missing expected startup messages"
}
if ($content -match "Windows Application Data Guidelines") {
Write-Host "✓ Log contains OS standard compliance information"
} else {
Write-Host "⚠ Log missing OS standard compliance information"
}
- name: Test log rotation
if: matrix.os == 'ubuntu-latest'
run: |
echo "Testing log rotation functionality"
go test -v -timeout 2m ./internal/logs -run TestE2E_LogRotation
- name: Test concurrent logging
if: matrix.os == 'ubuntu-latest'
run: |
echo "Testing concurrent logging functionality"
go test -v -race -timeout 3m ./internal/logs -run TestE2E_ConcurrentLogging
oauth-tests:
name: OAuth E2E Tests
runs-on: ubuntu-latest
needs: build-frontend
env:
GO111MODULE: "on"
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: "1.25"
cache: true
- name: Download dependencies
run: go mod download
- name: Run OAuth test server unit tests
run: go test -v -race -timeout 5m ./tests/oauthserver/...
- name: Run OAuth integration tests
env:
OAUTH_INTEGRATION_TESTS: "1"
run: go test -v -race -timeout 5m ./tests/oauthserver/... -run TestIntegration
stress-tests:
name: Stress Tests
runs-on: ubuntu-latest
needs: [build-frontend, e2e-tests]
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: "1.25"
cache: true
- name: Download frontend artifact
uses: actions/download-artifact@v4
with:
name: frontend-dist-e2e
path: frontend/dist
- name: Copy frontend dist for embedding
run: |
mkdir -p web/frontend
cp -r frontend/dist web/frontend/
- name: Run concurrent stress tests
run: |
# Run the concurrent test multiple times to catch race conditions
for i in {1..5}; do
echo "Stress test iteration $i"
go test -v -race -timeout 10m ./internal/server -run TestE2E_ConcurrentOperations
done
- name: Run memory stress test
run: |
# Run tests with memory limit
GOMAXPROCS=1 GOMEMLIMIT=100MiB go test -v -timeout 15m ./internal/server -run TestE2E